Welcome back to another Epsilon update! We hope you had a nice start to 2019, and that you are excited for this month’s update. After the many reveals for December and several questions we’ve had from fans, we decided to share a more technical update for this month.

One of the most complex systems in Pokémon is of course the battling. Over 20 years of development and additions to Pokémon has made it so that this system is a large undertaking to replicate. In the last year we’ve made large strides in this, so today we’ll be explaining how this system works.

One of the first things we did for our battling code was splitting up the graphical front end from the logic back end. This means our code can easily be run without any of the graphical overhead, which allows for useful functionality, such as unit testing and machine learning. An entire battle can be run in milliseconds!

After this the actual battle loop is somewhat simple. Each Pokémon chooses what it wants to do; for example, choosing a specific move, switching into another Pokémon, or running away, after which the actual turn runs. The choices are gathered, ordered according to type, priority, and speed, and then run sequentially.

Up until this point the logic for battling was fairly simple. However, battling starts getting more interesting when unique effects, such as those related to moves, abilities, and so on, start to be considered. Without these effects battling would indeed be very bland, and as such each has its own unique flavour.

We thought long and hard about how to handle these effects best. We wanted to make these effects easily accessible and editable to less experienced, starting-up fangame developers, and allow our users to be able to mod these files later on. To accommodate this, we decided to handle these effects through easy to edit scripts. We initially worked with Lua, but its dynamic typing combined with the sometimes complex types in the battle library meant this was harder to work with, and issues often crept into the scripts.

To resolve the issue with Lua, we decided to write a simple new language for this, which combined Lua’s simple syntax with a static type system. This language, called Upsilon, along with its VS Code plugin, makes it very easy to write new effects for battling.

An example effect, specifically for the move Blizzard, can be found below:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 -- When a move actually hits a Pokémon, this function triggers, -- with as parameters the move as its being executed (this contains -- things such as the user, the effectiveness per hit per Pokémon, etc), -- the target Pokémon and what hit this is (for multi-hit moves) function onMoveHit ( iExecutingMove move, iBattlePokémon target, number hitNumber ) -- roll a 10% chance (This can of course be modified by effects such as Serene Grace) if (move.battle.random.effectChance(move.user, target, 10 )) then -- and if this returns true, make the Pokémon frozen target.setStatus( "frozen" ) end end -- Override the accuracy of the move function overrideAccuracy ( iExecutingMove move, numRef acc, iBattlePokemon target) -- If there is a weather effect, and this weather is Hail if move.battle.weather ~= nil and move.battle.weather.scriptName == "hail" then -- The move should always hit (we use -1 for this) acc.set( - 1 ) end end

Blizzard is a relatively simple move of course, and there exist many more complex moves (as well as many more simple moves).

There exist more of these specific trigger functions for specific individual effects, and it’s fairly easy to add more of these functions as we continue along.

We are currently working on writing all these effects and making sure they all behave as we’d expect them to, using many unit tests, and hope to get all of this done for you as fast as possible.

Are you interested in helping with this undertaking? We are still looking for enthusiastic experienced developers on our team, so apply now!

This concludes our monthly update, make sure to follow us on our Twitter and subreddit!





All reside, confined evermore, until stirred.