• 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] [Tutorial] How to add three type Pokemon

220
Posts
13
Years
    • Seen Nov 29, 2021
    How to add a third type:

    WARNING: This tutorial will break anything that relies upon [PBEffects::Type3], which is used for moves that assign a third type. It's possible to make those moves function and have three-typed Pokemon, but that is beyond the scope of this tutorial.

    Step 1: Assign a free byte to your third type. The numbers available for use should be listed in def pbCompilePokemonData under Complier. For this example we'll be using "X" (make sure to use an actual number for yours).
    To do this, find where "Type2" is in pbCompilePokemonData (just scroll down a bit), and copy it. Then change the name from "Type2" to "Type3". Your code should look something like this:
    Code:
    "Habitat"=>[7,...],
    "Type2"=>[9,"e",PBTypes],
    "Type3"=>[X,"e",PBTypes],
    "HiddenAbility"=>[40,...],

    Great, now we've established a data byte for our third type, on to step 2!



    Step 2: Getting Type3= from pokemon.txt. This can seem quite complex. Don't worry! Take it slow, and make changes one step at a time. Personally I like to copy anything I'm changing, and then comment out the original with hashtags (#) so that I have a backuhp in case something goes wrong. If something does go wrong, just revert to the previous step!

    Still in Compiler, find the following section:
    Code:
    if !lastsection["Type2"] || lastsection["Type2"]==""
                if !lastsection["Type1"] || lastsection["Type1"]==""
                  raise _INTL("No Pokémon type is defined in section {2} (PBS/pokemon.txt)",key,sectionDisplay) if hash==requiredtypes
                  next
                end
             lastsection["Type2"]=lastsection["Type1"].clone[/]
    		 end

    This is what reads Type2 from pokemon.txt, and if it's missing makes it the same as Type1. Thankfully we don't have to modify this at all.
    Instead, just before the first line, insert this line:
    Code:
    if !lastsection["Type3"] || lastsection["Type3"]==""
    What this does is checks to see if Type3 is missing or blank and if it is, does something (in our case, we'll be making it set Type3 to Type2).
    Now to actually assign Type3 we need to put something after:
    Code:
    lastsection["Type2"]=lastsection["Type1"].clone[/]
    We need to assign Type3. To do that, add this on the next line:
    Code:
            lastsection["Type3"]=lastsection["Type2"].clone
            end

    And we're done with step 2! At this point our code should look like this:
    Code:
            if !lastsection["Type3"] || lastsection["Type3"]==""
              if !lastsection["Type2"] || lastsection["Type2"]==""
                if !lastsection["Type1"] || lastsection["Type1"]==""
                  raise _INTL("No Pokémon type is defined in section {2} (PBS/pokemon.txt)",key,sectionDisplay) if hash==requiredtypes
                  next
                end
              lastsection["Type2"]=lastsection["Type1"].clone
              end
            lastsection["Type3"]=lastsection["Type2"].clone
            end



    Step 3: Assigning the type to a Pokemon.
    Go to PokeBattle_Pokemon (it should be near the very bottom of the list), and search for:
    Code:
    def type2
    Beneath that section, add this:
    Code:
    # Returns this pokemon's third type.
      def type3
        dexdata=pbOpenDexData
        pbDexDataOffset(dexdata,@species,10)
        ret=dexdata.fgetb
        dexdata.close
        return ret
      end
    It's that simple! Almost. We also have to do some work to PokeBattle_Battler. Head over there and find where it says "attr_accessor :type2". Just beneath that add in "attr_accessor :type3". Likewise beneath
    Code:
    @type2        = pkmn.type2
    add
    Code:
    @type3        = pkmn.type3
    (Note: This happens in two places, don't miss one!)

    Under def pbInitBlank, find:
    Code:
    @type2        = 0
    and add
    Code:
    @type3        = 0

    Under def pbUpdate, find:
    Code:
    @type2   = @pokemon.type2
    and add
    Code:
    @type3   = @pokemon.type3

    def pbHasType? also needs modification. Search for it and replace it with:
    Code:
      def pbHasType?(type)
        ret=false
        if type.is_a?(Symbol) || type.is_a?(String)
          ret=isConst?(self.type1,PBTypes,type.to_sym) ||
              isConst?(self.type2,PBTypes,type.to_sym) ||
    		  isConst?(self.type3,PBTypes,type.to_sym)
        else
          ret=(self.type1==type || self.type2==type || self.type3==type)
        end
        return ret
      end

    Next do a search for "[PBEffects::Type3]". There will be many results. For each of them, you'll have to change it to type3. How varies from use to use, but just look for how type1 and type2 are handelled and mimic that. This is the long, boring part.

    For Roost, we need to make sure that all instances of flying are removed. To do so find it in PokeBattle_Move and PokeBattle_AI replace it with the following (in both cases it's prefaced with "# Roost", so search for that) (thanks James Davy!):
    Code:
        if isConst?(otype1,PBTypes,:FLYING) && opponent.effects[PBEffects::Roost]
          # the following if statement checks if a Pokémon is a mono-Flying type
          if isConst?(otype2,PBTypes,:FLYING) && (isConst?(otype3,PBTypes,:FLYING) ||
             otype3==-1)
            otype1=getConst(PBTypes,:NORMAL) || 0
          else
            otype1=otype2
          end
        end
        if isConst?(otype2,PBTypes,:FLYING) && opponent.effects[PBEffects::Roost]
          otype2=otype1
        elsif isConst?(otype3,PBTypes,:FLYING) && opponent.effects[PBEffects::Roost]
          otype3=-1
        end



    Step 4: Showing the type on a summary screen. This part is as tricky as you want it to be. Three types don't fit nicely on the current summary screen so you have two options: Ignore it, or change the graphics yourself. If you do want to change the graphics yourself, the Summary background can be found at /Graphics/Pictures/summary1.png.

    Now if you want to just ignore it, the three icons fit neatly enough that it shouldn't be an issue, it'll just look slightly weird. A word of warning, this only works with the default summary screen, as the information is layered on top of it. If you're using a custom summary screen you may have to fiddle with the values.

    To start, find the following in PScreen_Summary:
    Code:
    type2rect=Rect.new(0,pokemon.type2*28,64,28)
    Just beneath that line, add the following:
    Code:
    type3rect=Rect.new(0,pokemon.type2*28,64,28)

    Then a bit bellow that you should find:
    Code:
        if pokemon.type1==pokemon.type2
    We're about to change this massively. Replace the entire section between the above and:
    Code:
        if pokemon.level<PBExperience::MAXLEVEL
    With the following (NOTE! Make sure NOT to remove "if pokemon.level<PBExperience::MAXLEVEL"):
    Code:
        if pokemon.type1==pokemon.type2
          overlay.blt(436,146,@typebitmap.bitmap,type1rect) # If just one, display in middle
        elsif pokemon.type2==pokemon.type3
          overlay.blt(370,146,@typebitmap.bitmap,type1rect) # If just two, display type 1 in middle
          overlay.blt(436,146,@typebitmap.bitmap,type2rect) # And type 2 to the right
        else
          overlay.blt(304,146,@typebitmap.bitmap,type1rect) # Else type 1 on the left
          overlay.blt(370,146,@typebitmap.bitmap,type2rect) # Type 2 in the middle
          overlay.blt(436,146,@typebitmap.bitmap,type3rect) # And type 3 on the right
        end

    Our code should now look like this:
    Code:
        type2rect=Rect.new(0,pokemon.type2*28,64,28)
        type3rect=Rect.new(0,pokemon.type3*28,64,28)
    
        if pokemon.type1==pokemon.type2
          overlay.blt(436,146,@typebitmap.bitmap,type1rect) # If just one, display in middle
        elsif pokemon.type2==pokemon.type3
          overlay.blt(370,146,@typebitmap.bitmap,type1rect) # If just two, display type 1 in middle
          overlay.blt(436,146,@typebitmap.bitmap,type2rect) # And type 2 to the right
        else
          overlay.blt(304,146,@typebitmap.bitmap,type1rect) # Else type 1 on the left
          overlay.blt(370,146,@typebitmap.bitmap,type2rect) # Type 2 in the middle
          overlay.blt(436,146,@typebitmap.bitmap,type3rect) # And type 3 on the right
        end
        
        if pokemon.level<PBExperience::MAXLEVEL

    Check it out! Add a third type to a Pokemon, go to it's summary screen, and behold!
    On to step 5!



    Step 5: Correcting the modifiers. Without this step, types won't actually have an effect on how much damage is dealt.
    Go to PBTypes_Extra, and replace PBTypes.getCombinedEffectiveness with the following (Credit: James Davy):
    Code:
     def PBTypes.getCombinedEffectiveness(attackType,opponentType1,opponentType2=nil,opponentType3=nil)
        if opponentType2==nil # checking if the first and second types matched was redundant as the mod2 assignment will show
          return PBTypes.getEffectiveness(attackType,opponentType1)*2 # return the effectiveness value against the single type
        else
          mod1=PBTypes.getEffectiveness(attackType,opponentType1)
          # the ternary operator here checks if the primary and secondary types match and sets a flat value of 2 if they do;
          # otherwise it will set mod2 to the secondary type's effectiveness value
          mod2=(opponentType1==opponentType2) ? 2 : PBTypes.getEffectiveness(attackType,opponentType2)
          # the ternary operator here checks if the tertiary type doesn't exist and sets a flat value of 2 if the condition
          # is true; otherwise it will set mod3 to the tertiary type's effectiveness value
          mod3=(opponentType3==nil) ? 2 : PBTypes.getEffectiveness(attackType,opponentType3)
          return (mod1*mod2*mod3) # returns the three effectiveness values multiplied together
        end
      end


    Step 6: Enjoy! There you have it. Now all you need to do is add a third type to a Pokemon and it will show up in game perfectly functional. Give Charizard that Dragon type! Beedrill that Flying type! It's now possible!

    Credit to sonicfan7895 and James Davy, who helped me work out large swaiths of this code.
     
    220
    Posts
    13
    Years
    • Seen Nov 29, 2021
    So my first tutorial. Hope you enjoyed, please leave any feedback that you think could help, and post any problems that go wrong with it.
     
    5
    Posts
    5
    Years
    • Seen Mar 25, 2020
    I know this post is old now, but I'm wondering if doing this multiple times would let me add more than 3 types (Except for the summary screen, that doesn't really matter). Like for example, could I use this to make a Pokemon that has every type?
     
    1,403
    Posts
    10
    Years
    • Seen Apr 29, 2024
    I think if you wanted to add a Pokémon that had every type you'd be better off adding a type that worked like that—i.e. had the correct weaknesses/resistances for having all 18 types—and update the other types to have the correct weakness/resistance to that type. I think the only other thing you'd need to do is find where STAB is calculated (maybe try looking for ADAPTABILITY) and always apply it for your new type.

    The obvious problem you'll run into otherwise is "how to fit 18 types in the UI", although I'm sure there are probably a few other tricky bits too.
     
    Last edited:
    1
    Posts
    3
    Years
    • Seen Apr 3, 2021
    Hello
    I did the tutorial but the third type isn't showing on the summary screen, It seems that type 3 is still considered as " type 2 "
     
    1
    Posts
    3
    Years
    • Seen May 21, 2021
    An incredible service you've provided here. I havent tried it yet- actually for that matter I have yet to even download Essentials but this post gives me confidence what I am trying to do is possible. Thank you, Black Temple Guardian your tutorial is appreciated
     
    Last edited:
    1
    Posts
    1
    Years
  • Really helpful, but since v20 came out, this guide no longer works. I hope you can make an updated guide soon!
     

    Frost the Fox

    FroststormFrenzy
    16
    Posts
    2
    Years
    • Seen Jun 14, 2023
    I would just like to bring up for vita_mori:

    v20's code can, with some minor modifications, be backported into v19. I've done it with the affection code, it just requires rerouting functions to the right locations. So while I haven't messed with v20, it should be possible to follow v19 tutorials on v20 and vice versa.

    This tutorial, however, wasn't made for even v19. I've done it on v19, and can tell you now, this isn't even how it worked there. What I did was just replace all existing type3 with type4, then duplicated all of the type2 code to make a new type3, however replacing the original type3 is an optional step that's only required if you want to tell them apart
     

    Frost the Fox

    FroststormFrenzy
    16
    Posts
    2
    Years
    • Seen Jun 14, 2023
    Not sure in v20, I'd have to look into it. It should be similar to v19, in which you just need to copy all of the type 2 code and rename it to type 3, or whatever type number is being made
     
    188
    Posts
    9
    Years
    • Seen Jan 21, 2024
    Here's how you could implement triple-type Pokémon in v20.1:

    "Types" in Species will need to be changed to the following since the type values have been consolidated into one entry that returns an array:
    Code:
    "Types"             => [0, "eEE", :Type, :Type, :Type],

    Note that [PBEffects::Type3] is the extra type added from the effect of Forest's Curse, Trick-or-Treat and any custom moves you implemented that add types. You can change it if you want, but make sure you change all occurrences.

    UI_Summary will need to be changed to allow for all three types to be shown (Note: what I suggest is not likely to be neat):
    Code:
        # Draw Pokémon type(s)
        @pokemon.types.each_with_index do |type, i|
          type_number = GameData::Type.get(type).icon_position
          type_rect = Rect.new(0, type_number * 28, 64, 28)
          # type_x = (@pokemon.types.length == 1) ? 402 : 370 + (66 * i)
          case(@pokemon.types.length)
          when 1 then type_x = 402
          when 2 then type_x = 370 + (66 * i)
          when 3 then type_x = 338 + (66 * i)
          end
          overlay.blt(type_x, 146, @typebitmap.bitmap, type_rect)
        end

    All this is untested.
     
    87
    Posts
    4
    Years
  • Here's how you could implement triple-type Pokémon in v20.1:

    "Types" in Species will need to be changed to the following since the type values have been consolidated into one entry that returns an array:
    Code:
    "Types"             => [0, "eEE", :Type, :Type, :Type],

    Note that [PBEffects::Type3] is the extra type added from the effect of Forest's Curse, Trick-or-Treat and any custom moves you implemented that add types. You can change it if you want, but make sure you change all occurrences.

    UI_Summary will need to be changed to allow for all three types to be shown (Note: what I suggest is not likely to be neat):
    Code:
        # Draw Pokémon type(s)
        @pokemon.types.each_with_index do |type, i|
          type_number = GameData::Type.get(type).icon_position
          type_rect = Rect.new(0, type_number * 28, 64, 28)
          # type_x = (@pokemon.types.length == 1) ? 402 : 370 + (66 * i)
          case(@pokemon.types.length)
          when 1 then type_x = 402
          when 2 then type_x = 370 + (66 * i)
          when 3 then type_x = 338 + (66 * i)
          end
          overlay.blt(type_x, 146, @typebitmap.bitmap, type_rect)
        end

    All this is untested.



    I tested it and it appears to work (don't know for the niche technical mechanics though) , the only problem is that you have to edit all the references to types in Compiler_CompilePBS Compiler_WritePBS to make it work

    (Then of course you'd have to change the graphics for the Pokedex and Pc screen but that's optional)
     
    Back
    Top