• 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] Gain Happiness / Friendship from EXP?

  • 30
    Posts
    11
    Years
    • Seen Apr 9, 2023
    Hey guys, long story short I'm looking to make it so whenever your Pokemon successfully beats another, it gains some happiness.
    I know the way the game currently works is its happening whenever you level up, but I would like to re-balance how Happiness works entirely in my game and remove it from levels and instead make it happen every time you gain experience (as I assume this is the easiest way to emulate "My pokemon beat some one else's Pokemon!")

    I am admittedly not very knowledgeable when it comes to this sort of thing. Most of the major features and things I've done with my game have just been basically editing already made scripts or duplicating them in ways to accomplish my goal.

    That's what I'm trying to do here, but I can't seem to figure out how to make it happen, as my attempts so far have either returned errors or done nothing at all with respect to happiness.

    Maybe you guys would know more? Specifically, what I should put where?

    Here is the "Gaining Experience." Script in _battle as it stands now.

    Code:
    ################################################################################
    # Gaining Experience.
    ################################################################################
      def pbGainEXP
        return if !@internalbattle
        successbegin=true
        badgelevel=20 # InsurgenceLv Mod is here
        badgelevel=25  if self.pbPlayer.numbadges>=1
        badgelevel=35  if self.pbPlayer.numbadges>=2
        badgelevel=40  if self.pbPlayer.numbadges>=3
        badgelevel=45  if self.pbPlayer.numbadges>=4
        badgelevel=50  if self.pbPlayer.numbadges>=5
        badgelevel=55  if self.pbPlayer.numbadges>=6
        badgelevel=60  if self.pbPlayer.numbadges>=7
        badgelevel=65  if self.pbPlayer.numbadges>=8
        badgelevel=70  if self.pbPlayer.numbadges>=9
        badgelevel=75  if self.pbPlayer.numbadges>=11
        badgelevel=80  if self.pbPlayer.numbadges>=13
        badgelevel=85  if self.pbPlayer.numbadges>=14
        badgelevel=90  if self.pbPlayer.numbadges>=15
        badgelevel=95  if self.pbPlayer.numbadges>=17
        badgelevel=100 if self.pbPlayer.numbadges>=18
        for i in 0...4 # Not ordered by priority
          if !@doublebattle && pbIsDoubleBattler?(i)
            @battlers[i].participants=[]
            next
          end
          if pbIsOpposing?(i) && @battlers[i].participants.length>0 && @battlers[i].isFainted?
            battlerSpecies=@battlers[i].pokemon.species
            # Original species, not current species
            baseexp=@battlers[i].pokemon.baseExp
            level=@battlers[i].level
            # First count the number of participants
            partic=0
            expshare=0
            for j in @battlers[i].participants
              next if !@party1[j] || !pbIsOwner?(0,j)
              partic+=1 if @party1[j].hp>0 && !@party1[j].isEgg?
            end
            for j in [email protected]
              next if !@party1[j] || !pbIsOwner?(0,j)
              expshare+=1 if @party1[j].hp>0 && !@party1[j].isEgg? && 
                 (isConst?(@party1[j].item,PBItems,:EXPSHARE) ||
                  isConst?(@party1[j].itemInitial,PBItems,:EXPSHARE))
            end
            # Now calculate EXP for the participants
            if partic>0 || expshare>0
              if !@opponent && successbegin && pbAllFainted?(@party2)
                @scene.pbWildBattleSuccess
                successbegin=false
              end
              for j in [email protected]
                thispoke=@party1[j]
                next if !@party1[j] || !pbIsOwner?(0,j)
                ispartic=0
                haveexpshare=(isConst?(thispoke.item,PBItems,:EXPSHARE) ||
                              isConst?(thispoke.itemInitial,PBItems,:EXPSHARE)) ? 1 : 0
                for k in @battlers[i].participants
                  ispartic=1 if k==j
                end
                if thispoke.hp>0 && !thispoke.isEgg?
                  exp=0
                  if expshare>0
                    if partic==0
                      exp=(level*baseexp).floor
                      exp=(exp/expshare).floor*haveexpshare
                    else
                      exp=(level*baseexp/2).floor
                      exp=(exp/partic).floor*ispartic + (exp/expshare).floor*haveexpshare
                    end
                  elsif ispartic==1
                    exp=(level*baseexp/partic).floor
                  end
                  exp=(exp*6/2).floor if @opponent
                  if USENEWEXPFORMULA   # Use new (Gen 5) Exp. formula
                    exp=(exp/5).floor
                    leveladjust=(2*level+10.0)/(level+thispoke.level+10.0)
                    leveladjust=leveladjust**5
                    leveladjust=Math.sqrt(leveladjust)
                    exp=(exp*leveladjust).floor
                    exp+=1 if ispartic>0 || haveexpshare>0
                  else                  # Use old (Gen 1-4) Exp. formula
                    exp=(exp/7).floor
                  end
      #            print("#{thispoke.trainerID}")
                  isOutsider=((thispoke.trainerID != self.pbPlayer.id && 
                     thispoke.trainerID != 0) ||
                     (thispoke.language!=0 && thispoke.language!=self.pbPlayer.language))
       #           print("#{isOutsider}")
                  if isOutsider
                    if thispoke.language!=0 && thispoke.language!=self.pbPlayer.language
                      exp=(exp*17/10).floor
                    else
                      exp=(exp*3/2).floor
                    end
                  end
                  if thispoke.level >= badgelevel # InsurgenceLv Mod is here
    								exp = 1 * ispartic
    							else
    								exp=(exp*3/2).floor if isConst?(thispoke.item,PBItems,:LUCKYEGG) ||
    								isConst?(thispoke.itemInitial,PBItems,:LUCKYEGG)
                  end
                  growthrate=thispoke.growthrate
                  newexp=PBExperience.pbAddExperience(thispoke.exp,exp,growthrate)
                  exp=newexp-thispoke.exp
                  if exp > 0
    #### KUROTSUNE - 020 - START
                    if isOutsider || isConst?(thispoke.item,PBItems,:LUCKYEGG)
    #### KUROTSUNE - 020 - END
                      pbDisplayPaused(_INTL("{1} gained a boosted {2} Exp. Points!",thispoke.name,exp))
                    else
                      pbDisplayPaused(_INTL("{1} gained {2} Exp. Points!",thispoke.name,exp))
                    end
                    #Gain effort value points, using RS effort values
                    totalev=0
                    for k in 0..5
                      totalev+=thispoke.ev[k]
                    end
                    # Original species, not current species
                    evyield=@battlers[i].pokemon.evYield
                    for k in 0..5
                      evgain=evyield[k]
                      evgain*=2 if isConst?(thispoke.item,PBItems,:MACHOBRACE) ||
                                   isConst?(thispoke.itemInitial,PBItems,:MACHOBRACE)
                      case k
                        when 0
                          if isConst?(thispoke.item,PBItems,:POWERWEIGHT)
                            evgain+=4
                          end
                        when 1
                          if isConst?(thispoke.item,PBItems,:POWERBRACER)
                            evgain+=4
                          end
                        when 2
                          if isConst?(thispoke.item,PBItems,:POWERBELT) 
                            evgain+=4
                          end
                        when 3
                          if isConst?(thispoke.item,PBItems,:POWERANKLET) 
                            evgain+=4
                          end
                        when 4
                          if isConst?(thispoke.item,PBItems,:POWERLENS) 
                            evgain+=4
                          end
                        when 5
                          if isConst?(thispoke.item,PBItems,:POWERBAND) 
                            evgain+=4
                          end
                      end
                      evgain*=2 if thispoke.pokerusStage>=1 # Infected or cured
                      if evgain>0
                        # Can't exceed overall limit
                        if totalev+evgain>510
                          evgain-=totalev+evgain-510
                        end
                        # Can't exceed stat limit
                        if thispoke.ev[k]+evgain>252
                          evgain-=thispoke.ev[k]+evgain-252
                        end
                        # Add EV gain
                        thispoke.ev[k]+=evgain
                        if thispoke.ev[k]>252
                          print "Single-stat EV limit 252 exceeded.\r\nStat: #{k}  EV gain: #{evgain}  EVs: #{thispoke.ev.inspect}"
                          thispoke.ev[k]=252
                        end
                        totalev+=evgain
                        if totalev>510
                          print "EV limit 510 exceeded.\r\nTotal EVs: #{totalev} EV gain: #{evgain}  EVs: #{thispoke.ev.inspect}"
                        end
                      end
                    end
                    newlevel=PBExperience.pbGetLevelFromExperience(newexp,growthrate)
                    tempexp=0
                    curlevel=thispoke.level
                    thisPokeSpecies=thispoke.species
                    if newlevel<curlevel
                      debuginfo="#{thispoke.name}: #{thispoke.level}/#{newlevel} | #{thispoke.exp}/#{newexp} | gain: #{exp}"
                      raise RuntimeError.new(
                         _INTL("The new level ({1}) is less than the Pokémon's\r\ncurrent level ({2}), which shouldn't happen.\r\n[Debug: {3}]",
                         newlevel,curlevel,debuginfo))
                      return
                    end
                    if thispoke.respond_to?("isShadow?") && thispoke.isShadow?
                      thispoke.exp+=exp
                    else
                      tempexp1=thispoke.exp
                      tempexp2=0
                      # Find battler
                      battler=pbFindPlayerBattler(j)
                      loop do
                        #EXP Bar animation
                        startexp=PBExperience.pbGetStartExperience(curlevel,growthrate)
                        endexp=PBExperience.pbGetStartExperience(curlevel+1,growthrate)
                        tempexp2=(endexp<newexp) ? endexp : newexp
                        thispoke.exp=tempexp2
                        @scene.pbEXPBar(thispoke,battler,startexp,endexp,tempexp1,tempexp2)
                        tempexp1=tempexp2
                        curlevel+=1
                        if curlevel>newlevel
                          thispoke.calcStats 
                          battler.pbUpdate(false) if battler
                          @scene.pbRefresh
                          break
                        end
                        oldtotalhp=thispoke.totalhp
                        oldattack=thispoke.attack
                        olddefense=thispoke.defense
                        oldspeed=thispoke.speed
                        oldspatk=thispoke.spatk
                        oldspdef=thispoke.spdef
                        if battler
                          if battler.pokemon && @internalbattle
                            battler.pokemon.changeHappiness("level up")
                          end
                        end
                        thispoke.calcStats
                        battler.pbUpdate(false) if battler
                        @scene.pbRefresh
                        pbDisplayPaused(_INTL("{1} grew to Level {2}!",thispoke.name,curlevel))
                        @scene.pbLevelUp(thispoke,battler,oldtotalhp,oldattack,
                           olddefense,oldspeed,oldspatk,oldspdef)
                        # Finding all moves learned at this level
                        movelist=thispoke.getMoveList
                        for k in movelist
                          if k[0]==thispoke.level   # Learned a new move
                            pbLearnMove(j,k[1])
                          end
                        end
                      end
                    end
                  end
                end
              end
            end
            # Now clear the participants array
            @battlers[i].participants=[]
          end
        end
      end

    Hope its not absurdly obvious for you guys. Thanks in advance if you are able to help me accomplish this!
     
  • 87
    Posts
    7
    Years
    • Seen Nov 22, 2023
    How would you like the Pokemon to gain happiness?
    Depending on the experience gained?
    A fixed amount?

    Here is how to do it you'd like a fixed amount.
    In Pokebattle_Battle, add the red part.
    Code:
      def pbGainExpOne(index,defeated,partic,expshare,haveexpall,showmessages=true)
        thispoke=@party1[index]
        # Original species, not current species
        level=defeated.level
        baseexp=defeated.pokemon.baseExp
        evyield=defeated.pokemon.evYield
        [COLOR="red"]# Gain Happiness through experience
        thispoke.changeHappiness("gainexperience")[/COLOR]

    We just created a new method called "gainexperience."
    Right now it doesn't do anything, we have to define how much experience to give.

    Go to PokeBattle_Pokemon and look for def changeHappiness(method)
    Add the red part:
    Code:
    # Changes the happiness of this Pokémon depending on what happened to change it.
      def changeHappiness(method)
        gain=0; luxury=false
        case method
    [COLOR="Red"]    when "gainexperience"
          gain=1
          gain+=5 if @happiness<200
          luxury=true[/COLOR]
        when "walking"
          gain=1
          gain+=1 if @happiness<200
          gain+=1 if @obtainMap==$game_map.map_id
          luxury=true
        when "levelup"
          gain=2
          gain=3 if @happiness<200
          gain=5 if @happiness<100
          luxury=true
        when "groom"
          gain=4
          gain=10 if @happiness<200
          luxury=true
        when "faint"
          gain=-1
        when "vitamin"
          gain=2
          gain=3 if @happiness<200
          gain=5 if @happiness<100
        when "evberry"
          gain=2
          gain=5 if @happiness<200
          gain=10 if @happiness<100
        when "powder"
          gain=-10
          gain=-5 if @happiness<200
        when "energyroot"
          gain=-15
          gain=-10 if @happiness<200
        when "revivalherb"
          gain=-20
          gain=-15 if @happiness<200
        else
          Kernel.pbMessage(_INTL("Unknown happiness-changing method."))
        end
        gain+=1 if luxury && self.ballused==pbGetBallType(:LUXURYBALL)
        if isConst?(self.item,PBItems,:SOOTHEBELL) && gain>0
          gain=(gain*1.5).floor
        end
        @happiness+=gain
        @happiness=[[255,@happiness].min,0].max
      end

    As per the code, the Pokemon will always gain at least 1 happiness , plus 5 more if they are below 200 happiness.
    Furthermore, the "luxury=true" activates that Luxury Ball bonus. Set that boolean to false if you'd like to disable that.

    I don't believe this works with the experience share or the experience share all.
    If you could specify a few more details, I'll try to help.
     
    Last edited:
  • 30
    Posts
    11
    Years
    • Seen Apr 9, 2023
    Thanks for your assistance! This is essentially what I am trying to do, glad it wasn't too complicated.
    I had tried pokemon.changehappiness etc, but I didn't try "thispoke"
    I don't fully understand that whole thing, its always been confusing to me. I guess that's a fundamental part of Ruby though, huh?

    So, yes I am looking for a set amount of happiness to be gained no matter the amount of experience, because I want the story side of this to basically be that our Pokemon are happy when they succeed in battle, just like how when they faint they lose happiness already.

    I also hadn't thought about it until you brought it up, but I would be happy if it didn't work with the EXPshare, because I want it to be about actually participating in the battle, so if this current idea does that seemingly by accident that would be a happy coincidence, but if it does impact EXPshare experience, that's fine I suppose.
    Its not meant to be a major part of the game, just something I'd like to make a possibility.

    Anyway, only problem is your suggestion to add the red in _battle... well that doesn't exist for me. I assume this is because the version of the script you are using is from a newer version of essentials?
    I've been working on this game for god knows how long now, and never bothered to update.
    I posted my experience script in the original post here.

    Are you able to tell me where exactly I need to add your suggested method? I'm not actually sure how much it matters where you add things like this, so I don't want to just jam it in there over and over again until it doesn't return errors.
    If you have any questions lemme know, otherwise thanks so much for your help so far.
     
    Last edited:
  • 87
    Posts
    7
    Years
    • Seen Nov 22, 2023
    Assuming you're on v16.2 or v17.2, it should be there - I just checked as I have both versions.
    Go to PokeBattle_Battle and do a CTRL + F for "evyield=defeated.pokemon.evYield"
    Paste the red part right under there.

    Placement of the script is semi-important.
    For instance, if you wanted happiness to distribute to all party members due to an exp share all, then you'd probably look for that code and do something similar - or even paste it in there.
    You may also place code anywhere within a method and it could still work but some may say that placing it just anywhere is a bad practice; consistency is a good thing, especially in coding.
    I honestly do not think I placed it in the best place. I placed it in the middle of the ev gain code.
    Perhaps a better place would be above the comment that says "# Original species, not current species"

    Let me know if you need anything else!

    P.S. Don't feel like like you're burdening me, I am challenging myself to code/event in the best ways possible.
    The only way to do that is if I help others - not to mention how good it feels. :D
     
  • 30
    Posts
    11
    Years
    • Seen Apr 9, 2023
    Ya idk why its not there, but that's why I posted my script haha. Was hoping you would just look at what I had and give advise based on that.
    No worries though, I kind of did what I said I wouldn't and just threw it in some where.
    I ended up pasting it right before this script
    Code:
    newlevel=PBExperience.pbGetLevelFromExperience(newexp,growthrate)
                    tempexp=0
                    curlevel=thispoke.level
                    thisPokeSpecies=thispoke.species

    Ended up working fine, but it was interacting with the EXPshare or whatever.
    Not my favorite thing, but really doesn't matter.
    EVs already do that, so it makes sense that it would do that for Happiness in this situation as well.

    But maybe if I put it some where else that would change?
    Maybe before the " # Now calculate EXP for the participants " part?
     
    Last edited:
  • 87
    Posts
    7
    Years
    • Seen Nov 22, 2023
    Try above this line:
    #Gain effort value points, using RS effort values
    totalev=0
    for k in 0..5
    totalev+=thispoke.ev[k]
    end
     
  • 30
    Posts
    11
    Years
    • Seen Apr 9, 2023
    Still gives EXP to both pokemon.
    Which is fine, really. Not that big of a deal.
    I already have things set up to EXPshare EV grind, so its probably only fair that it shares Friendship too.
    Doesn't make as much sense from an in-game explanation, but as a gameplay feature this is probably how it should be.
     
    Back
    Top