Users browsing this thread: 1 Guest(s)
Possible solution to the sap death bug

#6
Posts: 200
Threads: 1
Thanks Received: 10
Thanks Given: 0
Joined: Oct 2015
Reputation: 18
Status
None
pardon the delayed reply.

(12-12-2020, 02:15 AM)Bropedio Wrote:
assassin Wrote:Whittle away much of each monster's HP.  kill one of them.  its Quake will kill the others, it'll revive itself, another one will counter with Quake and revive itself, etc., etc.  an infinite loop until they run out of MP!

This is a really good example of how my initial code snippet could go horribly, horribly wrong. Though to be honest, it's something I might be comfortable living with, if only because a monster that revives itself upon death will always need to run out of MP before the battle ends, anyway (unless, I suppose, if you want the player to run away, or use some specific means of avoiding the death counter, like Snare or insta-kill stuff). In this example, I think it may be more appropriate to consider the reactive script itself to be the bug. Maybe.

well, my example script was kept short for simplicity and to show a worst-case scenario.  worst case isn't necessary to have bugginess.  suppose we provided an escape hatch from the infinite loop, in the form of Life only being cast some fraction of the time, or it targeting random allies as opposed to always oneself.

we'd no longer have the sustained, wide open wormhole to the other dimension.  but we could still have a given enemy doing 2, 3, or more final attacks in a given batch -- so a more fleeting wormhole, limiting those Gamma Quadrant menaces and setting the stage for a thrilling 7th season. Wink  these smaller yet multiple quantities are still enough to cross into "erroneous" territory, albeit not disastrous.

the way i see it:

1) Square intended only one Command 1Fh per entity per counterattack and periodic damage/healing batch.
2) Square also intended enemy finals to get different, preferential treatment from normal counters, as evidenced by the "catch-all"/"death override" established in Function C2/4C5B (and processed further in C2/4BF4), which ascribes lofty omni-counter powers to $3A56.

a strict adherence to #1 can undermine Square's goal in #2.  the result is also intuitively dumb, weird, and anti-climactic, because unlike having one less FC 05 command (for instance) execute during the course of battle, a monster that departs without a final is missing its single chance at a signature send-off (and in many cases, its most lethal counterattack, or attack period).  it's a blatant loose end, incomplete story, etc. -- often an effect distinct from that of reducing a more commoditized counter.

thus, we need to situationally waive/bend #1 to allow the foe to execute its final attack once.  this goal informed my patch's title (contained in the download URL in my 12/10/20 post).

at the same time, a change that subverts #1 without being necessary to provide that chance (singular) is excessive in my view; the climax has already happened, the potentially nasty attack has been uncorked, and the foe has said its piece (sometimes literally, if it's a boss with dialogue).  iow, the border between 0 and 1 successful FC 12 executions is significantly different from that between some non-zero N and N+1 executions, and merits unique treatment.

thus, my patch does the bare minimum to permit the monster's final.

now, i've keyed in on the importance of ensuring a once-per-battle occurrence, as it's unique and distinct from multiple-per-battle ones.  i get that lines can also be drawn between once- and multiple- per-monster-life-cycle commands.  however, once we've seen Final #2 or beyond, it's becoming commoditized to where it's hard to justify breaking Square's One Command 1Fh Per Batch rule (and allowing the back-and-forths, sometimes indefinite, that they were apparently trying to avoid), as what we're enabling is no longer rare or priceless.  worth executing when no rule-breaking is needed?  of course.

i do think the fact that the game won't check for battle end at C2/47ED (or process prerequisites at C2/5C73) until this batch is done processing probably figures into Square's desire to put a firebreak on the batch.  iow, INTER-batch shenanigans apparently bothered them less than INTRA.


Bropedio Wrote:
assassin Wrote:
Bropedio Wrote:(Edit: On second thought, this would still function correctly, as Enemy B's next Sap tick will trigger its reactive script, due to $3A56).
will C2/5018 allow this?  i think the omni-counter might have to wait until *another* entity's periodic damage/healing occurs, or an entity takes a normal turn.

Even if $5018 aborts the command, I think the calling routine will still proceed to the "prepare counterattacks" routine (at $140C), which will check for newly dead entities anyway.

ah, good point.

to be sure: by "next Sap tick", did you mean "the pending Sap tick [that] will prevent Enemy B from queuing its reactive script"?

at first, i thought you meant the one after that. in that case, i was gonna say that the next tick opportunity only pertains to start-up, inherent Seizure (or Regen).  if Seizure/Regen is given mid-battle, or Poison is given at any time (as it's not a permanent start-up status; see C2/2675), dying should remove the status, and the next tick never happens -- making us dependent on other entities for the omni-counter.


assassin Wrote:
Bropedio Wrote:My next thought is -- why not remove the check at $4CA2 altogether? If a duplicate reaction script is queued, it will inevitably be aborted due to the $33FC flag. And the $3A56 flag will only override the $33FC flag once (per my changes above).

the queuing does create needless junk for C2/4B7B and C2/4BF4 to process.

there's another reason, from my October 2015 notes and semi-coherent to December 2020 me, which i'm in the process of deciphering.

made some progress about a month ago.  here goes:

Code:
  - dropping "not queueing Command 1Fh when one already in buffer" restriction when "one Command
    1Fh per batch" limit still in place.  can cause potential problem if two non-dead entries
    occurring now, then would-be dead entry in future part of batch gets screwed since we already
    had one execution.
     - not exactly foreseeable
     - should have no problem if one of the "now" entries is would-be dead, since death will
       carry thru to execution of non-dead-when-queued Command 1Fh.

unfortunately, many of my notes require me to remember at least 40% or so of what i was talking about, and then they "complete the puzzle".

i'll elaborate on the carry through, as that's a part i actually DO remember. suppose you have a sequence of queued and potentially executed Command 1Fh counterattacks, looking like this chronologically:
trigger1 trigger2 counter1 counter2

("trigger" is the act causing the Command 1Fh to be queued, and "counter" is the actual executing of the Command 1Fh.)

if the entity isn't dead at trigger1 but is dead at trigger2, and there is a limit of 1 execution per batch, we might be apprehensive about one of those being wasted on a non-dead (as in non-final) counter.  however, we actually won't be cheated when counter2 is squelched by the per-batch limitation, because, due to chronology, counter1 observes the conditions that were prevalent at trigger2 (i.e. the entity being dead).  this is even though it's arguably more *logical*, imho, for it to inherit the conditions prevailing during trigger1.

that carry-through elaboration explains why the 3rd bulletpoint is a counterexample to the concerns in the 1st.  what ELUDED me is why the 1st bulletpoint is any worse off for allowing two queued counters than if just one was permitted.

my best stab at it:
allowing trigger2 to queue our 2nd counter somehow prolongs Batch N, to where a future 3rd counter is now considered part of that same batch alongside Counter #1 -- and where it wouldn't have been had counter2 been stifled, and our queue kept shorter.  that is, if the 3rd counter were put into Batch N+1, it would've been free to execute.  i think the following sequence could result in a wasting of Counter #3:
trigger1 trigger2 counter1 trigger3 counter2 counter3
(where death occurs like halfway through sequence or later)

yeah, trigger3's timing is pretty specific and tight.  and there are limited candidates for trigger3: probably Special Action queue stuff (e.g. status auto-expiration).

it's also possible that i reasoned myself into a pretzel back in October 2015; e.g.: how trigger2's proximity to trigger1 might screw former ==> why counter1 saves the day ==> when later death means it can't.  but i think i'm onto something 5+ years later, and it does seem ever-so-slightly familiar. ;P

------

to be thorough, i'm gonna try answering a sibling of your earlier question:

Bropedio Wrote:
Bropedio Wrote:I also am wondering whether your patch at $4CA2 would have any effect at all. Under what circumstance would a "normal" attack be preparing its counterattacks while the counterattack queue had pending periodic damage? Wouldn't the counterattack queue have to be empty before the "normal" attack queue got checked?
OK, I thought through the above, and figured out a scenario that would break. If an attack triggers a counterattack from Enemy A, and Enemy B gets a sap queued while the attack executes, then if Enemy A's reaction targets Enemy B, then the pending Sap tick will prevent Enemy B from queuing its reactive script, even if it is killed by the counterattack. (Edit: On second thought, this would still function correctly, as Enemy B's next Sap tick will trigger its reactive script, due to $3A56).

the sibling is: what about a case where the payload of a counterattack (as opposed to the invoking Command 1Fh) is in the queue?  this is potentially problematic because if the entity didn't die until more recently, the counter has missed its chance to be of the coveted FC 12 variety (whereas a waiting Command 1Fh will adapt to a since-occurred death).  (i'm disregarding the lingering $3A56 flag and its bail-out powers.)

what's coming to mind (relying on memory more than starting from the ground up):
1) monster with a string of consecutive counters (no FEs or FDs between them in script), a non-final (as in, not last in queue) one of those fatally hitting itself.
2) contrasting #1, monster with a string of consecutive counters, 2 of those hitting a different monster, 1 fatally.  this is an example of a present Command 1Fh blocking a queuing.
3) something with a character multi-targeting enemies, multiple or all of them having a counterattack (Command 1Fh) triggered, and then the first acting enemy hitting one that was due to act later?  argh; i thought i'd come up a variant of #1 way back when, but all i can see it accomplishing today is a variant of the more benign #2.  it's possible the memory is from a time where i thought things were more FIFO, so if Monster A expanded its queue (e.g. from hitting itself on a counter), that Monster B's initially-triggered counterattack would run before these additions.

you were good at coming up with that blocked-by-queued-Sap scenario.  any idea of more qualifying cases here?  in particular, something resembling #3 and multi-targeting. Laugh
Quote  



Messages In This Thread
RE: Possible solution to the sap death bug - by assassin - 01-19-2021, 05:13 AM

Forum Jump:

Users browsing this thread: 1 Guest(s)


Theme by Madsiur2017Custom Graphics by JamesWhite