• Just a reminder that providing specifics on, sharing links to, or naming websites where ROMs can be accessed is against the rules. If your post has any of this information it will be removed.
  • Ever thought it'd be cool to have your art, writing, or challenge runs featured on PokéCommunity? Click here for info - we'd love to spotlight your work!
  • 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] [Pokemon Essentials v18.2] Creating A Type-changing Move

zedcoeur

Zed Coeur
  • 29
    Posts
    5
    Years
    • Seen Apr 15, 2022
    (Reposting with hopefully the proper category. If not, sorry mods)

    Hello, everyone! I'm new to PokeCommunity, but looking around, I've seen some pretty interesting concepts for moves and abilities.

    I am currently trying to develop a new move called Adaptive Storm that starts out as Normal-type every round, but whenever the user is hit by a damaging move, Adaptive Storm changes to a type that is super-effective to the move the user was hit by. For example, if the user was hit with, say, Flamethrower, Adaptive Storm has a chance of becoming a Ground, Rock, or Water type move. If the user is hit with Moonblast, Adaptive Storm can turn into a Poison or Steel type move. More examples follow, but with every possible example, Adaptive Storm reverts back to Normal type at the end of each round.

    I have tried copying and altering code from moves Color Change, Conversion 2 and Revenge, and scripts like Move_Usage_Calculations and BattleHandlers_Abilities, and nothing has worked.

    All the help will be greatly appreciated, because I have no idea what to do at this point.

    Thanks!
     
    I am currently trying to develop a new move called Adaptive Storm that starts out as Normal-type every round, but whenever the user is hit by a damaging move, Adaptive Storm changes to a type that is super-effective to the move the user was hit by. For example, if the user was hit with, say, Flamethrower, Adaptive Storm has a chance of becoming a Ground, Rock, or Water type move. If the user is hit with Moonblast, Adaptive Storm can turn into a Poison or Steel type move. More examples follow, but with every possible example, Adaptive Storm reverts back to Normal type at the end of each round.

    I have tried copying and altering code from moves Color Change, Conversion 2 and Revenge, and scripts like Move_Usage_Calculations and BattleHandlers_Abilities, and nothing has worked.

    [BIG EDIT, I thought you wanted the new type to remain after the end of the turn, hence my off-topic first response]

    This is a nice question actually. I like this kind of code that requires thinking ^^

    Here is my (UNTESTED) attempt.

    Code:
    class PokeBattle_Move_XXX < PokeBattle_Move
      
      def initialize(battle,move)
        super
        @lastHitType = nil # will store the type of the last move that hit the user.
      end 
      
      def pbChangeUsageCounters(user,specialUsage)
        super
        @lastHitType = nil # Reset it at every turn.
        return if user.lastAttacker.empty? # No update.
        lastAttackerIndex = user.lastAttacker[-1] # Last attacker
        @lastHitType = @battle.battlers[lastAttackerIndex].lastMoveUsedType
      end
      
      def pbBaseType(user)
        return super if !@lastHitType # Normal type if the user was not attacked this turn.
        
        # Compute a type that's super effective on @lastHitType
        responseTypes = []
        
        # List all super effective types: 
        for i in 0..PBTypes.maxValue
          next if PBTypes.isPseudoType?(i)
          next if isConst?(i,PBTypes,:SHADOW)
          
          responseTypes.push(i) if PBTypes.superEffective?(i, @lastHitType)
        end
        
        # Random type among the super effective types.
        return responseTypes[rand(responseTypes.length)] || super(user)
      end
    end

    I do not guarantee it will 100% work right now, it requires some testing, but I think it's a solid first attempt.

    PS: Why do you mention V18.2? The last version is v18.1 ^^"
     
    Last edited:
    [BIG EDIT, I thought you wanted the new type to remain after the end of the turn, hence my off-topic first response]

    This is a nice question actually. I like this kind of code that requires thinking ^^

    Here is my (UNTESTED) attempt.

    Code:
    class PokeBattle_Move_XXX < PokeBattle_Move
      
      def initialize(battle,move)
        super
        @lastHitType = nil # will store the type of the last move that hit the user.
      end 
      
      def pbChangeUsageCounters(user,specialUsage)
        super
        @lastHitType = nil # Reset it at every turn.
        return if user.lastAttacker.empty? # No update.
        lastAttackerIndex = user.lastAttacker[-1] # Last attacker
        @lastHitType = @battle.battlers[lastAttackerIndex].lastMoveUsedType
      end
      
      def pbBaseType(user)
        return super if !@lastHitType # Normal type if the user was not attacked this turn.
        
        # Compute a type that's super effective on @lastHitType
        responseTypes = []
        
        # List all super effective types: 
        for i in 0..PBTypes.maxValue
          next if PBTypes.isPseudoType?(i)
          next if isConst?(i,PBTypes,:SHADOW)
          
          responseTypes.push(i) if PBTypes.superEffective?(i, @lastHitType)
        end
        
        # Random type among the super effective types.
        return responseTypes[rand(responseTypes.length)] || super(user)
      end
    end

    I do not guarantee it will 100% work right now, it requires some testing, but I think it's a solid first attempt.

    PS: Why do you mention V18.2? The last version is v18.1 ^^"

    Thanks, I'll give this a shot!

    PS: I mixed up v17.2 and v18.1 and somehow came up with v18.2. My b ^^;
     
    Just tested StCooler's code, and it doesn't seem to function properly. I tested it against a Gengar and Giratina, and both times the opponent was immune, meaning the move's type remained as Normal. My thought process is maybe change this:

    for i in 0..PBTypes.maxValue
    next if PBTypes.isPseudoType?(i)
    next if isConst?(i,PBTypes,:SHADOW)

    responseTypes.push(i) if PBTypes.superEffective?(i, @lastHitType)

    to this:

    for i in 0..PBTypes.maxValue
    next if PBTypes.isPseudoType?(i)
    next if !PBTypes.superEffective?(@lastHitType, i)

    responseTypes.push(i)

    I'll try it and see if it works
     
    Alright, just gave the new code a shot, didn't quite work. Not really sure what else I could change to make this a functioning move effect.
     
    Alright, just gave the new code a shot, didn't quite work. Not really sure what else I could change to make this a functioning move effect.

    I think the error is here:
    In the code I gave you, change this line:
    Code:
        return responseTypes[rand(responseTypes.length)] || super(user)
    to these lines:
    Code:
        return super(user) if responseTypes.length == 0
        return responseTypes[rand(responseTypes.length)]
     
    Last edited:
    I think the error is here:
    In the code I gave you, change this line:
    Code:
        return responseTypes[rand(responseTypes.length)] || super(user)
    to these lines:
    Code:
        return super(user) if responseTypes.length == 0
        return responseTypes[rand(responseTypes.length)]

    Tested, move still comes out as a Normal type move.
     
    Tested, move still comes out as a Normal type move.

    So, we'll have to debug.

    Open your file moves.txt, check the function code given to the move (it's the fourth item on the line). Let's say it's XXX.
    Find the code of your move; is the class PokeBattle_Move_XXX with the same XXX as found in moves.txt?

    Then, at the end of:
    Code:
      def pbChangeUsageCounters(user,specialUsage)
    paste:
    Code:
        pbMessage(_INTL("lastHitType = {1}", PBTypes.getName(@lastHitType))
    At the beginning of:
    Code:
      def pbBaseType(user)
    paste:
    Code:
        pbMessage(_INTL("lastHitType = {1}", PBTypes.getName(@lastHitType))
    In the same function:
    Code:
      def pbBaseType(user)
    right before the two "return" I told you to add, paste this:
    Code:
        pbMessage(_INTL("responseTypes = {1}", PBTypes.getName(responseTypes.length))
    Now run the game, use the move, and tell me what these messages say.
     
    So, we'll have to debug.

    Open your file moves.txt, check the function code given to the move (it's the fourth item on the line). Let's say it's XXX.
    Find the code of your move; is the class PokeBattle_Move_XXX with the same XXX as found in moves.txt?

    Then, at the end of:
    Code:
      def pbChangeUsageCounters(user,specialUsage)
    paste:
    Code:
        pbMessage(_INTL("lastHitType = {1}", PBTypes.getName(@lastHitType))
    At the beginning of:
    Code:
      def pbBaseType(user)
    paste:
    Code:
        pbMessage(_INTL("lastHitType = {1}", PBTypes.getName(@lastHitType))
    In the same function:
    Code:
      def pbBaseType(user)
    right before the two "return" I told you to add, paste this:
    Code:
        pbMessage(_INTL("responseTypes = {1}", PBTypes.getName(responseTypes.length))
    Now run the game, use the move, and tell me what these messages say.

    So upon attempting to use the move, I immediately get an error saying "no implicit conversion from nil to integer."

    I checked to make sure that the move code in moves.txt and the script matched, and they do.
     
    So upon attempting to use the move, I immediately get an error saying "no implicit conversion from nil to integer."

    I checked to make sure that the move code in moves.txt and the script matched, and they do.

    You monster.
    YOU MADE ME IMPLEMENT IT.

    This code works:
    Code:
    class PokeBattle_Move_200 < PokeBattle_Move
    
      def initialize(battle,move)
        super
        @new_type = nil
      end 
      
      # Optional: just to let the player know the new type.
      def pbDisplayUseMessage(user)
        super
        if @new_type
          @battle.pbDisplay(_INTL("{1} became {2}-type!", @name, PBTypes.getName(@new_type)))
        end 
      end
    
      def pbBaseType(user)
        @new_type = nil
        return super if user.lastAttacker.empty? # Didn't receive an attack this turn. 
        
        lastAttackerIndex = user.lastAttacker[-1] # Last attacker
        lastHitType = battle.battlers[lastAttackerIndex].lastMoveUsedType
        return super if !lastHitType || lastHitType == -1 # Normal type if the user was not attacked this turn.
        
        # Compute a type that's super effective on @lastHitType
        responseTypes = []
        
        # List all super effective types: 
        for i in 0..PBTypes.maxValue
          next if PBTypes.isPseudoType?(i)
          next if isConst?(i,PBTypes,:SHADOW)
          
          responseTypes.push(i) if PBTypes.superEffective?(i, lastHitType)
        end
        # Random type among the super effective types.
        return super(user) if responseTypes.length == 0 
        
        @new_type = responseTypes[rand(responseTypes.length)]
        return @new_type
      end
    end

    In short, my error was that I thought that pbChangeUsageCounters was used before pbBaseType, which of course is not the case. So whenever it computed its new type, the "lastHitType" had not been updated, hence the normal type.
    But now, the new type is computed exactly when needed.
     
    You monster.
    YOU MADE ME IMPLEMENT IT.

    This code works:
    Code:
    class PokeBattle_Move_200 < PokeBattle_Move
    
      def initialize(battle,move)
        super
        @new_type = nil
      end 
      
      # Optional: just to let the player know the new type.
      def pbDisplayUseMessage(user)
        super
        if @new_type
          @battle.pbDisplay(_INTL("{1} became {2}-type!", @name, PBTypes.getName(@new_type)))
        end 
      end
    
      def pbBaseType(user)
        @new_type = nil
        return super if user.lastAttacker.empty? # Didn't receive an attack this turn. 
        
        lastAttackerIndex = user.lastAttacker[-1] # Last attacker
        lastHitType = battle.battlers[lastAttackerIndex].lastMoveUsedType
        return super if !lastHitType || lastHitType == -1 # Normal type if the user was not attacked this turn.
        
        # Compute a type that's super effective on @lastHitType
        responseTypes = []
        
        # List all super effective types: 
        for i in 0..PBTypes.maxValue
          next if PBTypes.isPseudoType?(i)
          next if isConst?(i,PBTypes,:SHADOW)
          
          responseTypes.push(i) if PBTypes.superEffective?(i, lastHitType)
        end
        # Random type among the super effective types.
        return super(user) if responseTypes.length == 0 
        
        @new_type = responseTypes[rand(responseTypes.length)]
        return @new_type
      end
    end

    In short, my error was that I thought that pbChangeUsageCounters was used before pbBaseType, which of course is not the case. So whenever it computed its new type, the "lastHitType" had not been updated, hence the normal type.
    But now, the new type is computed exactly when needed.

    Perfect! Thank you so much, and sorry I brought you to a point where you needed to implement it ^^; 'Ppreciate the help!
     
    Back
    Top