Skip to content
Merged
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
639 changes: 412 additions & 227 deletions runtime/ui/lang/de.inc

Large diffs are not rendered by default.

639 changes: 412 additions & 227 deletions runtime/ui/lang/es.inc

Large diffs are not rendered by default.

639 changes: 412 additions & 227 deletions runtime/ui/lang/fr.inc

Large diffs are not rendered by default.

639 changes: 412 additions & 227 deletions runtime/ui/lang/it.inc

Large diffs are not rendered by default.

639 changes: 412 additions & 227 deletions runtime/ui/lang/ja.inc

Large diffs are not rendered by default.

639 changes: 412 additions & 227 deletions runtime/ui/lang/ko.inc

Large diffs are not rendered by default.

639 changes: 412 additions & 227 deletions runtime/ui/lang/nl.inc

Large diffs are not rendered by default.

639 changes: 412 additions & 227 deletions runtime/ui/lang/pt-BR.inc

Large diffs are not rendered by default.

639 changes: 412 additions & 227 deletions runtime/ui/lang/ru.inc

Large diffs are not rendered by default.

639 changes: 412 additions & 227 deletions runtime/ui/lang/zh-Hans.inc

Large diffs are not rendered by default.

639 changes: 412 additions & 227 deletions runtime/ui/lang/zh-Hant.inc

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions runtime/ui/rando_tab.mm
Original file line number Diff line number Diff line change
Expand Up @@ -657,7 +657,7 @@ static void gen_overlay(float scale) {
ImGui::EndPopup();
}

bool spoiler_view_draw(const std::string &seed, float scale); // spoiler_view.mm
int spoiler_view_draw(const std::string &seed, float scale); // spoiler_view.mm: 0 closed, 2 took B
static std::string g_spoiler_seed; // seed whose spoiler page is open

// ---- the tab, in two columns (as the Controls tab's Configure inputs): Seeds and the seed option categories on the
Expand Down Expand Up @@ -1511,7 +1511,9 @@ static void seed_sheet(float scale, const char *active) {
static bool spoiler_test; // LARECOMP_SPOILER_TEST=<seed>: open that seed's spoiler page (test hook)
if (!spoiler_test && getenv("LARECOMP_SPOILER_TEST")) { spoiler_test = true; g_spoiler_seed = getenv("LARECOMP_SPOILER_TEST"); }
if (!g_spoiler_seed.empty()) { // the spoiler page replaces the tab until Back
if (!spoiler_view_draw(g_spoiler_seed, scale)) g_spoiler_seed.clear();
int r = spoiler_view_draw(g_spoiler_seed, scale);
if (r != 1) g_back_frame = ImGui::GetFrameCount(); // (B was the page's: not the menu's as well)
if (r == 0) g_spoiler_seed.clear();
return;
}
static bool opts_once; // the options the player last set (larecomp.ini)
Expand Down
450 changes: 390 additions & 60 deletions runtime/ui/spoiler_view.mm

Large diffs are not rendered by default.

18 changes: 18 additions & 0 deletions runtime/ui/tracker_overlay.mm
Original file line number Diff line number Diff line change
Expand Up @@ -1002,6 +1002,24 @@ static bool map_page_shown(void) {
return g_loaded > 0;
}

// The spoiler page (spoiler_view.mm): has the running seed's check `loc` been collected? 1 yes, 0 no, -1 can't tell
// (no seed running, or a check the save has no flag for: shop shelves, instruments). Render thread, like the drawing.
extern "C" int tracker_check_collected(const char *loc) {
static std::unordered_map<std::string, int> idx;
static size_t idx_for = ~(size_t)0;
if (!rando_seed_dir()) return -1;
if (!g_loaded) load();
if (g_loaded <= 0) return -1;
if (idx_for != g_checks.size()) {
idx.clear();
for (size_t i = 0; i < g_checks.size(); i++) idx[g_checks[i].name] = (int)i;
idx_for = g_checks.size();
}
auto it = idx.find(loc);
if (it == idx.end() || g_checks[it->second].flag < 0) return -1;
return flag_set(g_checks[it->second].flag) ? 1 : 0;
}

// status colours (best first: in logic, trick logic, needs an item, collected) and their text
static const ImU32 kStCol[4] = {IM_COL32(0x3F, 0xBF, 0x7F, 255), IM_COL32(0xA5, 0x8A, 0xF0, 255), IM_COL32(0xF2, 0xA3, 0x3A, 255),
IM_COL32(0x6F, 0x7C, 0x82, 255)};
Expand Down
22 changes: 20 additions & 2 deletions tools/menu_strings.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,12 +187,13 @@ def py_strings(path, want):
yield a.left.value + '%s' # ('Settings: ' + ', '.join(...))


MARKUP = re.compile(r'^(# |## |- | )')
MARKUP = re.compile(r'^(# |## |### |- | )')


def spoiler_keys():
sys.path.insert(0, os.path.join(ROOT, 'tools', 'rando'))
import spoiler_view as sv
import check_names as cn
path = os.path.join(ROOT, 'tools', 'rando', 'spoiler_view.py')
for s in py_strings(path, {'append'}):
s = MARKUP.sub('', s)
Expand All @@ -202,6 +203,17 @@ def spoiler_keys():
yield "%s's Soul", 'spoiler_view.py', False
yield "%s' Soul", 'spoiler_view.py', False
yield '%s:', 'spoiler_view.py', False # ("- Mabe Village:")
yield 'room %s', 'spoiler_view.py', False # ("Double stalfos (room A3)", "Catfish's Maw, room D7": room shuffle)
yield 'The last of the %s Triforce pieces you need ends the game.', 'spoiler_view.py', False
yield '2nd', 'spoiler_view.py', True # ("Shield (2nd)": the second copy of a progressive item)
for k in ('shop-slot3-2nd', 'shop-slot5-2nd', 'shop-slot5-3rd'): # (the Town Tool Shop's next items: check_names.py)
yield cn.display_name(k), 'spoiler_view.py', True
import entrance_names
for v in entrance_names.NAMES.values():
yield v, 'spoiler_view.py', True
for v in sv.PLACE:
if v:
yield v, 'spoiler_view.py', True
for d in (sv.AREAS, sv.DUNGEONS, sv.DPREFIX):
for v in d.values():
yield v, 'spoiler_view.py', True
Expand All @@ -215,6 +227,12 @@ def spoiler_keys():
if os.path.exists(yml):
for m in re.finditer(r'^\s+-\s+([a-z0-9-]+)\s*$', open(yml).read(), re.M):
yield sv.pretty_loc(m.group(1)), 'spoiler_view.py', True
yield cn.display_name(m.group(1)), 'spoiler_view.py', True # (the tracker's wording, used since 2026-11)
# dungeon checks in the tracker's wording ("Beetles"): every item location of LAS's logic
lg = os.path.join(ROOT, 'third_party', 'LAS-Randomizer', 'RandomizerCore', 'Data', 'logic.yml')
if os.path.exists(lg):
for m in re.finditer(r'^(D\d-[a-z0-9-]+):\s*\n\s+type:\s*(item|follower)\b', open(lg).read(), re.M):
yield cn.display_name(m.group(1)), 'spoiler_view.py', True
# settings ("Settings: " + the options that are on, dashes as spaces)
for f in glob.glob(os.path.join(ROOT, 'runtime', 'ui', 'rando_tab.mm')) + glob.glob(os.path.join(ROOT, 'runtime', 'rando.c')):
for m in re.finditer(r'"([a-z0-9]+(?:-[a-z0-9]+)+)"', open(f).read()):
Expand Down Expand Up @@ -323,7 +341,7 @@ def comp(s, src, d=0):
# matches them, so they're texts of their own
PATTERNS = ['leaving %s', 'outside %s', 'Outside %s', 'Room %s', 'Warp hole: %s', 'Level %s', '%s #%s',
'Bush %s', 'Dig %s', 'Pot %s', 'pot %s', 'pot %s in room %s', '%s: pot %s', '%s: pot %s in room %s',
'rupee %s', 'Apple tree (%s), %s of 3', 'Trendy prize %s', 'Trendy figure %s', 'fairy %s', 'Step %s',
'rupee %s', 'Apple tree (%s), %s of 3', 'Trendy prize %s', 'Trendy figure %s', 'fairy %s', 'Step %s', 'Sphere %s',
'Seed %s']
# the separators L_line joins parts with: a language may have its own ("、" for ", ", " : " in French)
SEPARATORS = [', ', ': ']
Expand Down
5 changes: 4 additions & 1 deletion tools/rando/check_names.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,11 @@ def display_name(name, kind=None, area=None, where=None):
m = re.match(r'trendy-prize-(\d+)$', name)
if m:
return f'Trendy Game: prize {m.group(1)}'
m = re.match(r'shop-slot(\d)-(2nd|3rd)$', name) # (a shelf's next item once the first is bought)
if m:
return f"Town Tool Shop: shelf {m.group(1)}, {'second' if m.group(2) == '2nd' else 'third'} item"
m = re.match(r'(D\d)-(.*)$', name)
if m and not m.group(2).startswith('pot-'):
if m and not re.match(r'pot-\d\d[A-P]-', m.group(2)): # (potsanity's numbered pots: their own wording)
return spelled(m.group(2))
if kind in KIND_WORD:
parts = [KIND_WORD[kind]]
Expand Down
75 changes: 75 additions & 0 deletions tools/rando/entrance_names.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
"""Plain names for the entrance randomizer's doors (tools/rando/entrance_data.yml ids), for the readable spoiler.

The same name serves both sides: "Mabe Village library" is the library's door outside and the library inside.
Anything missing falls back to the id, spelled out.
"""

NAMES = {
# Tal Tal Mountain Range / Tal Tal Heights
'd8-west-side-exit': 'Turtle Rock, west side door', 'd8-east-side-exit': 'Turtle Rock, east side door',
'fire-cave-north': 'Fire cave, north door', 'fire-cave-south': 'Fire cave, south door',
'windfish-egg': "Wind Fish's egg", 'taltal-cucco-house': 'Tal Tal Heights, rooster house',
'd7-eagles-tower': "Eagle's Tower", 'd8-turtle-rock': 'Turtle Rock',
'taltal-phone-d8': 'Telephone booth by Turtle Rock', 'taltal-mad-batter': 'Mad Batter well, Tal Tal',
'taltal-crossing-west': 'Tal Tal crossing cave, west door', 'taltal-crossing-east': 'Tal Tal crossing cave, east door',
'mountain-access-entrance': 'Mountain cave, bottom door', 'mountain-access-exit': 'Mountain cave, top door',
'mountain-access-chest-ledge': 'Mountain cave, ledge door', 'papahl-cave-lower': "Papahl's cave, lower door",
'papahl-cave-upper': "Papahl's cave, upper door", 'taltal-bird-key-cave': 'Bird Key cave',
'five-chest-tunnel-west': 'Five chest cave, west door', 'five-chest-tunnel-east': 'Five chest cave, east door',
'five-chest-game-exit': 'Five chest game, exit door', 'outer-rainbow-cave-west': 'Rainbow cave, outer west door',
'inner-rainbow-cave-west': 'Rainbow cave, inner west door', 'inner-rainbow-cave-east': 'Rainbow cave, inner east door',
'outer-rainbow-cave-east': 'Rainbow cave, outer east door', 'taltal-east-fairy': 'Fairy fountain, Tal Tal east',
'path-to-d7-south': "Cave to Eagle's Tower, south door", 'path-to-d7-north': "Cave to Eagle's Tower, north door",
# Goponga Swamp / Tabahl Wasteland / Kanalet
'goponga-cave-west': 'Goponga Swamp cave, west door', 'goponga-cave-east': 'Goponga Swamp cave, east door',
'd2-bottle-grotto': 'Bottle Grotto', 'manbo-cave': "Manbo's cave",
'd4-connector-west': "Cave by Angler's Tunnel, west door", 'd4-anglers-tunnel': "Angler's Tunnel",
'd4-connector-east': "Cave by Angler's Tunnel, east door", 'damp-cave': 'Damp cave',
'raft-return-north': 'Raft cave, north door', 'raft-return-south': 'Raft cave, south door',
'mr-write-house': "Mr. Write's house", 'swamp-phone': 'Telephone booth, Goponga Swamp',
'moblin-cave': 'Moblin cave', 'dampe-house': "Dampe's house", 'raft-shop': 'Rapids Ride raft shop',
'woods-north-cave': 'Mysterious Forest, north cave', 'crazy-tracy-house': "Crazy Tracy's house",
'kanalet-tunnel-west': 'Kanalet tunnel, west door', 'kanalet-tunnel-east': 'Kanalet tunnel, east door',
'kanalet-phone': 'Telephone booth by Kanalet Castle', 'kanalet-castle-roof-west': 'Kanalet Castle, roof west door',
'kanalet-castle-roof-east': 'Kanalet Castle, roof east door', 'kanalet-castle-front': 'Kanalet Castle, front door',
'kanalet-south-cave': 'Cave south of Kanalet Castle',
# Mysterious Forest / Koholint Prairie / Cemetery
'woods-crossing-cave-north': 'Forest crossing cave, north door',
'woods-crossing-cave-south': 'Forest crossing cave, south door', 'woods-mad-batter': 'Mad Batter well, forest',
'witch-hut': "Witch's hut", 'd6-north-side-exit': 'Face Shrine, north side door',
'graveyard-cave-west': 'Cemetery cave, west door', 'graveyard-cave-east': 'Cemetery cave, east door',
'd0-color-dungeon': 'Color Dungeon', 'prairie-fairy': 'Fairy fountain, Koholint Prairie',
'quadruplet-house-west': "Quadruplets' house, west door", 'quadruplet-house-east': "Quadruplets' house, east door",
'dream-shrine': 'Dream Shrine', 'ukuku-cave-west': 'Ukuku cave, west door', 'ukuku-cave-east': 'Ukuku cave, east door',
'prairie-phone-north': 'Telephone booth, Ukuku Prairie north', 'prairie-phone-west': 'Telephone booth, Ukuku Prairie west',
'seashell-mansion': 'Seashell Mansion', 'd6-face-shrine': 'Face Shrine',
'd6-connector-west': 'Cave to Face Shrine, west door', 'd6-connector-east': 'Cave to Face Shrine, east door',
'armos-fairy': 'Fairy fountain by the Armos maze', 'rooster-grave': "Flying Rooster's grave",
'river-crossing-cave-west': 'River crossing cave, west door', 'river-crossing-cave-east': 'River crossing cave, east door',
'southern-face-shrine': 'Southern Face Shrine', 'armos-maze-cave': 'Armos maze cave',
# Mabe Village
'town-tool-shop': 'Town Tool Shop', 'mabe-kennel': "BowWow's kennel", 'madam-meowmeow-house': "Madam MeowMeow's house",
'marin-tarin-house': "Marin and Tarin's house", 'mabe-library': 'Mabe Village library', 'ulrira-house': "Ulrira's house",
'mabe-phone': 'Telephone booth, Mabe Village', 'trendy-game': 'Trendy Game',
# south: Key Cavern, Martha's Bay, Animal Village, Yarna Desert
'd3-key-cavern': 'Key Cavern', 'bay-cliff-cave-north': 'Cliff cave by the bay, north door',
'bay-cliff-cave-plateau': 'Cliff cave by the bay, plateau door', 'bay-cliff-cave-south': 'Cliff cave by the bay, south door',
'richard-villa': "Richard's villa", 'richard-villa-cave-exit': "Cave behind Richard's villa",
'animal-village-rabbit-house': 'Animal Village, rabbit house', 'schule-donavitch-house': "Schule Donavitch's house",
'christine-house': "Christine's house", 'hidden-zora-house': "Zora's house", 'animal-village-bomb-cave': 'Animal Village, bombed cave',
'desert-lanmola-cave': 'Lanmola cave, Yarna Desert', 'd1-tail-cave': 'Tail Cave', 'mamu-cave': "Mamu's cave",
'd5-catfishs-maw': "Catfish's Maw", 'catfish-maw-dive-east': "Catfish's Maw, east dive spot",
'catfish-maw-dive-west': "Catfish's Maw, west dive spot", 'animal-village-phone': 'Telephone booth, Animal Village',
'bear-chef-house': "Chef Bear's house", 'banana-sale-house': "Sale's banana house", 'bay-mad-batter': 'Mad Batter well, bay',
'bay-batter-tunnel-north': 'Tunnel to the bay Mad Batter, north door',
'bay-batter-tunnel-south': 'Tunnel to the bay Mad Batter, south door', 'bay-phone': "Telephone booth, Martha's Bay",
'mermaid-statue': 'Mermaid statue', 'bay-fisherman-boat': "Fisherman's boat", 'boomerang-cave': 'Boomerang cave',
'ghost-house': "Ghost's house",
}


def name(door):
if door in NAMES:
return NAMES[door]
s = door.replace('-', ' ')
return s[:1].upper() + s[1:]
6 changes: 6 additions & 0 deletions tools/rando/las_headless.py
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,12 @@ def reach_with_progress(to_reach, placements, *a, **k):
import hint_sheet # the Hint Sheet's steps: progression items in playthrough order
print('hint sheet steps:', hint_sheet.steps(sh.logic_defs, pl, settings, lambda k, acc: sh.checkAccess(k, acc, settings['logic']),
sph, out_dir), flush=True)
try: # the spoiler's Route (presentation only: tools/rando/route.py)
import route
print('route:', route.build(sh.logic_defs, pl, settings, lambda k, acc: sh.checkAccess(k, acc, settings['logic']),
sph, out_dir), 'stops', flush=True)
except Exception as e:
print('route: skipped:', e, flush=True)
if settings.get('hints'): # owl statues and phone booths (tools/rando/seed_hints.py)
import seed_hints
print('hints:', seed_hints.pick(sh.logic_defs, pl, settings, lambda k, acc: sh.checkAccess(k, acc, settings['logic']),
Expand Down
Loading
Loading