EasyRPG / Player

RPG Maker 2000/2003 and EasyRPG games interpreter
https://easyrpg.org/player/
GNU General Public License v3.0
991 stars 186 forks source link

Embric of Wulfhammer's Castle: "Row" battle command is missing #680

Closed Siltala closed 4 years ago

Siltala commented 8 years ago

With bug #601 having been fixed, most of the commands are now correctly shown and usable in git. However, one of the commands, 'Row' is still missing.

Steps to reproduce:

Ghabry commented 8 years ago

Row is a special command that everybody has. Is not implemented yet because i never found it useful.

Ghabry commented 6 years ago

Asked cherry about the "Row" command but he hasn't figured this out yet. So feel free to suggest what the "Row" command shall do :D

carstene1ns commented 6 years ago

Just leaving these two links here: https://rpgmaker.net/articles/371/ https://forums.rpgmakerweb.com/index.php?threads/do-you-remember-the-row-thing.20014/

What I remember/think of it:

Ghabry commented 6 years ago

I remember one non RPG Maker game that used a row system (Pier solar, don't play it, didn't age well) and in this game the front-row completely protected the back row from normal attacks.

The 60/40 makes sense, maybe 70/30 would be better, otherwise your healer is still hitted to often :D.

Ghabry commented 6 years ago

If I understood this correctly the row does the following: Physical attacks get a 25% bonus (or you receive 25% extra damage when):

Pincer is always 0% bonus. And at the end I see another 75% modifier with the same conditions, so I'm confused.

Looks like the hit-chance is modified in the same way (though not by 25% but by "25 out of 100" + hitchance %)

Enemy is always in the "Front row".

So this is boring.

ghost commented 4 years ago

I can confirm that the damage from physical attacks is increased by 25% if the source and the target are in the front row. From my tests with RPG_RT it looks like that being in the back row doesn't reduce the probability being targeted by an enemy.

fmatthew5876 commented 4 years ago

To implement Row properly we'll need to use reverse engineering tools to inspect the RPG_RT binary. The last time I did a quick glance, row has a lot of subtle interactions with damage, dodge rate, and other things. It will be very hard to get row correct by black box testing.

If you're interested in implementing this feature, I can dig into RPG_RT and write out the behaviors I find.

ghost commented 4 years ago

I'm definitely keen on learning more about the technical details of the row behaviors. But I'm not sure if my skills are sufficient to implement the whole row feature.

fmatthew5876 commented 4 years ago

Ok so good news is as far as I can tell, row only affects normal physical attacks. The adjustments are rather simple

Physical Attack Evasion Adjustment

After the adjustment for HasPhysicalEvasionUp(), the to_hit rate is further adjusted like so:

If defender is an actor:

Damage Adjustment

This happens after dmg = max(0, atk / 2 - def / 4), before any other adjustments

If attacker is an actor:

Next, attribute adjustments are applied, then

If defender is an actor:

After this charging, critical hit, strong defense, etc..

All of these numbers should be confirmed with testing

ghost commented 4 years ago

Thank you for providing the data! I did some tests the last days and I noticed that in Normal and Initiative encounter conditions the player party has a damage advantage against the enemy party. I tested this with 800 Attack and Defense for both the players and the enemies (to make calculations easier) which means in normal cases the damage ranges between 160 and 240. I encountered the following:

If encounter condition is Surround: to_hit -= 25 regardless of row

This explains the insane dodge rates I had in my tests with the Surround encounter condition...

Still have to do more tests with the Back, Surround and Pincer encounter conditions to get (halfway) accurate damage values.

fmatthew5876 commented 4 years ago

Oops, your example is right. I messed up, the 125 is damage bonus based on source row, the 75 is damage reduction based on target row. I will update the post.

ghost commented 4 years ago

More damage values:

Back encounter condition:

Surround encounter condition:

Pincer encounter condition:

Noticeable is the lower average damage in the Back and Surround encounter conditions and the odd player damage values in the Surround encounter condition (this -6.25% is coming from calculating 1.25 times 0.75 which equals 0.9375). In the Surround and Pincer encounter conditions the row doesn't matter on the damage dealt.

fmatthew5876 commented 4 years ago

Regarding the mechanics of the row state and row adjustment itself. This one is a little strange. RPG_RT has 2 flags, a row flag and a rowAlt flag. I haven't yet figured out why there are 2.

Some of these mechanics below are already implemented.

Savegames

Row Command in Menu Scene

Battle Adjustments

Row Command in Battle

if (rowAlt != row) {
  adj = (rowAlt == BACK_ROW) ? 24 : -24;
  if (encounterCondition == pincer || !mirrored) {
    x += adj
  } else {
    if (encounterCondition == back) {
       x += adj
    } else {
       x -= adj
      }
    }    
  }
  row = rowAlt;
}

Battle Start Adjustments

Ghabry commented 4 years ago

btw are row changes in battle temporary or do they carry over? Would've expected a flag for "temporary row" but this rowAlt is synced with row in update so doesnt look temporary.

fmatthew5876 commented 4 years ago

I don't believe they are temporary, row is the main flag and battle modifies it.

It looks like this rowAlt only exists because for some reason I haven't determined, they want to update the actors row position one frame after processing the row command.

At least until we understand 2k3 battle system better and refactor it, we could probably get away with not emulating rowAlt and the 1 frame difference as a first pass.

ghost commented 4 years ago

I did the hit rate tests now. Because it is impossible to get the exact accuracy values with black box testing I used the terms "Normal hit rate" (which translates to about 90% hit rate) and "Reduced hit rate" (which translates to about 65% hit rate) if I encountered frequent dodges. The hit rate percentage values are taken from your comment which contains the technical details.

Normal and Initiative encounter condition:

Back encounter condition:

Surround encounter condition:

Pincer encounter condition:

The Surround encounter condition makes the battle literally a dodge-fest and interestingly the Pincer encounter condition doesn't change the damage and hit rate values at all.

ghost commented 4 years ago

I have added a PR (#2321) now which implements the damage and accuracy modifiers depending on the row. But I have an other question: What is from your point of view the correct way to implement the in-battle row command? For me it looks like changes in liblcf are required (new BattleCommand type) and the biggest problem is probably the static database entry needed for the row battle command (this battle command is always available independent of the battle commands set in the LCF database).

fmatthew5876 commented 4 years ago

There is no lcf enum for row. RPG_RT hard codes the Row command to always be present at the last battle command in the command window.

So it should be rather easy, you just need to add it directly, and then flip the row when the command is used.

fmatthew5876 commented 4 years ago

@rueter37 Really good catch with pincer attack. It looks like pincer uses an entirely different code path which is why I missed (WTF RPG_RT??). I confirmed by setting a break point and the normal attack code never executes during pincer..

I'm still looking for this

fmatthew5876 commented 4 years ago

Ok, so while there is an alternate code path for actor weapon attacks, which has to do with dual wield etc.. This was staring me in the face, I just read the code wrong.

You are right that pincer makes row meaningless, which makes sense. I've updated the earlier posts.

ghost commented 4 years ago

Thank you for the pointer how to implement the in-battle row command. I have added a PR (#2322) which implements the in-battle row command. Merging #2321 and #2322 into master closes this issue.

Ghabry commented 4 years ago

There is also this row command discussion by bugmenot which matches quite close to what matthew figured out: (even the "Back attack is broken" case and "*It's in the damage calculation, but never gets applied since Enemies are not of type 'Actor'. Either copy pasta or dummied out features.")

https://rpgmaker.net/forums/topics/17752/?post=640190#post640190

Ghabry commented 4 years ago

From IRC:

fmatthew5876 commented 4 years ago

Ally -> Ally should consider the row of the attacking ally and the defending ally, according to RE code. Should be confirmed with a test.

fmatthew5876 commented 3 years ago

So I think I understand now why rowAlt exists.

The row command tries to behave like any other battle command, in that when you select it it doesn't happen right away. First the actor gets added to the battleProgress list, and acts on their turn. Before they act (like any other action), the interpreter gets called.

So I guess they used this rowAlt thing to enable that. Still seems very convoluted way to do this though..