Patch: Independent Stop
#1
Hello everyone, I finally got around to solving something that I've been thinking about for a while. Stop and Slow, when combined, results in the Stop timer lasting TWICE as long, which is somewhat overpowered. I also feel that since they are both Time Magics, they shouldn't be stackable (see: Haste and Slow being mutually exclusive).

This moves the code that decrements the Stop timer to before the $3ADC,X check. That means it will be independent of the ATB multiplier (Slow/Haste), but will also increment four times as fast, which is compensated for by initializing the Stop Timer to four times its original value.

This patch includes assassin's Premature Continuation Fix so as to not cause conflicts. It requires no free space.

[spoiler]
Code:
;xkas 0.06
hirom
;header

;Stop - set
org $C24680
LDA #$48                ;Time until Stop wears off x 4


;Called whenever battle timer is incremented.
;Handles various time-based events for entities.  Advances their timers, does
;periodic damage/healing from Poison/Regen/etc., checks for running, and more.

;(assassin's Premature Continuation Fix included)

org $C25A83
timed_events:
LDA $3A91               ;Lower byte of battle time counter equivalent
INC $3A91               ;increment that counter equiv.
AND #$0F    
CMP #$0A    
BCS .other              ;Branch if lower nibble of time counter was >= #$0A
                        ;otherwise, A now corresponds to one of the 10
                        ;onscreen entities.

ASL 
TAX 
LDA $3AA0,X
LSR 
BCC .exit               ;Exit if entity not present in battle

;Stop block, relocated
LDA $3AF1,X             ;Get Stop timer, originally set to #$12
                        ;at C2/467D
BEQ .noStop             ;Branch if it's 0, as that *should* mean the
                        ;entity is not stopped.

DEC $3AF1,X             ;Decrement Stop timer
BNE .exit               ;did it JUST run down on this tick?  if not, exit

;Premature Continuation Fix
JMP expire_Stop         ;go set up Stop to wear off
NOP                     ;Note that I could have fit the entire patch in this
                        ;function with "STA $B8 / BRA $5B30", but the latter
                        ;instruction would've been so cheap and ugly that I'd
                        ;have had to kill myself.
.noStop
;End of Stop block

CLC 
LDA $3ADC,X             ;Timer that determines how often timers and time-based
                        ;events will countdown and happen for this entity.
ADC $3ADD,X             ;Add ATB multiplier (set at C2/09D2: 64 normally,
                        ;32 if Slowed, 84 if Hasted)
STA $3ADC,X
BCC .exit               ;Exit if timer didn't meet or exceed 256

LDA $3AA0,X
BIT #$10                ;is entity Wounded, Petrified, or Stopped, or is
                        ;somebody else under the influence of Quick?
BNE .exit               ;Exit if any are true

LDA $3B05,X             ;Condemned counter - originally set at 09B4.
                        ;To be clear, this counter is "one off" from the
                        ;actual numerals you'll see onscreen:
                        ;00 value = numerals disabled
                        ;01 value = numerals at "00", 02 = "01", 03 = "02", etc
CMP #$02
BCC .l_5AC9             ;Branch if counter < 2.  [i.e. numerals < "01",
                        ;meaning they're "00" or disabled.]
DEC 
STA $3B05,X             ;decrement counter
DEC                     ;just think of this second "DEC" as an optimized
                        ;"CMP #$01", as we're not altering the counter.
BNE .l_5AC9             ;Branch if counter now != 1  [i.e. numerals != "00"]

JSR $5BC7               ;Cast Doom when countdown numerals reach 0
.l_5AC9
JSR $5C1B               ;Check if character runs from combat
JSR $5B4F               ;Trigger Poison, Seizure, Regen, Phantasm, or
                        ;Tentacle Drain damage
TDC 
JSR dec_timers          ;Decrement Reflect, Freeze, and Sleep timers if
                        ;applicable, and check if any have worn off
INC $3AF0,X             ;advance this entity's pointer to the next entry
                        ;in the 5AEA function table
LDA $3AF0,X
TXY                     ;preserve X in Y
AND #$07                ;convert it to 0-7, wrapping as necessary
ASL 
TAX 
JMP ($5AEA,X)           ;determine which periodic/damage healing type
                        ;will be checked on this entity's next tick.
.other
SBC #$0A                ;should only be reached if $3A91 AND 15 was >= 10
                        ;[i.e. not corresponding to any specific entity]
                        ;at start of function.  now subtract 10.
ASL 
TAX 
JMP ($5AFA,X)

TYX                     ;restore X from Y
.exit
RTS 

org $C25B06
dec_timers:

org $C25B36
queue_removal:


;assassin's patch
;Set to check for Poison on this entity's next tick
org $C25B3B
LDA #$10
BRA reuse               ;finish this function's work by using its near-twin's
                        ;code.

;Added code to mark Stop for removal upon its timer's expiration
expire_Stop:
STA $B8                 ;flag Stop for removal)
BRA queue_removal       ;queue Stop to be removed. but leave Reflect, Freeze,
                        ;and Sleep timers untouched. let them resume on the
                        ;next tick, just like the entity's Condemned countdown
                        ;and periodic Regen/Seizure/etc. do, which is the
                        ;sensible behavior.  after all, time is supposed to
                        ;unfreeze *after* Stop wears off.
NOP
RTS                     ;Never reached, but just in case


;Set to check for Regen, Seizure, Phantasm on this entity's next tick
;(identical results to original function, but reordered slightly)
LDA #$08
reuse:
TYX
ORA $3E4C,X
STA $3E4C,X             ;Set bit 3 of $3E4C,X .  or bit 4 if we
                        ;reached here from Function C2/5B3B.
RTS
[/spoiler]
Reply
#2
nice.  a status exerting such sway over one that supersedes it (or at least everything it normally affects) seemed weird.  maybe not full-on contradiction or snake eating its own tail, but getting there.
Reply
#3
Thank. Honestly, I'm tempted to just replace the ADC $3ADD,X with ADC #$40 and be done with it. I'm not sure Slow and Haste have any business interfering with status timers or periodical ticks at all. That is, from a game mechanics and balance perspective; thematically it makes sense in some cases (Poison, Sleep) and less sense in others (Regen, Stop, Reflect).
Reply
#4
the current way (with your above patch) makes sense enough to me..  i see Slow and Haste as having the same scope as Stop, albeit subordinate to it.

also, C2/09D2 is quite deliberate about things.  storing a value to $3ADD immediately after it checks for these statuses.

if Square didn't want the two to affect anything outside ATB and ready stances, they could've made them modify a copy of the Speed stat instead.  however, they went the route of giving time magics a wider influence.

what's your reason for having Poison separate from Regen?  would Seizure (and Phantasm's unnamed clone) go with the latter?  as for Reflect, are you seeing it as something that's happening immediately around you as opposed to of you?  if that's the case, why should it be influenced by Stop?
Reply
#5
Haha, yeah, it's pretty explicit; $3ADD is only used for this specific purpose! I should have clarified that I was thinking in modding terms, not in terms of sticking close to Square's vision. Even the decision to let Slow affect all timers, including Stop, is pretty explicit, so this patch already strays from bugfix territory.

Fun fact: there is in fact an unused copy of the Speed stat! C2/286D stores Speed into both $3B2D and $3B19, but only the latter is ever used. It's possible they intended to go that route at some point, but abandoned it.

My reasoning is vaguely based on separating buffs/debuffs into magical or physical type; Sleep, Freeze and Poison being physical, while Reflect is of a magical nature.

Sap and Regen are deliberately vague about what they represent; in the case of PCs, the Regen effect is clearly magical, while Sap could represent both physical injuries and magical curses (Phantasm obviously being the latter). However, a creature with inherent Sap or Regen could simply represent it having innate regenerative capabilities, or it suffering from sickness/starvation and wasting away (like Peepers).

Your point about Reflect and Stop is valid. The idea, I suppose, is that physical statuses are innate to your body while magical ones act on your body as an outside force. As such, Reflect's timer shouldn't be influenced by Stop, a separate outside force. The whole thing gets fuzzy with Sap and Regen, and I deliberately contradict myself with Poison, Sleep, and Freeze by saying that thematically, they should be affected by Stop, while on the other hand arguing that buffs and debuffs should remain mostly self-contained and independent of each other for gameplay reasons.

On the other hand, for the same gameplay reasons, I wouldn't want Stop and Poison to stack anyway. The biggest issue is allowing Sleep and Freeze to stack with Stop, I think. There might be no elegant way around it.

EDIT: Come to think of it, Stop itself is used ambiguously by the game, representing both Time magic and physical paralysis or immobilization (for example, Areneid's !Numb or Marshal's !Net). Another reason, I think, to only let it affect ATB and Wait timers.
Reply


Forum Jump:


Users browsing this thread: 2 Guest(s)