Solved Changing a pokemons type with an item

TheMaper

Rookie
Member
Posts
7
#1
Hello, so I've been having a bit of trouble with changing a pokemons type by using an item.

Currently I have this as the test item:
613,ORANGEVIAL,Orange Vial,Orange Vials,2,300,"An orange vial.",1,1,0,
and the code that I'm using is under PItem_ItemEffects and looks like this:
ItemHandlers::UseOnPokemon.add(:ORANGEVIAL,proc{|item,pokemon,scene|
if pokemon.hp>0
pokemon.Type1=(PBTypes:FIRE)
pokemon.healStatus
scene.pbRefresh
scene.pbDisplay(_INTL("{1}'s Type was altered.",pokemon.name))
next false
else
scene.pbDisplay(_INTL("{1}'s HP is too low.",pokemon.name))
next true
end
})
The goal of this item is to require a pokemon be above 0 hp, change their type depending on the item, and remove statuses (Incase a poisoned pokemon becomes poison type or a burned pokemon becomes firetype).

Any help would be much appreciated :) I'm a little new to messing with scripts. But I can tell the jargon of (PBTypes:Fire) is not quite right.
 

Mr. Gela

Elite Trainer
Member
#2
Hmmm, much like base stats, a Pokémon's type is inherited from their form, and not a value you can change individually, like shininess would be. I'll try to take a look at this in the near future for you but until then, I just wanted to let you know this isn't the way to pursue it. What I'd do is, inside "PokeBattle_Pokemon", create a new accessor, call it whatever ("typeOverride"?), then give it a default value of nil. Have the item change "typeOverride" to ":FIRE", and then modify hasType?, type1 and type2 methods in this same script section to ignore their true values if "typeOverride" isn't "zero".
 

Mr42leon

Novice
Member
Posts
10
#3
Isn't it easier if you just use this item like an evolutionary stone?
I mean, if you're going to change the type, just do it like an evo.
 

TheMaper

Rookie
Member
Posts
7
#4
Thank you for the help. So I made the typeOverride acessor on line 36 of "PokeBattle_Pokemon"
attr_accessor(:typeOverride) # Type Overwrite:
and then I wanted to test if the numbers were being passed correctly so I under "item_effects" I modified it slightly like so
ItemHandlers::UseOnPokemon.add(:ORANGEVIAL,proc{|item,pokemon,scene|
if pokemon.hp>0
@typeOverride=1
pokemon.healStatus
scene.pbRefresh
scene.pbDisplay(_INTL("{1}'s Type was altered.{@typeOverride}",pokemon.name,typeOverride))
next false
else
scene.pbDisplay(_INTL("{1}'s HP is too low.",pokemon.name))
next true
end
})
and under "PokeBattle_Pokemon" I added this:
def typeOverride=(value)
if value==1
@typeOverride=:FIRE
else @typeOverride=nil
end
end
I was hoping by adding {@typeoverride} and typeOverride to the end list that it would display the value of ":FIRE" as from then item giving it the value of 1, then that would translate to :FIRE in the text, but I guess I did it wrong. It seems similar to php but not quite.

As for why I chose an item over an evolution stone is because I'm looking to allow the player to modify any Pokemon as they choose. (that's 18*721 possible forms if I did it that way). It seems more efficient to have typeOverrides values (1-18, 0 being nil) correlate to type1=X and type2=X. Using 18 different items to get the all the possible values.

In any case, I think I'll do a bit more studying on ruby and then try playing around with it a bit more. Thank you for pointing me in the right direction.
 
Last edited:

Mr. Gela

Elite Trainer
Member
#5
There's a mistake in "@typeOverride=1". The @ makes it a "class" uh... (Not good with terminology) a "class method?" Basically, typeOverride is a method under the PokeBattle_Pokemon class, right? This means that, just like you can set "pokemon.hp" in a conditional branch, the correct syntax would be (object).typeOverride, in this case pokemon.typeOverride=whatever. Sorry for the vague explanation. You're doing great. In fact, you don't really need "@typeOverride=:FIRE", assigning numbers to it is fine, as long as you make those numbers interpreted in the hasType?, type1 and type2 methods. You should consider each type in the order they are found in your types.txt in your PBS folder. It'll be easier that way too.
 

TheMaper

Rookie
Member
Posts
7
#6
Okay, that makes a lot more sense :P. So I replaced the @typeOverride and now I can see the text that the value of :FIRE is being passed over. When previously the text would be "Value _" and nothing so I could assume it was nil.
ItemHandlers::UseOnPokemon.add(:ORANGEVIAL,proc{|item,pokemon,scene|
if pokemon.hp>0
pokemon.typeOverride=1
pokemon.healStatus
scene.pbRefresh
scene.pbDisplay(_INTL("{1}'s Type was altered. value {2}",pokemon.name,pokemon.typeOverride))
next false
else
scene.pbDisplay(_INTL("{1}'s HP is too low.",pokemon.name))
next true
end
})
# typeOverride. When == 0:Nil 1:Fire
def typeOverride=(value)
if value==1
@typeOverride=:FIRE
else @typeOverride=nil
end
end

So now I just need to figure out the proper way to edit the pbHasType?, Type1, and Type2, methods. I was going to set them equal to typeOverride if it's value was greater than or equal to 1, but I have a feeling that if I made a second item called "Blue vial" or whatever that would change a pokemons type to water, and the player used that item on another pokemon, then retroactively the first pokemons type would change (because it's also equal to typeOverrides current value). So maybe I should looking into the is_a? symbol? object? and see if that reads directly from the pokemon.txt and modify that instead.
 

MGriffin

Trainer
Member
Posts
66
#7
I think that making Type1 (and you might need to change pbHasType? too, if it doesn't call Type1) return the override value if it exists should work out fine. Each Pokémon has its own typeOverride value, so I don't think having a Blue Vial that sets the value to (say) 2 should cause you any troubles (assuming you make the appropriate changes in typeOverride=).

EDIT: Are you saying that you want to choose between Type1 or Type2 to override? In this case I guess the simplest option is to have both typeOverride1 and typeOverride2.
 

TheMaper

Rookie
Member
Posts
7
#8
I wasn't sure if the pokemon had their own values or not, but assuming they do that's pretty cool. So I went and made another typeOverride, so that I would have one for each type1, and type2 (allowing the player to mix and match).

I modified PokeBattle_Battler slightly to have @type1, and @type2 equal typeOverride1, and typeOverride2
I tried changing it to just typeOverride1, @typeOverride1, but I could not get any changes in game so I assumed I had to change pbHasType. So I made this monstrosity :P.
def pbHasType?(type)
if typeOverride1 >= 1
type = typeOverride1
self.type1==type
elsif typeOverride2 >= 1
type = typeOverride2
self.type2==type
else type.is_a?(Symbol) || type.is_a?(String)
type = getConst(PBTypes,type)
end
return false if type==nil || type<0
ret = (self.type1==type || self.type2==type)
ret |= (@effects[PBEffects::Type3]==type) if @effects[PBEffects::Type3]>=0
return ret
end
end
end
As you would imagine, it didn't work xD. I know it's probably just full of errors, but essentially I was trying to make it by default look to typeOverride for the pokemons type, else continue as normal.
 

MGriffin

Trainer
Member
Posts
66
#9
Yeah, I'm a little lost by what's going on in pbHasType?. Line line for example looks like it doesn't do anything:
Code:
self.type1==type
But it looks like you'll be fine if you just override the definitions of type1 and type2 that come after pbHasType?, something like this:

Code:
  def type1
    if @typeOverride1==nil
      dexdata=pbOpenDexData
      pbDexDataOffset(dexdata,self.fSpecies,8)
      ret=dexdata.fgetb
      dexdata.close
      return ret
    else
      return @typeOverride1
    end
  end
You've already set @typeOverride1 to something like :FIRE so I don't think it makes sense to compare >= 1.

EDIT: But looking at pbHasType? maybe type1 shouldn't return the symbol? i.e. maybe you want to say return getConst(PBTypes,@typeOverride1) instead of return @typeOverride1
 
Last edited:

TheMaper

Rookie
Member
Posts
7
#10
Just an update now that I've finally got a chance to play around with it some more. So I removed the changes I made to pbHasType and placed the def type1 directly underneath, but no luck. I also seem to get an error with fSpecies under def type1 doing any actions in battle.
---------------------------
Pokemon Brightleaf
---------------------------
[Pokémon Essentials version 17.2]

Exception: NoMethodError

Message: undefined method `fSpecies' for #<PokeBattle_Battler:0x10a5e148>

PokeBattle_Battler:584:in `type1'

PokeBattle_Battler:576:in `pbHasType?'

PokeBattle_Battle:1605:in `pbRun_ebs'

EliteBattle_0:287:in `pbRun'

PokeBattle_Battle:2648:in `pbCommandPhase_ebs'

PokeBattle_Battle:2592:in `loop'

PokeBattle_Battle:2682:in `pbCommandPhase_ebs'

PokeBattle_Battle:2581:in `each'

PokeBattle_Battle:2581:in `pbCommandPhase_ebs'

EliteBattle_0:294:in `pbCommandPhase'



This exception was logged in

C:\Users\TheMaper\Saved Games\Pokemon Brightleaf\errorlog.txt.

Press Ctrl+C to copy this message to the clipboard.
---------------------------
OK
---------------------------
I looked through the scripts for other places fSpecies is used and it seems fine. I tried replacing self with pokemon, and that removes the error, but I still don't think it's right. I probably made an error along the way, so here's everything I've done thus far.

PokeBattle_Battler
Lines 215 and 253 I've changed from pkmn.type1 to pkmn.typeOverride1, and lines 216, 254 I've changed to pkmn.typeOverride2.
https://gyazo.com/126e5c74a278b0e913a2c0a5244754fc
And here is how I've set up def type1 under pbHasType?
Ruby:
  def pbHasType?(type)
    if type.is_a?(Symbol) || type.is_a?(String)
      type = getConst(PBTypes,type)
    end
    return false if type==nil || type<0
    ret = (self.type1==type || self.type2==type)
    ret |= (@effects[PBEffects::Type3]==type) if @effects[PBEffects::Type3]>=0
    return ret
  end

   def type1
    if @typeOverride1==nil
      dexdata=pbOpenDexData
      pbDexDataOffset(dexdata,self.fSpecies,8)
      ret=dexdata.fgetb
      dexdata.close
      return ret
    else
      return getConst(PBTypes,@typeOverride1)
    end
  end
 
    def type2
    if @typeOverride2==nil
      dexdata=pbOpenDexData
      pbDexDataOffset(dexdata,self.fSpecies,8)
      ret=dexdata.fgetb
      dexdata.close
      return ret
    else
      return getConst(PBTypes,@typeOverride2)
    end
  end

PItem_ItemEffects
Ruby:
ItemHandlers::UseOnPokemon.add(:ORANGEVIAL,proc{|item,pokemon,scene|
   if pokemon.hp>0
          pokemon.typeOverride1=1
          pokemon.healStatus
          scene.pbRefresh
          scene.pbDisplay(_INTL("{1}'s Type was altered. value {2}",pokemon.name,pokemon.typeOverride1))
     next false
   else
     scene.pbDisplay(_INTL("{1}'s HP is too low.",pokemon.name))
     next true
   end
})

PokeBattle_Pokemon
Ruby:
# typeOverride1. When == 0:Normal 1:Fighting 2:Fly 3:Poison 4:Ground 5:Rock
# 6:Bug 7:Ghost 8:Steel 9:??? 10:Fire 11:Water 12:Grass 13:Electric 14:Psychic
# 15:Ice 16:Dragon 17:Dark 18:Shadow 19:Fairy
   def typeOverride1=(value)
    if value==1
      @typeOverride1=:FIGHTING
    else @typeOverride1=pkmn.type1
    end
  end
 
# typeOverride2.
   def typeOverride2=(value)
    if value==1
      @typeOverride2=:FIGHTING
    else @typeOverride2=pkmn.type2
    end
  end
 

MGriffin

Trainer
Member
Posts
66
#11
So the body of the if in my type1 suggestion should just be whatever was originally in type1. I guess I have a different version of Essentials to you, and that's why those don't line up? In any case, the only thing I added was the if around the existing code, and the else to apply the override, so you should be able to replicate that with whatever is in your code already.
 

TheMaper

Rookie
Member
Posts
7
#12
... ;) I'm stupid, that's all. There's a different HasType then the one under PokeBattle_pokemon which is called pbHasType? and is where I was editing.
So and update to the actually def type1 and def type 2, and it's working, perfectly. Thank you all so much!
One more question for the road. Is there a more efficient way to add all the type values besides a string of elsif's like so? Like some kind of list command?
Ruby:
   def typeOverride1=(value)
   def typeOverride1=(value)
    if value==0
      @typeOverride1=:NORMAL
        elsif value==1
        @typeOverride1=:FIGHTING
          elsif value==2
          @typeOverride1=:FLYING
            else @typeOverride1=nil
          end
        end
      end
    end
EDIT: It would seem using case value and then when's works perfect. Once again, thank you everyone for your help!
 
Last edited:

MGriffin

Trainer
Member
Posts
66
#13
Case works. In this case your values are going from 0 to N so you could also use a list, and in the general case you can use a hash.

Using a list:
Code:
def typeOverride1=(value)
  @typeOverride1 = [:NORMAL, :FIGHTING, :FLYING][value]
end
Using a hash:
Code:
def typeOverride1=(value)
  @typeOverride1 = {0 => :NORMAL, 1 => :FIGHTING, 2 => :FLYING}[value]
end
You should totally turn this into a resource!

… with super-mega bonus points on the line if it's possible to automatically recolor the sprites to match the override types! :)
 
Posts
7
#14
I was definately thinking of doing that. I was just trying to figure out how to match them to a rgba (or hsl or whatever) code. Then I was gonna link it for everyone :P. I'll add you guys to the credits too. I'll get working on it after I get home.

EDIT: If my memory serves me right, ebs statuses show a color overlay on your pokemon whenever they are statused so I think I'll look there.

EDITx2: So after some searching what I've found is this under PokeBattle_Scene: @sprites["pokemon1"].tone=Tone.new(-255,-255,-255,-255). Of course this is for when the pokemon enters a battle, as for a permanent shift outside of battle I'll have to do a bit more tweaking.
 
Last edited:
Top