I have 2 states which are not performing as expected.
The first is Paralysis. I have always thought it a bit ridiculous that someone who is paralyzed evades an attack, so I added the feature EVA -100%. Yet enemies can still evade.
The second is counter Attack. For all my physical skills I have amended the damage formula to prevent 'Null' damage. So the damage formula for the basic Attack is
[a.atk * 4 - b.def * 2, 1].max
This ensures that at least 1HP damage is done, irrespective of the differences in stats, levels etc. This works fine for everything except Counter Attack (which I believe uses Skill #1, Attack). Sometimes the counter attack gives around 100HP damage, other times - same actor, same enemy, even the same fight - it gives Null.
Does anyone have any suggestions?
Thanks.
2 questions about States
● ARCHIVED · READ-ONLY
-
-
Assuming you use the default damage calculation:
Only skills with hit type "Physical Attack" are affected by EVA, skills with hit type "Magical Attack" are affected by MEV instead. Ex-Parameters are summed up, so it is not impossible to overcome a -100% EVA feature by stacking up positive bonuses in theory.
In addition, attacks can also miss independently from the targets evasion rate.
Evaluating the damage formula is only the first step in damage calculation. The result also gets multiplied by the targets element rate and its physical/magical damage rate. Guard/Critical modifiers are applied and the final result is rounded down to an integer. Those effects could reduce an original damage value of 1 down to 0 for example.
Since I don't know the exact circumstances that's all I can say. :) -
Do you use any custom script?
-
@Another Fen
I'll add MEV -100% and see if that solves it, though my memory is that the paralyzed enemy evaded a physical blow. Also 'evade' appeared in a pop-up, so I know it wasn't a miss. At the moment, no enemy has so many stacking bonuses to come anywhere near 100%.
I take your point about the rounding down, but that is precisely what that particular formula prevents. It calculates what the maximum damage could be, and applies that. If the ordinary damage formula part returns zero, it applies the 1.
But also, if the formula produced zero (or one) it would do so consistently. However, ordinary physical attacks can be producing damage in an ordinary turn and sometimes for a counter attack, but then - even within the same battle, so no one's stats have altered - it can return Null. With no alteration in stats that should be consistently either [n]HP damage or Null.
@DoubleX
A lot of custom scripts. Those affecting battle are, however, the ordinary Yanfly ones. i.e.
Battle Engine
Enemy HP bars
Enemy Info
Enemy elemental pop-ups -
Personally, I don't think changing the MEV makes sense, unless you view offensive magic as a purely physical thing. If it is mainly a mental force of will, I don't think Paralysis would affect it.
Now, a state like Depress Will would do precisely that (and reduce the MDF and possibly add a multiple over 100 to the MDR), as the magical equivalent of Paralysis.
As for why your Counter-attacks sometimes get 0, does your Attack Skill have any Variance and/or Critical settings in it? My guess is those could cause the randomness you're seeing. Especially if the atk*4-def*2 formula produces a number which is low but not 1. -
@whitesphere
Good point about the nature of a magic attack.
There is a small variance, but the formula automatically chooses the higher value, so if the variance produced zero, or even less, it would still return 1HP damage. -
I think the easiest way to help you here were if you could provide a demo project containing the scripts and settings you used. It does not have to be a complete copy of your working project of couse as long as the issue persists within it.
If you don't want to make that part of your project public at all, you may also send it via PM to me or someone else to look at. -
Thanks for the offer. I'll have to think about it because the person with the counter attack skill doesn't appear until nearly 3 hours into the game, so it will need some juggling to arrange. I probably won't have time until this evening to start tinkering.
-
One thing I found out was variance is applied *after* the damage formula is evaulated. Is your formula in the damage box in the engine, or in a script?
-
It's in the usual skill damage box.
-
Ok, then the variance and resistances is probably the problem. Does it still happen if you set the variance to 0?
Edit: I just saw this was for counterattack only, which throws out my original post. I think counterattack is a separate function, which might be the problem. -
Just to make sure it is not a problem with your formula you could add this script to your project.
It prevents the formula evaluation from returning 0 instead of raising an error message:
class RPG::UsableItem::Damage def eval(a, b, v) [Kernel.eval(@formula), 0].max * sign #rescue 0 endend(New scripts won't become effective in test battle before you saved your project)
I don't think the variance could be the problem since its range is rounded down too. So it should not be possible to reduce the damage value by 100% by a less-than-100% variance range. Again assuming that the damage calculation process is equal to the default. -
I believe the actual variance code is (summarized, as I don't have RPG Maker ACE on me at the moment).I don't think the variance could be the problem since its range is rounded down too. So it should not be possible to reduce the damage value by 100% by a less-than-100% variance range. Again assuming that the damage calculation process is equal to the default.
Pick a random number between 0 and your variance
Multiply the damage by that number (in decimal form, so if the random number is 19, it does 0.19), store this number somewhere (I'll call it a)
Return either the damage + a or the damage - a, with 50% chance of either.
Its that last line that voids a bound below as far as I can tell. Since it has a 50% chance of returning the damage - that number, it could drop it below 1, especially if it was 1 to begin with. Though, that should take a variance above 50% to make it happen (as 1 - 0.6 * 1 = 0.4, which rounds to 0), so I doubt this is the issue anymore unless he set his variance at 50% or higher, and even then, it should be alternating between 0, 1, and 2 if that were the case.
You know though, I'd like to see his damage formula at this point though, as I'm curious how he is getting 100 HP and NULL in the same battle with same attack, same battler, same actor. From my experience, due to variance being computed so late in the equation, attacks that do zero always do zero, variance or no variance (assuming no changes in resistances or stats). -
My variance is set at 8%, because I don't like massive swings on damage due to variance.
@billgisp
You have my formula in the OP. However, here it is again:
[a.atk * 4 - b.def * 2, 1].max
That addition of [damage formula, 1.]max is applied to virtually every skill and the only problem seems to occur with counter attack.
And if you're curious about how I'm getting 100HP and NULL in the same battle, etc., just think how I feel!!! It has me totally bewildered. -
Does the Null phenomenon still appear despite the script I posted?
Event though the "rescue" strategy usually just covers typing errors, it's not impossible that the default behaviour of the formula evaluation curtains another kind of fault here.
The default variance application process looks like this:
Code:def apply_variance(damage, variance) amp = [damage.abs * variance / 100, 0].max.to_i var = rand(amp + 1) + rand(amp + 1) - amp damage >= 0 ? damage + var : damage - varend -
Here's a thought...what happens if you change the command then in skill 1 (default attack) to just 4*a.atk - 2*b.def? In other words, remove the max. What happens with counterattack then? Is it still as variable? If not, then counterattack is not evaluating the formula right for some reason.
-
@Another Fen
Yes, it still returns NULL, even with that snippet. I did this, btw, before trying the next suggestion.
@bgillisp
I altered the formula back to the default, but there came a NULL after a few 'correct' damage results. -
Ok, that tells me it was not the min formula causing it. I was just wondering if that was not being evaluated correctly somehow. Let me pull up RPGMaker ACE and investigate how it does counterattacks. If I read this correctly, you didn't add any scripts to change how counterattacks work?
-
@bgillisp
No, there aren't any. -
Still assuming the default calculation is used, you could try this test script.
It should print the return values of several methods involved in the damage calculation.
The script is made for testing purposes only, you should remove it afterwards or change the first line to if false :
(Empty brackets mean that a method was most likely not called within the damage calculation process)Spoilerif trueONLY_PRINT_ZERO_DAMAGE = true # <- Change this value to <false> if a zero-damage # attack is not printed!CONSOLE_OUTPUT = false # Print on console <true> or as a box <false># --------------------------------------------------# Don't do changes below this line unless you know what you are doing# --------------------------------------------------# Method redefinition check: (Not trustworthy)results = Array.new%w( item_apply item_test item_hit item_eva item_cri item_element_rate pdr mdrmake_damage_value rec apply_critical apply_variance apply_guard ).each do |name| regex = /def #{name}\W/ hits = $RGSS_SCRIPTS.select { |set| regex === set[3] } if hits.length > 2 or (hits.length > 1 and name != "item_apply") results.push([name, hits.map { |set| "[%03d:%s]" % [$RGSS_SCRIPTS.index(set), set[1] || "NO VALID NAME"] }]) endendunless results.empty? send(CONSOLE_OUTPUT ? :print : :msgbox, "Some Methods may have been defined multiple times:\n" + results.map { |name, scripts| "#{name} : #{scripts.join(", ")}" }.join("\n"))end# Test:$item_test_array = nil$testmethod_cnt = 0class Module def log_method_result_test(method) method_alias = :"$ALIASFORDAMAGETEST__#{$testmethod_cnt += 1}__" alias_method(method_alias, method) define_method(method) do |*args| result = send(method_alias, *args) if $item_test_array != nil $item_test_array.push([self, method, result]) end return result end endendclass RPG::UsableItem log_method_result_test:)physical?) log_method_result_test:)magical?)endclass RPG::UsableItem::Damage log_method_result_test:)eval) log_method_result_test:)recover?)endclass Game_Battler alias_method:)item_apply_ILC_test, :item_apply) def item_apply(user, item) $item_test_array = Array.new item_apply_ILC_test(user, item) # --- Evaluate: if (@result.hp_damage == 0 and @result.mp_damage == 0) or not ONLY_PRINT_ZERO_DAMAGE send(CONSOLE_OUTPUT ? :print : :msgbox, "===============================\n" \ "#{user.name} uses #{item.name} on #{self.name}\n" \ "causing damage for #{@result.hp_damage} HP and #{@result.mp_damage} MP:\n"\ "-------------------------------\n" \ "Item Test: #{find_test_result(self, :item_test)}, " \ "Hit Rate: #{find_test_result(self, :item_hit)}, " \ "Evasion Rate: #{find_test_result(self, :item_eva)}\n" \ "Used: #{@result.used}\n" \ "Missed: #{@result.missed}\n" \ "Evaded: #{@result.evaded}\n" \ "#{@result.hit? ? "SUCCESS" : "FAILURE" }\n" \ "-------------------------------\n" \ "Formula Result: #{find_test_result(item.damage, :eval)}\n" \ "Element Rate: #{find_test_result(self, :item_element_rate)}\n" \ "Physical Rate: #{find_test_result(item, :physical?)} " \ "-> #{find_test_result(self, :pdr)}\n" \ "Magical Rate: #{find_test_result(item, :magical?)} " \ "-> #{find_test_result(self, :mdr)}\n" \ "Recovery Rate: #{find_test_result(item.damage, :recover?)} " \ "-> #{find_test_result(self, :rec)}\n" \ "Damage after critical: #{find_test_result(self, :apply_critical)}\n"\ "Damage after variance: #{find_test_result(self, :apply_variance)}\n"\ "Damage after guard: #{find_test_result(self, :apply_guard)}\n" \ "===============================\n\n") end $item_test_array = nil end def find_test_result(source, method) res = $item_test_array.select { |set| set[0, 2] == [source, method] } return res.collect { |set| set[2] } end log_method_result_test:)item_test) log_method_result_test:)item_hit) log_method_result_test:)item_eva) log_method_result_test:)item_cri) log_method_result_test:)item_element_rate) log_method_result_test:)pdr) log_method_result_test:)mdr) log_method_result_test:)rec) log_method_result_test:)apply_critical) log_method_result_test:)apply_variance) log_method_result_test:)apply_guard)endend
Edit: Extended the script a little bit (trying to find redefinitions of the said methods in a non reliable way).
The script should print a result whenever an attack does no direct damage for any reason. If it doesn't, try to change the value in line 3 to false, save your project and try again. If it still doesn't then I don't know...^^