Exp Gain Tweaking [Help needed]

Discussion in 'RPG Maker MV' started by SaucissonSec, Jun 15, 2019 at 3:16 AM.

  1. SaucissonSec

    SaucissonSec ᕙ໒( ˵ ಠ ╭͜ʖ╮ ಠೃ ˵ )७ᕗ Veteran

    Messages:
    38
    Likes Received:
    6
    Location:
    Frenchie France
    First Language:
    Frenglish
    Primarily Uses:
    RMMV
    Hello guys!
    Working on my project, i’m wishing to implement a particular Exp gain system, but I can’t figure out how to make it work :/

    In some RPGs like CrossCode (great game btw), the Exp you gain from killing enemies is relative to your level vs the levels of your enemies. If you kill an enemy that is way weaker than you, you’ll get only 1 exp, but defeating an enemy of your level will grant you ~50-100 Exp. This pushes the player to seek stronger enemies, making the game consistently challenging while also soft-forbidding the player to grind for Exp.

    You could partially achieve the same result using the default Exp curve, set up to be exponentially increasing, but there are downsides to that.

    • The player won’t be frustrated from gaining less exp and will be less likely to seek stronger enemies
    • The exponentially increasing exp need can disorient players and will complicate balancing.
    • Using consistent exp gain like I said previously will greatly simplify the balancing:
      • No more Exp calculation! Example: Each level will need 2500 exp, and you can get 100 exp for killing an enemy of your level, 50 exp if 1 level lower, 25 exp if 2 levels lower, 1 exp if 3 or more levels lower… Elite enemies give x2, and bosses give x5
    (CrossCode actually slightly increases the needed exp and gained exp over time, but its purely in a psychologic manner, the needed enemy kills stay pretty much the same)

    • You can also have a variable curve of exp depending if you want the player to spend more time in an area or less.
    • This also gives the developer complete control of the maximum level the player can have at any point in the game, allowing for easy enemy stat calculation.
    • This can also help setting up difficulty levels. By simply lowering/increasing the levels of enemies while keeping their stats, the player will automatically have weaker/stronger stats when facing them, thus making the game harder/easier.


    Is there any way I can setup a system like that? Is there a way to tweak the vanilla engine for that, or is there any plugins out there that could help me?

    Thanks a lot for your help!
     
    #1
  2. mathmaster74

    mathmaster74 just...John Veteran

    Messages:
    265
    Likes Received:
    175
    Location:
    Sheboygan, WI USA
    First Language:
    English
    Primarily Uses:
    RMMV
    #2
    SaucissonSec likes this.
  3. ShadowDragon

    ShadowDragon Veteran Veteran

    Messages:
    154
    Likes Received:
    45
    Location:
    Netherlands
    First Language:
    Dutch
    Primarily Uses:
    RMMV
    there are a few tutorials how to set this up, but it require a plugin or lunatic code. here is only one example, but there are
    around 4 out there similair than this, just adjust the way you need fit.
     
    #3
    SaucissonSec likes this.
  4. mathmaster74

    mathmaster74 just...John Veteran

    Messages:
    265
    Likes Received:
    175
    Location:
    Sheboygan, WI USA
    First Language:
    English
    Primarily Uses:
    RMMV
    @SaucissonSec Since I was party to that thread I shared earlier, and was close to a solution, I went back and ironed out the last "bug". Here's what works without a plugin or lunatic code if you want to set it up so experience is awarded immediately after each enemy dies:

    Set up a battle event page for each enemy in the troop. Set the condition to Enemy HP (X) <= 0%, where X is the EnemyID you set this page up for. Then enter the following Event commands:
    ◆Script:for (var i = 1; i <= $gameParty.aliveMembers().length; i++) { //Sets a loop to award Exp to each alive party member.
    : : var Difference = ($gameActors.actor(i).level + 5).clamp(0, 11); //See below for full explanation.
    : : var Multiplier = [5, 4.3, 3.7, 3.2, 2.8, 2.4, 2, 1.8, 1.6, 1.4, 1.2, 1][Difference]; //Multiplier amounts can be changed and/or added to.
    : : var ExPts = 80 * Multiplier / $gameParty.aliveMembers().length; //80 is the amount of Base Exp enemy is worth. Change to suit.
    : : $gameActors.actor(i).gainExp(ExPts); //Awards proper Exp per formula each time an enemy dies up until the last one.
    : :};
    ◆Control Variables:#0001 EnemiesDefeated += 1 //Keeps count of enemies defeated.
    ◆If:EnemiesDefeated = 2 //The value here should be the number of enemies minus 1. Condition runs when only 1 enemy is left.
    ◆Change Enemy State:Entire Troop, + Immortal //"Entire Troop" at this point is the last enemy.

    :End
    ◆If:#1 Bat is affected by Immortal //This was page #1 in my example. The enemy denoted here should match enemy the page is made for.
    ◆Change Enemy State:Entire Troop, - Immortal //Allows battle to end now that last enemy is defeated and Exp is awarded for it.

    :End

    Difference was set up based on an example provided by a user who originally asked for the script. They had set up tiers for level differences as follows: actor - enemy = -6, actor - enemy = -5, actor - enemy = -4, ..., actor - enemy = 4, and actor - enemy > 4, so that there were 11 differences in level that earned unique multipliers. Since their differences started at -6, a modifier of +6 was applied to compute difference. Since the var Difference returned a NaN error if the enemy level was referenced globally, I just plugged in the actual enemy level (something you should be able to decide upon if you're making each page for the target enemy) as a minus, and then combined with the modifier of +6 (because the clamp starts at 0...so shift -6 up to 0, -5 up to 1, etc.) In this example, the enemy is level 1, so actor - enemy + modifier = actor - 1 + 6, which reduces to actor + 5.

    Multiplier was also set up according to the specific original request. If they had wanted 12 level differences with unique multipliers, that's easily added in by giving one more value in the [Multiplier list] and setting upper bound of clamp to 12.

    Note that for this to work, you need to decide on 1) a Base amount of Exp (before Multiplier) the enemy is worth, 2) the enemy's level, and 3) what multipliers you're going to use (and how many). It's not a one shot deal like a nice & easy plugin, but it's not overly complicated either. I don't know how it will or will not affect Victory Aftermath, but can say that Level up notifications are immediate in battle by turn, so...that imo is cooler than getting the level up after a close battle is over where the level up during battle could have made a difference. Regardless of the solution you decide to use, I wish you the best, and am just happy I figured this all out. :smile:
     
    #4
    SaucissonSec likes this.
  5. SaucissonSec

    SaucissonSec ᕙ໒( ˵ ಠ ╭͜ʖ╮ ಠೃ ˵ )७ᕗ Veteran

    Messages:
    38
    Likes Received:
    6
    Location:
    Frenchie France
    First Language:
    Frenglish
    Primarily Uses:
    RMMV
    Wow, quick and very detailed answer! I will take a look once I have some time. Thank you for your support!

    EDIT: Testing it rn. I'll give you feedback on how that works and see about Victory Aftermath compatibility
     
    Last edited: Jun 15, 2019 at 7:00 AM
    #5
  6. SaucissonSec

    SaucissonSec ᕙ໒( ˵ ಠ ╭͜ʖ╮ ಠೃ ˵ )७ᕗ Veteran

    Messages:
    38
    Likes Received:
    6
    Location:
    Frenchie France
    First Language:
    Frenglish
    Primarily Uses:
    RMMV
    Test complete!
    @mathmaster74, your solution worked perfectly smoothly. Leveling inside combat works as well as the formula you mentioned!
    However, and that may be a big downside, Victory Aftermath won't calculate the gained exp, thus there is no feedback whatsoever about how much exp the player got from killing an enemy :/
    Unless I find some plugin to display gained exp to the player, I won't be able to use your system...:kaosigh:

    ...

    Oh, hang on a second.
    Right before sending my reply here's what I found from HimeWorks: http://himeworks.com/2016/02/battle-action-exp/
    I'm gonna check if it can be of use, and get back to you ;)

    EDIT: Ugh... :kaodes:After looking up HimeWorks plugin, from what I see, it is restricted to a global formula, which is not compatible with your idea. Additionally, it only allows 1 actor from gaining Exp from killing the enemies. The plugin won't work for our case. Also, the Popup addon only works with HimeWorks formula and not with any type of in-battle exp gain.

    I see only one solution now, which is creating a plugin to display a pop up with the gained exp on a downed enemy and potentially an alert for leveling up allowing me to disable Victory Aftermath Exp screen.
    I won't give up on this idea!:kaosalute:

    EDIT 2: I submitted my request for the needed feedback plugin. I find your idea of gaining exp directly in battle fantastic, and i'm not giving it up, definitely! We're gonna get a working exp system out of this!
    Here's the link: https://forums.rpgmakerweb.com/index.php?threads/simple-in-battle-gained-exp-popup.110009/
     
    Last edited: Jun 15, 2019 at 9:35 AM
    #6
    mathmaster74 likes this.
  7. mathmaster74

    mathmaster74 just...John Veteran

    Messages:
    265
    Likes Received:
    175
    Location:
    Sheboygan, WI USA
    First Language:
    English
    Primarily Uses:
    RMMV
    @SaucissonSec Glad to see you like my work. :smile: Even more glad to have a way for the Exp feedback to present at the time of the enemy's death! :biggrin: Here's the same setup with 2 lines added into the script:

    ◆Script:for (var i = 1; i <= $gameParty.aliveMembers().length; i++) {
    : : var Difference = ($gameActors.actor(i).level + 5).clamp(0, 11);
    : : var Multiplier = [5, 4.3, 3.7, 3.2, 2.8, 2.4, 2, 1.8, 1.6, 1.4, 1.2, 1][Difference];
    : : var ExPts = 80 * Multiplier / $gameParty.aliveMembers().length;
    : : $gameActors.actor(i).gainExp(ExPts);
    : : var text = $gameActors.actor(i).name() + ' has gained ' + Math.round(ExPts) + ' Exp!' //Builds the message for output.
    : : $gameMessage.add(text); //prints Exp gain right along with the level up notices!
    : :};
    ◆Control Variables:#0001 EnemiesDefeated += 1
    ◆If:EnemiesDefeated = 2
    ◆Change Enemy State:Entire Troop, + Immortal

    :End
    ◆If:#1 Bat is affected by Immortal
    ◆Change Enemy State:Entire Troop, - Immortal

    :End

    I wasn't able to make it appear as a single value above the enemy vanquished because, well...the exp is being split "i" ways where "i" = the number of alive party members, and then each party member in my example had a different level, so the split is not even. It would be possible to store the "i" values of ExPts to an array variable built inside the loop and then set another variable outside the loop equal to the sum of the "i" amounts in that array. From there, you could create and print a message for total party experience (which would be what the enemy had been worth total). This would also mean you now have the value stored in a variable, and all you would need is to have it pop up to get your desired result. I do not know how to take a value and make a pop up like in your .gif though. Still...if the player adds up the notices for each actor's exp award when an enemy goes down using the script lines added here, they will then know what that enemy was worth to the party...this time around. Of course, if anyone leveled up, the same enemy will have a new level difference against those party members...which would lead to new multipliers...which would lead to a new ExPts amounts...which would lead to a new sum...so the same enemy is now worth less ExPts to the party...which is as it should be. :wink:

    EDIT: Looking over the script, it assumed that all actors are alive party members. :oops: Hence, if a party member (other than the last one) died in battle, you would get undesired results with the issue of Exp as it stood. :eek: The following modifications fix that:

    ◆Script:var j = 1; //Here, j will be the new actorID reference variable.
    : :for (var i = 1; i <= $gameParty.aliveMembers().length; i++) {
    : : if ($gameActors.actor(j) < $gameParty.aliveMembers()) { //Is actor(j) alive?
    : : var Difference = ($gameActors.actor(j).level + 5).clamp(0, 11);
    : : var Multiplier = [5, 4.3, 3.7, 3.2, 2.8, 2.4, 2, 1.8, 1.6, 1.4, 1.2, 1][Difference];
    : : var ExPts = 80 * Multiplier / $gameParty.aliveMembers().length;
    : : $gameActors.actor(j).gainExp(ExPts);
    : : var text = $gameActors.actor(j).name() + ' has gained ' + Math.round(ExPts) + ' Exp!'
    : : $gameMessage.add(text); j++; //moves on to next actorID
    : : } else { j++; i--; //If actor(j) was dead, moves to next actor w/o advancing i
    : : };
    : :};
    ◆Control Variables:#0001 EnemiesDefeated += 1
    ◆If:EnemiesDefeated = 2
    ◆Change Enemy State:Entire Troop, + Immortal

    :End
    ◆If:#1 Bat is affected by Immortal
    ◆Change Enemy State:Entire Troop, - Immortal

    :End

    :cool:
     
    Last edited: Jun 15, 2019 at 4:50 PM
    #7
    SaucissonSec likes this.
  8. SaucissonSec

    SaucissonSec ᕙ໒( ˵ ಠ ╭͜ʖ╮ ಠೃ ˵ )७ᕗ Veteran

    Messages:
    38
    Likes Received:
    6
    Location:
    Frenchie France
    First Language:
    Frenglish
    Primarily Uses:
    RMMV
    Thanks again for your continuous effort. You’re right, Exp gained is different between each actor, meaning that the popup should appear on top of each actor’s portrait and not on the enemies. I’ll update the request thread accordingly. I’ll check if I can do something using Yanfly’s messages plugins to see if i can make a window appear displaying gained exp without breaking the battle’s rhythm.

    EDIT: Maybe we can work something around using $gameVariables.setValue( ID, value) so we can store our ExPts into an usable variable for Yanfly’s plugins. I’ll check that out and keep you updated.
     
    #8
  9. SaucissonSec

    SaucissonSec ᕙ໒( ˵ ಠ ╭͜ʖ╮ ಠೃ ˵ )७ᕗ Veteran

    Messages:
    38
    Likes Received:
    6
    Location:
    Frenchie France
    First Language:
    Frenglish
    Primarily Uses:
    RMMV
    SUCCESS! :kaojoy:

    Using these plugins: YEP_Message_Eval_Text (with YEP_MessageCore) and YEP_GabWindow, we got our popup! We can do anything out of Yanfly plugins lol
    upload_2019-6-15_13-16-6.png

    So here's what I did: upload_2019-6-15_13-15-3.png
    Full plugin command: GabText \c[4]\evaltext<<['Actor1','Actor2'][\V[2]]>>\c[0] Gained \c[16]\v[3]\c[0] EXP!

    I'm currently working on how we could replace 'Actor1' and 'Actor2' by using scripts for this command to work universally, with my poor JS knowledge i'll need your help here @mathmaster74 :/
    Also, i still need to figure out how to check if the actor leveled up from killing the enemy.
    Overall, we got something working for my game! It could be a personal achievement if we could make that work for any actors if they change during the game.
    What do you think?

    EDIT: I'm stuck :/ Your method requires me to send player feedback within the "for" loop, which cannot be done using the plugins I mentioned, which means we are stuck here.

    EDIT 2: @Magnus0808 helped me out, check my request thread: https://forums.rpgmakerweb.com/index.php?threads/simple-in-battle-gained-exp-popup.110009/
    I'll see how to make his plugin works and keep you updated.
     

    Attached Files:

    Last edited: Jun 16, 2019 at 2:38 AM
    #9
  10. mathmaster74

    mathmaster74 just...John Veteran

    Messages:
    265
    Likes Received:
    175
    Location:
    Sheboygan, WI USA
    First Language:
    English
    Primarily Uses:
    RMMV
    @SaucissonSec Based on what you have, it looks like we just need to store the "i" number of ExPts amounts in global game variables and then print our pop-ups. I've set corresponding global variables with the actor name strings to eliminate the need for message evals, too. This worked in my tests using ONLY Yanfly's Gab Window plugin:

    ◆Script:var j = 1; //This references actor ID separate from party member ID to keep things straight
    : :for (var i = 1; i <= $gameParty.aliveMembers().length; i++) {
    : : if ($gameActors.actor(j) < $gameParty.aliveMembers()) {
    : : var Difference = ($gameActors.actor(j).level + 5).clamp(0, 11);
    : : var Multiplier = [5, 4.3, 3.7, 3.2, 2.8, 2.4, 2, 1.8, 1.6, 1.4, 1.2, 1][Difference];
    : : var ExPts = 80 * Multiplier / $gameParty.aliveMembers().length;
    : : $gameActors.actor(j).gainExp(ExPts);
    : : var ExpVar = 300+j; var ExpActor = 400+j; //Replaced message printout w/ actor name and exp reference variable numbers*
    : : $gameVariables.setValue(ExpVar, ExPts); $gameVariables.setValue(ExpActor, $gameActors.actor(j).name()); j++; //Setup for gab
    : : } else { j++; i--; //This is what ensures ALL and ONLY alive members are counted.
    : : };
    : :};
    ◆If:Script:$gameActors.actor(1) < $gameParty.aliveMembers() //Only prints if actor 1 alive.
    ◆Plugin Command:GabText \c[4]\v[401]\c[0] Gained \c[16]\v[301]\c[0] EXP! //If actor 1 alive, builds gab text.
    ◆Plugin Command:ShowGab

    :End
    ◆If:Script:$gameActors.actor(2) < $gameParty.aliveMembers() //Just a repeat for actor 2, etc.
    ◆Plugin Command:GabText \c[4]\v[402]\c[0] Gained \c[16]\v[302]\c[0] EXP!
    ◆Plugin Command:ShowGab

    :End
    ◆If:Script:$gameActors.actor(3) < $gameParty.aliveMembers()
    ◆Plugin Command:GabText \c[4]\v[403]\c[0] Gained \c[16]\v[303]\c[0] EXP!
    ◆Plugin Command:ShowGab

    :End
    ◆If:Script:$gameActors.actor(4) < $gameParty.aliveMembers() //I stopped at the default 4 actors, but you can do this for more.
    ◆Plugin Command:GabText \c[4]\v[404]\c[0] Gained \c[16]\v[304]\c[0] EXP!
    ◆Plugin Command:ShowGab

    :End
    ◆Control Variables:#0001 EnemiesDefeated += 1
    ◆If:EnemiesDefeated = 2
    ◆Change Enemy State:Entire Troop, + Immortal

    :End
    ◆If:#1 Bat is affected by Immortal
    ◆Change Enemy State:Entire Troop, - Immortal

    :End

    *Note: Because this code uses variables in the 300s and 400s (see * line in spoiler), if you use the same reference numbers, you need to change your variable maximum above these reference amounts (say up to 500) in the database, or the script will try to set values to non-existing variables, throw no error, and then the later code will say the variables are all 0. (0 Gained 0 Exp!) :rolleyes:

    I prefer the way we were printing it out, but if you can massage your gab window timing and look to make it preferable, then...enjoy! :biggrin:
     
    #10

Share This Page