Thread: Development: Adding [a] new type[s] in gen 3?
View Single Post
Old January 29th, 2013 (2:15 AM). Edited January 30th, 2013 by Jambo51.
Jambo51's Avatar
Jambo51 Jambo51 is offline
Glory To Arstotzka
    Join Date: Jun 2009
    Gender: Male
    Nature: Quiet
    Posts: 732
    So, last night, I worked out how type effectiveness is done in FireRed. You'll be pleased to know that it's relatively simple. Firstly, the method of storage:

    [Attack type - 1 byte][Target Type - 1 Byte][Effectiveness value - 1 Byte]
    This data is stored at 0x24F050.

    There are several of these, kept in an array which ends with a 0xFE value. The game loops over each entry in the array, checking if the attack type matches the used attack's type, and if it does, then checks the Target Type against the 2 types of the targeted Pokémon.

    If either type matches, it loads the effectiveness byte and branches off to another routine which takes care of physically making the attack super effective/not effective. The type effectiveness values are as follows:

    Note, these are in hex
    00 - Has No effect (Eg, Ghost on Normal)
    05 - 50% effectiveness
    14 - 200% Effectiveness
    These values are used as they represent 0%, 50% and 200% respectively of 0xA (10). The gamd multiplies the calculated damage by whatever value is present after working out type effectiveness, and multiplies the current damage value by it. It then divides by 10, this giving us a satisfactory answer.

    In essence:
    private short TypeEffectiveness (short existingDamage, byte attackType)
        byte value = rom[0x24F050];
        int counter = 0;
        while (value != 0xFE)
            if (value == attackType)
                for (int i = 0; i < 2; i++)
                    byte targetType = ram[0x2023C05 + (ram[0x2023D6C] * 0x58) + i];
                    if (targetType == rom[0x24F050 + counter + 1])
                        byte effectivenessValue = rom[0x24F050 + counter + 2];
                        ChangeEffectiveness(effectivenessValue, existingDamage);
            counter += 3;
            value = rom[0x24F050 + counter];
        return existingDamage;
    Hopefully, that high level language recreation will help explain what it does.

    What you may gleam from these values, however, is that, unless explicitly told otherwise, the game treats all moves as normal effectiveness on any type.

    If neither type matches, it jumps to the loop counter, increments it and continues checking until it hits that magical 0xFE value.

    However, the way it is implemented leaves something to be desired as it is very slow (looping over several entries), and taking up more space than needed, both in terms of code and data. It's obviously wasteful in so far as it continues to check even after having already found both effectiveness values, as well as the wasteful nature of the loop in and of itself.
    Hey guys, please check out my recreations of the gen 1 and 2 music on my custom engine at my SoundCloud! - Here!
    Reply With Quote