Skip to content

Commit 5aa7cff

Browse files
authored
Merge pull request #10 from AtmaTek/1_1_0
1 1 0
2 parents 40f0fab + ab5b33e commit 5aa7cff

40 files changed

+1459
-224
lines changed

args/arguments.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ def __init__(self):
44
self.groups = [
55
"settings",
66
"objectives",
7-
"starting_party", "characters", "swdtechs", "blitzes", "lores", "rages", "dances", "commands",
7+
"starting_party", "characters", "swdtechs", "blitzes", "lores", "rages", "dances", "steal", "commands",
88
"xpmpgp", "scaling", "bosses", "encounters", "boss_ai",
99
"espers", "natural_magic",
1010
"starting_gold_items", "items", "shops", "chests",

args/chests.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ def parse(parser):
1010
help = "Chest contents shuffled and given percent randomized")
1111
chests_contents.add_argument("-ccrt", "--chest-contents-random-tiered", action = "store_true",
1212
help = "Chest contents randomized by tier")
13+
chests_contents.add_argument("-ccrs", "--chest-contents-random-scaled", action = "store_true",
14+
help = "Chest contents randomized by tier. Probability of higher tiers begins low and increases as more chests are opened")
1315
chests_contents.add_argument("-cce", "--chest-contents-empty", action = "store_true",
1416
help = "Chest contents empty")
1517

@@ -28,6 +30,8 @@ def flags(args):
2830
flags += f" -ccsr {args.chest_contents_shuffle_random_percent}"
2931
elif args.chest_contents_random_tiered:
3032
flags += " -ccrt"
33+
elif args.chest_contents_random_scaled:
34+
flags += " -ccrs"
3135
elif args.chest_contents_empty:
3236
flags += " -cce"
3337

@@ -44,6 +48,8 @@ def options(args):
4448
contents_value = "Shuffle + Random"
4549
elif args.chest_contents_random_tiered:
4650
contents_value = "Random Tiered"
51+
elif args.chest_contents_random_scaled:
52+
contents_value = "Random Scaled"
4753
elif args.chest_contents_empty:
4854
contents_value = "Empty"
4955

args/coliseum.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ def name():
22
return "Coliseum"
33

44
def parse(parser):
5-
from data.items import Items
5+
from constants.items import ITEM_COUNT
66

77
coliseum = parser.add_argument_group("Coliseum")
88

@@ -19,7 +19,7 @@ def parse(parser):
1919
help = "Coliseum rewards randomized")
2020

2121
coliseum.add_argument("-crvr", "--coliseum-rewards-visible-random", default = None, type = int,
22-
nargs = 2, metavar = ("MIN", "MAX"), choices = range(Items.ITEM_COUNT),
22+
nargs = 2, metavar = ("MIN", "MAX"), choices = range(ITEM_COUNT),
2323
help = "Random number of rewards within given range visible before beginning the match. Remaining rewards will display as question marks")
2424
coliseum.add_argument("-crm", "--coliseum-rewards-menu", action = "store_true",
2525
help = "Display rewards in item selection menu. Hidden rewards will display as question marks")

args/commands.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ def parse(parser):
1212
commands.add_argument("-rec3", "--random-exclude-command3", type = int, choices = RANDOM_EXCLUDE_COMMANDS, metavar = "VALUE", default = NONE_COMMAND, help = "Exclude selected command from random possibilities")
1313
commands.add_argument("-rec4", "--random-exclude-command4", type = int, choices = RANDOM_EXCLUDE_COMMANDS, metavar = "VALUE", default = NONE_COMMAND, help = "Exclude selected command from random possibilities")
1414
commands.add_argument("-rec5", "--random-exclude-command5", type = int, choices = RANDOM_EXCLUDE_COMMANDS, metavar = "VALUE", default = NONE_COMMAND, help = "Exclude selected command from random possibilities")
15+
commands.add_argument("-rec6", "--random-exclude-command6", type = int, choices = RANDOM_EXCLUDE_COMMANDS, metavar = "VALUE", default = NONE_COMMAND, help = "Exclude selected command from random possibilities")
1516

1617
def process(args):
1718
if not args.commands:
@@ -43,6 +44,8 @@ def process(args):
4344
args.random_exclude_commands.append(args.random_exclude_command4)
4445
if args.random_exclude_command5 != NONE_COMMAND:
4546
args.random_exclude_commands.append(args.random_exclude_command5)
47+
if args.random_exclude_command6 != NONE_COMMAND:
48+
args.random_exclude_commands.append(args.random_exclude_command6)
4649

4750
random_exists = "Random" in args.command_strings or "Random Unique" in args.command_strings
4851
blitz_excluded = name_id["Blitz"] in args.random_exclude_commands
@@ -67,6 +70,8 @@ def flags(args):
6770
flags += f" -rec4 {args.random_exclude_command4}"
6871
if args.random_exclude_command5 != NONE_COMMAND:
6972
flags += f" -rec5 {args.random_exclude_command5}"
73+
if args.random_exclude_command6 != NONE_COMMAND:
74+
flags += f" -rec6 {args.random_exclude_command6}"
7075

7176
return flags
7277

@@ -89,6 +94,7 @@ def options(args):
8994
add_exclude_command(args.random_exclude_command3)
9095
add_exclude_command(args.random_exclude_command4)
9196
add_exclude_command(args.random_exclude_command5)
97+
add_exclude_command(args.random_exclude_command6)
9298

9399
return result
94100

args/log.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def _log_tab(tab_name, left_groups, right_groups):
1717
def log():
1818
_log_tab("Game", ["settings"], [])
1919
args.group_modules["objectives"].log(args)
20-
_log_tab("Party", ["starting_party", "swdtechs", "blitzes", "lores", "rages", "dances"], ["characters", "commands"])
20+
_log_tab("Party", ["starting_party", "swdtechs", "blitzes", "lores", "rages", "dances", "steal"], ["characters", "commands"])
2121
_log_tab("Battle", ["xpmpgp", "bosses", "boss_ai"], ["scaling", "encounters"])
2222
_log_tab("Magic", ["espers"], ["natural_magic"])
2323
_log_tab("Items", ["starting_gold_items", "items"], ["shops", "chests"])

args/misc.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ def parse(parser):
4343
help = "Remove NPC")
4444
parser.y_npc_group = y_npc
4545

46+
remove_flashes = misc.add_mutually_exclusive_group()
47+
remove_flashes.add_argument("-frw", "--flashes-remove-worst", action = "store_true",
48+
help = "Removes only the worst flashes from animations. Ex: Learning Bum Rush, Bum Rush, Quadra Slam/Slice, Flash, etc.")
49+
remove_flashes.add_argument("-frm", "--flashes-remove-most", action = "store_true",
50+
help = "Removes most flashes from animations. Includes Kefka Death.")
51+
4652
def process(args):
4753
args.y_npc = False # are any y_npc flags enabled?
4854

@@ -92,6 +98,11 @@ def flags(args):
9298
elif args.y_npc_remove:
9399
flags += " -yremove"
94100

101+
if args.flashes_remove_worst:
102+
flags += " -frw"
103+
if args.flashes_remove_most:
104+
flags += " -frm"
105+
95106
return flags
96107

97108
def options(args):
@@ -123,6 +134,12 @@ def options(args):
123134
elif args.y_npc_remove:
124135
y_npc = "Remove"
125136

137+
remove_flashes = "Original"
138+
if args.flashes_remove_worst:
139+
remove_flashes = "Worst"
140+
elif args.flashes_remove_most:
141+
remove_flashes = "Most"
142+
126143
return [
127144
("Auto Sprint", args.auto_sprint),
128145
("Original Name Display", args.original_name_display),
@@ -131,6 +148,7 @@ def options(args):
131148
("Scan All", args.scan_all),
132149
("Event Timers", event_timers),
133150
("Y NPC", y_npc),
151+
("Remove Flashes", remove_flashes)
134152
]
135153

136154
def menu(args):

args/objectives.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@ def parse(parser):
88

99
def process(args):
1010
from constants.objectives.results import types as result_types
11+
from constants.objectives.results import id_type as result_id_type
1112
from constants.objectives.conditions import types as condition_types
1213

1314
class Result:
14-
def __init__(self, name, format_string, value_range, args):
15+
def __init__(self, _id, name, format_string, value_range, args):
16+
self.id = _id
1517
self.name = name
1618
self.format_string = format_string
1719
self.value_range = value_range
@@ -49,7 +51,7 @@ def __init__(self, letter, result, conditions, conditions_required_min, conditio
4951
pass
5052
value_index = 0
5153

52-
result_type = result_types[values[value_index]]
54+
result_type = result_id_type[values[value_index]]
5355
value_index += 1
5456

5557
if result_type.value_range is not None:

args/steal.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
def name():
2+
return "Steal"
3+
4+
def parse(parser):
5+
steal = parser.add_argument_group("Steal")
6+
7+
steal_chances = steal.add_mutually_exclusive_group()
8+
steal_chances.add_argument("-sch", "--steal-chances-higher", action = "store_true",
9+
help = "Steal Rate is improved and rare steals are more likely")
10+
steal_chances.add_argument("-sca", "--steal-chances-always", action = "store_true",
11+
help = "Steal will always succeed if enemy has an item")
12+
13+
def process(args):
14+
pass
15+
16+
def flags(args):
17+
flags = ""
18+
19+
if args.steal_chances_higher:
20+
flags += " -sch"
21+
if args.steal_chances_always:
22+
flags += " -sca"
23+
24+
return flags
25+
26+
def options(args):
27+
steal_chances = "Original"
28+
if args.steal_chances_higher:
29+
steal_chances = "Higher"
30+
if args.steal_chances_always:
31+
steal_chances = "Always"
32+
33+
return [
34+
("Chances", steal_chances),
35+
]
36+
37+
def menu(args):
38+
return (name(), options(args))
39+
40+
def log(args):
41+
from log import format_option
42+
log = [name()]
43+
44+
entries = options(args)
45+
for entry in entries:
46+
log.append(format_option(*entry))
47+
48+
return log

battle/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55
import battle.suplex_train_check
66
import battle.auto_status
77
import battle.end_checks
8+
from battle.animations import Animations
89

910
__all__ = ["Battle"]
1011
class Battle:
1112
def __init__(self):
1213
self.multipliers = Multipliers()
14+
self.animations = Animations()

battle/animations.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
from memory.space import Bank, Reserve, Read, Write
2+
import data.battle_animation_scripts as battle_animation_scripts
3+
import instruction.asm as asm
4+
import args
5+
6+
class Animations:
7+
def __init__(self):
8+
self.health_animation_reflect_mod()
9+
10+
if args.flashes_remove_most:
11+
flash_address_arrays = battle_animation_scripts.BATTLE_ANIMATION_FLASHES.values()
12+
self.remove_battle_flashes_mod(flash_address_arrays)
13+
self.remove_critical_flash()
14+
15+
if args.flashes_remove_worst:
16+
flash_address_arrays = []
17+
animation_names = ["Boss Death", "Ice 3", "Fire 3", "Bolt 3", "Schiller", "R.Polarity", "X-Zone",
18+
"Muddle", "Dispel", "Shock", "Bum Rush", "Quadra Slam", "Slash", "Flash",
19+
"Step Mine", "Rippler", "WallChange", "Ultima", "ForceField"]
20+
for name in animation_names:
21+
flash_address_arrays.append(battle_animation_scripts.BATTLE_ANIMATION_FLASHES[name])
22+
self.remove_battle_flashes_mod(flash_address_arrays)
23+
24+
def remove_critical_flash(self):
25+
space = Reserve(0x23410, 0x23413, "Critical hit screen flash", asm.NOP())
26+
27+
def remove_battle_flashes_mod(self, flash_address_arrays):
28+
ABSOLUTE_CHANGES = [0xb0, 0xaf]
29+
RELATIVE_CHANGES = [0xb5, 0xb6]
30+
# For each battle animation command
31+
for flash_addresses in flash_address_arrays:
32+
# For each address in its array
33+
for flash_address in flash_addresses:
34+
# Read the current animation command at the address
35+
animation_cmd = Read(flash_address, flash_address+1)
36+
if(animation_cmd[0] in ABSOLUTE_CHANGES):
37+
# This is an absolute color change. To remove flashing effects, set the value to E0 to cause no background change
38+
Write(flash_address+1, 0xE0, "Background color change (absolute)")
39+
elif(animation_cmd[0] in RELATIVE_CHANGES):
40+
# This is a relative color change. To remove flash effects, set the value to F0 to cause no background change
41+
Write(flash_address+1, 0xF0, "Background color change (relative)")
42+
else:
43+
# This is an error, reflecting a difference between the disassembly used to generate BATTLE_ANIMATION_FLASHES and the ROM
44+
raise ValueError(f"Battle Animation Script Command at 0x{flash_address:x} (0x{animation_cmd[0]:x}) did not match an expected value.")
45+
46+
def health_animation_reflect_mod(self):
47+
# Ref: https://www.ff6hacking.com/forums/thread-4145.html
48+
# Banon's Health command casts Cure 2 on the party with a unique animation.
49+
# Because the animation is unique, it has the step-forward component built into it.
50+
# And because Cure 2 can be reflected, if the command hits a mirrored target it will bounce and make Banon step forward again.
51+
# Note: this only occurs if the whole party doesn't have reflect, only a subset.
52+
# Used over and over, Banon can be made to walk completely off-screen.
53+
#
54+
# Fix:
55+
# We tell the HEALTH animation to ignore block graphics, which prevents the reflect animation from playing.
56+
# When encountering a reflection, the regular green Cure 2 animation will follow on the reflect recipient.
57+
src = [
58+
asm.INC(0x62C0, asm.ABS), #Makes the animation ignore blocking graphics
59+
asm.JSR(0xBC35, asm.ABS), #Call the subroutine that got displaced to inject the block override
60+
asm.RTS()
61+
]
62+
space = Write(Bank.C1, src, "Health animation fix")
63+
jsrAddr = space.start_address
64+
65+
# Replace the existing jump with one to our new service routine
66+
space = Reserve(0x1BB67, 0x1BB69, "Health animation JSR")
67+
space.write(asm.JSR(jsrAddr, asm.ABS))

0 commit comments

Comments
 (0)