Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
Siltala opened this issue Dec 18, 2015 · 25 comments · Fixed by #2322
Closed

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

Siltala opened this issue Dec 18, 2015 · 25 comments · Fixed by #2322

Comments

@Siltala
Copy link

Siltala commented Dec 18, 2015

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
Copy link
Member

Ghabry commented Dec 18, 2015

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

@Ghabry Ghabry modified the milestone: 0.5.0 Feb 4, 2016
@carstene1ns carstene1ns changed the title Embric of Wulfhammer's Castle: One battle command is still missing Embric of Wulfhammer's Castle: "Row" battle command is missing Jul 5, 2017
@Ghabry
Copy link
Member

Ghabry commented Oct 23, 2017

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
Copy link
Member

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:

  • Basically you have front and back row.
  • Not all actors can be in the front row, because it would be back row then ;-)
  • So back row is default
  • Front row "protects" back row, i.e. monsters target first row with higher chance (60/40 or 70/30 ?)
  • speculation: some things work better depending on the row
    • from back row: recovering HP?, preparing a special attack?
    • from front row: higher chance of critical hit?

@Ghabry
Copy link
Member

Ghabry commented Oct 23, 2017

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
Copy link
Member

Ghabry commented Nov 9, 2017

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

  • Battle Type is Normal or Initative and you are in the front row
  • Battle Type is Back Attack, row doesn't matter
  • Battle Type is Sourround attack and row is back (???, probably a bug because you can't change the row in Sourround and Pincer type battles)

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.

@Ghabry Ghabry modified the milestones: 0.6.1, 0.7.0 May 5, 2019
@ghost
Copy link

ghost commented Aug 28, 2020

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.

@mateofio
Copy link
Contributor

mateofio commented Aug 28, 2020

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
Copy link

ghost commented Aug 29, 2020

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.

@mateofio
Copy link
Contributor

mateofio commented Sep 4, 2020

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

  • Row adjustments only performed if target is an actor.
  • Row has no effect on skills
  • Row has no effect on self destruct
  • Row has no effect on how monsters choose targets

Physical Attack Evasion Adjustment

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

  • The row of the attacker has no effect on evasion

If defender is an actor:

  • If encounter condition is Normal, or Initiative and defender is in the back row: to_hit -= 25
  • If encounter condition is Surround: to_hit -= 25 regardless of row
  • If encounter condition is Back and defender is in the front row: to_hit -= 25
  • If encounter condition is Pincer row has no effect

Damage Adjustment

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

If attacker is an actor:

  • If encounter condition is Normal, or Initiative and attacker is in the front row: dmg = 125 * dmg / 100
  • If encounter condition is Surround: dmg = 125 * dmg / 100 regardless of row
  • If encounter condition is Back and attacker is in the back row: dmg = 125 * dmg / 100
  • If encounter condition is Pincer row has no effect

Next, attribute adjustments are applied, then

If defender is an actor:

  • If encounter condition is Normal, or Initiative and defender is in the back row: dmg = 75 * dmg / 100
  • If encounter condition is Surround: dmg = 75 * dmg / 100 regardless of row
  • If encounter condition is Back and defender is in the front row: dmg = 75 * dmg / 100
  • If encounter condition is Pincer row has no effect

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

All of these numbers should be confirmed with testing

@ghost
Copy link

ghost commented Sep 4, 2020

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:

  • Player in front row attacks Enemy: 200-300 Damage (+25%)
  • Player in back row attacks Enemy: 160-240 Damage (±0%)
  • Enemy attacks Player in front row: 160-240 Damage (±0%)
  • Enemy attacks Player in back row: 120-180 Damage (-25%)

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.

@mateofio
Copy link
Contributor

mateofio commented Sep 4, 2020

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
Copy link

ghost commented Sep 4, 2020

More damage values:

Back encounter condition:

  • Player in front row attacks Enemy: 120-180 Damage (-25%)
  • Player in back row attacks Enemy: 150-225 Damage (-6.25%)
  • Enemy attacks Player in front row: 120-180 Damage (-25%)
  • Enemy attacks Player in back row: 160-240 Damage (±0%)

Surround encounter condition:

  • Player in front row attacks Enemy: 150-225 Damage (-6.25%)
  • Player in back row attacks Enemy: 150-225 Damage (-6.25%)
  • Enemy attacks Player in front row: 120-180 Damage (-25%)
  • Enemy attacks Player in back row: 120-180 Damage (-25%)

Pincer encounter condition:

  • Player in front row attacks Enemy: 160-240 Damage (±0%)
  • Player in back row attacks Enemy: 160-240 Damage (±0%)
  • Enemy attacks Player in front row: 160-240 Damage (±0%)
  • Enemy attacks Player in back row: 160-240 Damage (±0%)

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.

@mateofio
Copy link
Contributor

mateofio commented Sep 4, 2020

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 flag is what is saved to LSD, rowAlt is not

Row Command in Menu Scene

  • Row command in menu toggles both flags and uses only row to decide the toggle. I.E if row == front then row = rowAlt = back
  • Menu does not allow all party members in the back row

Battle Adjustments

  • Above adjustments to evasion and damage only use the row flag.

Row Command in Battle

  • Row command is hard coded to always be present, you can't disable row feature from 2k3 battle
  • RPG_Actor::UpdateBattle() is called to update animations and actor state.
  • Row command execution is processed: toggles rowAlt flag only.
  • Next frame: RPG_Actor::UpdateBattle() runs again and checks the rowAlt flag. If they differ, actor X position is adjusted and row set to rowAlt.
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

  • When battle is started if no live actors are in the front, row, entire party is moved to front row.
  • When actor sprite is "spawned" onto the battle scene rowAlt = row
  • If row == BACK_ROW adjust actor position x += 24

@Ghabry
Copy link
Member

Ghabry commented Sep 4, 2020

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.

@mateofio
Copy link
Contributor

mateofio commented Sep 4, 2020

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
Copy link

ghost commented Sep 5, 2020

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:

  • Player in front row attacks Enemy: Normal hit rate
  • Player in back row attacks Enemy: Normal hit rate
  • Enemy attacks Player in front row: Normal hit rate
  • Enemy attacks Player in back row: Reduced hit rate

Back encounter condition:

  • Player in front row attacks Enemy: Reduced hit rate
  • Player in back row attacks Enemy: Reduced hit rate
  • Enemy attacks Player in front row: Reduced hit rate
  • Enemy attacks Player in back row: Normal hit rate

Surround encounter condition:

  • Player in front row attacks Enemy: Reduced hit rate
  • Player in back row attacks Enemy: Reduced hit rate
  • Enemy attacks Player in front row: Reduced hit rate
  • Enemy attacks Player in back row: Reduced hit rate

Pincer encounter condition:

  • Player in front row attacks Enemy: Normal hit rate
  • Player in back row attacks Enemy: Normal hit rate
  • Enemy attacks Player in front row: Normal hit rate
  • Enemy attacks Player in back row: Normal hit rate

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
Copy link

ghost commented Sep 5, 2020

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).

@mateofio
Copy link
Contributor

mateofio commented Sep 5, 2020

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.

@mateofio
Copy link
Contributor

mateofio commented Sep 5, 2020

@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

@mateofio
Copy link
Contributor

mateofio commented Sep 5, 2020

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
Copy link

ghost commented Sep 6, 2020

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
Copy link
Member

Ghabry commented Sep 9, 2020

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 Ghabry modified the milestones: 0.7.0, 0.6.3 Sep 9, 2020
@Ghabry
Copy link
Member

Ghabry commented Sep 10, 2020

From IRC:

  • Are ally->ally (state inflicted) attacks considered normal attacks?
  • Is the row relevant in this case?

@mateofio
Copy link
Contributor

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

@mateofio
Copy link
Contributor

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..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging a pull request may close this issue.

5 participants