• 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] Trying to change the way movesets of wild Pokemon are generated

286
Posts
5
Years
    • Seen May 9, 2024
    Hi, I'm trying to change the scripts so the movesets for wild Pokemon (and possibly trainer Pokemon) are generated differently. I am trying to make it so rather than having the Pokemon generated with the 4 most recent moves in its level-up movepool given its current level, the Pokemon will be generated with a random 4 moves that are in its level-up movepool up to the level it is currently at. For example, if a Pokemon has the moves defined in pokemon.txt as 1,GROWL,3,TACKLE,5,POUND,10,BITE,15,FURYATTACK,20,CRUNCH and it is level 17, it should have a moveset consisting of a random 4 moves out of Growl, Tackle, Pound, Bite, and Fury Attack, but not including Crunch. As far as I know, the script is currently set to give it the last 4 moves up to the level it is at so it couldn't have Growl. I am doing this so one doesn't have to necessarily use heart scales or breed to get old moves that are desired on the Pokemon (if I wanted Growl in this case). I was looking around the scripts and it seems as though this could be done in the PokeBattle_Pokemon or PField_Encounters script.
     
    1,682
    Posts
    8
    Years
    • Seen today
    So, it looks like you are interested in changing how def resetMoves works (class PokeBattle_Pokemon)
    Code:
        listend=movelist.length-4
        listend=0 if listend<0
        j=0
        for i in listend...listend+4
          moveid=(i>=movelist.length) ? 0 : movelist[i]
          @moves[j]=PBMove.new(moveid)
          j+=1
        end
    This is the bit that i see needs to change, as it selects the last 4 moves and sets them directly to the index.

    guess you can do moveid=movelist[rand(movelist.length)] to get a random move from the list, though you do have to check that the move is not already known by the pokemon. [email protected]?(moveid)

    but I'm just speculating right now, you'd have to do the actual scripting yourself.
    It's a start though.
     
    286
    Posts
    5
    Years
    • Seen May 9, 2024
    Thanks for your help! So I formulated this code (Sorry I don't know how to put it in the code box like you did):
    Code:
    def resetMoves
        moves=self.getMoveList
        movelist=[]
        for i in moves
          if i[0]<=self.level
            movelist[movelist.length]=i[1]
          end
        end
        movelist|=[] # Remove duplicates
        j=0
        threshold=4
        if movelist.length<4
          threshold=movelist.length
        end
        while j<threshold
          moveid=movelist[rand(movelist.length)]
          if @moves.include?(PBMove.new(moveid)) #Also tried "if @moves.include?(moveid)"
            j-=1
          else
            @moves[j]=PBMove.new(moveid)
          end
          j+=1
        end
    end
    I got it so everything works as expected except that the generated Pokemon sometimes have duplicate moves. I think this is because the move in movelist isn't defined as an integer while moveid is. I tried using another way above where I tried to create a new equivalent move and then check for equality, but it isn't working. I believe this is because the two moves, in this case, are not aliases, so == won't ever be true. Do you know how I could just check if the move ID of move[j] and the moveid variable in this method are equal?

    EDIT: I figured out how to fix this problem and the fixed code is below. Also thanks for helping with the code tags.
     
    Last edited:
    286
    Posts
    5
    Years
    • Seen May 9, 2024
    Ok, so I figured out what the problem was and how to fix it. For anyone who wants to implement this into their game, here is the method that should replace def resetMoves in the PokeBattle_Pokemon class:
    Code:
      def resetMoves
        moves=self.getMoveList
        movelist=[]
        for i in moves
          if i[0]<=self.level
            movelist[movelist.length]=i[1]
          end
        end
        movelist|=[] # Remove duplicates
        j=0
        threshold=4
        if movelist.length<4
          threshold=movelist.length
        end
        while j<threshold
          moveid=movelist[rand(movelist.length)]
          hasMove=false
          for i in 0...(@moves.length)
            if @moves[i].id==moveid
              hasMove=true
            end
          end
          if hasMove
            j-=1
          else
            @moves[j]=PBMove.new(moveid)
          end
          j+=1
        end
      end
    I'm pretty sure the code I used for checking to find if the generated move matches another one already in its moveset could be more efficient, but I think it works. The problem before was that it was checking just for an int value of the move ID in the array rather than the move's object's int value for the move ID. The array is an array of moves, not integers, so that wouldn't work.
     
    32
    Posts
    8
    Years
    • Seen May 6, 2020
    This is a really good idea. I've bookmarked this thread for future reference.

    Is it possible to generate moves from something more controlled, like the last 7 moves? It would be weird for a level 40 wild pokemon to have level 5 moves.
     
    286
    Posts
    5
    Years
    • Seen May 9, 2024
    Yes, that should be possible. You can replace the resetMoves method with this:
    Code:
      def resetMoves
        moves=self.getMoveList
        movelist=[]
        for i in moves
          if i[0]<=self.level
            movelist[movelist.length]=i[1]
          end
        end
        movelist|=[] # Remove duplicates
        j=0
        threshold=4
        if movelist.length<4
          threshold=movelist.length
        end
        maxLen=movelist.length
        [B]if maxLen>[COLOR="Red"]7[/COLOR]
          maxLen=[COLOR="red"]7[/COLOR]
        end[/B]
        while j<threshold
          [B]moveid=movelist[movelist.length-rand(maxLen)-1][/B]
          hasMove=false
          for i in 0...(@moves.length)
            if @moves[i].id==moveid
              hasMove=true
            end
          end
          if hasMove
            j-=1
          else
            @moves[j]=PBMove.new(moveid)
          end
          j+=1
        end
      end
    I didn't test this out, but it should theoretically work unless I missed something. If you wanted a random move out of the last 8 moves, or any other number, change the red 7s in the code to the number you see fit, just make sure you change both 7s to the same number. Let me know if there are any problems with this and I can try to fix it.
     
    Last edited:
    1,805
    Posts
    7
    Years
  • Have you looked at PField_EncounterModifiers scripts section?

    Code:
    # Used in the random dungeon map.  Makes the levels of all wild Pokémon in that
    # map depend on the levels of Pokémon in the player's party.
    # This is a simple method, and can/should be modified to account for evolutions
    # and other such details.  Of course, you don't HAVE to use this code.
    Events.onWildPokemonCreate+=proc {|sender,e|
       pokemon=e[0]
       if $game_map.map_id==51
         newlevel=pbBalancedLevel($Trainer.party) - 4 + rand(5)   # For variety
         newlevel=1 if newlevel<1
         newlevel=PBExperience::MAXLEVEL if newlevel>PBExperience::MAXLEVEL
         pokemon.level=newlevel
         pokemon.calcStats
         pokemon.resetMoves
       end
    }

    is the example block of code. You can modify it for their moveset like Vendily suggested. It may be more complex but pokemon.resetMoves is defined.
     
    465
    Posts
    7
    Years
    • Seen May 9, 2024
    So this code has actually been something i've been looking into and in most respects it works; however it seems to break when a new pokemon or trainers pokemon is generated when its defined with less than 4 possible moves or cant learn 4 moves (e.g. i get locked in until "script is taking too long" if generating a pancham and cyndquil with 3 moves defined on the trainer) the error calls to "PokeBattle_Pokemon:491:in `resetMoves' " in my scripts being "for i in 0...(@moves.length)" i can tell its a less than 4 move issue/move length issue as when i give both of them 4 moves it runs instantly otherwise im eternally hardlocked into loading
     
    Last edited:
    32
    Posts
    8
    Years
    • Seen May 6, 2020
    To get around that, I thought maybe the code could target only pokemon over a certain level? So long as you don't include a magikarp or something over level 20, maybe that could work?
     
    465
    Posts
    7
    Years
    • Seen May 9, 2024
    To get around that, I thought maybe the code could target only pokemon over a certain level? So long as you don't include a magikarp or something over level 20, maybe that could work?

    would work for wild pokemon but this is affecting trainer pokemon set with less than 4 moves aswell, meaning if the pokemon is made to have less than 4 moves it'll break the game.
     
    233
    Posts
    5
    Years
    • Seen Oct 9, 2023
    After experimenting with the code a bit, I think I found a solution to the bug you're facing, ArchyTheArc. I basically reset the @moves array for the Pokemon before letting the while-loop to determine the new moves run. I've marked my addition in red:

    Code:
      def resetMoves
        moves=self.getMoveList
        movelist=[]
        for i in moves
          if i[0]<=self.level
            movelist[movelist.length]=i[1]
          end
        end
        movelist|=[] # Remove duplicates
        j=0
        threshold=4
        if movelist.length<4
          threshold=movelist.length
        end
        [color=red]for i in [email protected]
          @moves[i] = PBMove.new(0)
        end[/color]
        while j<threshold
          moveid=movelist[rand(movelist.length)]
          hasMove=false
          for i in 0...(@moves.length)
            if @moves[i].id==moveid
              hasMove=true
            end
          end
          if hasMove
            j-=1
          else
            @moves[j]=PBMove.new(moveid)
          end
          j+=1
        end
      end
     
    Last edited:
    286
    Posts
    5
    Years
    • Seen May 9, 2024
    I know it's been a while since posting in this thread, but I made the code more efficient (game would sometimes crash with less efficient version) and also developed an additional method for better trainer move generation. I know that many people were interested in this, so I thought it necessary to update this thread. Note that I separated trainer move and wild move generation, so if you want to distinguish these, remember to change calls to each method based on who they are generated for (replace resetMoves with wildResetMoves for wild move generation and trainerResetMoves for trainer move generation). If you just want one of the methods used for both types of generation, replace the method names I used with ResetMoves. Either way, the new methods or method should replace the old ResetMoves method. Both of these should increase variation in gameplay to hopefully make it more interesting and entertaining with trainer move combinations previously not seen as often. These edits should include most of the problems addressed earlier in the thread as well.

    Here's the improved code for wild move generation:
    Code:
      def wildResetMoves
        moves=self.getMoveList
        movelist=[]
        for i in moves
          if i[0]<=self.level
            movelist[movelist.length]=i[1]
          end
        end
        movelist|=[] # Remove duplicates
        j=0
        threshold=4
        if movelist.length<4
          threshold=movelist.length
        end
        while j<threshold
          r=rand(movelist.length)
          moveid=movelist[r]
          @moves[j]=PBMove.new(moveid)
          movelist.delete_at(r)
          j+=1
        end
      end

    The difference I chose for trainer move generation was to guarantee that the first move in every trainer Pokemon moveset was a STAB move (if possible). Then, generation is the same as wild pokemon. This way, each Pokemon should be somewhat competitively viable instead of having possibility of having all bad moves or something. Here's the code for trainer move generation:
    Code:
      def trainerResetMoves
        moves=self.getMoveList
        movelist=[]
        for i in moves
          if i[0]<=self.level
            movelist[movelist.length]=i[1]
          end
        end
        movelist|=[] # Remove duplicates
        j=1
        threshold=4
        if movelist.length<4
          threshold=movelist.length
        end
        stabmoves=[]
        for i in movelist
          temp=PBMove.new(i)
          if self.hasType?(temp.type) && temp.isDamaging?
            stabmoves[stabmoves.length]=temp
          end
        end
        if stabmoves.length!=0
          @moves[0]=stabmoves[rand(stabmoves.length)] # Guarantees 1st as STAB move
        else
          j=0
        end
        while j<threshold
          r=rand(movelist.length)
          moveid=movelist[r]
          @moves[j]=PBMove.new(moveid)
          movelist.delete_at(r)
          j+=1
        end
      end
     
    286
    Posts
    5
    Years
    • Seen May 9, 2024
    I found a bug in the trainerResetMoves method, so I'm putting the fixed one here. It used to allow the STAB move selected as the first move to be selected again, sometimes giving Pokemon duplicate moves, but that should be fixed now.

    Code:
      def trainerResetMoves
        moves=self.getMoveList
        movelist=[]
        for i in moves
          if i[0]<=self.level
            movelist[movelist.length]=i[1]
          end
        end
        movelist|=[] # Remove duplicates
        j=1
        threshold=4
        if movelist.length<4
          threshold=movelist.length
        end
        stabmoves=[]
        stabmoveindexes=[]
        k=0
        for i in movelist
          temp=PBMove.new(i)
          if self.hasType?(temp.type) && temp.isDamaging?
            stabmoves[stabmoves.length]=temp
            stabmoveindexes[stabmoveindexes.length]=k
          end
          k+=1
        end
        if stabmoves.length!=0
          r=rand(stabmoves.length)
          @moves[0]=stabmoves[r] # Guarantees 1st move as STAB
          movelist.delete_at(stabmoveindexes[r]) # Removes selected move from movelist
        else
          j=0
        end
        while j<threshold
          r=rand(movelist.length)
          moveid=movelist[r]
          @moves[j]=PBMove.new(moveid)
          movelist.delete_at(r)
          j+=1
        end
      end
     
    Back
    Top