diff --git a/ic10emu/data/instruction_help_patches.json b/ic10emu/data/instruction_help_patches.json index 567b606..f2186ad 100644 --- a/ic10emu/data/instruction_help_patches.json +++ b/ic10emu/data/instruction_help_patches.json @@ -2,11 +2,13 @@ "english": { "bapz": "Branch to line c if abs(a) <= max(b * abs(a), float.epsilon * 8)", "bapzal": "Branch to line c if abs(a) <= max(b * abs(a), float.epsilon * 8) and store next line number in ra", - "bnaz": "Branch to line c if abs(a) > max b * abs(a), float.epsilon * 8)", - "bnazal": "Branch to line c if abs(a) > max b * abs(a), float.epsilon * 8) and store next line number in ra", + "bnaz": "Branch to line c if abs(a) > max (b * abs(a), float.epsilon * 8)", + "bnazal": "Branch to line c if abs(a) > max (b * abs(a), float.epsilon * 8) and store next line number in ra", "brapz": "Relative branch to line c if abs(a) <= max(b * abs(a), float.epsilon * 8)", "brnaz": "Relative branch to line c if abs(a) > max(b * abs(a), float.epsilon * 8)", - "sapz": "Register = 1 if |a| <= max(b * abs(a), float.epsilon * 8), otherwise 0", - "snaz": "Register = 1 if |a| > max(b * abs(a), float.epsilon), otherwise 0" + "sapz": "Register = 1 if abs(a) <= max(b * abs(a), float.epsilon * 8), otherwise 0", + "snaz": "Register = 1 if abs(a) > max(b * abs(a), float.epsilon), otherwise 0", + "log": "Register = base e log(a) or ln(a)", + "exp": "Register = exp(a) or e^a" } } diff --git a/ic10emu/data/instructions_help.txt b/ic10emu/data/instructions_help.txt index 4eb1875..ea7f53c 100644 --- a/ic10emu/data/instructions_help.txt +++ b/ic10emu/data/instructions_help.txt @@ -37,8 +37,8 @@ bltzal Branch to line b if a < 0 and store next line number in ra bna Branch to line d if abs(a - b) > max(c * max(abs(a), abs(b)), float.epsilon * 8) bnaal Branch to line d if abs(a - b) <= max(c * max(abs(a), abs(b)), float.epsilon * 8) and store next line number in ra bnan Branch to line b if a is not a number (NaN) -bnaz Branch to line c if abs(a) > max b * abs(a), float.epsilon * 8) -bnazal Branch to line c if abs(a) > max b * abs(a), float.epsilon * 8) and store next line number in ra +bnaz Branch to line c if abs(a) > max (b * abs(a), float.epsilon * 8) +bnazal Branch to line c if abs(a) > max (b * abs(a), float.epsilon * 8) and store next line number in ra bne Branch to line c if a != b bneal Branch to line c if a != b and store next line number in ra bnez branch to line b if a != 0 @@ -66,7 +66,7 @@ ceil Register = smallest integer greater than a cos Returns the cosine of the specified angle (radians) define Creates a label that will be replaced throughout the program with the provided value. div Register = a / b -exp Register = exp(a) +exp Register = exp(a) or e^a floor Register = largest integer less than a hcf Halt and catch fire j Jump execution to line a @@ -79,7 +79,7 @@ lbn Loads LogicType from all output network devices with provided type and name lbns Loads LogicSlotType from slotIndex from all output network devices with provided type and name hashes using the provide batch mode. Average (0), Sum (1), Minimum (2), Maximum (3). Can use either the word, or the number. lbs Loads LogicSlotType from slotIndex from all output network devices with provided type hash using the provide batch mode. Average (0), Sum (1), Minimum (2), Maximum (3). Can use either the word, or the number. ld Loads device LogicType to register by direct ID reference. -log Register = log(a) +log Register = base e log(a) or ln(a) lr Loads reagent of device's ReagentMode where a hash of the reagent type to check for. ReagentMode can be either Contents (0), Required (1), Recipe (2). Can use either the word, or the number. ls Loads slot LogicSlotType on device to register. max Register = max of a or b @@ -97,7 +97,7 @@ rand Register = a random value x with 0 <= x < 1 round Register = a rounded to nearest integer s Stores register value to LogicType on device by housing index value. sap Register = 1 if abs(a - b) <= max(c * max(abs(a), abs(b)), float.epsilon * 8), otherwise 0 -sapz Register = 1 if |a| <= max(b * abs(a), float.epsilon * 8), otherwise 0 +sapz Register = 1 if abs(a) <= max(b * abs(a), float.epsilon * 8), otherwise 0 sb Stores register value to LogicType on all output network devices with provided type hash. sbn Stores register value to LogicType on all output network devices with provided type hash and name. sbs Stores register value to LogicSlotType on all output network devices with provided type hash in the provided slot. @@ -122,7 +122,7 @@ sltz Register = 1 if a < 0, otherwise 0 sna Register = 1 if abs(a - b) > max(c * max(abs(a), abs(b)), float.epsilon * 8), otherwise 0 snan Register = 1 if a is NaN, otherwise 0 snanz Register = 0 if a is NaN, otherwise 1 -snaz Register = 1 if |a| > max(b * abs(a), float.epsilon), otherwise 0 +snaz Register = 1 if abs(a) > max(b * abs(a), float.epsilon), otherwise 0 sne Register = 1 if a != b, otherwise 0 snez Register = 1 if a != 0, otherwise 0 sqrt Register = square root of a diff --git a/ic10emu/generate_data.py b/ic10emu/generate_data.py index 79373e3..187bd7e 100644 --- a/ic10emu/generate_data.py +++ b/ic10emu/generate_data.py @@ -46,6 +46,20 @@ def main(): extract_data(install_path, data_path, lang) + +translation_regex = re.compile(r"") + +def replace_translation(m: re.Match[str]) -> str: + match m.groups(): + case (_code, key): + return key + case _: + return m.string + +def trans(s: str) -> str: + return re.sub(translation_regex, replace_translation, s) + + def extract_data(install_path: Path, data_path: Path, language: str): tree = ET.parse(data_path / f"{language}.xml") root = tree.getroot() @@ -74,18 +88,18 @@ def extract_data(install_path: Path, data_path: Path, language: str): if key is None or value is None: continue if match := logic_type.match(key): - enum_help_strings[f"LogicType.{match.group(1)}"] = value + enum_help_strings[f"LogicType.{match.group(1)}"] = trans(value) logictypes[match.group(1)] = (None, value) if match := logic_slot_type.match(key): - enum_help_strings[f"LogicSlotType.{match.group(1)}"] = value + enum_help_strings[f"LogicSlotType.{match.group(1)}"] = trans(value) slotlogictypes[match.group(1)] = (None, value) if match := color.match(key): - enum_help_strings[f"Color.{match.group(1)}"] = value + enum_help_strings[f"Color.{match.group(1)}"] = trans(value) if match := script_command.match(key): if not match.group(1).lower() == "command": - operation_help_strings[f"{match.group(1).lower()}"] = value + operation_help_strings[f"{match.group(1).lower()}"] = trans(value) if match := script_desc.match(key): - operation_help_strings[f"{match.group(1).lower()}"] = value + operation_help_strings[f"{match.group(1).lower()}"] = trans(value) op_help_patch_path = Path("data") / "instruction_help_patches.json" if op_help_patch_path.exists(): @@ -205,8 +219,8 @@ def extract_data(install_path: Path, data_path: Path, language: str): exported_stationpedia_path = install_path / "Stationpedia" / "Stationpedia.json" if exported_stationpedia_path.exists(): with exported_stationpedia_path.open(mode="r") as f: - exported: dict[str, list[dict[str, Any]]] = json.load(f) # type:ignore[reportAny] - for page in exported["pages"]: # type:ignore[reportUnknownVariableType] + exported: dict[str, list[dict[str, Any]]] = json.load(f) + for page in exported["pages"]: stationpedia[page["PrefabHash"]] = (page["PrefabName"], page["Title"]) hashables_path = Path("data") / "stationpedia.txt" diff --git a/www/data/database.json b/www/data/database.json index f159dc2..3ea6eb4 100644 --- a/www/data/database.json +++ b/www/data/database.json @@ -350,7 +350,7 @@ "name": "ApplianceTabletDock", "slots": [ { - "name": "", + "name": "Tablet", "typ": "Tool" } ], @@ -1713,7 +1713,7 @@ "typ": "Flare" }, { - "name": "", + "name": "Chamber", "typ": "Blocked" } ], @@ -2146,14 +2146,14 @@ "title": "Authoring Tool" }, "ItemAuthoringToolRocketNetwork": { - "desc": "", + "desc": "ItemAuthoringToolRocketNetwork", "hash": -1731627004, "item": { "slotclass": "Tool", "sorting": "Tools" }, "name": "ItemAuthoringToolRocketNetwork", - "title": "" + "title": "ItemAuthoringToolRocketNetwork" }, "ItemBasketBall": { "desc": "", @@ -2356,7 +2356,7 @@ "title": "Cable Coil" }, "ItemCableCoilHeavy": { - "desc": "Use heavy cable coil for power systems with large draws. Unlike , which can only safely conduct 5kW, heavy cables can transmit up to 100kW.", + "desc": "Use heavy cable coil for power systems with large draws. Unlike StructureCableCoil, which can only safely conduct 5kW, heavy cables can transmit up to 100kW.", "hash": 2060134443, "item": { "maxquantity": 50, @@ -2514,7 +2514,7 @@ "title": "Chem Light (Yellow)" }, "ItemCoalOre": { - "desc": "Humanity wouldn't have got to space without humble, combustible coal. Burn it in a , smelt it in the Furnace to create alloys, or use it in the Reagent Processor to make Spray Paint (Black).", + "desc": "Humanity wouldn't have got to space without humble, combustible coal. Burn it in a SolidFuelGenerator, smelt it in the Furnace to create alloys, or use it in the Reagent Processor to make Spray Paint (Black).", "hash": 1724793494, "item": { "ingredient": true, @@ -11428,14 +11428,14 @@ "title": "Meteorite" }, "MonsterEgg": { - "desc": "", + "desc": "MonsterEgg", "hash": -1667675295, "item": { "slotclass": "None", "sorting": "Default" }, "name": "MonsterEgg", - "title": "" + "title": "MonsterEgg" }, "MotherboardComms": { "desc": "When placed in a Computer and connected to a Landingpad Data And Power, a Medium Satellite Dish, and a Vending Machine allows Stationeers to trade with suppliers. Adjust the horizontal and vertical attributes of the Medium Satellite Dish either directly or through logic. You need a communications signal of 95% or above to establish reliable communications with a trader. A minimum of a 3x3 clear pad area with a Landingpad Center at the center is required for a trader to land.", @@ -11458,14 +11458,14 @@ "title": "Logic Motherboard" }, "MotherboardMissionControl": { - "desc": "", + "desc": "MotherboardMissionControl", "hash": -127121474, "item": { "slotclass": "Motherboard", "sorting": "Default" }, "name": "MotherboardMissionControl", - "title": "" + "title": "MotherboardMissionControl" }, "MotherboardProgrammableChip": { "desc": "When placed in a Computer, the IC Editor allows players to write and edit IC code, which can then be uploaded to a Integrated Circuit (IC10) if housed in an IC Housing.", @@ -12207,18 +12207,18 @@ "typ": "None" }, { - "name": "", + "name": "GasTank", "typ": "None" }, { - "name": "", + "name": "GasTank", "typ": "None" } ], "title": "Rover (Cargo)" }, "Rover_MkI": { - "desc": "A distant cousin of the jeep, the Mk I {Sinotai electric rover is one of the most simple and durable light vehicles in the known universe. Able to carry two passengers and cargo such as the Portable Gas Tank (Air) or , it is powered by up to three batteries, accepting everything including Battery Cell (Nuclear).\nA quad-array of hub-mounted electric engines propels the reinforced aluminium frame over most terrain and modest obstacles. While the Mk I is designed for stability in low-horizontality circumstances, if it rolls, try using your Crowbar to put it right way up.Connects to Logic Transmitter", + "desc": "A distant cousin of the jeep, the Mk I {Sinotai electric rover is one of the most simple and durable light vehicles in the known universe. Able to carry two passengers and cargo such as the Portable Gas Tank (Air) or Crate, it is powered by up to three batteries, accepting everything including Battery Cell (Nuclear).\nA quad-array of hub-mounted electric engines propels the reinforced aluminium frame over most terrain and modest obstacles. While the Mk I is designed for stability in low-horizontality circumstances, if it rolls, try using your Crowbar to put it right way up.Connects to Logic Transmitter", "hash": -2049946335, "item": { "slotclass": "None", @@ -12376,27 +12376,27 @@ "typ": "Battery" }, { - "name": "", + "name": "ContainerConnection", "typ": "None" }, { - "name": "", + "name": "ContainerConnection", "typ": "None" }, { - "name": "", + "name": "GasTankConnection", "typ": "None" }, { - "name": "", + "name": "GasTankConnection", "typ": "None" }, { - "name": "", + "name": "GasTankConnection", "typ": "None" }, { - "name": "", + "name": "GasTankConnection", "typ": "None" } ], @@ -15002,10 +15002,10 @@ "title": "Burnt Cable (3-Way Corner)" }, "StructureCableCorner3HBurnt": { - "desc": "", + "desc": "StructureCableCorner3HBurnt", "hash": 2393826, "name": "StructureCableCorner3HBurnt", - "title": "" + "title": "StructureCableCorner3HBurnt" }, "StructureCableCorner4": { "desc": "", @@ -19639,7 +19639,7 @@ "typ": "PowerAndData" } }, - "desc": "", + "desc": "StructureDrinkingFountain", "device": { "atmosphere": false, "reagents": false, @@ -19662,7 +19662,7 @@ "RequiredPower": "Read" }, "name": "StructureDrinkingFountain", - "title": "" + "title": "StructureDrinkingFountain" }, "StructureElectrolyzer": { "conn": { @@ -26586,7 +26586,7 @@ "title": "Liquid Pipe (Cross Junction)" }, "StructurePipeLiquidCrossJunction3": { - "desc": "You can upgrade this pipe to an using an Kit (Insulated Liquid Pipe) and a Wrench.", + "desc": "You can upgrade this pipe to an StructureInsulatedPipeLiquidCrossJunction3 using an Kit (Insulated Liquid Pipe) and a Wrench.", "hash": 1628087508, "name": "StructurePipeLiquidCrossJunction3", "title": "Liquid Pipe (3-Way Junction)" @@ -28457,7 +28457,7 @@ "typ": "None" }, { - "name": "", + "name": "HoldingSlot", "typ": "None" } ], @@ -30943,7 +30943,7 @@ "typ": "None" }, { - "name": "", + "name": "Export2", "typ": "None" }, { @@ -31798,7 +31798,7 @@ "typ": "Pipe" } }, - "desc": "As tidy as it is useful, the suit storage rack holds an Eva Suit, Space Helmet and a Jetpack Basic.\nWhen powered and connected to and , it will recharge the suit's batteries, refill the Canister (Oxygen) and your Filter (Nitrogen) Gas Canister. The wastetank will be pumped out to the pipe connected to the waste outlet.\nAll the rack's pipes must be connected or the unit will show an error state, but it will still charge the battery.", + "desc": "As tidy as it is useful, the suit storage rack holds an Eva Suit, Space Helmet and a Jetpack Basic.\nWhen powered and connected to Oxygen and Propellant, it will recharge the suit's batteries, refill the Canister (Oxygen) and your Filter (Nitrogen) Gas Canister. The wastetank will be pumped out to the pipe connected to the waste outlet.\nAll the rack's pipes must be connected or the unit will show an error state, but it will still charge the battery.", "device": { "atmosphere": false, "reagents": false, diff --git a/www/src/ts/virtual_machine/device/card.ts b/www/src/ts/virtual_machine/device/card.ts index 5b48c4b..b4bd9ef 100644 --- a/www/src/ts/virtual_machine/device/card.ts +++ b/www/src/ts/virtual_machine/device/card.ts @@ -197,6 +197,7 @@ export class VMDeviceCard extends VMDeviceDBMixin(VMDeviceMixin(BaseElement)) { ` )} diff --git a/www/src/ts/virtual_machine/device/slot.ts b/www/src/ts/virtual_machine/device/slot.ts index 05341fd..6da1394 100644 --- a/www/src/ts/virtual_machine/device/slot.ts +++ b/www/src/ts/virtual_machine/device/slot.ts @@ -66,13 +66,19 @@ export class VMDeviceSlot extends VMDeviceMixin(VMDeviceDBMixin(BaseElement)) { const img = html``; return html` -
+
+
+ ${this.slotIndex} +
${img} @@ -80,7 +86,7 @@ export class VMDeviceSlot extends VMDeviceMixin(VMDeviceDBMixin(BaseElement)) { typeof slot.occupant !== "undefined", () => html`
${slot.occupant.quantity} / ${slot.occupant.max_quantity}
` @@ -127,7 +133,7 @@ export class VMDeviceSlot extends VMDeviceMixin(VMDeviceDBMixin(BaseElement)) { } _handleSlotClick(e: Event) { - console.log(e); + console.log(e, e.currentTarget, e.target); } renderFields() { diff --git a/www/stationpedia.py b/www/stationpedia.py index fd1093c..e697db4 100644 --- a/www/stationpedia.py +++ b/www/stationpedia.py @@ -110,6 +110,23 @@ class DBPage(TypedDict): device: NotRequired[DBPageDevice] +translation_regex = re.compile(r"") +translation_keys: set[str] = set() +translation_codes: set[str] = set() +def replace_translation(m: re.Match[str]) -> str: + match m.groups(): + case (code, key): + translation_keys.add(key) + translation_codes.add(code) + return key + case _ as g: + print("bad translation match?", g, m.string) + return m.string + +def trans(s: str) -> str: + return re.sub(translation_regex, replace_translation, s) + + def extract_all() -> None: db: dict[str, DBPage] = {} pedia: Pedia = {"pages": [], "reagents": {}} @@ -142,8 +159,8 @@ def extract_all() -> None: item_props = page.get("Item", None) item["name"] = name item["hash"] = name_hash - item["title"] = title - item["desc"] = re.sub(linkPat, r"\1", desc) + item["title"] = trans(title) + item["desc"] = trans(re.sub(linkPat, r"\1", desc)) match slots: case []: item["slots"] = None @@ -151,7 +168,7 @@ def extract_all() -> None: item["slots"] = [{}] * len(slots) # type: ignore[reportAssignmentType] for slot in slots: item["slots"][int(slot["SlotIndex"])] = { - "name": slot["SlotName"], + "name": trans(slot["SlotName"]), "typ": slot["SlotType"], } @@ -299,6 +316,12 @@ def extract_all() -> None: db[name] = item + + print("Translation codes:") + pprint(translation_codes) + print("Translations keys:") + pprint(translation_keys) + logicable = [item["name"] for item in db.values() if item["logic"] is not None] slotlogicable = [ item["name"] for item in db.values() if item["slotlogic"] is not None