Merge remote-tracking branch 'origin' into OverworldShuffle
This commit is contained in:
102
Rom.py
102
Rom.py
@@ -9,17 +9,20 @@ import RaceRandom as random
|
||||
import struct
|
||||
import sys
|
||||
import subprocess
|
||||
import bps.apply
|
||||
import bps.io
|
||||
try:
|
||||
import bps.apply
|
||||
import bps.io
|
||||
except ImportError:
|
||||
raise Exception('Could not load BPS module')
|
||||
|
||||
from BaseClasses import CollectionState, ShopType, Region, Location, OWEdge, Door, DoorType, RegionType, PotItem
|
||||
from DoorShuffle import compass_data, DROptions, boss_indicator
|
||||
from Dungeons import dungeon_music_addresses
|
||||
from KeyDoorShuffle import count_locations_exclude_logic
|
||||
from Regions import location_table, shop_to_location_table, retro_shops
|
||||
from RoomData import DoorKind
|
||||
from Text import MultiByteTextMapper, CompressedTextMapper, text_addresses, Credits, TextTable
|
||||
from Text import Uncle_texts, Ganon1_texts, TavernMan_texts, Sahasrahla2_texts, Triforce_texts, Blind_texts, BombShop2_texts, junk_texts
|
||||
from Text import Uncle_texts, Ganon1_texts, Ganon_Phase_3_No_Silvers_texts, TavernMan_texts, Sahasrahla2_texts
|
||||
from Text import Triforce_texts, Blind_texts, BombShop2_texts, junk_texts
|
||||
from Text import KingsReturn_texts, Sanctuary_texts, Kakariko_texts, Blacksmiths_texts, DeathMountain_texts, LostWoods_texts, WishingWell_texts, DesertPalace_texts, MountainTower_texts, LinksHouse_texts, Lumberjacks_texts, SickKid_texts, FluteBoy_texts, Zora_texts, MagicShop_texts, Sahasrahla_names
|
||||
from Utils import output_path, local_path, int16_as_bytes, int32_as_bytes, snes_to_pc
|
||||
from Items import ItemFactory
|
||||
@@ -28,7 +31,7 @@ from OverworldShuffle import default_flute_connections, flute_data
|
||||
|
||||
|
||||
JAP10HASH = '03a63945398191337e896e5771f77173'
|
||||
RANDOMIZERBASEHASH = 'da6f3d011c2e50ccf6450f5e69c7c735'
|
||||
RANDOMIZERBASEHASH = 'efb10737d732625792a9af7fdda2c4e9'
|
||||
|
||||
|
||||
class JsonRom(object):
|
||||
@@ -201,7 +204,7 @@ def patch_enemizer(world, player, rom, baserom_path, enemizercli, random_sprite_
|
||||
options = {
|
||||
'RandomizeEnemies': world.enemy_shuffle[player] != 'none',
|
||||
'RandomizeEnemiesType': 3,
|
||||
'RandomizeBushEnemyChance': world.enemy_shuffle[player] == 'random',
|
||||
'RandomizeBushEnemyChance': world.enemy_shuffle[player] in ['random', 'legacy'],
|
||||
'RandomizeEnemyHealthRange': world.enemy_health[player] != 'default',
|
||||
'RandomizeEnemyHealthType': {'default': 0, 'easy': 0, 'normal': 1, 'hard': 2, 'expert': 3}[world.enemy_health[player]],
|
||||
'OHKO': False,
|
||||
@@ -247,9 +250,9 @@ def patch_enemizer(world, player, rom, baserom_path, enemizercli, random_sprite_
|
||||
'SwordGraphics': "sword_gfx/normal.gfx",
|
||||
'BeeMizer': False,
|
||||
'BeesLevel': 0,
|
||||
'RandomizeTileTrapPattern': world.enemy_shuffle[player] == 'random',
|
||||
'RandomizeTileTrapPattern': world.enemy_shuffle[player] in ['random', 'legacy'],
|
||||
'RandomizeTileTrapFloorTile': False,
|
||||
'AllowKillableThief': bool(random.randint(0, 1)) if world.enemy_shuffle[player] == 'random' else world.enemy_shuffle[player] != 'none',
|
||||
'AllowKillableThief': bool(random.randint(0, 1)) if world.enemy_shuffle[player] == 'legacy' else world.enemy_shuffle[player] != 'none',
|
||||
'RandomizeSpriteOnHit': random_sprite_on_hit,
|
||||
'DebugMode': False,
|
||||
'DebugForceEnemy': False,
|
||||
@@ -1270,6 +1273,9 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
|
||||
rom.write_byte(0x18017E, 0x01) # Fairy fountains only trade in bottles
|
||||
|
||||
# Starting equipment
|
||||
if world.fakeboots[player]:
|
||||
rom.write_byte(0x18008E, 0x01)
|
||||
|
||||
equip = [0] * (0x340 + 0x4F)
|
||||
equip[0x36C] = 0x18
|
||||
equip[0x36D] = 0x18
|
||||
@@ -1751,6 +1757,7 @@ def hud_format_text(text):
|
||||
|
||||
def apply_rom_settings(rom, beep, color, quickswap, fastmenu, disable_music, sprite,
|
||||
ow_palettes, uw_palettes, reduce_flashing):
|
||||
|
||||
if not os.path.exists("data/sprites/official/001.link.1.zspr") and rom.orig_buffer:
|
||||
dump_zspr(rom.orig_buffer[0x80000:0x87000], rom.orig_buffer[0xdd308:0xdd380],
|
||||
rom.orig_buffer[0xdedf5:0xdedf9], "data/sprites/official/001.link.1.zspr", "Nintendo", "Link")
|
||||
@@ -1839,7 +1846,6 @@ def apply_rom_settings(rom, beep, color, quickswap, fastmenu, disable_music, spr
|
||||
|
||||
if reduce_flashing:
|
||||
rom.write_byte(0x18017f, 1)
|
||||
|
||||
default_ow_palettes(rom)
|
||||
if ow_palettes == 'random':
|
||||
randomize_ow_palettes(rom)
|
||||
@@ -1910,6 +1916,61 @@ def dump_zspr(basesprite, basepalette, baseglove, outfilename, author_name, spri
|
||||
with open('%s' % outfilename, "wb") as zspr_file:
|
||||
zspr_file.write(write_buffer)
|
||||
|
||||
# .zspr file dumping logic copied with permission from SpriteSomething:
|
||||
# https://github.com/Artheau/SpriteSomething/blob/master/source/meta/classes/spritelib.py#L443 (thanks miketrethewey!)
|
||||
def dump_zspr(basesprite, basepalette, baseglove, outfilename, author_name, sprite_name):
|
||||
palettes = basepalette
|
||||
# Add glove data
|
||||
palettes.extend(baseglove)
|
||||
HEADER_STRING = b"ZSPR"
|
||||
VERSION = 0x01
|
||||
SPRITE_TYPE = 0x01 # this format has "1" for the player sprite
|
||||
RESERVED_BYTES = b'\x00\x00\x00\x00\x00\x00'
|
||||
QUAD_BYTE_NULL_CHAR = b'\x00\x00\x00\x00'
|
||||
DOUBLE_BYTE_NULL_CHAR = b'\x00\x00'
|
||||
SINGLE_BYTE_NULL_CHAR = b'\x00'
|
||||
|
||||
write_buffer = bytearray()
|
||||
|
||||
write_buffer.extend(HEADER_STRING)
|
||||
write_buffer.extend(struct.pack('B', VERSION)) # as_u8
|
||||
checksum_start = len(write_buffer)
|
||||
write_buffer.extend(QUAD_BYTE_NULL_CHAR) # checksum
|
||||
sprite_sheet_pointer = len(write_buffer)
|
||||
write_buffer.extend(QUAD_BYTE_NULL_CHAR)
|
||||
write_buffer.extend(struct.pack('<H', len(basesprite))) # as_u16
|
||||
palettes_pointer = len(write_buffer)
|
||||
write_buffer.extend(QUAD_BYTE_NULL_CHAR)
|
||||
write_buffer.extend(struct.pack('<H', len(palettes))) # as_u16
|
||||
write_buffer.extend(struct.pack('<H', SPRITE_TYPE)) # as_u16
|
||||
write_buffer.extend(RESERVED_BYTES)
|
||||
# sprite.name
|
||||
write_buffer.extend(sprite_name.encode('utf-16-le'))
|
||||
write_buffer.extend(DOUBLE_BYTE_NULL_CHAR)
|
||||
# author.name
|
||||
write_buffer.extend(author_name.encode('utf-16-le'))
|
||||
write_buffer.extend(DOUBLE_BYTE_NULL_CHAR)
|
||||
# author.name-short
|
||||
write_buffer.extend(author_name.encode('ascii'))
|
||||
write_buffer.extend(SINGLE_BYTE_NULL_CHAR)
|
||||
write_buffer[sprite_sheet_pointer:sprite_sheet_pointer +
|
||||
4] = struct.pack('<L', len(write_buffer)) # as_u32
|
||||
write_buffer.extend(basesprite)
|
||||
write_buffer[palettes_pointer:palettes_pointer +
|
||||
4] = struct.pack('<L', len(write_buffer)) # as_u32
|
||||
write_buffer.extend(palettes)
|
||||
|
||||
checksum = (sum(write_buffer) + 0xFF + 0xFF) % 0x10000
|
||||
checksum_complement = 0xFFFF - checksum
|
||||
|
||||
write_buffer[checksum_start:checksum_start +
|
||||
2] = struct.pack('<H', checksum) # as_u16
|
||||
write_buffer[checksum_start + 2:checksum_start +
|
||||
4] = struct.pack('<H', checksum_complement) # as_u16
|
||||
|
||||
with open('%s' % outfilename, "wb") as zspr_file:
|
||||
zspr_file.write(write_buffer)
|
||||
|
||||
def write_sprite(rom, sprite):
|
||||
if not sprite.valid:
|
||||
return
|
||||
@@ -2257,23 +2318,30 @@ def write_strings(rom, world, player, team):
|
||||
ganon_item = 'arrow'
|
||||
|
||||
if ganon_item == 'arrow':
|
||||
no_silver_text = Ganon_Phase_3_No_Silvers_texts[random.randint(0, len(Ganon_Phase_3_No_Silvers_texts) - 1)]
|
||||
silverarrows = world.find_items('Silver Arrows', player)
|
||||
|
||||
random.shuffle(silverarrows)
|
||||
silverarrow_hint = (' %s?' % hint_text(silverarrows[0]).replace('Ganon\'s', 'my')) if silverarrows else '?\nI think not!'
|
||||
tt['ganon_phase_3_no_silvers'] = 'Did you find the silver arrows%s' % silverarrow_hint
|
||||
tt['ganon_phase_3_no_silvers_alt'] = 'Did you find the silver arrows%s' % silverarrow_hint
|
||||
if silverarrows:
|
||||
hint_phrase = hint_text(silverarrows[0]).replace("Ganon's", "my")
|
||||
silverarrow_hint = f'Did you find the silver arrows {hint_phrase}?'
|
||||
else:
|
||||
silverarrow_hint = no_silver_text
|
||||
tt['ganon_phase_3_no_silvers'] = silverarrow_hint
|
||||
tt['ganon_phase_3_no_silvers_alt'] = silverarrow_hint
|
||||
|
||||
prog_bow_locs = world.find_items('Progressive Bow', player)
|
||||
distinguished_prog_bow_loc = next((location for location in prog_bow_locs if location.item.code == 0x65), None)
|
||||
progressive_silvers = world.difficulty_requirements[player].progressive_bow_limit >= 2 or world.swords[player] == 'swordless'
|
||||
if distinguished_prog_bow_loc:
|
||||
prog_bow_locs.remove(distinguished_prog_bow_loc)
|
||||
silverarrow_hint = (' %s?' % hint_text(distinguished_prog_bow_loc).replace('Ganon\'s', 'my')) if progressive_silvers else '?\nI think not!'
|
||||
tt['ganon_phase_3_no_silvers'] = 'Did you find the silver arrows%s' % silverarrow_hint
|
||||
|
||||
hint_phrase = hint_text(distinguished_prog_bow_loc).replace("Ganon's", "my")
|
||||
silverarrow_hint = f'Did you find the silver arrows {hint_phrase}?' if progressive_silvers else no_silver_text
|
||||
tt['ganon_phase_3_no_silvers'] = silverarrow_hint
|
||||
if any(prog_bow_locs):
|
||||
silverarrow_hint = (' %s?' % hint_text(random.choice(prog_bow_locs)).replace('Ganon\'s', 'my')) if progressive_silvers else '?\nI think not!'
|
||||
tt['ganon_phase_3_no_silvers_alt'] = 'Did you find the silver arrows%s' % silverarrow_hint
|
||||
hint_phrase = hint_text(random.choice(prog_bow_locs)).replace("Ganon's", "my")
|
||||
silverarrow_hint = f'Did you find the silver arrows {hint_phrase}?' if progressive_silvers else no_silver_text
|
||||
tt['ganon_phase_3_no_silvers_alt'] = silverarrow_hint
|
||||
elif ganon_item == 'bomb':
|
||||
tt['ganon_phase_3_no_bow'] = 'You can\'t best\nme without\nexplosives!'
|
||||
tt['ganon_phase_3_silvers'] = 'Explosives!\nMy one true\nweakness!'
|
||||
|
||||
Reference in New Issue
Block a user