State Damage Modifiers

Tsukihime

Veteran
Veteran
Joined
Jun 30, 2012
Messages
8,230
Reaction score
3,079
First Language
English
 ​

In RPG Maker MV, damage calculations are performed when one battler uses an action on another battler (including themselves).

So for example, let's say your actor attacked an enemy using skill #3. The game would look at skill #3's damage formula and use that to determine the base damage that the skill can deal.

In addition to this "base damage", we also have some extra damage modifiers, such as the guard effect which halves the damage received, as well as the critical hit modifier, which increases damage based on a critical multiplier.

This plugin allows you to further apply additional damage modifiers, which essentially allows you to change the damage even further. These modifiers will be applied to states, so whenever the state is active, the damage modifiers will be used.

State damage modifiers can be applied to both the attacker as well as the target. Attacker damage modifiers are applied before the target damage modifiers.
 

More information and downloads are available at HimeWorks
 
Last edited by a moderator:

Tsukihime

Veteran
Veteran
Joined
Jun 30, 2012
Messages
8,230
Reaction score
3,079
First Language
English
I think I need to separate the "attack" modifiers from the "defense" modifiers.


Currently, the same formula is being used for both attacking and defending, which forces you to write extra code to check whether you're actually attacking or defending.
 

Aluvien

Veteran
Veteran
Joined
Nov 14, 2014
Messages
33
Reaction score
15
First Language
English
Primarily Uses
Thanks for this, I'll put it to good use. I did run into a slight bug - if a state prevents more damage than you would otherwise take, you gain the extra as healing. I just changed line 133 to
 

return Math.max(value,0);and that took care of it. I think your idea for separating the attack and defense modifiers is a good one - currently many of my notetags are five or six lines where they could otherwise be one. Finally, do you know how to check for a skill's type in this context (so for instance, you could make a state that increases damage from physical attacks)?  It seems like isPhysical() would be relevant, but "this" in a notetag refers to Window and I haven't managed to figure out the correct syntax yet. Thanks again for making this!
 

Tsukihime

Veteran
Veteran
Joined
Jun 30, 2012
Messages
8,230
Reaction score
3,079
First Language
English
I have updated the plugin to split the modifiers based on your role:

- Attacker modifiers: these are applied when you're attacking

- Defender modifiers: these are applied when you're attacked

So if A attacks B, then A is the attacker, and B is the defender.

It is possible for A to target himself, in which case both attacker and defender modifiers will be applied.

The changes required:

<state damage modifier> FORMULA</state damage modifier>to
Code:
<state damage modifier: attacker>  FORMULA</state damage modifier>
or "defender"
I did run into a slight bug - if a state prevents more damage than you would otherwise take, you gain the extra as healing.
For the max issue, I'm not sure if that's something I will add to the plugin itself, since some people might actually want it to go negative and, thus, heal you.

While the default formula evaluation does assume 0 is the min value, I don't want to impose such a restriction.

Finally, do you know how to check for a skill's type in this context (so for instance, you could make a state that increases damage from physical attacks)?
If you would like to check the skill's element type, you can use

this.item().damage.elementIdIf you want the skill type, you can use

Code:
this.item().stypeId
Print out this.item() if you want to see all of the available properties.If you're referring to the hit type (certain, physical, magical), take a look at those properties.
 
Last edited by a moderator:

Aluvien

Veteran
Veteran
Joined
Nov 14, 2014
Messages
33
Reaction score
15
First Language
English
Primarily Uses
While the default formula evaluation does assume 0 is the min value, I don't want to impose such a restriction.
Ahh, that makes sense, then.

Regarding this.item - were you able to get this to work? When I try console.log(this.item), it comes back as undefined. Console.log(this.item()) then crashes the game. I've poked around for awhile with this.Game_Action.prototype.xxx, but I haven't found anything useful yet.
 

Tsukihime

Veteran
Veteran
Joined
Jun 30, 2012
Messages
8,230
Reaction score
3,079
First Language
English
Ahh, that makes sense, then.

Regarding this.item - were you able to get this to work? When I try console.log(this.item), it comes back as undefined. Console.log(this.item()) then crashes the game. I've poked around for awhile with this.Game_Action.prototype.xxx, but I haven't found anything useful yet.
Sorry, I just realized I was testing my formula in the plugin, and not the state damage modifier.

I assumed the formula was evaluated in the context of the action, but it wasn't due to how javascript works.

I've updated it so that the function IS evaluated in the action's context, so `this` references the current action.

Now you can say refer to the current action using `this` and the calls I showed above will work.

Line 197

OLD

Code:
value = fn.call(a, b, v, d);
NEW
Code:
value = fn.call(this, a, b, v, d);
I will keep this in mind for future plugins.
 
Last edited by a moderator:

Aluvien

Veteran
Veteran
Joined
Nov 14, 2014
Messages
33
Reaction score
15
First Language
English
Primarily Uses
They're all working great now, thanks! I'm also going to leave a note here for any future users: if you don't want excess prevented damage to heal, do NOT use the change I posted above. It turns out the game treats healing and damage the same behind the scenes, so that "fix" prevents all direct healing. Rather, structure your defensive notetags like this:

<state damage modifier: defender>if(d < 0){ return d;}else{ return desired formula;}</state damage modifier>This lets healing skip past your damage reduction, which would otherwise cancel it out (such as in my earlier fix) or increase it (such as if you made a flat d - number).

EDIT: You could potentially do the same thing in fewer lines of code with

<state damage modifier: defender>if(d > 0){ return desired code;}</state damage modifier>but I haven't tested that yet.
 
Last edited by a moderator:

Tsukihime

Veteran
Veteran
Joined
Jun 30, 2012
Messages
8,230
Reaction score
3,079
First Language
English
I was thinking maybe there was a way to handle healing and damage separately, but then you have cases where you actually want the formula to amplify both healing AND damaging effects, so it probably isn't a good idea to just assume they should be separate things.


For example, if you have an enemy that absorbs fire, do you necessarily want to treat it as a damaging or a healing attack
 

Aluvien

Veteran
Veteran
Joined
Nov 14, 2014
Messages
33
Reaction score
15
First Language
English
Primarily Uses
I think in that situation maybe a better solution would be to create a custom state for that enemy capable of absorbing fire, maybe something like

<state damage modifier: defender>if(d > 0 && this.item().damage.elementId != 3){ return formula;}</state damage modifier>if you want fire to bypass your damage reduction (unfortunately I don't have an elem absorb plugin on hand to test this myself). This does have downsides of its own - as your game design has higher numbers of absorbing monsters and higher numbers of interchangeable states (so you can expect to take one state and apply it to many kinds of monsters), the number of custom states you'd have to make rises very quickly. On the other hand, if such a monster is rare and will use few states, this might be a good way to go.  It really is a very flexible plugin to be able to do things like this.

EDIT: Aha! Here we go:

<state damage modifier: defender>var x = this.item().damage.elementId;if(d > 0 || b.elementRate(x) < 0){ return formula;}</state damage modifier>So if you happen to absorb a particular element even temporarily, your state will let "damage" from it heal you and be amplified by your defensive state. The exact syntax used will have to vary based on the way your absorb plugin handles it of course, but I think the general idea should work. This *should* let the same state work for whoever regardless of elemental absorption rate.
 
Last edited by a moderator:

Tsukihime

Veteran
Veteran
Joined
Jun 30, 2012
Messages
8,230
Reaction score
3,079
First Language
English
Speaking of absorption, you could potentially implement elemental absorption, or *arbitrary* damage absorption rules using the state damage formula.


For example, if you know that the element is Fire, you could just negate the value and now you'll be healed.


If you didn't want to deal with element rates and just wanted to say "this state will absorb all fire attacks", you would just check the skills' damage element and determine whether to negate or not.
 

Aluvien

Veteran
Veteran
Joined
Nov 14, 2014
Messages
33
Reaction score
15
First Language
English
Primarily Uses
I ran across a couple things while playtesting. Neither are game-breaking, but are kind of a pain if you don't know about them:

First, defensive states are currently preventing exactly twice as much damage as they should. I tested this as rigorously as I could. I used a fresh project, no other scripts, and set the basic Attack damage to exactly 10 with 0 variance. I gave the entire party a state that returned d - 10 so that they should take 0 damage from attacks (that was the only line of code). When they were attacked, they would instead heal for 10. When they were attacked while guarding, they healed for 15, etc. I experimented with different numbers and found no exceptions. I also tested this in my current game project and got the same result. I didn't test attacker states.

Second, users should be careful to always include an else branch when using an if statement. If you only have, say, if(d>0){code}, with no else statement, then all sorts of things will make the game crash - such as using a healing item or being physically attacked. It doesn't have to be complicated - just drop in an else statement of any kind and you're good.

 
 

Tsukihime

Veteran
Veteran
Joined
Jun 30, 2012
Messages
8,230
Reaction score
3,079
First Language
English
Plugin has been updated with some fixes and improvements.

I ran across a couple things while playtesting. Neither are game-breaking, but are kind of a pain if you don't know about them:

First, defensive states are currently preventing exactly twice as much damage as they should. I tested this as rigorously as I could. I used a fresh project, no other scripts, and set the basic Attack damage to exactly 10 with 0 variance. I gave the entire party a state that returned d - 10 so that they should take 0 damage from attacks (that was the only line of code). When they were attacked, they would instead heal for 10. When they were attacked while guarding, they healed for 15, etc. I experimented with different numbers and found no exceptions. I also tested this in my current game project and got the same result. I didn't test attacker states.
I found this line of code left in there

Game_Action.prototype.applyDefenderStateDamageModifiers = function(target, critical, value) { var states = target.states(); states = states.concat(target.states());Which basically duplicated all the states. That is why they were being evaluated twice.This has been addressed.

Second, users should be careful to always include an else branch when using an if statement. If you only have, say, if(d>0){code}, with no else statement, then all sorts of things will make the game crash - such as using a healing item or being physically attacked. It doesn't have to be complicated - just drop in an else statement of any kind and you're good.
My code currently assumes the user will provide a valid return value.

Code:
value = fn.call(this, a, b, v, d);
What I can do is check whether there is a return value, and if not, just assume the formula did nothing and pass on the current damage value.
Code:
value = fn.call(this, a, b, v, d) || value;
Then you don't need to worry about having to always return the current damage if you don't want the formula to do anything.
 

gotnovicks

Veteran
Veteran
Joined
Feb 15, 2015
Messages
76
Reaction score
9
First Language
Portuguese
Primarily Uses
N/A
Hi hime, awesome work :)

@EDIT:

I was having an formula issue, but I found out the problem is not the formula, but a plugin compatibility issue.

I'm using yanfly passive states, but if a state has a damage modifier notetag, the damage modifier does not work while using as a pssive state.

Do you have any plans for a "passive skills/state" plugin?

also I'd ask you for some compatibility add-on...
 
Last edited by a moderator:

Tsukihime

Veteran
Veteran
Joined
Jun 30, 2012
Messages
8,230
Reaction score
3,079
First Language
English
My plugin assumes grabbing a battler's states() returns ALL states, whether it's temporary, permanent, passive, and so on.


I looked at yanfly's plugin and states also include passive states.


Upon testing, the plugin seems to work fine with his plugin.


Have you verified that it is the passive states causing the problem?
 
Last edited by a moderator:

gotnovicks

Veteran
Veteran
Joined
Feb 15, 2015
Messages
76
Reaction score
9
First Language
Portuguese
Primarily Uses
N/A
My plugin assumes grabbing a battler's states() returns ALL states, whether it's temporary, permanent, passive, and so on.

I looked at yanfly's plugin and states also include passive states.

Upon testing, the plugin seems to work fine with his plugin.

Have you verified that it is the passive states causing the problem?
I can't look at it right now, but I tested by adding manually the state, and it works. but when the state comes from a equip with passive state, it does not work.

@Edit: ok, i tested in a clean project and the state I want didn't work, but then I used a simple one (return d * 2) and it worked... I guess the problem is t in the formula...

so the formula is:

<state damage modifier: defender>var rdm = Math.randomInt(100) + 1;if (rdm <= 10) {return 0;} else {return d;}</state damage modifier>When with this state, the defender has a 10% chance on returning 0 when receiving damage. 
 
Last edited by a moderator:

Tsukihime

Veteran
Veteran
Joined
Jun 30, 2012
Messages
8,230
Reaction score
3,079
First Language
English
Add a

console.log(rdm)after the first line to print out the value to console.Open the console by pressing F8
 

gotnovicks

Veteran
Veteran
Joined
Feb 15, 2015
Messages
76
Reaction score
9
First Language
Portuguese
Primarily Uses
N/A
Add a

console.log(rdm)after the first line to print out the value to console.Open the console by pressing F8
It prints 2 values in two lines (15 and 80 at the first time, 75 and 42 and the second time). Is it right? I guess the code is generating the random code twice...
 

Tsukihime

Veteran
Veteran
Joined
Jun 30, 2012
Messages
8,230
Reaction score
3,079
First Language
English
I just noticed that the changes I made regarding a previously reported issue (duped states) came back into the code. That's the reason why it's being called twice.


I've checked the code and it should be gone now.


Anyways in both cases they are greater than 10 so the damage modifier doesn't do anything.
 

gotnovicks

Veteran
Veteran
Joined
Feb 15, 2015
Messages
76
Reaction score
9
First Language
Portuguese
Primarily Uses
N/A
I just noticed that the changes I made regarding a previously reported issue (duped states) came back into the code. That's the reason why it's being called twice.

I've checked the code and it should be gone now.

Anyways in both cases they are greater than 10 so the damage modifier doesn't do anything.
I redownloaded and changed the code to be <= 100 (just to test, to make sure it will trigger the 0 damage)... but it still doesnt work :/

it doesnt duplicate the code anymore but the console now shows this:

Array[3]0: Object1: Object2: Objectlength: 3> __proto__: Array[0]I made it just "return 0" without the random thing... and it didn't work. '-'
 
Last edited by a moderator:

Tsukihime

Veteran
Veteran
Joined
Jun 30, 2012
Messages
8,230
Reaction score
3,079
First Language
English
I redownloaded and changed the code to be <= 100 (just to test, to make sure it will trigger the 0 damage)... but it still doesnt work :/

it doesnt duplicate the code anymore but the console now shows this:

Array[3]0: Object1: Object2: Objectlength: 3> __proto__: Array[0]I made it just "return 0" without the random thing... and it didn't work. '-'
It looks like I left in some test code to show that the states aren't being duped.

Anyways it looks like you have 3 states, and I'm assuming one of those states is the one with the damage modifier.

Now the problem here is that in a new project, it worked, but it isn't working in your current project. I would assume there is a compatibility issue somewhere, but I don't think it is with yanfly's plugin.

Perhaps there's a new version of passive states?
 

Users Who Are Viewing This Thread (Users: 0, Guests: 1)

Latest Threads

Latest Posts

Latest Profile Posts

Stream will be live shortly! Going to do another art stream tonight so that I can finish my Fauna Focus piece~ Feel free to drop by!
Humans are fallible creatures, we all know that. It's when we're forced to look at ourselves that we start to disagree. :p
Expectation: Working on boss battle.
Reality: "Look at how awful are these code and database organization. Let me clean this mess", *yet, casually adding more modules that I have no idea if I would use it later*
Trying to learn to read Japanese so I read my manga. I like to buy them without all the edits made during translation.
The only thing getting me through today so far is coffee. And lots of it.

Forum statistics

Threads
97,852
Messages
947,384
Members
129,079
Latest member
DerLaPux
Top