• 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.

[Scripting Question] Extra Type Effectivenss

Pokeminer20

PDM20, Coder of Chaos!
412
Posts
10
Years
utilizing this (https://www.pokecommunity.com/showthread.php?t=391589) tutorial and common sense, I've experimented in attempting an all 18 type pokemon. I've tried 18 types but it causes an overflow issue with the byte data and downgraded to 15 (16 might be the highest, as 17 also overflows). I'm basically stuck on step 5, but with my extra 12 types. this is purely for curiosity reasons and just to say I achieved it, but I can't common sense the code to work with all types and my latest attempt hasn't worked either. (I'm testing with a 15 type Arceus that has ground type as type #5 and electric attacks hit it.) this is my current code.

Code:
class PBTypes
  @@TypeData = nil

  def PBTypes.loadTypeData
    if !@@TypeData
      @@TypeData = load_data("Data/types.dat")
      @@TypeData[0].freeze
      @@TypeData[1].freeze
      @@TypeData[2].freeze
      @@TypeData[3].freeze
      @@TypeData[4].freeze
      @@TypeData[5].freeze
      @@TypeData[6].freeze
      @@TypeData[7].freeze
      @@TypeData[8].freeze
      @@TypeData[9].freeze
      @@TypeData[10].freeze
      @@TypeData[11].freeze
      @@TypeData[12].freeze
      @@TypeData[13].freeze
      @@TypeData[14].freeze
      @@TypeData.freeze
    end
    return @@TypeData
  end

  def PBTypes.isPseudoType?(type)
    return PBTypes.loadTypeData()[0].include?(type)
  end

  def PBTypes.isSpecialType?(type)
    return PBTypes.loadTypeData()[1].include?(type)
  end

  def PBTypes.getEffectiveness(attackType,opponentType)
    return 2 if !opponentType || opponentType<0
    return PBTypes.loadTypeData()[2][attackType*(PBTypes.maxValue+1)+opponentType]
  end

  def PBTypes.getCombinedEffectiveness(attackType,opponentType1,opponentType2=nil,opponentType3=nil,opponentType4=nil,opponentType5=nil,opponentType6=nil,opponentType7=nil,opponentType8=nil,opponentType9=nil,opponentType10=nil,opponentType11=nil,opponentType12=nil,opponentType13=nil,opponentType14=nil,opponentType15=nil)
    mod1  = PBTypes.getEffectiveness(attackType,opponentType1)
    mod2  = 2
    mod3  = 2
    mod4  = 2
    mod5  = 2
    mod6  = 2
    mod7  = 2
    mod8  = 2
    mod9  = 2
    mod10 = 2
    mod11 = 2
    mod12 = 2
    mod13 = 2
    mod14 = 2
    mod15 = 2
    if opponentType2!=nil && opponentType2>=0 && opponentType1!=opponentType2
      mod2 = PBTypes.getEffectiveness(attackType,opponentType2)
    end
    if opponentType3!=nil && opponentType3>=0 &&
       opponentType1!=opponentType3 && opponentType2!=opponentType3
      mod3 = PBTypes.getEffectiveness(attackType,opponentType3)
    end
    if opponentType4!=nil && opponentType4>=0 &&
       opponentType1!=opponentType4 && opponentType2!=opponentType4 && 
       opponentType3!=opponentType4
      mod4 = PBTypes.getEffectiveness(attackType,opponentType4)
    end
    if opponentType5!=nil && opponentType5>=0 &&
       opponentType1!=opponentType5 && opponentType2!=opponentType5 && 
       opponentType3!=opponentType5 && opponentType4!=opponentType5
      mod5 = PBTypes.getEffectiveness(attackType,opponentType5)
    end
    if opponentType6!=nil && opponentType6>=0 &&
       opponentType1!=opponentType6 && opponentType2!=opponentType6 && 
       opponentType3!=opponentType6 && opponentType4!=opponentType6 && 
       opponentType5!=opponentType6
      mod6 = PBTypes.getEffectiveness(attackType,opponentType6)
    end
    if opponentType7!=nil && opponentType7>=0 &&
       opponentType1!=opponentType7 && opponentType2!=opponentType7 && 
       opponentType3!=opponentType7 && opponentType4!=opponentType7 && 
       opponentType5!=opponentType7 && opponentType6!=opponentType7
      mod7 = PBTypes.getEffectiveness(attackType,opponentType7)
    end
    if opponentType8!=nil && opponentType8>=0 &&
       opponentType1!=opponentType8 && opponentType2!=opponentType8 && 
       opponentType3!=opponentType8 && opponentType4!=opponentType8 && 
       opponentType5!=opponentType8 && opponentType6!=opponentType8 && 
       opponentType7!=opponentType8
      mod8 = PBTypes.getEffectiveness(attackType,opponentType8)
    end
    if opponentType9!=nil && opponentType9>=0 &&
       opponentType1!=opponentType9 && opponentType2!=opponentType9 && 
       opponentType3!=opponentType9 && opponentType4!=opponentType9 && 
       opponentType5!=opponentType9 && opponentType6!=opponentType9 && 
       opponentType7!=opponentType9 && opponentType8!=opponentType9
      mod9 = PBTypes.getEffectiveness(attackType,opponentType9)
    end
    if opponentType10!=nil && opponentType10>=0 &&
       opponentType1!=opponentType10 && opponentType2!=opponentType10 && 
       opponentType3!=opponentType10 && opponentType4!=opponentType10 && 
       opponentType5!=opponentType10 && opponentType6!=opponentType10 && 
       opponentType7!=opponentType10 && opponentType8!=opponentType10 && 
       opponentType9!=opponentType10
      mod10 = PBTypes.getEffectiveness(attackType,opponentType10)
    end
    if opponentType11!=nil && opponentType11>=0 &&
       opponentType1!=opponentType11 && opponentType2!=opponentType11 && 
       opponentType3!=opponentType11 && opponentType4!=opponentType11 && 
       opponentType5!=opponentType11 && opponentType6!=opponentType11 && 
       opponentType7!=opponentType11 && opponentType8!=opponentType11 && 
       opponentType9!=opponentType11 && opponentType10!=opponentType11
      mod11 = PBTypes.getEffectiveness(attackType,opponentType11)
    end
    if opponentType12!=nil && opponentType12>=0 &&
       opponentType1!=opponentType12 && opponentType2!=opponentType12 && 
       opponentType3!=opponentType12 && opponentType4!=opponentType12 && 
       opponentType5!=opponentType12 && opponentType6!=opponentType12 && 
       opponentType7!=opponentType12 && opponentType8!=opponentType12 && 
       opponentType9!=opponentType12 && opponentType10!=opponentType12 && 
       opponentType11!=opponentType12
      mod12 = PBTypes.getEffectiveness(attackType,opponentType12)
    end
    if opponentType13!=nil && opponentType13>=0 &&
       opponentType1!=opponentType13 && opponentType2!=opponentType13 && 
       opponentType3!=opponentType13 && opponentType4!=opponentType13 && 
       opponentType5!=opponentType13 && opponentType6!=opponentType13 && 
       opponentType7!=opponentType13 && opponentType8!=opponentType13 && 
       opponentType9!=opponentType13 && opponentType10!=opponentType13 && 
       opponentType11!=opponentType13 && opponentType12!=opponentType13
      mod13 = PBTypes.getEffectiveness(attackType,opponentType13)
    end
    if opponentType14!=nil && opponentType14>=0 &&
       opponentType1!=opponentType14 && opponentType2!=opponentType14 && 
       opponentType3!=opponentType14 && opponentType4!=opponentType14 && 
       opponentType5!=opponentType14 && opponentType6!=opponentType14 && 
       opponentType7!=opponentType14 && opponentType8!=opponentType14 && 
       opponentType9!=opponentType14 && opponentType10!=opponentType14 && 
       opponentType11!=opponentType14 && opponentType12!=opponentType14 && 
       opponentType13!=opponentType14
      mod14 = PBTypes.getEffectiveness(attackType,opponentType14)
    end
    if opponentType15!=nil && opponentType15>=0 &&
       opponentType1!=opponentType15 && opponentType2!=opponentType15 && 
       opponentType3!=opponentType15 && opponentType4!=opponentType15 && 
       opponentType5!=opponentType15 && opponentType6!=opponentType15 && 
       opponentType7!=opponentType15 && opponentType8!=opponentType15 && 
       opponentType9!=opponentType15 && opponentType10!=opponentType15 && 
       opponentType11!=opponentType15 && opponentType12!=opponentType15 && 
       opponentType13!=opponentType15 && opponentType14!=opponentType15
      mod15 = PBTypes.getEffectiveness(attackType,opponentType15)
    end
    return (mod1*mod2*mod3*mod4*mod5*mod6*mod7*mod8*mod9*mod10*mod11*mod12*mod13*mod14*mod15)
  end

  def PBTypes.isIneffective?(attackType,opponentType1,opponentType2=nil,opponentType3=nil,opponentType4=nil,opponentType5=nil,opponentType6=nil,opponentType7=nil,opponentType8=nil,opponentType9=nil,opponentType10=nil,opponentType11=nil,opponentType12=nil,opponentType13=nil,opponentType14=nil,opponentType15=nil)
    e = PBTypes.getCombinedEffectiveness(attackType,opponentType1,opponentType2,opponentType3,opponentType4,opponentType5,opponentType6,opponentType7,opponentType8,opponentType9,opponentType10,opponentType11,opponentType12,opponentType13,opponentType14,opponentType15)
    return e==0
  end

  def PBTypes.isNotVeryEffective?(attackType,opponentType1,opponentType2=nil,opponentType3=nil,opponentType4=nil,opponentType5=nil,opponentType6=nil,opponentType7=nil,opponentType8=nil,opponentType9=nil,opponentType10=nil,opponentType11=nil,opponentType12=nil,opponentType13=nil,opponentType14=nil,opponentType15=nil)
    e = PBTypes.getCombinedEffectiveness(attackType,opponentType1,opponentType2,opponentType3,opponentType4,opponentType5,opponentType6,opponentType7,opponentType8,opponentType9,opponentType10,opponentType11,opponentType12,opponentType13,opponentType14,opponentType15)
    return e>0 && e<8
  end

  def PBTypes.isNormalEffective?(attackType,opponentType1,opponentType2=nil,opponentType3=nil,opponentType4=nil,opponentType5=nil,opponentType6=nil,opponentType7=nil,opponentType8=nil,opponentType9=nil,opponentType10=nil,opponentType11=nil,opponentType12=nil,opponentType13=nil,opponentType14=nil,opponentType15=nil)
    e = PBTypes.getCombinedEffectiveness(attackType,opponentType1,opponentType2,opponentType3,opponentType4,opponentType5,opponentType6,opponentType7,opponentType8,opponentType9,opponentType10,opponentType11,opponentType12,opponentType13,opponentType14,opponentType15)
    return e==8
  end

  def PBTypes.isSuperEffective?(attackType,opponentType1,opponentType2=nil,opponentType3=nil,opponentType4=nil,opponentType5=nil,opponentType6=nil,opponentType7=nil,opponentType8=nil,opponentType9=nil,opponentType10=nil,opponentType11=nil,opponentType12=nil,opponentType13=nil,opponentType14=nil,opponentType15=nil)
    e = PBTypes.getCombinedEffectiveness(attackType,opponentType1,opponentType2,opponentType3,opponentType4,opponentType5,opponentType6,opponentType7,opponentType8,opponentType9,opponentType10,opponentType11,opponentType12,opponentType13,opponentType14,opponentType15)
    return e>8
  end
end

besides length, anything looking scuffed?
 
Last edited:

Pokeminer20

PDM20, Coder of Chaos!
412
Posts
10
Years
Upon looking more on google, and locating more attempts to add anymore than 3 typings, it seems link the only think these add-ons have in common is no matter what, type effectiveness doesn't work for any of them. I was able to locate the original "Step 5" thread and even with a downloadable copy of essentials with this mod, type 3 effectiveness still doesn't work, be it how the formula acts, or if it needs a complete overhaul, upon giving a Pokemon ground type and fighting an electric type, those electric moves still do damage while in the type 3 position. seems like most type 3 dreams are crushed, but I shall locate a method that works.
 
233
Posts
5
Years
  • Age 33
  • Seen Oct 9, 2023
While the script you've got here is a start, you also need to consider that each function you gave more parameters to now needs to be edited in every single section of the battle code... so, you are right in that the battle system would need a major overhaul to support more than 2 types + the extra third type effect in battle. Even just adding functionality for a third type (so up to 4 types in battle) requires lots of minute changes all over the battle code, so with 18 types... o_O you'd definitely want to use an array to store all the possible types for each Pokemon/battler at that point, but that would also completely change how you work with types in the battle code in general. Heh, now I might take a crack at it...
 
Last edited:

Pokeminer20

PDM20, Coder of Chaos!
412
Posts
10
Years
the solution has been found. by looking at all the post of the original thread I linked here, the poster uploaded this https://www.pokecommunity.com/showthread.php?t=379877 which is basically step 5, but in more detailed. in post #7, the one helping the OP states modifying def def pbTypeModifier in the PokeBattle_Move section, and def pbHasType in PokeBattle_Battler. as I have yet to fully mod def pbTypeModifier, I shall work on it more(to work with all my alterations) but will post the pbHasType? mod here.


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) ||
          isConst?(self.type4,PBTypes,type.to_sym) ||
          isConst?(self.type5,PBTypes,type.to_sym) ||
          isConst?(self.type6,PBTypes,type.to_sym) ||
          isConst?(self.type7,PBTypes,type.to_sym) ||
          isConst?(self.type8,PBTypes,type.to_sym) ||
          isConst?(self.type9,PBTypes,type.to_sym) ||
          isConst?(self.type10,PBTypes,type.to_sym) ||
          isConst?(self.type11,PBTypes,type.to_sym) ||
          isConst?(self.type12,PBTypes,type.to_sym) ||
          isConst?(self.type13,PBTypes,type.to_sym) ||
          isConst?(self.type14,PBTypes,type.to_sym) ||
          isConst?(self.type15,PBTypes,type.to_sym)
    else
      ret=(self.type1==type || self.type2==type || self.type3==type || self.type4==type || self.type5==type || self.type6==type || self.type7==type || self.type8==type || self.type9==type || self.type10==type ||self.type11==type || self.type12==type || self.type13==type || self.type14==type || self.type15==type)
    end
    return ret
  end
 
Last edited:
233
Posts
5
Years
  • Age 33
  • Seen Oct 9, 2023
That solution is better, just need to keep in mind two additional things. One is that any type conversion abilities/moves, or really anything that manually handles types needs to be edited (ex. Protean, Conversion, Transform, etc.).
The other is that when the battle code calculates the type modifier, the "neutral effectiveness" value is set to 2 to the power of NUMTYPES (the max number of types a Pokemon in battle can have), which is 8 in Essentials v16.2+ because of dual-types + the extra type given by moves like Forest's Curse, so everywhere that 8 appears in the battle code needs to be replaced with 2 to the power of how many ever types you want a battler to have at most. In the case of OP it would be 2^15 (because a battle can have at most 15 types). So I think with the solutions OP posted + these additional things, having multiple types should work perfectly.
 
Last edited:

Pokeminer20

PDM20, Coder of Chaos!
412
Posts
10
Years
That solution is better, just need to keep in mind two additional things. One is that any type conversion abilities/moves, or really anything that manually handles types needs to be edited (ex. Protean, Conversion, Transform, etc.).
The other is that when the battle code calculates the type modifier, the "neutral effectiveness" value is set to 2 to the power of NUMTYPES (the max number of types a Pokemon in battle can have), which is 8 in Essentials v16.2+ because of dual-types + the extra type given by moves like Forest's Curse, so everywhere that 8 appears in the battle code needs to be replaced with 2 to the power of how many ever types you want a battler to have at most. In the case of OP it would be 2^15 (because a battle can have at most 15 types). So I think with the solutions OP posted + these additional things, having multiple types should work perfectly.

even replacing those instances of 8 causes a new issue I'll call "the Hyper Effectiveness" Bug. case in point, the game uses a method called "typemod' that determines how effective a move is. typemod 0 is immune, typemod 0-3 is not very, and typemod 4 and 8 are super effective. there is another call called @skill, but I haven't a clue what it does, but it probably correlates to the type chart somehow. anyway, upon modifying the formula to what I altered just after post #4, the new formula, formerly being mod1*mod2*mod3, now is mod1*mod2*mod3...mod15*mod16*modex(modex being the effect typing that forest curse like moves now use.) here's my current code.

Code:
  def pbTypeModifier(type,attacker,opponent)
    return 131072 if type<0
    return 131072 if isConst?(type,PBTypes,:GROUND) && opponent.pbHasType?(:FLYING) &&
                opponent.hasWorkingItem(:IRONBALL) && !USENEWBATTLEMECHANICS
    atype=type # attack type
    otype1=opponent.type1
    otype2=opponent.type2
    otype3=opponent.type3
    otype4=opponent.type4
    otype5=opponent.type5
    otype6=opponent.type6
    otype7=opponent.type7
    otype8=opponent.type8
    otype9=opponent.type9
    otype10=opponent.type10
    otype11=opponent.type11
    otype12=opponent.type12
    otype13=opponent.type13
    otype14=opponent.type14
    otype15=opponent.type15
    otype16=opponent.type16
    otypeex=opponent.effects[PBEffects::TypeExtra] || -1
    # Roost is the same
    # Get effectivenesses
    mod1=PBTypes.getEffectiveness(atype,otype1)
    mod2=(otype1==otype2) ? 2 : PBTypes.getEffectiveness(atype,otype2)
    mod3=(otype2==otype3) ? 2 : PBTypes.getEffectiveness(atype,otype3)
    mod4=(otype3==otype4) ? 2 : PBTypes.getEffectiveness(atype,otype4)
    mod5=(otype4==otype5) ? 2 : PBTypes.getEffectiveness(atype,otype5)
    mod6=(otype5==otype6) ? 2 : PBTypes.getEffectiveness(atype,otype6)
    mod7=(otype6==otype7) ? 2 : PBTypes.getEffectiveness(atype,otype7)
    mod8=(otype7==otype8) ? 2 : PBTypes.getEffectiveness(atype,otype8)
    mod9=(otype8==otype9) ? 2 : PBTypes.getEffectiveness(atype,otype9)
    mod10=(otype9==otype10) ? 2 : PBTypes.getEffectiveness(atype,otype10)
    mod11=(otype10==otype11) ? 2 : PBTypes.getEffectiveness(atype,otype11)
    mod12=(otype11==otype12) ? 2 : PBTypes.getEffectiveness(atype,otype12)
    mod13=(otype12==otype13) ? 2 : PBTypes.getEffectiveness(atype,otype13)
    mod14=(otype13==otype14) ? 2 : PBTypes.getEffectiveness(atype,otype14)
    mod15=(otype14==otype15) ? 2 : PBTypes.getEffectiveness(atype,otype15)
    mod16=(otype15==otype16) ? 2 : PBTypes.getEffectiveness(atype,otype16)
    modex=(otypeex<0 || otype1==otypeex || otype2==otypeex || otype3==otypeex || otype4==otypeex || otype5==otypeex || otype6==otypeex || otype7==otypeex || otype8==otypeex || otype9==otypeex || otype10==otypeex || otype11==otypeex || otype12==otypeex || otype13==otypeex || otype14==otypeex || otype15==otypeex || otype16==otypeex) ? 2 : PBTypes.getEffectiveness(atype,otypeex)
#RINGTARGET to last end is the same
    return mod1*mod2*mod3*mod4*mod5*mod5*mod6*mod7*mod8*mod10*mod11*mod12*mod13*mod14*mod15*mod16*modex
  end
my working theory is that 2 is used as neutral damage, which when set to 4 causes super effective damage. I'm unsure how to do it but if I knew how to rework the damage calculations or conditional these effectiveness, I might be able to perfect this (setting each instance of 2 in mon2 - modex results in not effective, but and 2's present will add another effecticveness layer)
 

Pokeminer20

PDM20, Coder of Chaos!
412
Posts
10
Years
of course after posting that I find the solution. after doing everything above, locate
Code:
damage=(damage*typemod/8.0).round
and replace it with
Code:
damage=(damage*typemod/65536.0).round
and mechanically, everything is fine. however, there's more to modify, because since it now sees 65536 as pure neutral, 8+ now is barely effective, but will say 'super effective' and to fix that, locate "def pbEffectMessages" and alter it accordingly to whatever you need.

for a basic example, I'd recomend using This:
Code:
  def pbEffectMessages(attacker,opponent,ignoretype=false,alltargets=nil)
    if opponent.damagestate.critical
      if alltargets && alltargets.length>1
        @battle.pbDisplay(_INTL("A critical hit on {1}!",opponent.pbThis(true)))
      else
        @battle.pbDisplay(_INTL("A critical hit!"))
      end
    end
    if !pbIsMultiHit && attacker.effects[PBEffects::ParentalBond]==0
      if opponent.damagestate.typemod>131072
        if alltargets && alltargets.length>1
          @battle.pbDisplay(_INTL("It's super effective on {1}!",opponent.pbThis(true)))
        else
          @battle.pbDisplay(_INTL("It's super effective!"))
        end
      elsif opponent.damagestate.typemod>=1 && opponent.damagestate.typemod<32768
        if alltargets && alltargets.length>1
          @battle.pbDisplay(_INTL("It's not very effective on {1}...",opponent.pbThis(true)))
        else
          @battle.pbDisplay(_INTL("It's not very effective..."))
        end
      end
    end
 
1,403
Posts
10
Years
  • Seen Apr 18, 2024
I would strongly recommend trying to use a sensible floating point representation of typemod (i.e. 1 = neutral, > 1 = super-effective, < 1 = resisted; so you just multiply it directly onto the number instead of /8 first) rather than keeping the 2/4/8/16/32 thing if you're going to make changes to that part of the code.

You'll still have to modify all the places that check for effectiveness, but at least you'll be able to use sensible numbers that the next person to read your code will understand.

I have no idea why Essentials hasn't changed to this obvious solution yet…
 
Back
Top