diff --git a/app/desktop.py b/app/desktop.py index 0a41628..68aebfe 100755 --- a/app/desktop.py +++ b/app/desktop.py @@ -9,7 +9,7 @@ import webview import flask -from pylocal import core, desktop, dev, tick +from pylocal import core, desktop, dev, items, tick core.desktop_mode = True sig_exit = threading.Event() @@ -34,7 +34,7 @@ if __name__ == "__main__": storage_dir = pathlib.Path(os.environ["HOME"]) / "Library/Application Support/seagull" else: storage_dir = pathlib.Path(os.environ["HOME"]) / ".local/share/seagull" - desktop.path_storagedir = pathlib.Path(storage_dir) + desktop.path_storagedir = storage_dir if argo.debug: desktop.api.debug_mode = True diff --git a/app/index.wsgi b/app/index.wsgi index 0349ebb..cfdfd24 100755 --- a/app/index.wsgi +++ b/app/index.wsgi @@ -10,7 +10,7 @@ import threading import flask from gevent.pywsgi import WSGIServer -from pylocal import core, dev, tick +from pylocal import core, dev, items, tick sig_exit = threading.Event() diff --git a/app/pylocal/items.py b/app/pylocal/items.py new file mode 100644 index 0000000..3682c0a --- /dev/null +++ b/app/pylocal/items.py @@ -0,0 +1,26 @@ +import subprocess +import xml.etree.ElementTree as xmltree + +from . import core + +valid_resources = [ + "food", "shinies", "psi" # early game +] + +def generate_item(resource, target): + if core.desktop_mode: + rant_path = core.path_appdir / "opt/rant/bin/rant" + else: + rant_path = "rant" # rely on OS PATH + proc_rant = subprocess.run([rant_path, (core.path_appdir / f"rant/{resource}/{target}.rant").as_posix()], capture_output=True) + return proc_rant.stdout.decode() + +class TickItem(object): + def __init__(self, resource, amount, target): + if resource not in valid_resources: + raise TypeError + + self.resource = resource + self.amount = amount + self.target = target + self.desc = generate_item(resource, target) \ No newline at end of file diff --git a/app/pylocal/tick.py b/app/pylocal/tick.py index c283265..84d940c 100644 --- a/app/pylocal/tick.py +++ b/app/pylocal/tick.py @@ -4,7 +4,7 @@ import subprocess import flask -from . import core +from . import core, items def generate_flavor_text(): if core.desktop_mode: @@ -45,7 +45,11 @@ def tick(): case 1: # FLAVOR result["log"] = generate_flavor_text() case 10: # ENCHUMAN - result["items"] = {} # TODO: implement items + result["items"] = { + # TODO: read ranges from XML rule files + "food": [items.TickItem("food", random.uniform(0.0, 20.0), "humans")], + "shinies": [items.TickItem("food", random.uniform(0.0, 20.0), "humans")] + } case _: core.log.warning("undefined tick: {0}".format(result["event_type"])) diff --git a/app/rant/food/humans.rant b/app/rant/food/humans.rant new file mode 100644 index 0000000..2ef4620 --- /dev/null +++ b/app/rant/food/humans.rant @@ -0,0 +1,53 @@ +@require "../wordlist" +[$desc_food] @text { + { + [pick: ] @weight 1.25 | + [pick: ] @weight 1.1 | + [pick: ] @weight 1.1 | + [pick: ] @weight 0.9 | + [pick: ] @weight 0.75 | + [pick: ] @weight 0.5 | + { # stuffed/filled/covered + `{ + [pick: ] @weight 1 | + [pick: ] @weight 1 | + [pick: ] @weight 1 | + [pick: ] @weight 1 | + [pick: ] @weight 1 | + [pick: ] @weight 0.5 | + [pick: ] @weight 0.5 | + [pick: ] @weight 0.25 | + [pick: ] @weight 0.33 | + [pick: ] @weight 0.25 + } `{stuffed|filled|covered|dipped|coated} + } @weight 1 # stuffed/filled/covered + } +} + +[$get_entree] @text { + { + [pick: ] | + [pick: ] + } +} + +[$mod_order] @text { + { + add | no | sub | extra | + half | left | right | side + } `{ + [pick: ] | + [pick: ] | + [pick: ] | + [pick: ] | + [pick: ] + } +} + +{ + a piece of `[pick: ] | + a `{ + [if: [%maybe]]{[desc_food]} [get_entree] | + [pick: ] + } +} \ No newline at end of file diff --git a/app/rant/shinies/humans.rant b/app/rant/shinies/humans.rant new file mode 100644 index 0000000..434fe01 --- /dev/null +++ b/app/rant/shinies/humans.rant @@ -0,0 +1,4 @@ +{ + a watch | + a bracelet +} \ No newline at end of file diff --git a/app/rules/items/humans.xml b/app/rules/items/humans.xml new file mode 100644 index 0000000..42927ca --- /dev/null +++ b/app/rules/items/humans.xml @@ -0,0 +1,24 @@ + + + ENCHUMAN + + 0 + 10 + + + 0 + 20 + + + 0 + 20 + + + 0 + 50 + + + 0 + 15 + + \ No newline at end of file diff --git a/static/js/desktop-structuredclone.js b/static/js/desktop-structuredclone.js index 217f914..65b7bcc 100644 --- a/static/js/desktop-structuredclone.js +++ b/static/js/desktop-structuredclone.js @@ -1,3 +1,5 @@ function structuredClone(val) { - return JSON.parse(JSON.stringify(val)); + var output = JSON.parse(JSON.stringify(val)); + if (window.pywebview.api.debug_mode) { console.log(("structuredClone:" + val) + " => " + outval); } + return output; } \ No newline at end of file diff --git a/static/js/seagull-desktop.js b/static/js/seagull-desktop.js index 54a998b..445248e 100644 --- a/static/js/seagull-desktop.js +++ b/static/js/seagull-desktop.js @@ -1,4 +1,5 @@ var desktop_mode = true; +var tick_meter_running = false; async function prepare_gamestate() { var gamestate_loaded = null; @@ -18,6 +19,8 @@ async function prepare_gamestate() { gamestate = JSON.parse(gamestate_loaded); record_log("Welcome back! Game loaded.") } + + tick_meter_running = true; } function save_game() { @@ -25,8 +28,6 @@ function save_game() { record_log("Game saved."); } -var tick_meter_running = true; - function reset_game() { tick_meter_running = false; window.pywebview.api.delete_data("gamestate"); diff --git a/static/js/seagull.js b/static/js/seagull.js index 4e60698..a6d6134 100644 --- a/static/js/seagull.js +++ b/static/js/seagull.js @@ -12,6 +12,7 @@ const gamestate_default = { "statever": "1", "tick": 1, "name": "Nameless", + "class": "Seaglet", "level": 1, "shinies": 0, "colony": 1, @@ -19,7 +20,9 @@ const gamestate_default = { "autosave": 35, "story_beat": 0, "xp": 0, - "xp_next": 50 + "xp_next": 50, + "enc_human": "pause", + "enc_seagull": "pause" }; var bool_log_alt = false @@ -48,6 +51,8 @@ function update_ui() { page_elements["lbl_colony"].innerHTML = gamestate["colony"]; page_elements["lbl_shinies"].innerHTML = gamestate["shinies"]; page_elements["lbl_food"].innerHTML = gamestate["food"]; + page_elements["lbl_xp"].innerHTML = gamestate["xp"]; + page_elements["lbl_xp_next"].innerHTML = gamestate["xp_next"]; } var dev_toolbox_open = false; @@ -96,9 +101,8 @@ async function game_tick() { } else if (tickdata["event_type"] == 1) { // Flavor event - no gameplay effect, but occasionally says something fun. record_log(tickdata["log"]); - } else if (tickdata["event_type"] == 10) { - // Human encounter. This is a stub. - record_log("You have encountered a human."); + } else if (tickdata["event_type"] == 10) { // ENCHUMAN + } // sanity check @@ -134,6 +138,7 @@ target.addEventListener(start_event, function (ev) { page_elements["div_name"] = document.querySelector("#side-seagull-name"); page_elements["div_name_editor"] = document.querySelector("#side-seagull-name-editor"); page_elements["lbl_name"] = document.querySelector("#lbl-seagull-name"); + page_elements["lbl_class"] = document.querySelector("#lbl-seagull-class"); page_elements["lbl_colony"] = document.querySelector("#lbl-seagull-colony"); page_elements["lbl_shinies"] = document.querySelector("#lbl-seagull-shinies"); page_elements["lbl_food"] = document.querySelector("#lbl-seagull-food"); @@ -141,6 +146,8 @@ target.addEventListener(start_event, function (ev) { page_elements["lbl_tick"] = document.querySelector("#main-day-counter"); page_elements["lbl_xp"] = document.querySelector("#lbl-seagull-xp-current"); page_elements["lbl_xp_next"] = document.querySelector("#lbl-seagull-xp-next"); + page_elements["menu_enc_human"] = document.querySelector("#menu-enc-human"); + page_elements["menu_enc_seagull"] = document.querySelector("#menu-enc-seagull"); prepare_gamestate().then(update_ui());