Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions args/challenges.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ def parse(parser):
help = "Exp. Eggs will not appear in coliseum/auction/shops/chests/events")
challenges.add_argument("-nil", "--no-illuminas", action = "store_true",
help = "Illuminas will not appear in coliseum/auction/shops/chests/events")
challenges.add_argument("-noshoes", "--no-sprint-shoes", action = "store_true",
help = "Sprint Shoes will not appear in coliseum/auction/shops/chests")
challenges.add_argument("-nu", "--no-ultima", action = "store_true",
help = "Ultima cannot be learned from espers/items/natural magic")
challenges.add_argument("-nfps", "--no-free-paladin-shields", action = "store_true",
Expand All @@ -30,6 +32,9 @@ def flags(args):
flags += " -nee"
if args.no_illuminas:
flags += " -nil"
if args.no_sprint_shoes:
flags += " -noshoes"

if args.no_ultima:
flags += " -nu"
if args.no_free_paladin_shields:
Expand All @@ -46,6 +51,7 @@ def options(args):
("No Moogle Charms", args.no_moogle_charms),
("No Exp Eggs", args.no_exp_eggs),
("No Illuminas", args.no_illuminas),
("No Sprint Shoes", args.no_sprint_shoes),
("No Ultima", args.no_ultima),
("No Free Paladin Shields", args.no_free_paladin_shields),
("No Free Characters/Espers", args.no_free_characters_espers),
Expand Down
5 changes: 5 additions & 0 deletions args/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ def parse(parser):
misc = parser.add_argument_group("Misc.")
misc.add_argument("-as", "--auto-sprint", action = "store_true",
help = "Player always sprints. Sprint Shoes have no effect")
misc.add_argument("-shoedash", "--sprint-shoes-b-dash", action = "store_true",
help = "Holding B with sprint shoes on will increase movement speed beyond a sprint. Can cause a visual bug in Owzer's Mansion.")
misc.add_argument("-ond", "--original-name-display", action = "store_true",
help = "Display original character names in party and party select menus")
misc.add_argument("-rr", "--random-rng", action = "store_true",
Expand Down Expand Up @@ -63,6 +65,8 @@ def flags(args):

if args.auto_sprint:
flags += " -as"
if args.sprint_shoes_b_dash:
flags += " -shoedash"
if args.original_name_display:
flags += " -ond"
if args.random_rng:
Expand Down Expand Up @@ -142,6 +146,7 @@ def options(args):

return [
("Auto Sprint", args.auto_sprint),
("Sprint Shoes B-Dash", args.sprint_shoes_b_dash),
("Original Name Display", args.original_name_display),
("Random RNG", args.random_rng),
("Random Clock", args.random_clock),
Expand Down
2 changes: 2 additions & 0 deletions constants/objectives/results.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@
],
}

category_types["Item"].append(ResultType(60, "Sprint Shoes", "Sprint Shoes", None))

categories = list(category_types.keys())

id_type = {}
Expand Down
2 changes: 2 additions & 0 deletions data/items.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,8 @@ def get_excluded(self):
exclude.append(name_id["Exp. Egg"])
if self.args.no_illuminas:
exclude.append(name_id["Illumina"])
if self.args.no_sprint_shoes:
exclude.append(name_id["Sprint Shoes"])
if self.args.no_free_paladin_shields:
exclude.append(name_id["Paladin Shld"])
exclude.append(name_id["Cursed Shld"])
Expand Down
19 changes: 19 additions & 0 deletions objectives/results/sprint_shoes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from objectives.results._objective_result import *
from data.item_names import name_id as item_name_id

class Field(field_result.Result):
def src(self):
return [
field.AddItem(item_name_id["Sprint Shoes"]),
]

class Battle(battle_result.Result):
def src(self):
return [
battle_result.AddItem(item_name_id["Sprint Shoes"]),
]

class Result(ObjectiveResult):
NAME = "Sprint Shoes"
def __init__(self):
super().__init__(Field, Battle)
142 changes: 129 additions & 13 deletions settings/auto_sprint.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from memory.space import Reserve
from memory.space import Allocate, Bank, Reserve
import instruction.asm as asm
import args

Expand All @@ -12,25 +12,141 @@ def mod(self):

WALK_SPEED = 2
SPRINT_SPEED = 3
DASH_SPEED = 4

if args.auto_sprint or args.sprint_shoes_b_dash:
src = self.get_auto_sprint_src(WALK_SPEED, SPRINT_SPEED, DASH_SPEED)
space = Allocate(Bank.F0, 49, "Sprint subroutine")
space.write(src)
src = [
asm.JSL(space.start_address_snes),
]
space = Reserve(0x04e21, 0x04e37, "auto sprint", asm.NOP())
space.write(src)

self.sliding_dash_fix()

def get_auto_sprint_src(self, WALK_SPEED, SPRINT_SPEED, DASH_SPEED):
import args
CURRENT_MAP_BYTE = 0x82 # 2 bytes
OWZERS_MANSION_ID = 0x0D1 # the door room can create visual artifacts on the map while dashing
CONTROLLER1_BYTE2 = 0x4219
SPRINT_SHOES_BYTE = 0x11df
SPRINT_SHOES_MASK = 0x20
B_BUTTON_MASK = 0x80
FIELD_RAM_SPEED = 0x0875

src = [
asm.LDA(CONTROLLER1_BYTE2, asm.ABS),
asm.AND(B_BUTTON_MASK, asm.IMM8),
asm.BNE("WALK"), # branch if b button down
if args.auto_sprint:
src = [
asm.LDA(CONTROLLER1_BYTE2, asm.ABS),
asm.AND(B_BUTTON_MASK, asm.IMM8),
asm.BNE("WALK"), # branch if b button down

"SPRINT",
asm.LDA(SPRINT_SPEED, asm.IMM8),
asm.BRA("STORE"),

"WALK",
asm.LDA(WALK_SPEED, asm.IMM8),
]

"SPRINT",
asm.LDA(SPRINT_SPEED, asm.IMM8),
asm.BRA("STORE_SPEED"),
if args.sprint_shoes_b_dash:
src = [
"CHECK_OWZERS",
asm.REP(0x20), # set register A bit size to 16
asm.LDA(CURRENT_MAP_BYTE, asm.ABS), # if current map owzers mansion, disable the b-button
asm.CMP(OWZERS_MANSION_ID, asm.IMM16),
asm.BEQ("STORE_DEFAULT"),
asm.SEP(0x20),
asm.LDA(CONTROLLER1_BYTE2, asm.ABS),
asm.AND(B_BUTTON_MASK, asm.IMM8),
asm.BNE("DASH1"), # b button just store default

"WALK",
asm.LDA(WALK_SPEED, asm.IMM8),
"STORE_DEFAULT",
asm.SEP(0x20),
asm.LDA(SPRINT_SPEED, asm.IMM8),
asm.BRA("STORE"),

"STORE_SPEED",
asm.STA(FIELD_RAM_SPEED, asm.ABS_Y),
"DASH1",
asm.LDA(SPRINT_SHOES_BYTE, asm.ABS), # If sprint shoes equipped, store dash speed
asm.AND(SPRINT_SHOES_MASK, asm.IMM8),
asm.BNE("DASH2"),
asm.LDA(WALK_SPEED, asm.IMM8),
asm.BRA("STORE"),

"DASH2",
asm.LDA(DASH_SPEED, asm.IMM8), # load fastest speed (DASH)
]

src += [
"STORE",
asm.STA(FIELD_RAM_SPEED, asm.ABS_Y), # store speed in ram
asm.SEP(0x20),
asm.RTL(), # return
]
space = Reserve(0x04e21, 0x04e37, "auto sprint", asm.NOP())

return src


# DIRECTION VALUE
# $087F ------dd
# d: facing direction
# 00 = up
# 01 = right
# 10 = down
# 11 = left

# https://silentenigma.neocities.org/ff6/index.html
# Will leave bits of documentation about in the vent neocities does not stand the test of time

# With dash enabled, this causes a bug that the player will appear to be standing still when
# running down or right at move speed 5. This is because two sprite instances are thrown out of
# the animation cycle when running at that speed; while Up/Left correctly omits the standing
# sprite, Down/Right omits the stepping sprites, since the offsets lag by an iteration.
def sliding_dash_fix(self):
DIRECTION_VALUE = 0x087f

# C0/0000: 4A LSR ; Shift offset bits right
# C0/0001: 4A LSR ; Shift offset bits right
# C0/0002: 48 PHA ; Push offset value to stack
# C0/0003: B9 7F 08 LDA $087F,y ; Load direction value
# C0/0006: C9 01 CMP #$01 ; Check if direction is Right
# C0/0008: F0 07 BEQ $D69E ; Branch if the direction is Right
# C0/000A: C9 02 CMP #$02 ; Check if the direction is Down
# C0/000C: F0 03 BEQ $D69E ; Branch if the direction is Down
# C0/000E: 68 PLA ; Pull offset back off of stack
# C0/000F: 80 02 BRA $D6A0 ; Branch to the third LSR
# C0/0011: 68 PLA ; Pull offset back off of stack
# C0/0012: 1A INC ; Increase the offset value by 1
# C0/0013: 4A LSR ; Shift offset bits right
# C0/0014: 60 RTS ; Return from subfunction
subroutine_src = [
asm.LSR(),
asm.LSR(),
asm.PHA(),
asm.LDA(DIRECTION_VALUE, asm.ABS_Y),
asm.DEC(),
asm.BEQ("FACING_RIGHT"),
asm.DEC(),
asm.BNE("RETURN"),
"FACING_RIGHT",
asm.PLA(),
asm.INC(),
asm.PHA(),
"RETURN",
asm.PLA(),
asm.LSR(),
asm.RTS(),
]
subroutine_space = Allocate(Bank.C0, 20, "walking speed calculation", asm.NOP())
subroutine_space.write(subroutine_src)

src = [
asm.JSR(subroutine_space.start_address, asm.ABS)
]

space = Reserve(0x5885, 0x5887, "Sprite offset calculation 1", asm.NOP())
space.write(src)

space = Reserve(0x5892, 0x5894, "Sprite offset calculation 2")
space.write(src)