Files
Archipelago/worlds/stardew_valley/client.py
T

115 lines
4.4 KiB
Python

from __future__ import annotations
import re
import Utils
from BaseClasses import CollectionState, Location
from NetUtils import JSONMessagePart
from . import StardewValleyWorld
from .logic.logic import StardewLogic
from .stardew_rule.rule_explain import explain, ExplainMode, RuleExplanation
def cmd_explain(world: StardewValleyWorld, target_name: str, state: CollectionState) -> list[JSONMessagePart]:
logic = world.logic
if target_name.startswith("item "):
is_item_explain = True
target_name = target_name[len("item "):]
else:
is_item_explain = False
if target_name.startswith("missing "):
expected = True
target_name = target_name[len("missing "):]
elif target_name.startswith("how "):
expected = False
target_name = target_name[len("how "):]
else:
expected = None
possible_answers = logic.registry.item_rules.keys() if is_item_explain else world.get_all_location_names()
result, usable, response = Utils.get_intended_text(target_name, possible_answers)
if usable:
if is_item_explain:
rule = logic.has(result)
else:
rule = logic.region.can_reach_location(result)
expl = explain(rule, state, expected=expected, mode=ExplainMode.CLIENT)
world.previous_explanation = expl
return parse_explanation(expl)
else:
return [{"type": "color", "color": "salmon", "text": response}]
def cmd_more(world: StardewValleyWorld, index: str, state: CollectionState) -> list[JSONMessagePart]:
logic = world.logic
if world.previous_explanation is None:
return [{"type": "color", "color": "salmon", "text": "No previous explanation found"}]
try:
expl = world.previous_explanation.more(int(index))
except (ValueError, IndexError):
return [{"type": "text", "text": "Which previous rule do you want to be explained?"}]
world.previous_explanation = expl
return parse_explanation(expl)
def parse_explanation(explanation: RuleExplanation) -> list[list[JSONMessagePart]]:
# Split the explanation in parts, by isolating all the delimiters, being \(, \), & , -> , | , \d+x , \[ , \] , \(\w+\), \n\s*
result_regex = r"\s*(\(|\)| & | -> | \| |\d+x | \[|\](?: ->)?\s*| \(\w+\)|\n)"
splits = re.split(result_regex, str(explanation).strip())
messages = []
contents = []
content_length = 0
for s in splits:
if len(s) == 0:
continue
content_length += len(s)
if s == "True":
messages.append({"type": "color", "color": "green", "text": s})
elif s == "False":
messages.append({"type": "color", "color": "salmon", "text": s})
elif s.startswith("Reach Location "):
messages.append({"type": "text", "text": "Reach Location "})
messages.append({"type": "location_name", "text": s[15:]})
elif s.startswith("Reach Entrance "):
messages.append({"type": "text", "text": "Reach Entrance "})
messages.append({"type": "entrance_name", "text": s[15:]})
elif s.startswith("Reach Region "):
messages.append({"type": "text", "text": "Reach Region "})
messages.append({"type": "color", "color": "yellow", "text": s[13:]})
elif s.startswith("Received event "):
messages.append({"type": "text", "text": "Received event "})
messages.append({"type": "item_name", "text": s[15:]})
elif s.startswith("Received "):
messages.append({"type": "text", "text": "Received "})
messages.append({"type": "item_name", "flags": 0b001, "text": s[9:]})
elif s.startswith("Has "):
if s[4].isdigit():
messages.append({"type": "text", "text": "Has "})
digit_end = re.search(r"\D", s[4:])
digit = s[4:4 + digit_end.start()]
messages.append({"type": "color", "color": "cyan", "text": digit})
messages.append({"type": "text", "text": s[4 + digit_end.start():]})
else:
messages.append({"text": s, "type": "text"})
else:
messages.append({"text": s, "type": "text"})
if content_length > 5000 and s.endswith("\n"):
contents[-1]["text"] = contents[-1]["text"][:-1]
messages.append(contents)
contents = []
content_length = 0
messages.append(contents)
return messages