
FNaF Discord Bot
This project is a completely re-implementation of FNaF’s internal game logic as a finite state machine, that is displayed to and controlled from discord.
You can invite the bot to your server using this invite link and play with it yourself.
Original Version
This isn’t the first time I’ve attempted this. The original version of this bot worked by running the actual game. It would then screenshot it to display on discord. When an input was entered, A set of preprogrammed mouse movements and clicks would execute using PyAutoGUI to perform that action. Additionally, PyAutoGUI would attempt to detect what screen it was on by using known objects on the screen.
While this worked and played okayish, it had lots of problems:
- There was a large delay before display the frame to the user and accepting input
- The game would often failed to detect what screens it was on.
- There were frequent crashes due to entering impossible conditions
- Screenshots often had static or black screens because of ingame flickering
Overall, it was just too fragile to keep working on, even after putting in a lot of work to fix the bugs that came up.
Furthermore, only one instance of the game could be run at a time and it would use my PC to do it. This meant that it was infeasible to distrubute to the public as it often leaked my desktop and I couldn’t just have the game running 24/7.
I started investigating using a Linux Virtual Machine providing a VNC view into the game, however this wouldn’t fix the problems with instability and latency.
2.0
When I came back to this project, my new plan was to completely re-implement the game’s logic in typescript and render the game using screenshots.
While this might sound a bit ambitious, it was suprising doable. Internally, the game uses a small set of renders to display the cameras and office. Additionally, the game’s size is quite small so re-implementing the logic is reasonably feasible. This meant that I actually stood a chance at re-creating the game.
Getting access to the screenshots was the easy part. Using the CTFAK decompiler, I could access all the images and import them into my project. Annyoingly, I had to manually create the office screenshots, since the buttons and animatronics were rendered together by pasting over part of the image. However, this was only 16 combinations I had to make, so I did this by hand.
Now for the hard part, reimplementing the logic. After looking through a few AI breakdowns and frequently consulting the wiki, I was able to replicate the AI quite accurately.
All the characters move on a fixed interval. When it’s their time to move they roll a number between 0-20 and if the number is below it’s current AI level, they’ll move to their next step. They’ll keep doing this until they reaches your office.
If your door is closed when they attempt to enter the office, they’ll instead teleport back a few steps. If the door is open, you’ll game over after putting your cameras down.
Finite State Machine
I originally planned to implement this in realtime using setTimeout
, however this became difficult to keep track of and debug. However, since the game’s state is so simple I realised I could represent it in a finite state machine.
This meant the entire render interval was essentially:
let state = createInitialGame(settings)
while (!state.isGameOver) {
inputs = getInputs()
state = tick(state, inputs)
render(state)
}
This made debugging incredibly easy as I could simply view the entire game state after each frame. Additionally, I could tune the game speed to be more fair for someone playing on discord.
Having the entire state as a single object was really powerful. It meant I could do unit testing, by simply acting on the state and checking the changes.
Image Caching
An issue I ran into early on way the delay for displaying a frame, since it would take a few seconds to upload and the user to download. However, since I would be reuploading the same images again and again I could upload them once and just link back to the images to embed. I had the bot upload all the images in a private discord channel and then store the links.
The End Result
The final result was a very playable game of FNaF that you could play entirely over discord. The entire project start to finish took about 5 days. I’m quite happy to have to attempted a project that I’d previously failed on and come out with a much better version, as well as being able to use discopic in an actual project
It was also nice to get experience on creating game logic. It’s something I’m a bit lacking on and It’s good to get some practice in. It’s something I aim to do with most of my projects, just step a little outside my comfort zone in order to get some new skills.