• Our software update is now concluded. You will need to reset your password to log in. In order to do this, you will have to click "Log in" in the top right corner and then "Forgot your password?".
  • Welcome to PokéCommunity! Register now and join one of the best fan communities on the 'net to talk Pokémon and more! We are not affiliated with The Pokémon Company or Nintendo.

[Discussion] Pokémon Battle System help 2 (Java)

LCCoolJ95

Limited Capacity
638
Posts
14
Years
  • Happy Sunday, so I have an odd question to ask in terms of a project that I want to do for school. So, my goal is to create a Pokemon Battle System, not a game. I just want to create something that is similar in the vain of Pokemon Showdown, albeit a few changes. I want make this in a language that I feel comfortable working with, Java. I already created objects (classes) for the Pokemon, I'm thinking about making some for the abilities, items, and moves as well. I even made a separate project within the main project that has constants of the pokemon, abilities, moves, and items. I should make one for natures too, and other possible interactions. The only problem I have is that I can't seem to find the "raw code" of how the battle system works. How it counts the amount of turns for moves like Future Sight, and switch in, etc. I also couldn't really find the raw code of battle/ability effects too. So I was wondering if someone could point me in the right direction of some sort, that would be awesome! I do have some formulas, like how stats are boosted/reduced.
     
    2,243
    Posts
    19
    Years
  • I cannot provide the code, but I can give some guidelines as to how to replicate it just by observing behavioral patterns. I've been slowly developing an engine in C, so I have had to give this some thought (though it being C, I don't have the same luxury of using objects as in Java).

    1. Carefully establish the "battle context", or rather the the variables needed to keep track of the status of the battle. Decompose what composes a battle context into useful objects. I would likely decompose a battle context into BattleContext(), MonsterSlot(), and PokemonInstance() objects at the very least, based on the variables that need to be taken into account. The BattleContext() object would keep track of context variables like weather, terrain, gravity, and so on. The MonsterSlot() object would keep track of multi-turn moves (such as Future Sight, as mentioned), volatile status conditions (confusion, attract, and so on), stat modifications, and so on. The PokemonInstance() object could keep track of current stats, current forms, non-volatile status (like burn, poison, etc).

    2. Think of the battle system as a state machine. It first iterates the battle context and sets up the turn (doing things like checking to see if a weather effect has expired). Secondly, it listens to the player for their decision. Then it processes what the AI is going to do (I wouldn't let the AI take into consideration the decisions of the player, but that's up to you). From there, it calculates the outcome of the turn. Finally, it checks to see if an end condition has been met. If not, it loops back to the turn setup step. If yes, it then branches to ether a win handler or a loss handler. Of course, this is a simplification of the battle system, as there is a lot to take into consideration.

    3. Carefully consider the way certain moves act. Multi-turn moves like Wish and Future Sight need to decrement a constant number of turns until they reach zero to apply. Other turns like Double Kick apply for a variable number of turns. You can use a countdown in the MonsterSlot() object and a turn-count generator function to generate the amount of turns left until the attack takes effect or until the attack ends. The actual move effect would be either a function or an object's method (depending on how you structure moves).
     

    LCCoolJ95

    Limited Capacity
    638
    Posts
    14
    Years
  • I was thinking about using boolean arrays, sort like flags that set whether or not a Pokemon has a certain non-volatile status, a weather/terrain is up, etc. Am I allowed to post the things that I already made and discuss my process?
     
    2,243
    Posts
    19
    Years
  • Of course you can post what you've already done.

    In terms of non-volatile statuses, were you thinking about allowing a Pokémon to be inflicted by more than one? If so, the boolean array would definitely work. If not and you want the Pokémon to only be inflicted by one like the actual games, I would say use an 8-bit unsigned integer as an ID flag.

    Also, consider bitwise operations. You can take a Java byte and store 8 boolean values inside (while at the same time using the same amount of data as a standard boolean). So if you have eight boolean values you always want to take to the same places, store them in a byte and perform bitwise 'and' operations and then shift the bits to get the value of the boolean you want.

    // For example:

    byte x = 0b00010100;
    bool y = (bool)((x >> 2) & 0b1);

    // y resolves as True.
     
    Last edited:
    1,403
    Posts
    10
    Years
    • Seen Apr 29, 2024
    Alistair said:
    In terms of non-volatile statuses, were you thinking about allowing a Pokémon to be inflicted by more than one? If so, the boolean array would definitely work.

    Also, consider bitwise operations. You can take a Java byte and store 8 boolean values inside (while at the same time using the same amount of data as a standard boolean). So if you have eight boolean values you always want to take to the same places, store them in a byte and perform bitwise 'and' operations and then shift the bits to get the value of the boolean you want.

    Note, you're probably better off using EnumSet in Java, rather than rolling your own, since it'll do the same bit packing for you, and is both much more idiomatic, and (IMO) much more readable.
     
    971
    Posts
    7
    Years
    • Age 21
    • Seen Nov 28, 2022
    Also, consider bitwise operations. You can take a Java byte and store 8 boolean values inside (while at the same time using the same amount of data as a standard boolean). So if you have eight boolean values you always want to take to the same places, store them in a byte and perform bitwise 'and' operations and then shift the bits to get the value of the boolean you want.

    Why would you want to use bitwise operations for such simple and small tasks, when the language has a nice and convenient boolean data type? That's just making things harder and more confusing on yourself.
    If memory is really such a pressing issue, then surely the Pokemon class that LCC made can be optimized to use each and every bit, too, just like ROM Hacks.

    But I don't really see how any game made in 2020 would want to be so extremely minimal and confusing as was the case for GBA games and the like; we have much more than a few megabytes available to us. Might as well make use of them.
     

    LCCoolJ95

    Limited Capacity
    638
    Posts
    14
    Years
  • Of course you can post what you've already done.

    In terms of non-volatile statuses, were you thinking about allowing a Pokémon to be inflicted by more than one? If so, the boolean array would definitely work. If not and you want the Pokémon to only be inflicted by one like the actual games, I would say use an 8-bit unsigned integer as an ID flag.

    Also, consider bitwise operations. You can take a Java byte and store 8 boolean values inside (while at the same time using the same amount of data as a standard boolean). So if you have eight boolean values you always want to take to the same places, store them in a byte and perform bitwise 'and' operations and then shift the bits to get the value of the boolean you want.
    So here's what I got for the Pokémon object/class:
    Spoiler:
    Let me explain each value:
    pokemonID represents the ID of a Pokémon from a database that I will develop on the side, same goes for pokemonName. Right now, nickname is commented out because I wasn't too sure about it for now.
    baseStats are in an array of 6 integer values, instead of having six different variables. For me, this is a lot easier and more compact.
    heldItem represents the item id from the item table within the future database that will be created.
    Gender, base friendship, and weight will be used to calculate the power of certain moves, or moves that involve infatuation (probably going to turn weight into a double instead of an int).
    Ability is the same for Pokémon and items, but an abilities table within the database.
    EVs and IVs will be in arrays instead of having 6 variables each. I don't know if this is more efficient. If not, I'm up for input.
    moveset, currentPP, and PPUps have arrays of 4 instead of 6 because a moveset can only have 4 moves.

    The next few are interesting, the three Boolean arrays. The way I thought about this was using this:
    https://bulbapedia.bulbagarden.net/wiki/Status_condition
    And sort of using the arrays like flags in a Pokémon game. For example, if a Pokémon is paralyzed, one Boolean value in the nonvolatile array will be set to true, so that way it can't be burned, paralyzed, or put to sleep. Unless the Pokémon uses Rest, but that seems easy hopefully, just turn that part of the array to false, and asleep to on.
    realStats are going to use the baseStats array to calculate what a Pokémon's stat will read. For example, if I have a Blissey with 252 EVs and 31 IVs in HP, it should calculated and give me a Blissey with 716 HP. battleStats are the stats during the battle that can be manipulated (stat change, HP loss, etc.)
    Finally, an isShiny flag to, well, determine if the Pokémon is shiny or not.

    That's what I have so far, though I have ideas of creating Move, Item, and Ability objects. Just not too sure on how to implement them, you know? If anyone has any input, I'd love to hear it.

    Btw, are enums like C Header files where it can be used for constants. Cause if so, whoops. I made classes full of the values. Could that work, or switch over?
     
    1,403
    Posts
    10
    Years
    • Seen Apr 29, 2024
    Since you have base stats, IVs and EVs that are all the same type I'd probably create a class for stats (although it would be much nicer in a language that has lightweight "struct" syntax, like Scala's case classes).
    Code:
    class Stats {
      public final int hp, attack, defense, specialAttack, specialDefense, speed;
      public Stats(hp, attack, defense, specialAttack, specialDefense, speed) {
        this.hp = hp;
        this.attack =  attack;
        // etc...
      }
    }
    Personally I think it's fine to make these things public since they're final.

    Enums are named values. So you might do something like:
    Code:
    enum Stat {
      HP,
      ATTACK,
      DEFENSE,
      SPECIAL_ATTACK,
      SPECIAL_DEFENSE,
      SPEED
    }

    And then have something like getStat on your Stats class that does something like:
    Code:
      public int getStat(Stat stat) {
        switch (stat) {
        case HP: return hp;
        case ATTACK: return attack;
        // etc...
        }
      }

    The nice up-side of doing it this way is that you never have to worry about reading outside of your array's bounds.

    EDIT: Also I think an enum is more appropriate for your non-volatile status since you can only have one at a time. IMO you want to design your data structures so that any possible combination of values is a valid object (as much as is possible, this isn't particularly easy to do in Java). You'll probably want to have an int or something for the status to store data in too, since sleep and toxic care about the number of turns. Or actually, probably better to have a NonVolatile interface, and make each status implement it. That way you make sure that only the statuses that need to have an extra field actually have one.

    Code:
    public abstract class NonVolatile {
      public void endOfTurn(Pokemon pokemon) {} // For Poison and Burn to damage the Pokémon.
      public int modifyStat(int value, Stat stat) { return value; } // For Burn and Paralyze to cut their stats.
      public bool canAttack() { return true; } // For Sleep, Freeze and Paralyze.
    }
    
    public class ToxicPoison {
      private int turns;
      public ToxicPoison() { turns = 0; }
      public void endOfTurn(Pokemon pokemon) {
        turns++;
        pokemon.hp -= pokemon.maxHP * turns / 16;
      }
    }
     
    Last edited:

    LCCoolJ95

    Limited Capacity
    638
    Posts
    14
    Years
  • Since you have base stats, IVs and EVs that are all the same type I'd probably create a class for stats (although it would be much nicer in a language that has lightweight "struct" syntax, like Scala's case classes).
    Code:
    class Stats {
      public final int hp, attack, defense, specialAttack, specialDefense, speed;
      public Stats(hp, attack, defense, specialAttack, specialDefense, speed) {
        this.hp = hp;
        this.attack =  attack;
        // etc...
      }
    }
    Personally I think it's fine to make these things public since they're final.

    Enums are named values. So you might do something like:
    Code:
    enum Stat {
      HP,
      ATTACK,
      DEFENSE,
      SPECIAL_ATTACK,
      SPECIAL_DEFENSE,
      SPEED
    }

    And then have something like getStat on your Stats class that does something like:
    Code:
      public int getStat(Stat stat) {
        switch (stat) {
        case HP: return hp;
        case ATTACK: return attack;
        // etc...
        }
      }

    The nice up-side of doing it this way is that you never have to worry about reading outside of your array's bounds.

    EDIT: Also I think an enum is more appropriate for your non-volatile status since you can only have one at a time. IMO you want to design your data structures so that any possible combination of values is a valid object (as much as is possible, this isn't particularly easy to do in Java). You'll probably want to have an int or something for the status to store data in too, since sleep and toxic care about the number of turns. Or actually, probably better to have a NonVolatile interface, and make each status implement it. That way you make sure that only the statuses that need to have an extra field actually have one.

    Code:
    public abstract class NonVolatile {
      public void endOfTurn(Pokemon pokemon) {} // For Poison and Burn to damage the Pokémon.
      public int modifyStat(int value, Stat stat) { return value; } // For Burn and Paralyze to cut their stats.
      public bool canAttack() { return true; } // For Sleep, Freeze and Paralyze.
    }
    
    public class ToxicPoison {
      private int turns;
      public ToxicPoison() { turns = 0; }
      public void endOfTurn(Pokemon pokemon) {
        turns++;
        pokemon.hp -= pokemon.maxHP * turns / 16;
      }
    }
    Oh, I see. But wait, why a class for Stats? Wouldn't it be easier to just have it as an array variable, or is there something I'm missing? And in terms of the methods at the bottom of your post, I'm probably going to need help figuring out that part. Some moves don't do the same thing, obviously, but others have special effects that seem trivial. For example, Trick Room. It's easy to figure out who goes first (Priority is decided, then the Speed stat of each), but Trick Room flips the speed. Plus, moves that can count (i.e. Perish Song, Future Sight, etc.).
     
    1,403
    Posts
    10
    Years
    • Seen Apr 29, 2024
    Oh, I see. But wait, why a class for Stats? Wouldn't it be easier to just have it as an array variable, or is there something I'm missing?

    Because they aren't some random collection of zero-or-more ints, which is what an array is, they're exactly six positive (not checked in my code, to be fair) ints. If you want the class to be implemented as an array of ints, that would be better than directly using a plain array, but personally I'd still prefer having each stat with its own field because you can look at getStat and know that it cannot raise an exception, and your compiler knows that too. If you introduced a new stat into the Stat enum you'd get a compile error. Whereas if you resize your array so that it holds 7 ints you won't get any help knowing which bits to update, and worse yet, if you start trying to use the 7th element without having resized the array you'll just crash at runtime.

    Similarly I think having the Stat enum is better than using ints, because then the code makes more sense, compare these two possible bits of Move:
    Code:
    class Move {
      public Stat attackStat;
      public Stat defenseStat;
    }
    
    class Move {
      public int attackStat;
      public int defenseStat;
    }
    They look pretty similar, except that the first one you'd get a compile error if you made a mistake and thought that those were the values, not the indexes. attackStat + defenseStat compiles if they're both ints, even though that's nonsense.

    That said, I appreciate that lots of developers don't like to use types as much as I do, and while I wholeheartedly believe they're wrong, I don't want to argue about it over the internet.
     
    Back
    Top