giant freakin documentation and reorganization pass, it also uses cmake because all the building was getting too complicated for shell scripts
This commit is contained in:
29
pak/rant/flavor.rant
Normal file
29
pak/rant/flavor.rant
Normal file
@@ -0,0 +1,29 @@
|
||||
@require "wordlist"
|
||||
|
||||
[$title: str] @text {
|
||||
<$split_str = [split: <str>]>
|
||||
[cat: [upper: <split_str/0>] [lower: [join: <split_str/1..>]]]
|
||||
}
|
||||
|
||||
{
|
||||
You meet {
|
||||
a `[pick: <wordlist/nouns/birds>] |
|
||||
[title: `{
|
||||
[pick: <wordlist/names/people/butlers>] |
|
||||
[pick: <wordlist/names/people/computing>] |
|
||||
[pick: <wordlist/names/people/founders>] |
|
||||
[pick: <wordlist/names/streets/chicago>] |
|
||||
[pick: <wordlist/names/streets/newyork>] |
|
||||
[pick: <wordlist/names/surnames/english>] |
|
||||
[pick: <wordlist/names/surnames/irish>] |
|
||||
[pick: <wordlist/names/surnames/scottish>]
|
||||
}] the `[pick: <wordlist/nouns/birds>]
|
||||
}. {
|
||||
It completely ignores you. |
|
||||
You have a polite conversation about birdly affairs. |
|
||||
It scoffs and flies away.
|
||||
}
|
||||
} |
|
||||
{
|
||||
A nearby {`[pick: <wordlist/nouns/birds>]|colony of `[pick: <wordlist/nouns/birds>]s} seems to be harassing a human.
|
||||
}
|
55
pak/rant/food/humans.rant
Normal file
55
pak/rant/food/humans.rant
Normal file
@@ -0,0 +1,55 @@
|
||||
@require "wordlist"
|
||||
[$desc_food] @text {
|
||||
{
|
||||
[pick: <wordlist/adjectives/food>] @weight 1.25 |
|
||||
[pick: <wordlist/adjectives/taste>] @weight 1.1 |
|
||||
[pick: <wordlist/names/cities/united_states>] @weight 1.1 |
|
||||
[pick: <wordlist/names/cities/canada>] @weight 0.9 |
|
||||
[pick: <wordlist/names/cities/spain>] @weight 0.75 |
|
||||
[pick: <wordlist/names/cities/alpha>] @weight 0.5 |
|
||||
{ # stuffed/filled/covered
|
||||
`{
|
||||
[pick: <wordlist/nouns/fruit>] @weight 1 |
|
||||
[pick: <wordlist/nouns/meat>] @weight 1 |
|
||||
[pick: <wordlist/nouns/food>] @weight 1 |
|
||||
[pick: <wordlist/nouns/cheese>] @weight 1 |
|
||||
[pick: <wordlist/nouns/condiments>] @weight 1 |
|
||||
[pick: <wordlist/nouns/music_theory>] @weight 0.5 |
|
||||
[pick: <wordlist/nouns/music_production>] @weight 0.5 |
|
||||
[pick: <wordlist/nouns/set_theory>] @weight 0.25 |
|
||||
[pick: <wordlist/nouns/ghosts>] @weight 0.33 |
|
||||
[pick: <wordlist/nouns/web_development>] @weight 0.25
|
||||
} `{stuffed|filled|covered|dipped|coated}
|
||||
} @weight 1 # stuffed/filled/covered
|
||||
}
|
||||
}
|
||||
|
||||
[$get_entree] @text {
|
||||
{
|
||||
[pick: <wordlist/nouns/food>] |
|
||||
[pick: <wordlist/nouns/fast_food>]
|
||||
}
|
||||
}
|
||||
|
||||
##
|
||||
[$mod_order] @text {
|
||||
{
|
||||
add | no | sub | extra |
|
||||
half | left | right | side
|
||||
} `{
|
||||
[pick: <wordlist/nouns/condiments>] |
|
||||
[pick: <wordlist/nouns/cheese>] |
|
||||
[pick: <wordlist/nouns/food>] |
|
||||
[pick: <wordlist/nouns/seasonings>] |
|
||||
[pick: <wordlist/nouns/plants>]
|
||||
}
|
||||
}
|
||||
##
|
||||
|
||||
{
|
||||
a piece of `[pick: <wordlist/nouns/cheese>] cheese |
|
||||
a `{
|
||||
[if: [maybe]{[desc_food]}] [get_entree] |
|
||||
[pick: <wordlist/nouns/fruit>]
|
||||
}
|
||||
}
|
55
pak/rant/food/seagulls.rant
Normal file
55
pak/rant/food/seagulls.rant
Normal file
@@ -0,0 +1,55 @@
|
||||
@require "wordlist"
|
||||
[$desc_food] @text {
|
||||
{
|
||||
[pick: <wordlist/adjectives/food>] @weight 1.25 |
|
||||
[pick: <wordlist/adjectives/taste>] @weight 1.1 |
|
||||
[pick: <wordlist/names/cities/united_states>] @weight 1.1 |
|
||||
[pick: <wordlist/names/cities/canada>] @weight 0.9 |
|
||||
[pick: <wordlist/names/cities/spain>] @weight 0.75 |
|
||||
[pick: <wordlist/names/cities/alpha>] @weight 0.5 |
|
||||
{ # stuffed/filled/covered
|
||||
`{
|
||||
[pick: <wordlist/nouns/fruit>] @weight 1 |
|
||||
[pick: <wordlist/nouns/meat>] @weight 1 |
|
||||
[pick: <wordlist/nouns/food>] @weight 1 |
|
||||
[pick: <wordlist/nouns/cheese>] @weight 1 |
|
||||
[pick: <wordlist/nouns/condiments>] @weight 1 |
|
||||
[pick: <wordlist/nouns/music_theory>] @weight 0.5 |
|
||||
[pick: <wordlist/nouns/music_production>] @weight 0.5 |
|
||||
[pick: <wordlist/nouns/set_theory>] @weight 0.25 |
|
||||
[pick: <wordlist/nouns/ghosts>] @weight 0.33 |
|
||||
[pick: <wordlist/nouns/web_development>] @weight 0.25
|
||||
} `{stuffed|filled|covered|dipped|coated}
|
||||
} @weight 1 # stuffed/filled/covered
|
||||
}
|
||||
}
|
||||
|
||||
[$get_entree] @text {
|
||||
{
|
||||
[pick: <wordlist/nouns/food>] |
|
||||
[pick: <wordlist/nouns/fast_food>]
|
||||
}
|
||||
}
|
||||
|
||||
##
|
||||
[$mod_order] @text {
|
||||
{
|
||||
add | no | sub | extra |
|
||||
half | left | right | side
|
||||
} `{
|
||||
[pick: <wordlist/nouns/condiments>] |
|
||||
[pick: <wordlist/nouns/cheese>] |
|
||||
[pick: <wordlist/nouns/food>] |
|
||||
[pick: <wordlist/nouns/seasonings>] |
|
||||
[pick: <wordlist/nouns/plants>]
|
||||
}
|
||||
}
|
||||
##
|
||||
|
||||
{
|
||||
a piece of `[pick: <wordlist/nouns/cheese>] cheese |
|
||||
part of a `{
|
||||
[if: [maybe]{[desc_food]}] [get_entree] |
|
||||
[pick: <wordlist/nouns/fruit>]
|
||||
}
|
||||
}
|
4
pak/rant/shinies/humans.rant
Normal file
4
pak/rant/shinies/humans.rant
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
a watch |
|
||||
a bracelet
|
||||
}
|
4
pak/rant/shinies/seagulls.rant
Normal file
4
pak/rant/shinies/seagulls.rant
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
a watch |
|
||||
a bracelet
|
||||
}
|
23
pak/rules/items/humans.xml
Normal file
23
pak/rules/items/humans.xml
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ItemRules xmlns="seagull:rules/items">
|
||||
<Food>
|
||||
<Min>1</Min>
|
||||
<Max>10</Max>
|
||||
</Food>
|
||||
<Shinies>
|
||||
<Min>1</Min>
|
||||
<Max>20</Max>
|
||||
</Shinies>
|
||||
<Food StoryBeat="3">
|
||||
<Min>1</Min>
|
||||
<Max>20</Max>
|
||||
</Food>
|
||||
<Shinies StoryBeat="3">
|
||||
<Min>0</Min>
|
||||
<Max>50</Max>
|
||||
</Shinies>
|
||||
<Psi StoryBeat="3">
|
||||
<Min>0</Min>
|
||||
<Max>15</Max>
|
||||
</Psi>
|
||||
</ItemRules>
|
23
pak/rules/items/seagulls.xml
Normal file
23
pak/rules/items/seagulls.xml
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ItemRules xmlns="seagull:rules/items">
|
||||
<Food>
|
||||
<Min>1</Min>
|
||||
<Max>5</Max>
|
||||
</Food>
|
||||
<Shinies>
|
||||
<Min>1</Min>
|
||||
<Max>10</Max>
|
||||
</Shinies>
|
||||
<Food StoryBeat="3">
|
||||
<Min>5</Min>
|
||||
<Max>20</Max>
|
||||
</Food>
|
||||
<Shinies StoryBeat="3">
|
||||
<Min>5</Min>
|
||||
<Max>50</Max>
|
||||
</Shinies>
|
||||
<Psi StoryBeat="3">
|
||||
<Min>0</Min>
|
||||
<Max>15</Max>
|
||||
</Psi>
|
||||
</ItemRules>
|
45
pak/rules/upgrades/agility.xml
Normal file
45
pak/rules/upgrades/agility.xml
Normal file
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<UpgradeRules xmlns="seagull:rules/upgrades">
|
||||
<TreeData>
|
||||
<Name>Agility Upgrades</Name>
|
||||
<PrimaryColor>#00aa00</PrimaryColor>
|
||||
</TreeData>
|
||||
<Upgrade>
|
||||
<Id>speed1</Id>
|
||||
<Name>Speedier Seagull</Name>
|
||||
<Modifiers>
|
||||
<Mod Id="up_speed1" Name="Upgrade: Speedier Seagull" Speed="5" />
|
||||
</Modifiers>
|
||||
<Desc>You become just a little bit faster, which makes it easier to steal things before your prey's previous owners notice you're coming.</Desc>
|
||||
</Upgrade>
|
||||
<Upgrade>
|
||||
<Id>speed2</Id>
|
||||
<Name>Greased Wings</Name>
|
||||
<Desc>Applying a thin coat of old french fry oil makes you much faster. Why do humans throw this stuff out?</Desc>
|
||||
<Requirements>
|
||||
<Require>speed1</Require>
|
||||
</Requirements>
|
||||
<Modifiers>
|
||||
<Mod Id="up_speed2" Name="Upgrade: Greased Wings" Speed="10" />
|
||||
</Modifiers>
|
||||
</Upgrade>
|
||||
<Upgrade>
|
||||
<Id>theft_chance1</Id>
|
||||
<Name>Swooping Techniques</Name>
|
||||
<Modifiers>
|
||||
<Mod Id="up_theft_chance1" Name="Upgrade: Swooping Techniques" ChanceSteal="10" />
|
||||
</Modifiers>
|
||||
<Desc>It's all in the neck. The wings are just the steering wheel. You gain a bonus on all dice rolls for stealing.</Desc>
|
||||
</Upgrade>
|
||||
<Upgrade>
|
||||
<Id>theft_chance2</Id>
|
||||
<Name>The Element of Surprise</Name>
|
||||
<Desc>It's a lot easier to steal things if the previous owner doesn't see you coming. This technique gives you a bigger bonus on stealing rolls.</Desc>
|
||||
<Requirements>
|
||||
<Require>theft_chance1</Require>
|
||||
</Requirements>
|
||||
<Modifiers>
|
||||
<Mod Id="up_theft_chance2" Name="Upgrade: The Element of Surprise" ChanceSteal="15" />
|
||||
</Modifiers>
|
||||
</Upgrade>
|
||||
</UpgradeRules>
|
232
pak/static/css/seagull.css
Normal file
232
pak/static/css/seagull.css
Normal file
@@ -0,0 +1,232 @@
|
||||
html, body { height: 100% }
|
||||
|
||||
/** MAIN GAME **/
|
||||
|
||||
div#root {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 0;
|
||||
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
div#main-sidebar {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
max-width: 265px;
|
||||
/*padding-left: 5px;*/
|
||||
padding-right: 5px;
|
||||
border-right: 0.125em solid rgb(192, 192, 192);
|
||||
}
|
||||
|
||||
div#side-seagull-name {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
div#side-seagull-name-editor {
|
||||
display: none;
|
||||
}
|
||||
|
||||
div#main-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
div#main-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
min-height: 100px;
|
||||
vertical-align: middle;
|
||||
|
||||
border-bottom: 0.125em solid rgb(192,192,192);
|
||||
}
|
||||
|
||||
div#main-day-stats {
|
||||
width: 100%;
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
vertical-align: middle;
|
||||
font-size: large;
|
||||
}
|
||||
|
||||
div#main-button-bar {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
min-height: 125px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
div#main-log {
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
}
|
||||
|
||||
div.log-line {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
vertical-align: top;
|
||||
width: 100%;
|
||||
min-height: 1.5em;
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
div.log-line-alt {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
vertical-align: top;
|
||||
width: 100%;
|
||||
min-height: 1.5em;
|
||||
padding-top: 5px;
|
||||
|
||||
background-color: rgb(192, 192, 192);
|
||||
}
|
||||
|
||||
div.log-tick {
|
||||
font-size: 0.75em;
|
||||
margin-right: 0.2em;
|
||||
}
|
||||
|
||||
div.log-msg {
|
||||
margin-left: 0.2em;
|
||||
}
|
||||
|
||||
div#charsheet {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
|
||||
background-color: rgb(240, 240, 240);
|
||||
}
|
||||
|
||||
/** MODAL **/
|
||||
|
||||
div#modal-background {
|
||||
font-family: sans-serif;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
div#modal {
|
||||
width: 75%;
|
||||
height: 75%;
|
||||
margin: auto;
|
||||
margin-top: 50px;
|
||||
border: 0.25em dotted rgba(192, 192, 192, 255);
|
||||
background-color: rgba(255, 255, 255, 255);
|
||||
padding: 0.3em
|
||||
}
|
||||
|
||||
button.main-bar {
|
||||
width: 2.5em;
|
||||
height: 2.5em;
|
||||
margin: 2.5px;
|
||||
background-color: rgba(0,0,0,0);
|
||||
border: 1px solid black;
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
button#button-modal-close {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
|
||||
width: 2.5em;
|
||||
height: 2.5em;
|
||||
margin: 2.5px;
|
||||
background-color: rgba(0,0,0,0);
|
||||
border: 0px;
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
/** CHARSHEET **/
|
||||
|
||||
div#charsheet-root {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
div#charsheet-leftside {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 33%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
div.attr {
|
||||
/* common to all attribute blocks */
|
||||
font-size: x-large;
|
||||
color: #ffffff;
|
||||
width: 100%;
|
||||
height: 30%;
|
||||
|
||||
vertical-align: middle;
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
|
||||
text-align: center;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
div#attr-points {
|
||||
font-size: x-large;
|
||||
width: 100%;
|
||||
height: 10%;
|
||||
|
||||
vertical-align: middle;
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
|
||||
text-align: center;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
div#attr-agility {
|
||||
background: linear-gradient(to right, rgb(0,170,0), rgb(0,99,0));
|
||||
}
|
||||
|
||||
div#attr-instinct {
|
||||
background: linear-gradient(to right, rgb(170,0,255), rgb(90,0,135));
|
||||
}
|
||||
|
||||
div#attr-leadership {
|
||||
background: linear-gradient(to right, rgb(255,170,0), rgb(139,93,0));
|
||||
}
|
||||
|
||||
div#charsheet-rightside {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 67%;
|
||||
height: 100%;
|
||||
overflow-x: scroll;
|
||||
}
|
||||
|
||||
nav#nav-upgrades {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
nav#nav-upgrades li {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
div#charsheet-upgrade-tree {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
flex-direction: row;
|
||||
width: max-content;
|
||||
}
|
BIN
pak/static/image/seagull.jpg
Normal file
BIN
pak/static/image/seagull.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 27 KiB |
BIN
pak/static/image/splash.png
Normal file
BIN
pak/static/image/splash.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 187 KiB |
32
pak/static/js/dlg-charsheet.js
Normal file
32
pak/static/js/dlg-charsheet.js
Normal file
@@ -0,0 +1,32 @@
|
||||
var charsheet_elements = {}
|
||||
charsheet_elements["lbl_agility"] = document.getElementById("lbl-attr-agility");
|
||||
charsheet_elements["lbl_instinct"] = document.getElementById("lbl-attr-instinct");
|
||||
charsheet_elements["lbl_leadership"] = document.getElementById("lbl-attr-leadership");
|
||||
charsheet_elements["lbl_instinct_txt"] = document.getElementById("lbl-attr-instinct-txt");
|
||||
charsheet_elements["btn_upgrade_agility"] = document.getElementById("btn-upgrade-agility");
|
||||
charsheet_elements["btn_upgrade_instinct"] = document.getElementById("btn-upgrade-instinct");
|
||||
charsheet_elements["btn_upgrade_leadership"] = document.getElementById("btn-upgrade-leadership");
|
||||
charsheet_elements["blk_tree"] = document.getElementById("charsheet-upgrade-tree");
|
||||
|
||||
function update_charsheet() {
|
||||
charsheet_elements["lbl_agility"].innerHTML = gamestate["agility"];
|
||||
charsheet_elements["lbl_instinct"].innerHTML = gamestate["instinct"];
|
||||
charsheet_elements["lbl_leadership"].innerHTML = gamestate["leadership"];
|
||||
|
||||
if (gamestate["story_beat"] >= 3) {
|
||||
charsheet_elements["lbl_instinct_txt"].innerHTML = "Intelligence";
|
||||
charsheet_elements["btn_upgrade_instinct"].innerHTML = "Intelligence Upgrades";
|
||||
}
|
||||
}
|
||||
|
||||
async function display_tree(tree) {
|
||||
var upgrade_tree = await fetch(`/upgrades/${tree}`)
|
||||
.then(res => res.text())
|
||||
console.log(upgrade_tree)
|
||||
|
||||
charsheet_elements["blk_tree"].innerHTML = upgrade_tree
|
||||
}
|
||||
|
||||
charsheet_elements["btn_upgrade_agility"].addEventListener("click", (ev) => {display_tree("agility")});
|
||||
charsheet_elements["btn_upgrade_instinct"].addEventListener("click", (ev) => {display_tree("instinct")});
|
||||
charsheet_elements["btn_upgrade_leadership"].addEventListener("click", (ev) => {display_tree("leadership")});
|
38
pak/static/js/seagull-desktop.js
Normal file
38
pak/static/js/seagull-desktop.js
Normal file
@@ -0,0 +1,38 @@
|
||||
globalThis.desktop_mode = true;
|
||||
|
||||
async function prepare_gamestate() {
|
||||
var gamestate_loaded = null;
|
||||
try {
|
||||
gamestate_loaded = await window.pywebview.api.load_data("gamestate");
|
||||
} catch (exc) {
|
||||
console.error("no gamestate");
|
||||
gamestate_loaded = null;
|
||||
}
|
||||
|
||||
if (gamestate_loaded == null) {
|
||||
record_log("Welcome to Seagull Game! We haven't found a save in your app data, so we're starting a new game!");
|
||||
gamestate = structuredClone(gamestate_default);
|
||||
}
|
||||
else {
|
||||
console.log(gamestate_loaded);
|
||||
gamestate = JSON.parse(gamestate_loaded);
|
||||
record_log("Welcome back! Game loaded.")
|
||||
}
|
||||
|
||||
tick_meter_running = true;
|
||||
|
||||
if (window.pywebview.api.debug_mode) {
|
||||
dev_toolbox(true);
|
||||
}
|
||||
}
|
||||
|
||||
function save_game() {
|
||||
window.pywebview.api.save_data("gamestate", JSON.stringify(gamestate));
|
||||
record_log("Game saved.");
|
||||
}
|
||||
|
||||
function reset_game() {
|
||||
tick_meter_running = false;
|
||||
window.pywebview.api.delete_data("gamestate");
|
||||
window.location.reload();
|
||||
}
|
27
pak/static/js/seagull-web.js
Normal file
27
pak/static/js/seagull-web.js
Normal file
@@ -0,0 +1,27 @@
|
||||
globalThis.desktop_mode = false;
|
||||
|
||||
function load_gamestate() {
|
||||
var gamestate_loaded = window.localStorage.getItem("gamestate");
|
||||
|
||||
if (gamestate_loaded == null) {
|
||||
record_log("Welcome to Seagull Game! We haven't found a save in your browser storage, so we're starting a new game!");
|
||||
gamestate = structuredClone(gamestate_default);
|
||||
}
|
||||
else {
|
||||
gamestate = JSON.parse(gamestate_loaded);
|
||||
record_log("Welcome back! Game loaded.")
|
||||
}
|
||||
}
|
||||
|
||||
function save_game() {
|
||||
window.localStorage.setItem("gamestate", JSON.stringify(gamestate));
|
||||
record_log("Game saved.");
|
||||
}
|
||||
|
||||
var tick_meter_running = true;
|
||||
|
||||
function reset_game() {
|
||||
tick_meter_running = false;
|
||||
window.localStorage.removeItem("gamestate");
|
||||
window.location.reload();
|
||||
}
|
564
pak/static/js/seagull.js
Normal file
564
pak/static/js/seagull.js
Normal file
@@ -0,0 +1,564 @@
|
||||
const ver_numeric = 0;
|
||||
const ver_string = "pre alpha";
|
||||
|
||||
const sleep = ms => new Promise(r => setTimeout(r, ms)); // sleep(int ms)
|
||||
const avg = input => input.reduce((a,b) => a+b) / input.length; // avg([1,2,3...])
|
||||
const urlExists = async url => (await fetch(url)).ok
|
||||
|
||||
var page_elements = {};
|
||||
|
||||
globalThis.gamestate = {};
|
||||
globalThis.tick_meter_running = false;
|
||||
var ticks_since_last_save = 0;
|
||||
|
||||
globalThis.gamestate_default = {
|
||||
"statever": "1",
|
||||
"tick": 1,
|
||||
"name": "Nameless",
|
||||
"class": "Seaglet",
|
||||
"level": 1,
|
||||
"shinies": 0,
|
||||
"colony": 1,
|
||||
"food": 0,
|
||||
"autosave": 35,
|
||||
"story_beat": 0,
|
||||
"xp": 0,
|
||||
"xp_next": 50,
|
||||
"enc_human": "pause",
|
||||
"enc_seagull": "pause",
|
||||
"agility": 0,
|
||||
"instinct": 0,
|
||||
"leadership": 0,
|
||||
"income": {
|
||||
"last_food": Array(10).fill(0),
|
||||
"last_shinies": Array(10).fill(0),
|
||||
"calc_food": 0,
|
||||
"calc_shinies": 0
|
||||
},
|
||||
"modifiers": {
|
||||
"speed": [],
|
||||
"chancesteal": []
|
||||
},
|
||||
"upgrades": []
|
||||
};
|
||||
|
||||
const tickdiffs_reset = {
|
||||
"food": 0,
|
||||
"shinies": 0
|
||||
}
|
||||
var tickdiffs = {}
|
||||
|
||||
var bool_log_alt = false
|
||||
globalThis.record_log = function (text) {
|
||||
const div_logrow = document.createElement("div");
|
||||
if (bool_log_alt) { div_logrow.className = "log-line"; }
|
||||
else { div_logrow.className = "log-line-alt"; }
|
||||
bool_log_alt = !bool_log_alt;
|
||||
|
||||
const div_logtick = document.createElement("div");
|
||||
div_logtick.className = "log-tick"
|
||||
div_logtick.innerHTML = "Day " + gamestate["tick"];
|
||||
div_logrow.append(div_logtick);
|
||||
|
||||
const div_logmsg = document.createElement("div");
|
||||
div_logmsg.innerHTML = text;
|
||||
div_logmsg.className = "log-msg";
|
||||
div_logrow.append(div_logmsg);
|
||||
|
||||
page_elements["div_log"].append(div_logrow);
|
||||
}
|
||||
|
||||
function record_log_with_choices() {
|
||||
const div_logrow = document.createElement("div");
|
||||
if (bool_log_alt) { div_logrow.className = "log-line"; }
|
||||
else { div_logrow.className = "log-line-alt"; }
|
||||
bool_log_alt = !bool_log_alt;
|
||||
|
||||
const div_logtick = document.createElement("div");
|
||||
div_logtick.className = "log-tick"
|
||||
div_logtick.innerHTML = "Day " + gamestate["tick"];
|
||||
div_logrow.append(div_logtick);
|
||||
|
||||
const div_logdata = document.createElement("div");
|
||||
|
||||
const div_logmsg = document.createElement("div");
|
||||
div_logmsg.innerHTML = arguments[0];
|
||||
div_logmsg.className = "log-msg";
|
||||
div_logdata.append(div_logmsg);
|
||||
|
||||
const div_logactions = document.createElement("div");
|
||||
div_logactions.className = "log-button-row";
|
||||
|
||||
for (var i = 1; i < arguments.length; i += 2) {
|
||||
console.log(i)
|
||||
var label = arguments[i];
|
||||
var callback = arguments[i+1];
|
||||
|
||||
var btn_action = document.createElement("button");
|
||||
btn_action.innerHTML = label;
|
||||
btn_action.className = "log-action-button";
|
||||
btn_action.setAttribute("onclick", callback + "; tick_meter_running = true;");
|
||||
div_logactions.append(btn_action);
|
||||
}
|
||||
div_logdata.append(div_logactions);
|
||||
|
||||
div_logrow.append(div_logdata);
|
||||
page_elements["div_log"].append(div_logrow);
|
||||
tick_meter_running = false;
|
||||
}
|
||||
|
||||
globalThis.modal_dialog_open = false;
|
||||
globalThis.modal_dialog_scripted = false;
|
||||
globalThis.modal_dialog_name = "";
|
||||
var dialog_queue = [];
|
||||
|
||||
function modal_no_prop(event) { event.stopPropagation(); }
|
||||
|
||||
async function open_modal_dialog(dialog) {
|
||||
if (!modal_dialog_open) {
|
||||
tick_meter_running = false;
|
||||
modal_dialog_open = true;
|
||||
modal_dialog_name = dialog;
|
||||
|
||||
var modal_background = document.createElement("div");
|
||||
modal_background.setAttribute("id", "modal-background");
|
||||
modal_background.style.zIndex = "10";
|
||||
modal_background.style.visibility = "visible";
|
||||
modal_background = document.body.appendChild(modal_background);
|
||||
|
||||
var modal_close = document.createElement("button");
|
||||
modal_close.setAttribute("id", "button-modal-close");
|
||||
modal_close.innerHTML = "❌";
|
||||
modal_close.addEventListener("click", (ev) => {close_modal_dialog()});
|
||||
modal_close = modal_background.appendChild(modal_close);
|
||||
|
||||
var modal_root = document.createElement("div");
|
||||
modal_root.setAttribute("id", "modal");
|
||||
modal_root.onclick = modal_no_prop;
|
||||
modal_root = modal_background.appendChild(modal_root);
|
||||
|
||||
var dialog_data = await fetch(`/dialog/${dialog}`)
|
||||
.then(res => { return res.text(); });
|
||||
|
||||
modal_root.innerHTML = dialog_data;
|
||||
if (urlExists(`/static/js/dlg-${dialog}.js`)) {
|
||||
//*
|
||||
var script = document.createElement("script");
|
||||
script.setAttribute("id", "dialog-script");
|
||||
script.src = `/static/js/dlg-${dialog}.js`;
|
||||
document.head.appendChild(script);
|
||||
modal_dialog_scripted = true;
|
||||
}
|
||||
} else {
|
||||
var dialog_data = await fetch(`/dialog/${dialog}`)
|
||||
.then(res => { return res.text(); });
|
||||
var dialog_script = null;
|
||||
if (urlExists(`/static/js/dlg-${dialog}.js`)) {
|
||||
dialog_script = `/static/js/dlg-${dialog}.js`;
|
||||
}
|
||||
|
||||
dialog_queue.push([dialog_data, dialog_script, dialog]);
|
||||
}
|
||||
}
|
||||
|
||||
async function close_modal_dialog() {
|
||||
if (!modal_dialog_open) { return; }
|
||||
|
||||
var modal_background = document.getElementById("modal-background");
|
||||
var modal_root = document.getElementById("modal-root");
|
||||
var dialog_script = document.getElementById("dialog-script");
|
||||
if (dialog_script) {
|
||||
document.head.removeChild(dialog_script);
|
||||
}
|
||||
|
||||
if (dialog_queue.length == 0) {
|
||||
modal_background.style.zIndex = "-10";
|
||||
modal_background.style.visibility = "hidden";
|
||||
document.body.removeChild(modal_background);
|
||||
|
||||
tick_meter_running = true;
|
||||
modal_dialog_open = false;
|
||||
modal_dialog_name = "";
|
||||
modal_dialog_scripted = false;
|
||||
} else {
|
||||
next_dialog = dialog_queue.pop();
|
||||
modal_root.innerHTML = next_dialog[0];
|
||||
modal_dialog_name = next_dialog[2];
|
||||
if (next_dialog[1]) {
|
||||
script = document.createElement("script");
|
||||
script.setAttribute("id", "dialog-script");
|
||||
script.src = next_dialog[1];
|
||||
document.head.appendChild(script);
|
||||
modal_dialog_scripted = true;
|
||||
} else { modal_dialog_scripted = false; }
|
||||
}
|
||||
}
|
||||
|
||||
function update_ui() {
|
||||
page_elements["lbl_name"].innerHTML = gamestate["name"];
|
||||
page_elements["lbl_tick"].innerHTML = gamestate["tick"];
|
||||
page_elements["lbl_colony"].innerHTML = gamestate["colony"];
|
||||
page_elements["lbl_shinies"].innerHTML = gamestate["shinies"].toFixed(2);
|
||||
page_elements["lbl_food"].innerHTML = gamestate["food"].toFixed(2);
|
||||
page_elements["lbl_inc_food"].innerHTML = gamestate["income"]["calc_food"].toFixed(2);
|
||||
page_elements["lbl_inc_shinies"].innerHTML = gamestate["income"]["calc_shinies"].toFixed(2);
|
||||
page_elements["lbl_class"].innerHTML = gamestate["class"];
|
||||
page_elements["lbl_xp"].innerHTML = gamestate["xp"];
|
||||
page_elements["lbl_xp_next"].innerHTML = gamestate["xp_next"];
|
||||
page_elements["lbl_level"].innerHTML = gamestate["level"];
|
||||
page_elements["menu_enc_human"].value = gamestate["enc_human"];
|
||||
page_elements["menu_enc_seagull"].value = gamestate["enc_seagull"];
|
||||
}
|
||||
|
||||
var dev_toolbox_open = false;
|
||||
function dev_toolbox(open) {
|
||||
if (open != dev_toolbox_open) {
|
||||
if (open) {
|
||||
var div_toolbox = document.createElement("div");
|
||||
page_elements["div_toolbox"] = div_toolbox;
|
||||
div_toolbox.setAttribute("id", "dev_toolbox");
|
||||
fetch("/dev/get-toolbox")
|
||||
.then((response) => response.text())
|
||||
.then((resp) => {div_toolbox.innerHTML = resp})
|
||||
page_elements["div_sidebar"].appendChild(div_toolbox);
|
||||
}
|
||||
else {
|
||||
var div_toolbox = page_elements["div_toolbox"];
|
||||
page_elements["div_sidebar"].removeChild(div_toolbox);
|
||||
div_toolbox.remove();
|
||||
delete page_elements["div_toolbox"];
|
||||
}
|
||||
}
|
||||
|
||||
dev_toolbox_open = open;
|
||||
}
|
||||
|
||||
function reward_xp(amount) {
|
||||
gamestate["xp"] += amount;
|
||||
if (gamestate["xp"] >= gamestate["xp_next"]) {
|
||||
var old_xp_next = gamestate["xp_next"];
|
||||
gamestate["xp"] -= old_xp_next;
|
||||
gamestate["level"] += 1;
|
||||
gamestate["xp_next"] = (old_xp_next * 1.5) + (gamestate["level"] * 5);
|
||||
record_log(`You have advanced to level ${gamestate["level"]}.`);
|
||||
|
||||
if (gamestate["level"] == 2) {
|
||||
gamestate["story_beat"] = 1;
|
||||
record_log("The humans have fired off some sort of large rocket from a nearby platform. You watch it as it pierces the sky above you and fades into the heavens.");
|
||||
} else if (gamestate["level"] == 3) {
|
||||
gamestate["story_beat"] = 2;
|
||||
gamestate["class"] = "Seagull";
|
||||
record_log("You have grown up from a young, eager seaglet to a full blown Seagull. As your colony participates in the ritual honoring your coming of age, you begin to detect a shift in the winds, though you're not certain exactly how.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
globalThis.steal_resource = async function (resource, target, amount, itemstr) {
|
||||
var items = itemstr.split(",")
|
||||
var stealdata = await fetch(`/act/steal/${resource}/${target}`, {method: "POST", headers: {"Content-Type": "application/json"},body: JSON.stringify({gamestate: gamestate})})
|
||||
.then(res => { return res.json(); })
|
||||
.catch(e => { throw e; });
|
||||
|
||||
if (stealdata["success"] && amount > 0) {
|
||||
gamestate[resource] += amount;
|
||||
tickdiffs[resource] += amount;
|
||||
reward_xp(2);
|
||||
record_log(`Stole ${resource} from a ${target}: ${items.join(", ")}`);
|
||||
}
|
||||
else { record_log(`Didn't steal ${resource} from a ${target}`); }
|
||||
}
|
||||
|
||||
globalThis.recruit = async function (amount) {
|
||||
if (gamestate["shinies"] < amount) {
|
||||
record_log("You do not have enough shinies to recruit this seagull.");
|
||||
return;
|
||||
}
|
||||
var stealdata = await fetch("/act/recruit", {method: "POST", body: JSON.stringify({gamestate: gamestate})})
|
||||
.then(res => { return res.json(); })
|
||||
.catch(e => { throw e; });
|
||||
|
||||
if (stealdata["success"] && amount > 0) {
|
||||
gamestate["shinies"] -= amount;
|
||||
reward_xp(5);
|
||||
gamestate["colony"] += 1;
|
||||
record_log("Successfully recruited a seagull into the colony");
|
||||
}
|
||||
else { record_log("The other gull wasn't impressed. Recruiting failed."); }
|
||||
}
|
||||
|
||||
const hnd_devtoolkit = new Konami(() => {
|
||||
if (modal_dialog_name == "about") {
|
||||
close_modal_dialog();
|
||||
dev_toolbox(true);
|
||||
var snd = new Audio("/static/sound/open_dev_toolkit.wav");
|
||||
snd.play();
|
||||
}
|
||||
})
|
||||
|
||||
async function game_tick() {
|
||||
gamestate["tick"] += 1;
|
||||
ticks_since_last_save += 1;
|
||||
page_elements["lbl_tick"].innerHTML = gamestate["tick"];
|
||||
|
||||
if (gamestate["tick"] % 5 == 0) {
|
||||
var colony_tickdata = await fetch("/tick/colony", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
colony: gamestate["colony"] - 1,
|
||||
modifiers: [],
|
||||
avg_food: gamestate["income"]["calc_food"],
|
||||
avg_shinies: gamestate["income"]["calc_shinies"]
|
||||
}),
|
||||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
})
|
||||
.then(res => {
|
||||
var json = res.json()
|
||||
console.log(json)
|
||||
return json
|
||||
})
|
||||
.catch(e => {throw e;});
|
||||
|
||||
if (colony_tickdata["success"]) {
|
||||
gamestate["food"] += colony_tickdata["food"];
|
||||
tickdiffs["food"] += colony_tickdata["food"];
|
||||
gamestate["shinies"] += colony_tickdata["shinies"];
|
||||
tickdiffs["shinies"] += colony_tickdata["shinies"];
|
||||
|
||||
record_log(`Your colony provides you with ${colony_tickdata["food"].toFixed(2)} food and ${colony_tickdata["shinies"].toFixed(2)} shinies.`);
|
||||
}
|
||||
}
|
||||
|
||||
var tickdata = await fetch("/tick")
|
||||
.then(res => {
|
||||
var json = res.json()
|
||||
console.log(json)
|
||||
return json
|
||||
})
|
||||
.catch(e => { throw e; });
|
||||
console.log(JSON.stringify(tickdata));
|
||||
|
||||
if (tickdata["code"] != 200) {
|
||||
console.error("Non-200 tick code: " + tickdata["code"]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (tickdata["event_type"] == 0) {
|
||||
// pass
|
||||
} 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) { // ENCHUMAN
|
||||
var total_food = 0;
|
||||
var food_descs = [];
|
||||
var total_shinies = 0;
|
||||
var shinies_descs = [];
|
||||
|
||||
switch (page_elements["menu_enc_human"].value) {
|
||||
case "pause":
|
||||
tickdata.items.food.forEach((item) => {
|
||||
total_food += item["amount"];
|
||||
food_descs.push(item["desc"]);
|
||||
});
|
||||
tickdata.items.shinies.forEach((item) => {
|
||||
total_shinies += item["amount"];
|
||||
shinies_descs.push(item["desc"]);
|
||||
});
|
||||
|
||||
var logstring = "You have encountered a human. It is carrying these resources:\n\n"
|
||||
logstring += "<ol>\n"
|
||||
if (total_food > 0) {
|
||||
logstring += `<li><b>${total_food.toFixed(2)} food:</b> ${food_descs.join(", ")}</li>\n`;
|
||||
}
|
||||
if (total_shinies > 0) {
|
||||
logstring += `<li><b>${total_shinies.toFixed(2)} shinies:</b> ${shinies_descs.join(", ")}</li>\n`;
|
||||
}
|
||||
logstring += "</ol>\nWhat would you like to do?";
|
||||
|
||||
record_log_with_choices(logstring,
|
||||
"Steal food", `steal_resource('food', 'humans', ${total_food}, "${food_descs.toString()}")`,
|
||||
"Steal shinies", `steal_resource('shinies', 'humans', ${total_shinies}, "${shinies_descs.toString()}")`
|
||||
)
|
||||
|
||||
break;
|
||||
case "steal-food":
|
||||
record_log("You have encountered a human. Attempting to steal food.");
|
||||
tickdata.items.food.forEach((item) => {
|
||||
total_food += item["amount"];
|
||||
food_descs.push(item["desc"]);
|
||||
})
|
||||
steal_resource("food", "humans", total_food, food_descs.toString());
|
||||
break;
|
||||
case "steal-shinies":
|
||||
record_log("You have encountered a human. Attempting to steal shinies.");
|
||||
tickdata.items.shinies.forEach((item) => {
|
||||
total_shinies += item["amount"];
|
||||
shinies_descs.push(item["desc"]);
|
||||
})
|
||||
steal_resource("shinies", "humans", total_shinies, shinies_descs.toString());
|
||||
break;
|
||||
default:
|
||||
console.error("undefined action " + page_elements["menu_enc_human"]);
|
||||
break;
|
||||
}
|
||||
} else if (tickdata["event_type"] == 11) { // ENCGULL
|
||||
var total_food = 0;
|
||||
var food_descs = [];
|
||||
var total_shinies = 0;
|
||||
var shinies_descs = [];
|
||||
|
||||
switch (page_elements["menu_enc_seagull"].value) {
|
||||
case "pause":
|
||||
tickdata.items.food.forEach((item) => {
|
||||
total_food += item["amount"];
|
||||
food_descs.push(item["desc"]);
|
||||
});
|
||||
tickdata.items.shinies.forEach((item) => {
|
||||
total_shinies += item["amount"];
|
||||
shinies_descs.push(item["desc"]);
|
||||
});
|
||||
|
||||
var logstring = "You have encountered a seagull. It is carrying these resources:\n\n"
|
||||
logstring += "<ol>\n"
|
||||
if (total_food > 0) {
|
||||
logstring += `<li><b>${total_food.toFixed(2)} food:</b> ${food_descs.join(", ")}</li>\n`;
|
||||
}
|
||||
if (total_shinies > 0) {
|
||||
logstring += `<li><b>${total_shinies.toFixed(2)} shinies:</b> ${shinies_descs.join(", ")}</li>\n`;
|
||||
}
|
||||
logstring += "</ol>\nWhat would you like to do?";
|
||||
|
||||
record_log_with_choices(logstring,
|
||||
"Recruit", `recruit(${tickdata.recruit_cost})`,
|
||||
"Steal food", `steal_resource('food', 'seagulls', ${total_food}, "${food_descs.toString()}")`,
|
||||
"Steal shinies", `steal_resource('shinies', 'seagulls', ${total_shinies}, "${shinies_descs.toString()}")`
|
||||
)
|
||||
|
||||
break;
|
||||
case "recruit":
|
||||
recruit(tickdata.recruit_cost);
|
||||
break
|
||||
case "steal-food":
|
||||
record_log("You have encountered a seagull. Attempting to steal food.");
|
||||
tickdata.items.food.forEach((item) => {
|
||||
total_food += item["amount"];
|
||||
food_descs.push(item["desc"]);
|
||||
})
|
||||
steal_resource("food", "seagulls", total_food, food_descs.toString());
|
||||
break;
|
||||
case "steal-shinies":
|
||||
record_log("You have encountered a seagull. Attempting to steal shinies.");
|
||||
tickdata.items.shinies.forEach((item) => {
|
||||
total_shinies += item["amount"];
|
||||
shinies_descs.push(item["desc"]);
|
||||
})
|
||||
steal_resource("shinies", "seagulls", total_shinies, shinies_descs.toString());
|
||||
break;
|
||||
default:
|
||||
console.error("undefined action " + page_elements["menu_enc_human"]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// sanity check
|
||||
if (!("autosave" in gamestate)) {
|
||||
gamestate["autosave"] = 35;
|
||||
}
|
||||
if (ticks_since_last_save % gamestate["autosave"] == 0 && ticks_since_last_save != 0) {
|
||||
save_game();
|
||||
ticks_since_last_save = 0;
|
||||
}
|
||||
|
||||
gamestate["income"]["last_food"].shift()
|
||||
gamestate["income"]["last_food"].push(tickdiffs["food"])
|
||||
gamestate["income"]["last_shinies"].shift()
|
||||
gamestate["income"]["last_shinies"].push(tickdiffs["shinies"])
|
||||
tickdiffs = structuredClone(tickdiffs_reset);
|
||||
|
||||
gamestate["income"]["calc_food"] = avg(gamestate["income"]["last_food"])
|
||||
gamestate["income"]["calc_shinies"] = avg(gamestate["income"]["last_shinies"])
|
||||
|
||||
update_ui();
|
||||
}
|
||||
|
||||
var start_event = "";
|
||||
var target = null;
|
||||
if (desktop_mode) {
|
||||
// pywebview's native JS is nerfed in a few places and needs the additional python API
|
||||
// which gets loaded after initial DOM via injections
|
||||
start_event = "pywebviewready";
|
||||
target = window;
|
||||
}
|
||||
else {
|
||||
// in web mode, browsers are expected to have working local storage by this point
|
||||
start_event = "DOMContentLoaded";
|
||||
target = document;
|
||||
}
|
||||
|
||||
function update_action(enc, value) {
|
||||
gamestate[`enc_${enc}`] = value;
|
||||
}
|
||||
|
||||
target.addEventListener(start_event, function (ev) {
|
||||
tickdiffs = structuredClone(tickdiffs_reset);
|
||||
|
||||
page_elements["div_log"] = document.querySelector("#main-log");
|
||||
page_elements["div_sidebar"] = document.querySelector("#main-sidebar");
|
||||
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");
|
||||
page_elements["lbl_inc_food"] = document.querySelector("#lbl-seagull-food-income");
|
||||
page_elements["lbl_inc_shinies"] = document.querySelector("#lbl-seagull-shinies-income");
|
||||
page_elements["edt_name"] = document.querySelector("#edt-seagull-name");
|
||||
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["lbl_level"] = document.querySelector("#lbl-seagull-lvl");
|
||||
page_elements["menu_enc_human"] = document.querySelector("#menu-enc-human");
|
||||
page_elements["menu_enc_seagull"] = document.querySelector("#menu-enc-seagull");
|
||||
page_elements["btn_charsheet"] = document.querySelector("#button-charsheet");
|
||||
page_elements["btn_settings"] = document.querySelector("#button-settings");
|
||||
page_elements["btn_about"] = document.querySelector("#button-about");
|
||||
|
||||
page_elements["menu_enc_human"].addEventListener("change", (ev) => {update_action("human", ev.target.value)});
|
||||
page_elements["menu_enc_seagull"].addEventListener("change", (ev) => {update_action("seagull", ev.target.value)});
|
||||
page_elements["btn_charsheet"].addEventListener("click", (ev) => {open_modal_dialog("charsheet")});
|
||||
page_elements["btn_about"].addEventListener("click", (ev) => {open_modal_dialog("about")});
|
||||
|
||||
prepare_gamestate();
|
||||
|
||||
record_log("seagull game ver. " + ver_string);
|
||||
|
||||
const interval = setInterval(() => {
|
||||
if (tick_meter_running) { game_tick(); }
|
||||
}, 1200);
|
||||
|
||||
update_ui();
|
||||
});
|
||||
|
||||
function change_seagull_name() {
|
||||
page_elements["div_name"].style.display = "none";
|
||||
page_elements["div_name_editor"].style.display = "block";
|
||||
}
|
||||
|
||||
function confirm_seagull_name() {
|
||||
const new_name = page_elements["edt_name"].value;
|
||||
page_elements["lbl_name"].innerHTML = new_name;
|
||||
gamestate["name"] = new_name;
|
||||
save_game();
|
||||
|
||||
page_elements["div_name"].style.display = "block";
|
||||
page_elements["div_name_editor"].style.display = "none";
|
||||
}
|
||||
|
||||
function cancel_seagull_name() {
|
||||
page_elements["edt_name"].value = "";
|
||||
|
||||
page_elements["div_name"].style.display = "block";
|
||||
page_elements["div_name_editor"].style.display = "none";
|
||||
}
|
BIN
pak/static/sound/open_dev_toolkit.wav
Normal file
BIN
pak/static/sound/open_dev_toolkit.wav
Normal file
Binary file not shown.
16
pak/templates/about.j2
Normal file
16
pak/templates/about.j2
Normal file
@@ -0,0 +1,16 @@
|
||||
<div id="about-root">
|
||||
<h1>Seagull Game</h1>
|
||||
<p>© 2025 Nicole O'Connor.</p>
|
||||
<p>
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache.org</a>.
|
||||
</p>
|
||||
<p>
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
</p>
|
||||
</div>
|
27
pak/templates/charsheet.j2
Normal file
27
pak/templates/charsheet.j2
Normal file
@@ -0,0 +1,27 @@
|
||||
<div id="charsheet-root">
|
||||
<div id="charsheet-leftside">
|
||||
<div id "attr-points">
|
||||
Available Points: <span id="lbl-attr-points">0</span>
|
||||
</div>
|
||||
<div class="attr" id="attr-agility">
|
||||
Agility: <span id="lbl-attr-agility">0</span>
|
||||
</div>
|
||||
<div class="attr" id="attr-instinct">
|
||||
<span id="lbl-attr-instinct-txt">Instinct</span>: <span id="lbl-attr-instinct">0</span>
|
||||
</div>
|
||||
<div class="attr" id="attr-leadership">
|
||||
Leadership: <span id="lbl-attr-leadership">0</span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="charsheet-rightside">
|
||||
<div id="charsheet-upgrade-tabbar">
|
||||
<nav id="nav-upgrades"><ul>
|
||||
<li><button id="btn-upgrade-agility">Agility Upgrades</button></li>
|
||||
<li><button id="btn-upgrade-instinct">Instinct Upgrades</button></li>
|
||||
<li><button id="btn-upgrade-leadership">Leadership Upgrades</button></li>
|
||||
</ul></nav>
|
||||
</div>
|
||||
<div id="charsheet-upgrade-tree" class="mermaid">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
2
pak/templates/dev_toolbox.j2
Normal file
2
pak/templates/dev_toolbox.j2
Normal file
@@ -0,0 +1,2 @@
|
||||
{% if not desktop %}IP: {{ipaddr}}<br />{% endif %}
|
||||
<button id="dev-reset" onClick="reset_game()">Reset Game</button>
|
69
pak/templates/main_page.j2
Normal file
69
pak/templates/main_page.j2
Normal file
@@ -0,0 +1,69 @@
|
||||
<!DOCTYPE html>
|
||||
<!-- Your server today is {{ svchost }} -->
|
||||
<html>
|
||||
<head>
|
||||
<title>Seagull Game</title>
|
||||
{%- for style in styles -%}
|
||||
<link rel="stylesheet" href="{{ style }}">
|
||||
{%- endfor -%}
|
||||
{%- for script in scripts -%}
|
||||
{%- if script[1] -%}
|
||||
<script type="module" src="{{ script[0] }}"></script>
|
||||
{%- else -%}
|
||||
<script src="{{ script[0] }}"></script>
|
||||
{%- endif -%}
|
||||
{%- endfor -%}
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
<div style="background:yellow;border:2px red;">
|
||||
<h1>This doesn't work without JavaScript.</h1><br />
|
||||
<h2>You're probably using a browser extension or privacy tool that disables it.</h2>
|
||||
</div>
|
||||
</noscript>
|
||||
<div id="root">
|
||||
|
||||
<div id="main-sidebar">
|
||||
<div id="side-seagull-image"> <img width="256" src={{ seagull_pic }}> </div>
|
||||
<div id="side-seagull-name"><span id="lbl-seagull-name">Nameless</span> <a href="javascript:change_seagull_name()">✏️</a></div>
|
||||
<div id="side-seagull-name-editor"><input type="text" id="edt-seagull-name"> <a href="javascript:confirm_seagull_name()">✅</a><a href="javascript:cancel_seagull_name()">❌</a></div>
|
||||
<div id="side-seagull-stats">
|
||||
<p id="side-seagull-lvl">Lv <span id="lbl-seagull-lvl">1</span> <span id="lbl-seagull-class">LoadError</span></p>
|
||||
<p id="side-seagull-xp">XP: <span id="lbl-seagull-xp-current">0</span>/<span id="lbl-seagull-xp-next">0</span></p>
|
||||
<p id="side-seagull-misc">
|
||||
Colony: <span id="lbl-seagull-colony">1337</span><br />
|
||||
Shinies: <span id="lbl-seagull-shinies">420</span> <i>(+<span id="lbl-seagull-shinies-income">0</span>/day)</i><br />
|
||||
Food: <span id="lbl-seagull-food">69</span> <i>(+<span id="lbl-seagull-food-income">0</span>/day)</i>
|
||||
</p>
|
||||
</div>
|
||||
<hr />
|
||||
<div id="side-action-bar">
|
||||
<p>Human encounters: <select id="menu-enc-human">
|
||||
<option value="pause">Stop and ask</option>
|
||||
<option value="steal-food">Steal food</option>
|
||||
<option value="steal-shinies">Steal shiny things</option>
|
||||
</select></p>
|
||||
<p>Seagull encounters: <select id="menu-enc-seagull">
|
||||
<option value="pause">Stop and ask</option>
|
||||
<option value="recruit">Attempt recruiting</option>
|
||||
<option value="steal-food">Steal food</option>
|
||||
<option value="steal-shinies">Steal shiny things</option>
|
||||
</select></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="main-content">
|
||||
<div id="main-header">
|
||||
<div id="main-day-stats">It has been <span id="main-day-counter">a cosmically unknowable number of</span> days.</div>
|
||||
<div id="main-button-bar">
|
||||
<button id="button-charsheet" class="main-bar">📊</button>
|
||||
<button id="button-settings" class="main-bar">⚙️</button>
|
||||
<button id="button-about" class="main-bar">ℹ️</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="main-log"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
24
pak/upgrades/agility.mmd
Normal file
24
pak/upgrades/agility.mmd
Normal file
@@ -0,0 +1,24 @@
|
||||
---
|
||||
title: Agility Upgrades
|
||||
theme: base
|
||||
themeVariables:
|
||||
primaryColor: "#00aa00"
|
||||
---
|
||||
flowchart LR
|
||||
speed1@{label: "Speedier Seagull"}
|
||||
speed2@{label: "Greased Wings"}
|
||||
|
||||
theft_chance1@{label: "Swooping Techniques"}
|
||||
theft_chance2@{label: "The Element of Surprise"}
|
||||
|
||||
passive_shinies_income1@{label: "Get On The Floor"}
|
||||
passive_shinies_income2@{label: "Open The Door"}
|
||||
passive_shinies_income3@{label: "Walk Like A Dinosaur"}
|
||||
|
||||
speed1-->speed2
|
||||
theft_chance1-->speed1
|
||||
theft_chance1-->theft_chance2
|
||||
|
||||
theft_chance1-->passive_shinies_income1
|
||||
-->passive_shinies_income2
|
||||
-->passive_shinies_income3
|
34
pak/upgrades/instinct.mmd
Normal file
34
pak/upgrades/instinct.mmd
Normal file
@@ -0,0 +1,34 @@
|
||||
---
|
||||
title: Instinct Upgrades
|
||||
theme: base
|
||||
themeVariables:
|
||||
primaryColor: "#aa00ff"
|
||||
---
|
||||
flowchart LR
|
||||
xp_bonus1@{label: "Stop and Smell"};
|
||||
xp_bonus2@{label: "Ponder and Deliberate"};
|
||||
xp_bonus3@{label: "Plan and Strategize"};
|
||||
|
||||
theft_results1@{label: "Go For The Pockets"};
|
||||
theft_results2@{label: "Use The Winds"};
|
||||
|
||||
passive_food_income1@{label: "Gone Fishin'"};
|
||||
passive_food_income2@{label: "Gone Farmin'"};
|
||||
passive_food_income3@{label: "Gone Clickin'"};
|
||||
passive_food_income4@{label: "Gone Agin'"};
|
||||
passive_food_income5@{label: "Gone Minin'"};
|
||||
passive_food_income6@{label: "Gone Factorin'"};
|
||||
passive_food_income7@{label: "Gone Bankin'"};
|
||||
|
||||
passive_food_income1-->passive_food_income2
|
||||
-->passive_food_income3
|
||||
-->passive_food_income4
|
||||
-->passive_food_income5
|
||||
-->passive_food_income6
|
||||
-->passive_food_income7;
|
||||
|
||||
xp_bonus1-->xp_bonus2
|
||||
-->xp_bonus3;
|
||||
|
||||
theft_results1-->theft_results2
|
||||
-->xp_bonus3;
|
22
pak/upgrades/leadership.mmd
Normal file
22
pak/upgrades/leadership.mmd
Normal file
@@ -0,0 +1,22 @@
|
||||
---
|
||||
title: Leadership Upgrades
|
||||
theme: base
|
||||
themeVariables:
|
||||
primaryColor: "#ffaa00"
|
||||
---
|
||||
flowchart LR
|
||||
offline_gen@{label: "Tireless Colony"}
|
||||
offline_gen_bonus1@{label: "Swoop Where He's Unprepared"}
|
||||
offline_gen_bonus2@{label: "Fly Where You're Unexpected"}
|
||||
|
||||
recruit_chance1@{label: "Squawk Softly"}
|
||||
recruit_chance2@{label: "Wink"}
|
||||
recruit_chance3@{label: "Sea Tzu's Art of Swoop"}
|
||||
|
||||
recruit_chance1-->recruit_chance2
|
||||
recruit_chance2-->recruit_chance3
|
||||
|
||||
recruit_chance3-->offline_gen_bonus1
|
||||
offline_gen---->offline_gen_bonus1
|
||||
offline_gen_bonus1-->offline_gen_bonus2
|
||||
|
Reference in New Issue
Block a user