/
preshuffle.s
1301 lines (1097 loc) · 26.7 KB
/
preshuffle.s
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
;;; Main patch data. Note that the shuffle takes place in three steps:
;;;
;;; 1. Initial patch.
;;; 2. Shuffle.
;;; 3. Delayed patch.
;;;
;;; This file takes care of steps 1 and 3, as indicated by a prepended
;;; define clause. After the initial patch, the shuffle step will read
;;; and parse various tables in the ROM, and will potentially write
;;; rearranged and defragmented tables back. The upshot is that the
;;; initial step will write data that the parser will read, but cannot
;;; make use of any of the recovered space. The delayed step can write
;;; to this space, but may not know where certain tables ended up.
;;;
;;; Various flag-based defines will be prepended to this file, indicated
;;; by a `_` prefix.
;;; Indicate the fixed bank - this is always the case.
.bank $3c000 $c000:$4000
;;; Various global definitions.
define ObjectRecoil $340
define ObjectHP $3c0
define PlayerHP $3c1
define PlayerMaxHP $3c0
define ObjectAtk $3e0
define PlayerAtk $3e1
define ObjectDef $400
define PlayerLevel $421
define ObjectActionScript $4a0
define ObjectGold $500
define ObjectElementalDefense $500
define ObjectExp $520
define PlayerMP $708
define EquippedConsumableItem $715
define EquippedPassiveItem $716
define InvSwords $6430
define InvConsumables $6440
define InvPassive $6448
define InvQuest $6450
define InvMagic $6458
define ItemFlagsStart $64c0
define Difficulty $64a2
define ShouldRedisplayDifficulty $64a3
define SelectedConsumableIndex $642c
define SelectedQuestItemIndex $642e
.ifdef _EXTRA_PITY_MP
define PITY_MP_AMOUNT 20
define ONE_MINUS_PITY_MP 237
.else
define PITY_MP_AMOUNT 1
define ONE_MINUS_PITY_MP 0
.endif
define PITY_HP_AMOUNT 5
define SHOP_COUNT 11
define SCALING_LEVELS 48
;;; Constants
define ITEM_RABBIT_BOOTS $12
define ITEM_OPEL_STATUE $26
define SFX_MONSTER_HIT $21
define SFX_ATTACK_IMMUNE $3a
;;; Labels
.org $1c112
SetOrClearFlagsFromBytePair_24y:
.org $1c135
ReadFlagFromBytePair_24y:
.org $1c26f
ItemGet:
.org $1c2f4
ItemGet_Bracelet:
.org $1c308
ItemGet_FindOpenSlot:
.org $1c354
ItemUse_TradeIn:
.org $217cd
Shop_NothingPressed:
.org $21c7a
AfterLoadGame:
.org $2791c
PlayerDeath:
.org $279b0
ActivateOpelStatue:
.org $34bc0
ArmorDefense:
.org $34bc9
ShieldDefense:
.org $34e46
DisplayNumberInternal:
.org $35152
KillObject:
.org $355c0
KnockbackObject:
.org $3c000
PowersOfTwo:
.org $3c008
UpdateEquipmentAndStatus:
.org $3c125
StartAudioTrack:
.org $3cab6
MainLoop_01_Game:
.org $3cb84
CheckForPlayerDeath:
.org $3d21d
DialogAction_11:
.org $3d347
LoadAndShowDialog:
.org $3d354
WaitForDialogToBeDismissed:
.org $3d3ff
MainLoopItemGet:
.org $3e756
RestoreBanksAndReturn:
.org $3fe80
ReadControllersWithDirections:
.org $3ffa9
DisplayNumber:
.bank $14000 $8000:$4000
;;; NOTE: there's space here, but we glob it into the space
;;; recovered from defragging MapData... if we want it back
;;; we'll need to change the "end" address there.
;.org $17cfa
;;; just over 256 bytes free in map space
;.assert < $17e00
.org $17f00
;; another 256 free in map space
.assert < $18000
.bank $18000 $8000:$4000
.org $183fc
;; ~80 bytes free in middle of SFX data that could be used on the npc data page?
.assert < $1844d
.org $1aba3 ; empty space at end of npcdata
;; unused
.assert < $1ac00 ; end of free space started at $1aba3
.bank $1c000 $8000:$4000
;;; Patch the end of ItemUse to check for a few more items.
.org $1c34d
jmp PatchTradeInItem
.org $1c399 ; 58 bytes of free/unused space at start of itemuse jump
.assert < $1c3d3
.org $1c3eb ; 16 bytes of free/unused space in middle of itemuse jump
.assert < $1c3fb
.org $1c41b ; 30 bytes of free/unused space at end of itemuse jump
.assert < $1c439
.org $1c157
.word (PowersOfTwo) ; no need for multiple copies
;; Count uses of Flute of Lime and Alarm Flute - discard after two.
.org $1c6f2 ; 10 free bytes in middle of spawn condition table
PatchTradeInItem:
cmp #$31
beq +
cmp #$28 ; flute of lime
beq ++
bne ++++
.assert < $1c6fc
.org $1c6fe ; free space in middle of spawn condition table
+ lda #$40
sta $61
bne +++
++ lda #$80
sta $61
+++ lda $64a1
and $61
bne ++++
lda $64a1
ora $61
sta $64a1
;; Deselect current item
lda #$00
sta $0715
lda #$80
sta $642e
rts
++++ jmp ItemUse_TradeIn
.assert < $1c760
.org $1ca6f ; 10 free bytes in middle of dialog table
.assert < $1ca79
.org $1ca7b ; free space in middle of dialog table
.assert < $1cae3
;; Prevent soft-lock when encountering sabera and mado from reverse
;; Double-returns if the boss's sprite is not in the top quarter of
;; the screen. This is unused space after triggers.
.org $1e3c0
CheckBelowBoss:
lda $0380,x
bmi ++
; skip the check for sabera 1 and mado 1
lda $04a0,x
and #$fe
cmp #$e6 ; sabera and mado
bne +
lda #$dc
cmp $04c0,x ; first version has #$cf, second has #$dc
bne ++
+ sec
lda $d0
sbc $d0,x
bmi ++
lda $b0
sbc $b0,x
bmi ++
sbc #$40
++ rts
.assert < $1e3f0
.org $1e48b ; vampire pattern 0
jsr CheckBelowBoss
.org $1e971 ; kelbesque pattern 0
jsr CheckBelowBoss
.org $1ec8f ; sabera pattern 0
jsr CheckBelowBoss
.org $1ede8 ; mado pattern 0
jsr CheckBelowBoss
;; If LookingAt is $1f and the item goes into the $20 row then we can't
;; just reject - instead, add the item to an overflow chest.
;; We use the bytes at 64b8..64bf to store the overflow.
;;; ITEM GET PATCHES
;; Treasure chest spawns don't need to be so complicated.
;; Instead, just use the new dedicated ItemGet flags 200..27f
.org $1c5c3
;; Read the flag 200+chest, where chest is in $23
lda #$a2
sta $61
lda $23
sta $62
lda #$61
sta $24
lda #$00
sta $25
tay
jsr ReadFlagFromBytePair_24y
beq +
inc $20
+ rts
.org $1c5de
;; Patches to ItemGet to update the dedicated flag and
;; leave room for calling the difficulty methods
.org $1c287
jsr ItemGet_PickSlotAndAdd
.org $1c297
jmp ItemGetFollowup
;; 4 bytes free here
.assert < $1c29e
.org $1c29e
ItemGet_PickSlotAndAdd: ; move this up a few bytes
sty $62
.assert $1c2a0
.org $1c2a8
jsr ItemGet_FindOpenSlotWithOverflow
.ifdef _PROGRESSIVE_BRACELET
.org $1c2de
lda $29
bcc + ; just compared #$o4, swords are good to go
inc $6430,x ; try incrementing the power slot
bne ++ ; if it was empty (ff) then now we're zero
lsr ; clear carry if $29 was even (a bracelet)
lda $29
sbc #$00 ; subtract one if carry clear, to make it a ball
sta $23 ; store the *actual* item back in $23, which is used later
+ sta $6430,x ; store the item in its spot
++ lda $6430,x ; read the item back again (in case we jumped here)
sta $07dc ; store the actual item in the dialog spot to get right message
rts ; jmp PostInventoryMenu (note: would be nice to get items right)
.assert < $1c308
.endif
.org $1dc82
;; Freed from the chest spawn pointer table
.org $1dd64
;; Freed from the chest spawn data
.org $1e106
ItemGetRedisplayDifficulty:
.ifdef _DISPLAY_DIFFICULTY
nop ; TODO - just remove the path?
.else
rts
.endif
lda #$01
sta ShouldRedisplayDifficulty
rts
.org $1e110
KeyItemData:
.res 10, 0
ItemGetFollowup:
;; The vanilla code checks whether the last byte at ($24),y is negative
;; and if not, then it stores the positive value in $23 as some sort of
;; "chained" ItemGet and repeats the whole ItemGet routine from the
;; start. But no items actually use this, so we don't bother copying
;; it here. If we needed to, it's easy enough to `lda ($24),y;pha` and
;; then instead of a simple `rts` we `pla;bmi >rts;sta $23;jmp ItemGet`.
;; Check if this is a key item, and maybe increase difficulty.
lda $29
lsr
lsr
lsr
tay
lda $29
and #$07
tax
lda KeyItemData,y
and PowersOfTwo,x
beq +
lda Difficulty
cmp #$2f
bcs +
inc Difficulty
jsr ItemGetRedisplayDifficulty
;; Always set the dedicated 200+chest flag.
+ lda #$42
sta $61
;; $62 is already the item number, saved from earlier
lda #$61
sta $24
lda #$00
sta $25
tay
jmp SetOrClearFlagsFromBytePair_24y
ItemGet_FindOpenSlotWithOverflow:
tay ; copied from 1c2a8
bmi +
pla ; make the call into this actually a jump...
pla
stx $61 ; save this for now
jsr ItemGet_FindOpenSlot
;; if 23 nonzero then we failed to find a slot
;; if 61 is 20 then we really need to put it somewhere
;; in that case, add it to the overflow. when we
;; delete a key item, it will fall in
lda $23
beq +
lda $61
cmp #$20
bne +
;; need to find a place
ldx #$07
- lda $64b8,x
beq ++
dex
bpl -
+ rts
++ lda $29
sta $64b8,x
lda #$00
sta $23
rts
;; TODO - still plenty of space here
.assert < $1e17a
.ifdef _FIX_VAMPIRE
;;; Fix vampire to allow >60 HP. Normally at 61 HP there's an overflow
;;; and the teleport animation gets really fast until HP drops below 61.
.org $1e576
jsr ComputeVampireAnimationStart
nop
.assert $1e57a ; match up exactly to next instruction
.endif
;;; We moved the LV(menu) display from 06 to 0e so display that instead
.org $1fd27
lda #$0e
;; This looks like it's just junk at the end, but we could
;; probably go to $1ff47 if we don't care about developer mode
.org $1ff97
ComputeVampireAnimationStart:
bcs +
asl
bcs +
adc #$10
bcc ++
+ lda #$ff
++ rts
.bank $20000 $8000:$2000
;; Replace "drop item" code for key items to use an overflow buffer
.org $20372
jsr CheckDroppable
.org $20434
jsr MaybeDrop
nop
nop
.org $20ff0
InvItemData:
;; MUST BE EXACTLY 4 BYTES
.org $20534
nop
jsr FillQuestItemsFromBuffer
.assert $20538
;; NOTE: This prevents swords and orbs from sorting to avoid out-of-order
;; swords from clobbering one another. We swap the second and fourth
;; items from the table of row starts so that when we start at two instead
;; of zero, we end up skipping exactly the first and fourth rows.
.org $205a7
.byte $0c
.org $205a9
.byte $04
.org $21471 ; unused space, 130 or so bytes
CheckDroppable:
;; Loads A with something that has the :40 bit set if the item
;; is not droppable.
lda $64bf
beq +
;; there's overflow, so allow deleting if selecting from 3rd row
lda $6427
and #$38
cmp #$10
bne +
lda #$00
rts
+ lda InvItemData,x
rts
MaybeDrop: ; 21486
txa
and #$f0
cmp #$20
beq +
lda #$ff
sta $6430,x
rts
;; This is a key item and we have overflow.
;; Substitute the overflow and cycle...
+ lda $6430,x
pha
lda $64bf
sta $6430,x
ldx #$07
- lda $64b7,x
beq +
sta $64b8,x
dex
bne -
+ pla
sta $64b8,x
rts
FillQuestItemsFromBuffer: ; 214af
;; If there's anything in the buffer and any space in the inventory,
;; fill them in. Just take the most recently added ones, not worrying
;; about cycling the queue (that's only needed for dropping).
ldy #$08 ; predecrement, so start at $64c0
- dey
bmi + ; buffer is full
lda $64b8,y
bne - ; occupied, decrement and look at the next
;; If y == #$08 then buffer is empty - return.
+ iny
cpy #$08
beq +
;; Look for open spots in the quest item row
ldx #$08
- dex
bmi +
lda $6450,x
bpl -
;; We're looking at an open slot in x and an available item in y
lda $64b8,y
sta $6450,x
lda #$00
sta $64b8,y
iny
cpy #$08
bne -
;; The following is copied from $20534, patched to not sort
;; the swords or powerups (so it loads 2 instead of 0)
+ lda #$02
sta $2e
rts
;;; Support for fixing sword charge glitch
ReloadInventoryAfterLoad:
jsr PostInventoryMenu
jmp AfterLoadGame
;; FREE: 29 bytes
.assert < $21500
.org $20a37
;; FREE: 35 bytes
.assert < $20a5a
.ifdef _DISABLE_SHOP_GLITCH
;;; Disable the shop glitch by ensuring prices are updated immediately
;;; after moving the cursor, rather than a few frames later.
.org $21812
jmp Shop_NothingPressed
.endif
.ifdef _FIX_OPEL_STATUE
;;; Don't select Opel Statue at all. This patches the table at $2103b
;;; that translates an item ID to a "selected item" index, i.e. each
;;; type of item maps to a series 1..N. In this case, we just remap
;;; Opel Statue to zero so that it looks like nothing is selected.
.org $21061
.byte $00
.endif
.ifdef _DISABLE_SWORD_CHARGE_GLITCH
.org $21bce
jmp ReloadInventoryAfterLoad
.org $21bde
jmp ReloadInventoryAfterLoad
.endif
.bank $26000 $a000:$2000
.ifdef _DISPLAY_DIFFICULTY
;;; Start the loop at 6 instead of 5 to also show the difficulty
.org $27aca
ldx #$06
.endif
.ifdef _FIX_OPEL_STATUE
;; Search inventory for a statue
.org $2788d ; START OF FREE SPACE
CheckOpelStatue:
lda $6440,x
cmp #$26
beq +
dex
bpl CheckOpelStatue
jmp PlayerDeath
+ stx SelectedConsumableIndex
lda #$0a
sta EquippedConsumableItem
jmp ActivateOpelStatue
.assert < $27900 ; END OF FREE SPACE from $2788d or $278e9
.org $27903
and #$f0
;; Now check opel statue
.org $27912
ldx #$07
jmp CheckOpelStatue
;; 5 free bytes
.assert < $2791c
.endif
.bank $2e000 $a000:$2000
.org $2fbd5 ; NOTE: start of an unused block
;;; Prevent softlock from saving or checkpointing with zero health or MP.
;;; This handles cases such as (1) swamp runs when the last HP was lost
;;; exactly upon entering Oak, (2) reverse goa runs where flight is needed
;;; to exit, but the last MP was used and no wise men are available to
;;; restore, (3) the first sword requires flying to Swan and then passing
;;; through the gate. This patch guarantees starting with 5 HP and 1 MP,
;;; unless the player is swordless, in which case 20 MP are given (since
;;; it may be impossible to stay at an inn or buy magic-restoring items).
;;; This is entered by a patched call at $2fd82.
CheckForLowHpMp:
cmp #PITY_HP_AMOUNT
bcs +
lda #PITY_HP_AMOUNT
+ sta PlayerHP
;; Check if we've ever found any swords
lda ItemFlagsStart
and #$0f
;; If this is zero then we have no swords and should give 20 MP.
;; If it's nonzero, set it to -19 and then we'll add 20 unconditionally.
;; Note that we can ignore the swordless check via a flag.
beq +
lda #ONE_MINUS_PITY_MP
+ clc
adc #PITY_MP_AMOUNT
;; Now compare with MP - if it's less, set the minimum.
cmp PlayerMP
bcc +
sta PlayerMP
+ rts
.assert < $2fc00 ; end of unused block from $2fbd5
.ifdef _PITY_HP_AND_MP
.org $2fd82 ; normally "sta $03c1"
jsr CheckForLowHpMp
.endif ; _PITY_HP_AND_MP
.bank $34000 $8000:$2000
;;; Numeric displays
.org $34ee9 ; 06 - was LV(menu) but now it's difficulty
.byte $a2,$64,$3c,$2b,$03,$00 ; display difficulty right of lvl
.org $34f19 ; 0e - was unused, now it's LV(menu)
.byte $21,$04,$29,$29,$03,$00 ; copied from $34ee9
;; ADJUSTED DAMAGE CALCULATIONS
;; $61 is extra HP bit(s)
;; $62 is DEF
;; $63 is damage
.org $350fa
lda #$00
sta $61
sta $63 ; damage we're actually going to do
;; Check elemental immunity
lda ObjectElementalDefense,y
and ObjectElementalDefense,x
and #$0f
php
lda ObjectDef,y
lsr ; Just pull one extra bit for HP, could do one more if needed
rol $61
sta $62 ; Store actual shifted DEF in $62
lda PlayerAtk
adc ObjectAtk,x
sec
sbc $62 ; A <- atk - def
bcc +
plp
bne ++
sta $63 ; will do damage
pha ; to prevent pla from screwing up
+ pla ; to compensate for skipping the plp above
++ stx $10
sty $11
lda $63
bne ++
sta ObjectActionScript,x
lda ObjectActionScript,y
bmi +
jsr KnockbackObject
+ lda #SFX_ATTACK_IMMUNE
inc $63
bne +++
++ jsr KnockbackObject
lda #SFX_MONSTER_HIT
+++ jsr StartAudioTrack
jsr SubtractEnemyHP
bcc KillObject
lsr
lda $62
rol
sta ObjectDef,y
rts
;;; NOTE: must finish before 35152
.assert < $35152
;;; Change sacred shield to block curse instead of paralysis
.org $352ce
cmp #$05 ; ceramic shield blocks paralysis
.org $3534c
jsr CheckSacredShieldForCurse
.ifdef _DISABLE_STATUE_GLITCH
.org $3559a
;; Just always push down.
lda #$04
.endif
;; Adjusted stab damage for populating sword object ($02)
.org $35c5f
lda #$02
.ifdef _NERF_FLIGHT
jmp CheckSwordCollisionPlane
.else
sta $03e2
.endif
rts
.ifdef _RABBIT_BOOTS_CHARGE_WHILE_WALKING
.org $35e00
jsr CheckRabbitBoots
.endif
;.bank $36000 $a000:$2000
;
;.org $36086
;
; ;; Free space at end of UseMagicJump
;
;.assert < $36092
;
;;;; Make gate opening independent of locations
;.org $37879
; lda $23
; and #$f8
; cmp #$30
; beq GateCheckPassed
; lda $6c
; cmp #$73
; beq GateCheckPassed
; bne GateCheckFailed
;.assert < $3788f
;.org $3788f
;GateCheckFailed:
;.org $37896
;GateCheckPassed:
;;.org $3c010
;;;; Adjusted inventory update - use level instead of sword
;; ldy $0719 ; max charge level
;; lda #$01
;;- asl
;; dey
;; bpl -
;; ldy $0716 ; equipped passive item
;;- clc
;; adc $0421 ; player level
;; dey
;; cpy #$0d ; power ring - 1
;; beq -
;; sta $03e1 ; player attack
;; lda $0421 ; player level
;; cpy #$0f ; iron necklace - 1
;;.org $3c02d ; NOTE - MUST BE EXACT!!!!
.org $3c010
;; Adjusted inventory update - use level instead of sword
;; Also nerf power ring to only double the sword value, rather than the level.
ldy $0719 ; max charge level
lda #$01
- asl
dey
bpl -
ldy $0716 ; equipped passive item
cpy #$0e ; power ring
bne +
asl
+ clc
adc $0421 ; player level
sta $03e1 ; player attack
lda $0421 ; player level
sta $62
;; Max out armor and shield def at 2*level
sta $61
asl
adc $62
sta $61
ldy $0713
lda ArmorDefense,y
cmp $61
bcc +
lda $61
+ ldy $0716 ; equipped passive item
cpy #$10 ; iron necklace
bne +
asl
+ clc
adc $62 ; armor defense
jsr PatchUpdateShieldDefense
nop
.assert $3c04f ; NOTE: must be exact!
; STA PLAYER_DEF
.org $3c0f8
jsr PostUpdateEquipment
jmp RestoreBanksAndReturn
.org $3c446
PostUpdateEquipment:
;; Change 'lda' (ad) to 'jsr' (20) to enable these
.ifdef _LEATHER_BOOTS_GIVE_SPEED
jsr ApplySpeedBoots
.else
nop
nop
nop
.endif
rts
ApplySpeedBoots:
lda #$06 ; normal speed
sta $0341 ; player speed
lda $0716 ; equipped passive item
cmp #$13 ; leather boots
bne +
inc $0341 ; speed up by 1
+ rts
CheckSacredShieldForCurse:
lda $0714 ; equipped shield
cmp #$06 ; sacred shield
bne +
pla
pla
+ rts
;;; For fixing sword charge glitch
ReloadInventoryAfterContinue:
sta $07e8
jsr PostInventoryMenu
rts
;;; Remove the '10' bit if the player is flying ('20')
CheckSwordCollisionPlane:
sta $03e2 ; copied from $35c62
lda $03a1
and #$20
lsr
eor #$ff
and $03a2
sta $03a2
rts
;; 8 bytes free
.assert < $3c482 ; end of empty area from $3c446
.ifdef _DISABLE_SWORD_CHARGE_GLITCH
.org $3c9fb
jsr ReloadInventoryAfterContinue
.endif
.ifdef _CHECK_FLAG0
;;; Note: this is a debugging aid added to determine if anything
;;; is accidentally setting flag 0. It should not make a difference,
.org $3cb62 ; main game mode jump 08
jsr CheckFlag0 ; was jsr ReadControllersWithDirections
.endif ; _CHECK_FLAG0
.ifdef _DISPLAY_DIFFICULTY
.org $3cb65 ; inside GameModeJump_08_Normal
jsr CheckToRedisplayDifficulty ; was jsr CheckForPlayerDeath
.endif
.ifdef _NEVER_DIE
;;; Debug mode to never actually die - wrap around to maxhp instead.
.org $3cb89
lda $03c0
sta $03c1
nop
.org $3cbaf
bne +
.org $3cbc0
+ rts ; no change
.endif
.ifdef _DISABLE_WILD_WARP
.org $3cbc7
rts
.endif
.ifdef _NERF_WILD_WARP
.org $3cbec
.res 16, 0
.endif
.ifdef _TELEPORT_ON_THUNDER_SWORD
.org $3d161
.word (DialogFollowupAction_1f)
.endif
.org $3d223 ; part of DialogFollowupActionJump_11 (give 2nd item)
bpl GrantItemInRegisterA ; change from bne to handle sword of wind
.org $3d22b
GrantItemInRegisterA:
jsr PatchGrantItemInRegisterA
;;; Fix bug in dialog action 9 where carrying from the low byte of money
;;; would just increment the low byte again instead of the high byte.
.org $3d273
inc $0703
.org $3d27d
jmp PatchZebuStudentFollowUp
;; End of ActivateTriggerSquare restores game mode to normal,
;; but if sword of thunder comes from trigger square, this will
;; clobber the LOCATION_CHANGE mode. Patch it to call out to
;; FinishTriggerSquare to check for mode 02 and if it is, don't
;; change it back.
.org $3d54b ; change this to call FinishTriggerSquare
lda $41
cmp #$01 ; game mode: location change
jmp FinishTriggerSquare
.assert $3d552
.org $3d91f
jsr PostInventoryMenu
.org $3d971
jsr PostInventoryMenu
.ifdef _FIX_OPEL_STATUE
;;; Prevent ever "equipping" opel statue
.org $3db0d
OpelStatueReturn:
.org $3db0e
SetEquippedConsumableItem:
;; Figure out what's equipped
ldy SelectedConsumableIndex
bmi +
lda InvConsumables,y
cmp #ITEM_OPEL_STATUE
bne ++
+ ldy SelectedQuestItemIndex
bmi OpelStatueReturn
lda InvQuest,y
++ sec
jmp FinishEquippingConsumable
.org $3db28 ; Next routine starts here.
.endif