diff --git a/.github/workflows/cargo-build-test.yml b/.github/workflows/cargo-build-test.yml index d54fa2f..cafaa58 100644 --- a/.github/workflows/cargo-build-test.yml +++ b/.github/workflows/cargo-build-test.yml @@ -12,7 +12,7 @@ env: jobs: build: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v3 diff --git a/Cargo.toml b/Cargo.toml index 24b6918..55d7645 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rust-rl" -version = "0.1.1" +version = "0.1.4" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/README.md b/README.md index 9127091..c1809cf 100644 --- a/README.md +++ b/README.md @@ -2,18 +2,18 @@ #### using _rltk/bracket-lib_, and _specs_ -check out the page in the header for the wasm version, pick [a release of your choice](https://github.com/Llywelwyn/rust-rl/releases), or build manually with: +[![Rust](https://github.com/Llywelwyn/rust-rl/actions/workflows/cargo-build-test.yml/badge.svg)](https://github.com/Llywelwyn/rust-rl/actions/workflows/cargo-build-test.yml) + +check out the page in the header for the wasm version, pick [a release](https://github.com/Llywelwyn/rust-rl/releases), or build manually with: `git clone https://github.com/Llywelwyn/rust-rl/ && cd rust-rl && cargo build --release`, ![image](https://github.com/Llywelwyn/rust-rl/assets/82828093/b05e4f0b-2062-4abe-9fee-c679f9ef420d) -this year for roguelikedev does the complete tutorial, i followed along with thebracket's [_roguelike tutorial - in rust_](https://bfnightly.bracketproductions.com). the notes i made during the sprint are being kept below for posterity - further changes since then are noted in [changelog.txt](https://github.com/Llywelwyn/rust-rl/blob/9150ed39e45bee536060cdc769d274e639021012/changelog.txt), and in the release notes. - -i'm also working on translating over my progress into blog entries on my site @ [llyw.co.uk](https://llyw.co.uk/), with a larger focus on some of the more interesting implementation details. - --- +
+ boring details about the sprint where this project started
week 1 @@ -157,3 +157,4 @@ i'm also working on translating over my progress into blog entries on my site @ ![squares](https://github.com/Llywelwyn/rust-rl/assets/82828093/b752e1cb-340d-475d-84ae-68fdb4977a80)
+
diff --git a/docs/combat_system.txt b/docs/combat_system.txt index 13a780b..44e2f65 100644 --- a/docs/combat_system.txt +++ b/docs/combat_system.txt @@ -49,3 +49,7 @@ Complex example, with negative AC: bloodstains: if starts on bloodied tile, remove blood + heal, gain xp, grow (little dog -> dog), etc. - You have negative AC, so you roll 1d14 for damage reduction, and get an 8. - The total damage is 6 - 8 = -2, but damage can't be negative, so you take 1 point of damage. + +tl;dr +1. Lower AC is better +2. Aim for 0 AC - it's an important breakpoint. Every point of AC before 0 counts for a lot. diff --git a/raws/items.json b/raws/items.json index 2c0c678..7599afe 100644 --- a/raws/items.json +++ b/raws/items.json @@ -3,9 +3,10 @@ "id": "potion_health", "name": { "name": "potion of health", "plural": "potions of health" }, "renderable": { "glyph": "!", "fg": "#FF00FF", "bg": "#000000", "order": 2 }, + "class": "potion", "weight": 1, "value": 50, - "flags": ["CONSUMABLE", "DESTRUCTIBLE"], + "flags": ["CONSUMABLE", "DESTRUCTIBLE", "STACKABLE"], "effects": { "heal": "4d4+2" }, "magic": { "class": "uncommon", "naming": "potion" } }, @@ -13,9 +14,10 @@ "id": "potion_health_weak", "name": { "name": "potion of lesser health", "plural": "potions of lesser health" }, "renderable": { "glyph": "!", "fg": "#FF00FF", "bg": "#000000", "order": 2 }, + "class": "potion", "weight": 1, "value": 25, - "flags": ["CONSUMABLE", "DESTRUCTIBLE"], + "flags": ["CONSUMABLE", "DESTRUCTIBLE", "STACKABLE"], "effects": { "heal": "2d4+2" }, "magic": { "class": "uncommon", "naming": "potion" } }, @@ -23,27 +25,30 @@ "id": "scroll_identify", "name": { "name": "scroll of identify", "plural": "scrolls of identify" }, "renderable": { "glyph": "?", "fg": "#0FFFFF", "bg": "#000000", "order": 2 }, + "class": "scroll", "weight": 0.5, "value": 100, - "flags": ["CONSUMABLE", "DESTRUCTIBLE", "IDENTIFY"], + "flags": ["CONSUMABLE", "DESTRUCTIBLE", "STACKABLE", "IDENTIFY"], "magic": { "class": "uncommon", "naming": "scroll" } }, { "id": "scroll_removecurse", "name": { "name": "scroll of remove curse", "plural": "scrolls of remove curse" }, "renderable": { "glyph": "?", "fg": "#0FFFFF", "bg": "#000000", "order": 2 }, + "class": "scroll", "weight": 0.5, "value": 200, - "flags": ["CONSUMABLE", "DESTRUCTIBLE", "REMOVE_CURSE"], + "flags": ["CONSUMABLE", "DESTRUCTIBLE", "STACKABLE", "REMOVE_CURSE"], "magic": { "class": "rare", "naming": "scroll" } }, { "id": "scroll_health", "name": { "name": "scroll of healing word", "plural": "scrolls of healing word" }, "renderable": { "glyph": "?", "fg": "#00FFFF", "bg": "#000000", "order": 2 }, + "class": "scroll", "weight": 0.5, "value": 50, - "flags": ["CONSUMABLE", "DESTRUCTIBLE"], + "flags": ["CONSUMABLE", "DESTRUCTIBLE", "STACKABLE"], "effects": { "particle_line": "*;-;#53f06d;75.0;#f9ff9f;100.0", "ranged": "12", "heal": "1d4+2" }, "magic": { "class": "uncommon", "naming": "scroll" } }, @@ -51,9 +56,10 @@ "id": "scroll_mass_health", "name": { "name": "scroll of mass healing word", "plural": "scrolls of mass healing word" }, "renderable": { "glyph": "?", "fg": "#00FFFF", "bg": "#000000", "order": 2 }, + "class": "scroll", "weight": 0.5, "value": 200, - "flags": ["CONSUMABLE", "DESTRUCTIBLE"], + "flags": ["CONSUMABLE", "DESTRUCTIBLE", "STACKABLE"], "effects": { "particle": "*;#53f06d;200.0", "ranged": "12", "aoe": "3", "heal": "1d4+2" }, "magic": { "class": "rare", "naming": "scroll" } }, @@ -61,9 +67,10 @@ "id": "scroll_magicmissile", "name": { "name": "scroll of magic missile", "plural": "scrolls of magic missile" }, "renderable": { "glyph": "?", "fg": "#00FFFF", "bg": "#000000", "order": 2 }, + "class": "scroll", "weight": 0.5, "value": 50, - "flags": ["CONSUMABLE", "DESTRUCTIBLE"], + "flags": ["CONSUMABLE", "DESTRUCTIBLE", "STACKABLE"], "effects": { "particle_line": "*;-;#00b7ff;75.0;#f4fc83;100.0", "ranged": "12", "damage": "3d4+3;magic" }, "magic": { "class": "uncommon", "naming": "scroll" } }, @@ -71,9 +78,10 @@ "id": "scroll_embers", "name": { "name": "scroll of embers", "plural": "scrolls of embers" }, "renderable": { "glyph": "?", "fg": "#00FFFF", "bg": "#000000", "order": 2 }, + "class": "scroll", "weight": 0.5, "value": 100, - "flags": ["CONSUMABLE", "DESTRUCTIBLE"], + "flags": ["CONSUMABLE", "DESTRUCTIBLE", "STACKABLE"], "effects": { "particle": "*;#FFA500;200.0", "ranged": "10", "damage": "4d6;fire", "aoe": "2" }, "magic": { "class": "uncommon", "naming": "scroll" } }, @@ -81,9 +89,10 @@ "id": "scroll_fireball", "name": { "name": "scroll of fireball", "plural": "scrolls of fireball" }, "renderable": { "glyph": "?", "fg": "#00FFFF", "bg": "#000000", "order": 2 }, + "class": "scroll", "weight": 0.5, "value": 200, - "flags": ["CONSUMABLE", "DESTRUCTIBLE"], + "flags": ["CONSUMABLE", "DESTRUCTIBLE", "STACKABLE"], "effects": { "particle_burst": "▓;*;~;#FFA500;#000000;500.0;#ffd381;60.0", "ranged": "10", @@ -96,9 +105,10 @@ "id": "scroll_confusion", "name": { "name": "scroll of confusion", "plural": "scrolls of confusion" }, "renderable": { "glyph": "?", "fg": "#00FFFF", "bg": "#000000", "order": 2 }, + "class": "scroll", "weight": 0.5, "value": 100, - "flags": ["CONSUMABLE", "DESTRUCTIBLE"], + "flags": ["CONSUMABLE", "DESTRUCTIBLE", "STACKABLE"], "effects": { "particle_line": "*;-;#ad56a6;75.0;#cacaca;100.0", "ranged": "10", "confusion": "4" }, "magic": { "class": "uncommon", "naming": "scroll" } }, @@ -106,9 +116,10 @@ "id": "scroll_mass_confusion", "name": { "name": "scroll of mass confusion", "plural": "scrolls of mass confusion" }, "renderable": { "glyph": "?", "fg": "#00FFFF", "bg": "#000000", "order": 2 }, + "class": "scroll", "weight": 0.5, "value": 200, - "flags": ["CONSUMABLE", "DESTRUCTIBLE"], + "flags": ["CONSUMABLE", "DESTRUCTIBLE", "STACKABLE"], "effects": { "particle": "*;#ad56a6;200.0", "ranged": "10", "aoe": "3", "confusion": "3" }, "magic": { "class": "veryrare", "naming": "scroll" } }, @@ -116,9 +127,10 @@ "id": "scroll_magicmap", "name": { "name": "scroll of magic mapping", "plural": "scrolls of magic mapping" }, "renderable": { "glyph": "?", "fg": "#00FFFF", "bg": "#000000", "order": 2 }, + "class": "scroll", "weight": 0.5, "value": 50, - "flags": ["CONSUMABLE", "DESTRUCTIBLE", "MAGICMAP"], + "flags": ["CONSUMABLE", "DESTRUCTIBLE", "STACKABLE", "MAGICMAP"], "effects": {}, "magic": { "class": "common", "naming": "scroll" } }, @@ -126,6 +138,7 @@ "id": "equip_dagger", "name": { "name": "dagger", "plural": "daggers" }, "renderable": { "glyph": ")", "fg": "#808080", "bg": "#000000", "order": 2 }, + "class": "weapon", "weight": 1, "value": 2, "flags": ["EQUIP_MELEE"], @@ -135,6 +148,7 @@ "id": "equip_shortsword", "name": { "name": "shortsword", "plural": "shortswords" }, "renderable": { "glyph": ")", "fg": "#C0C0C0", "bg": "#000000", "order": 2 }, + "class": "weapon", "weight": 2, "value": 10, "flags": ["EQUIP_MELEE"], @@ -144,6 +158,7 @@ "id": "equip_rapier", "name": { "name": "rapier", "plural": "rapiers" }, "renderable": { "glyph": ")", "fg": "#C0C0C0", "bg": "#000000", "order": 2 }, + "class": "weapon", "weight": 2, "value": 10, "flags": ["EQUIP_MELEE"], @@ -153,6 +168,7 @@ "id": "equip_pitchfork", "name": { "name": "pitchfork", "plural": "pitchforks" }, "renderable": { "glyph": ")", "fg": "#C0C0C0", "bg": "#000000", "order": 2 }, + "class": "weapon", "weight": 2, "value": 5, "flags": ["EQUIP_MELEE"], @@ -162,6 +178,7 @@ "id": "equip_sickle", "name": { "name": "sickle", "plural": "sickles" }, "renderable": { "glyph": ")", "fg": "#C0C0C0", "bg": "#000000", "order": 2 }, + "class": "weapon", "weight": 2, "value": 5, "flags": ["EQUIP_MELEE"], @@ -171,6 +188,7 @@ "id": "equip_handaxe", "name": { "name": "handaxe", "plural": "handaxes" }, "renderable": { "glyph": ")", "fg": "#C0C0C0", "bg": "#000000", "order": 2 }, + "class": "weapon", "weight": 2, "value": 5, "flags": ["EQUIP_MELEE"], @@ -180,6 +198,7 @@ "id": "equip_longsword", "name": { "name": "longsword", "plural": "longswords" }, "renderable": { "glyph": ")", "fg": "#FFF8DC", "bg": "#000000", "order": 2 }, + "class": "weapon", "weight": 3, "value": 15, "flags": ["EQUIP_MELEE"], @@ -189,6 +208,7 @@ "id": "equip_smallshield", "name": { "name": "buckler", "plural": "bucklers" }, "renderable": { "glyph": "[", "fg": "#808080", "bg": "#000000", "order": 2 }, + "class": "armour", "weight": 2, "value": 5, "flags": ["EQUIP_SHIELD"], @@ -198,6 +218,7 @@ "id": "equip_mediumshield", "name": { "name": "medium shield", "plural": "medium shields" }, "renderable": { "glyph": "[", "fg": "#C0C0C0", "bg": "#000000", "order": 2 }, + "class": "armour", "weight": 6, "value": 10, "flags": ["EQUIP_SHIELD"], @@ -207,6 +228,7 @@ "id": "equip_largeshield", "name": { "name": "large shield", "plural": "large shields" }, "renderable": { "glyph": "[", "fg": "#FFF8DC", "bg": "#000000", "order": 2 }, + "class": "armour", "weight": 12, "value": 35, "flags": ["EQUIP_SHIELD"], @@ -216,6 +238,7 @@ "id": "equip_body_weakleather", "name": { "name": "leather jacket", "plural": "leather jackets" }, "renderable": { "glyph": "[", "fg": "#aa6000", "bg": "#000000", "order": 2 }, + "class": "armour", "weight": 8, "value": 5, "flags": ["EQUIP_BODY"], @@ -225,6 +248,7 @@ "id": "equip_body_leather", "name": { "name": "leather chestpiece", "plural": "leather chestpiece" }, "renderable": { "glyph": "[", "fg": "#aa6000", "bg": "#000000", "order": 2 }, + "class": "armour", "weight": 10, "value": 10, "flags": ["EQUIP_BODY"], @@ -234,6 +258,7 @@ "id": "equip_body_studdedleather", "name": { "name": "studded leather chestpiece", "plural": "studded leather chestpieces" }, "renderable": { "glyph": "[", "fg": "#aa6000", "bg": "#000000", "order": 2 }, + "class": "armour", "weight": 13, "value": 45, "flags": ["EQUIP_BODY"], @@ -243,6 +268,7 @@ "id": "equip_body_ringmail_o", "name": { "name": "orcish ring mail", "plural": "orcish ring mail" }, "renderable": { "glyph": "[", "fg": "#aa6000", "bg": "#000000", "order": 2 }, + "class": "armour", "weight": 45, "value": 50, "flags": ["EQUIP_BODY"], @@ -252,6 +278,7 @@ "id": "equip_body_ringmail", "name": { "name": "ring mail", "plural": "ring mail" }, "renderable": { "glyph": "[", "fg": "#aa6000", "bg": "#000000", "order": 2 }, + "class": "armour", "weight": 45, "value": 70, "flags": ["EQUIP_BODY"], @@ -261,6 +288,7 @@ "id": "equip_head_leather", "name": { "name": "leather cap", "plural": "leather caps" }, "renderable": { "glyph": "[", "fg": "#aa6000", "bg": "#000000", "order": 2 }, + "class": "armour", "weight": 2, "value": 10, "flags": ["EQUIP_HEAD"], @@ -270,6 +298,7 @@ "id": "equip_head_elvish", "name": { "name": "elvish leather helm", "plural": "elvish leather helms" }, "renderable": { "glyph": "[", "fg": "#aa6000", "bg": "#000000", "order": 2 }, + "class": "armour", "weight": 2, "value": 25, "flags": ["EQUIP_HEAD"], @@ -279,6 +308,7 @@ "id": "equip_head_o", "name": { "name": "orcish helm", "plural": "orcish helm" }, "renderable": { "glyph": "[", "fg": "#aa6000", "bg": "#000000", "order": 2 }, + "class": "armour", "weight": 6, "value": 25, "flags": ["EQUIP_HEAD"], @@ -288,6 +318,7 @@ "id": "equip_head_iron", "name": { "name": "iron helm", "plural": "iron helm" }, "renderable": { "glyph": "[", "fg": "#aa6000", "bg": "#000000", "order": 2 }, + "class": "armour", "weight": 10, "value": 45, "flags": ["EQUIP_HEAD"], @@ -297,6 +328,7 @@ "id": "equip_feet_leather", "name": { "name": "leather shoes", "plural": "leather shoes" }, "renderable": { "glyph": "[", "fg": "#aa6000", "bg": "#000000", "order": 2 }, + "class": "armour", "weight": 2, "value": 10, "flags": ["EQUIP_FEET"] @@ -305,6 +337,7 @@ "id": "equip_feet_elvish", "name": { "name": "elvish leather shoes", "plural": "elvish leather shoes" }, "renderable": { "glyph": "[", "fg": "#aa6000", "bg": "#000000", "order": 2 }, + "class": "armour", "weight": 2, "value": 25, "flags": ["EQUIP_FEET"], @@ -314,6 +347,7 @@ "id": "equip_feet_o", "name": { "name": "orcish boots", "plural": "orcish boots" }, "renderable": { "glyph": "[", "fg": "#aa6000", "bg": "#000000", "order": 2 }, + "class": "armour", "weight": 6, "value": 25, "flags": ["EQUIP_FEET"], @@ -323,6 +357,7 @@ "id": "equip_feet_iron", "name": { "name": "iron boots", "plural": "iron boots" }, "renderable": { "glyph": "[", "fg": "#aa6000", "bg": "#000000", "order": 2 }, + "class": "armour", "weight": 10, "value": 45, "flags": ["EQUIP_FEET"], @@ -332,6 +367,7 @@ "id": "equip_neck_protection", "name": { "name": "amulet of protection", "plural": "amulets of protection" }, "renderable": { "glyph": "\"", "fg": "#aa6000", "bg": "#000000", "order": 2 }, + "class": "amulet", "weight": 1, "value": 200, "flags": ["EQUIP_NECK"], @@ -341,6 +377,7 @@ "id": "equip_back_protection", "name": { "name": "cloak of protection", "plural": "cloaks of protection" }, "renderable": { "glyph": "[", "fg": "#aa6000", "bg": "#000000", "order": 2 }, + "class": "armour", "weight": 1, "value": 200, "flags": ["EQUIP_BACK"], @@ -350,6 +387,7 @@ "id": "wand_magicmissile", "name": { "name": "wand of magic missile", "plural": "wands of magic missile" }, "renderable": { "glyph": "/", "fg": "#00FFFF", "bg": "#000000", "order": 2 }, + "class": "wand", "weight": 2, "value": 100, "flags": ["CHARGES"], @@ -360,6 +398,7 @@ "id": "wand_fireball", "name": { "name": "wand of fireball", "plural": "wands of fireball" }, "renderable": { "glyph": "/", "fg": "#00FFFF", "bg": "#000000", "order": 2 }, + "class": "wand", "weight": 2, "value": 300, "flags": ["CHARGES"], @@ -370,6 +409,7 @@ "id": "wand_confusion", "name": { "name": "wand of confusion", "plural": "wands of confusion" }, "renderable": { "glyph": "/", "fg": "#00FFFF", "bg": "#000000", "order": 2 }, + "class": "wand", "weight": 2, "value": 200, "flags": ["CHARGES"], @@ -380,6 +420,7 @@ "id": "wand_digging", "name": { "name": "wand of digging", "plural": "wands of digging" }, "renderable": { "glyph": "/", "fg": "#00FFFF", "bg": "#000000", "order": 2 }, + "class": "wand", "weight": 2, "value": 300, "flags": ["CHARGES", "DIGGER"], @@ -390,16 +431,18 @@ "id": "food_rations", "name": { "name": "rations", "plural": "rations" }, "renderable": { "glyph": "%", "fg": "#FFA07A", "bg": "#000000", "order": 2 }, + "class": "comestible", "weight": 1, "value": 1, - "flags": ["FOOD", "CONSUMABLE"] + "flags": ["FOOD", "CONSUMABLE", "STACKABLE"] }, { "id": "food_apple", "name": { "name": "apple", "plural": "apples" }, "renderable": { "glyph": "%", "fg": "#00FF00", "bg": "#000000", "order": 2 }, + "class": "comestible", "weight": 0.5, "value": 1, - "flags": ["FOOD", "CONSUMABLE"] + "flags": ["FOOD", "CONSUMABLE", "STACKABLE"] } ] diff --git a/raws/props.json b/raws/props.json index f60ff11..0c48291 100644 --- a/raws/props.json +++ b/raws/props.json @@ -2,7 +2,7 @@ { "id": "door", "name": "door", - "renderable": { "glyph": "+", "sprite": 17, "fg": "#00FFFF", "bg": "#000000", "order": 2 }, + "renderable": { "glyph": "+", "fg": "#00FFFF", "bg": "#000000", "order": 2 }, "flags": ["DOOR"] }, { @@ -21,7 +21,7 @@ { "id": "prop_table", "name": "table", - "renderable": { "glyph": "-", "sprite": 52, "fg": "#AAAAAA", "bg": "#000000", "order": 2 }, + "renderable": { "glyph": "-", "fg": "#AAAAAA", "bg": "#000000", "order": 2 }, "flags": [] }, { @@ -33,25 +33,25 @@ { "id": "prop_statue", "name": "statue", - "renderable": { "glyph": "@", "sprite": 29, "fg": "#ffffff", "bg": "#000000", "order": 2 }, + "renderable": { "glyph": "@", "fg": "#ffffff", "bg": "#000000", "order": 2 }, "flags": [] }, { "id": "prop_bed", "name": "bed", - "renderable": { "glyph": "=", "sprite": 50, "fg": "#AAAAAA", "bg": "#000000", "order": 2 }, + "renderable": { "glyph": "=", "fg": "#AAAAAA", "bg": "#000000", "order": 2 }, "flags": [] }, { "id": "prop_chair", "name": "chair", - "renderable": { "glyph": "└", "sprite": 51, "fg": "#AAAAAA", "bg": "#000000", "order": 2 }, + "renderable": { "glyph": "└", "fg": "#AAAAAA", "bg": "#000000", "order": 2 }, "flags": [] }, { "id": "prop_candle", "name": "candle", - "renderable": { "glyph": "Ä", "sprite": 3, "fg": "#FFA500", "bg": "#000000", "order": 2 }, + "renderable": { "glyph": "Ä", "fg": "#FFA500", "bg": "#000000", "order": 2 }, "flags": [] }, { diff --git a/resources/curses11x20.png b/resources/curses11x20.png deleted file mode 100644 index 5f5e1e5..0000000 Binary files a/resources/curses11x20.png and /dev/null differ diff --git a/resources/curses12x24.png b/resources/curses12x24.png deleted file mode 100644 index 4504d0a..0000000 Binary files a/resources/curses12x24.png and /dev/null differ diff --git a/resources/curses16x16.pdn b/resources/curses16x16.pdn deleted file mode 100644 index a13f60d..0000000 Binary files a/resources/curses16x16.pdn and /dev/null differ diff --git a/resources/curses16x16.png b/resources/curses16x16.png deleted file mode 100644 index 042abea..0000000 Binary files a/resources/curses16x16.png and /dev/null differ diff --git a/resources/curses8x16.pdn b/resources/curses8x16.pdn deleted file mode 100644 index 02b2112..0000000 Binary files a/resources/curses8x16.pdn and /dev/null differ diff --git a/resources/curses8x16.png b/resources/curses8x16.png deleted file mode 100644 index 4b83036..0000000 Binary files a/resources/curses8x16.png and /dev/null differ diff --git a/resources/healthbar11x2.png b/resources/healthbar11x2.png deleted file mode 100644 index 96fb67c..0000000 Binary files a/resources/healthbar11x2.png and /dev/null differ diff --git a/resources/healthbar22x2.png b/resources/healthbar22x2.png deleted file mode 100644 index daa15d1..0000000 Binary files a/resources/healthbar22x2.png and /dev/null differ diff --git a/resources/nagidal22x20_centred.png b/resources/nagidal22x20_centred.png deleted file mode 100644 index 1383fb9..0000000 Binary files a/resources/nagidal22x20_centred.png and /dev/null differ diff --git a/resources/nagidal22x22_centred.png b/resources/nagidal22x22_centred.png deleted file mode 100644 index f941b27..0000000 Binary files a/resources/nagidal22x22_centred.png and /dev/null differ diff --git a/resources/nagidal24x24.png b/resources/nagidal24x24.png deleted file mode 100644 index 2d4aba9..0000000 Binary files a/resources/nagidal24x24.png and /dev/null differ diff --git a/resources/terminal10x10_gs_tc.png b/resources/terminal10x10_gs_tc.png deleted file mode 100644 index 5e0cdc9..0000000 Binary files a/resources/terminal10x10_gs_tc.png and /dev/null differ diff --git a/resources/vga8x16.png b/resources/vga8x16.png deleted file mode 100644 index 913e32c..0000000 Binary files a/resources/vga8x16.png and /dev/null differ diff --git a/resources/world16x16.png b/resources/world16x16.png deleted file mode 100644 index e05e1d5..0000000 Binary files a/resources/world16x16.png and /dev/null differ diff --git a/src/ai/approach_ai_system.rs b/src/ai/approach_ai_system.rs index 6e6e7a8..c3cc2ca 100644 --- a/src/ai/approach_ai_system.rs +++ b/src/ai/approach_ai_system.rs @@ -45,7 +45,6 @@ impl<'a> System<'a> for ApproachAI { continue; }; let mut path: Option = None; - let mut curr_abs_diff = 100; let idx = map.xy_idx(pos.x, pos.y); for tar_idx in target_idxs { let potential_path = a_star_search(idx, tar_idx, &mut *map); @@ -55,17 +54,6 @@ impl<'a> System<'a> for ApproachAI { potential_path.steps.len() < path.as_ref().unwrap().steps.len() { path = Some(potential_path); - let (x1, y1) = (pos.x, pos.y); - let (x2, y2) = ((tar_idx as i32) % map.width, (tar_idx as i32) / map.width); - curr_abs_diff = i32::abs(x2 - x1) + i32::abs(y2 - y1); - } else if potential_path.steps.len() == path.as_ref().unwrap().steps.len() { - let (x1, y1) = (pos.x, pos.y); - let (x2, y2) = ((tar_idx as i32) % map.width, (tar_idx as i32) / map.width); - let abs_diff = i32::abs(x2 - x1) + i32::abs(y2 - y1); - if abs_diff < curr_abs_diff { - path = Some(potential_path); - curr_abs_diff = abs_diff; - } } } } diff --git a/src/ai/turn_status_system.rs b/src/ai/turn_status_system.rs index db3acaa..e072e45 100644 --- a/src/ai/turn_status_system.rs +++ b/src/ai/turn_status_system.rs @@ -65,9 +65,7 @@ impl<'a> System<'a> for TurnStatusSystem { not_confused.push(entity); if entity == *player_entity { logger = logger - .colour(renderable_colour(&renderables, entity)) .append("You") - .colour(WHITE) .append("snap out of it."); log = true; } else { @@ -94,9 +92,7 @@ impl<'a> System<'a> for TurnStatusSystem { not_my_turn.push(entity); if entity == *player_entity { logger = logger - .colour(renderable_colour(&renderables, entity)) .append("You") - .colour(WHITE) .append("are confused!"); log = true; gamelog::record_event(EVENT::PlayerConfused(1)); diff --git a/src/camera.rs b/src/camera.rs index 090476b..00b6869 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -1,16 +1,14 @@ -use super::{ Hidden, Map, Mind, Position, Prop, Renderable, Pools }; +use super::{ Hidden, Map, Mind, Position, Prop, Renderable }; use bracket_lib::prelude::*; use specs::prelude::*; use std::ops::Mul; -use super::data::visuals::{ VIEWPORT_W, VIEWPORT_H }; -use super::data::prelude::*; const SHOW_BOUNDARIES: bool = false; pub fn get_screen_bounds(ecs: &World, _ctx: &mut BTerm) -> (i32, i32, i32, i32, i32, i32) { let player_pos = ecs.fetch::(); let map = ecs.fetch::(); - let (x_chars, y_chars, mut x_offset, mut y_offset) = (VIEWPORT_W, VIEWPORT_H, 1, 10); + let (x_chars, y_chars, mut x_offset, mut y_offset) = (69, 41, 1, 10); let centre_x = (x_chars / 2) as i32; let centre_y = (y_chars / 2) as i32; @@ -45,29 +43,13 @@ pub fn render_camera(ecs: &World, ctx: &mut BTerm) { if t_x >= 0 && t_x < map.width && t_y >= 0 && t_y < map.height { let idx = map.xy_idx(t_x, t_y); if map.revealed_tiles[idx] { - if 1 == 2 { - let (glyph, fg, bg) = crate::map::themes::get_tile_renderables_for_id( - idx, - &*map, - Some(*ecs.fetch::()), - None - ); - ctx.set(x + x_offset, y + y_offset, fg, bg, glyph); - } else { - ctx.set_active_console(0); - let (id, tint) = crate::map::themes::get_sprite_for_id( - idx, - &*map, - Some(*ecs.fetch::()) - ); - ctx.add_sprite( - Rect::with_size(x * 16 + x_offset * 16, y * 16 + y_offset * 16, 16, 16), - 0, - tint, - id - ); - ctx.set_active_console(TILE_LAYER); - } + let (glyph, fg, bg) = crate::map::themes::get_tile_renderables_for_id( + idx, + &*map, + Some(*ecs.fetch::()), + None + ); + ctx.set(x + x_offset, y + y_offset, fg, bg, glyph); } } else if SHOW_BOUNDARIES { ctx.set( @@ -85,11 +67,8 @@ pub fn render_camera(ecs: &World, ctx: &mut BTerm) { // Render entities { - ctx.set_active_console(ENTITY_LAYER); - let positions = ecs.read_storage::(); let renderables = ecs.read_storage::(); - let pools = ecs.read_storage::(); let minds = ecs.read_storage::(); let hidden = ecs.read_storage::(); let props = ecs.write_storage::(); @@ -105,7 +84,12 @@ pub fn render_camera(ecs: &World, ctx: &mut BTerm) { if pos.x < max_x && pos.y < max_y && pos.x >= min_x && pos.y >= min_y { let mut draw = false; let mut fg = render.fg; - let bg = BLACK; + let mut bg = crate::map::themes::get_tile_renderables_for_id( + idx, + &*map, + Some(*ecs.fetch::()), + None + ).2; // Draw entities on visible tiles if map.visible_tiles[idx] { draw = true; @@ -120,6 +104,9 @@ pub fn render_camera(ecs: &World, ctx: &mut BTerm) { let has_mind = minds.get(*ent); if let Some(_) = has_mind { draw = true; + if !map.revealed_tiles[idx] { + bg = RGB::named(BLACK); + } } } } @@ -131,51 +118,16 @@ pub fn render_camera(ecs: &World, ctx: &mut BTerm) { } } if draw { - if let Some(sprite) = render.sprite { - ctx.set_active_console(0); - ctx.add_sprite( - Rect::with_size( - entity_offset_x * 16 + x_offset * 16, - entity_offset_y * 16 + y_offset * 16, - 16, - 16 - ), - render.render_order, - RGBA::named(WHITE), - sprite - ); - ctx.set_active_console(ENTITY_LAYER); - } else { - ctx.set( - entity_offset_x + x_offset, - entity_offset_y + y_offset, - fg, - bg, - render.glyph - ); - } - if let Some(pool) = pools.get(*ent) { - if pool.hit_points.current < pool.hit_points.max { - ctx.set_active_console(HP_BAR_LAYER); - crate::gui::draw_lerping_bar( - ctx, - (entity_offset_x + x_offset) * 16 + 2, - (entity_offset_y + y_offset) * 16 - 1, - 14, - pool.hit_points.current, - pool.hit_points.max, - RGB::named(GREEN), - RGB::named(RED), - false, - false - ); - ctx.set_active_console(ENTITY_LAYER); - } - } + ctx.set( + entity_offset_x + x_offset, + entity_offset_y + y_offset, + fg, + bg, + render.glyph + ); } } } - ctx.set_active_console(TILE_LAYER); } } diff --git a/src/components.rs b/src/components.rs index b489abe..45ca1cf 100644 --- a/src/components.rs +++ b/src/components.rs @@ -41,7 +41,6 @@ pub struct OtherLevelPosition { #[derive(Component, ConvertSaveload, Clone)] pub struct Renderable { pub glyph: FontCharType, - pub sprite: Option, pub fg: RGB, pub bg: RGB, pub render_order: i32, @@ -244,16 +243,55 @@ pub enum BUC { Blessed, } +impl BUC { + pub fn noncursed(&self) -> bool { + match self { + BUC::Cursed => false, + _ => true, + } + } +} + #[derive(Component, Debug, Serialize, Deserialize, Eq, PartialEq, Hash, Clone)] pub struct Beatitude { pub buc: BUC, pub known: bool, } +#[derive(Debug, Serialize, Deserialize, Copy, Clone, PartialEq, Eq)] +pub enum ItemType { + Amulet, + Weapon, + Armour, + Comestible, + Scroll, + Spellbook, + Potion, + Ring, + Wand, +} + +impl ItemType { + pub fn string(&self) -> &str { + match self { + ItemType::Amulet => "Amulets", + ItemType::Weapon => "Weapons", + ItemType::Armour => "Armour", + ItemType::Comestible => "Comestibles", + ItemType::Scroll => "Scrolls", + ItemType::Spellbook => "Spellbooks", + ItemType::Potion => "Potions", + ItemType::Ring => "Rings", + ItemType::Wand => "Wands", + } + } +} + #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct Item { pub weight: f32, // in lbs pub value: f32, // base + pub category: ItemType, } #[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)] @@ -428,11 +466,45 @@ pub enum Intrinsic { Speed, // 4/3x speed multiplier } +impl Intrinsic { + pub fn describe(&self) -> &str { + match self { + Intrinsic::Regeneration => "regenerates health", + Intrinsic::Speed => "is hasted", + } + } +} + #[derive(Component, Serialize, Deserialize, Debug, Clone)] pub struct Intrinsics { pub list: HashSet, } +impl Intrinsics { + pub fn describe(&self) -> String { + let mut descriptions = Vec::new(); + for intrinsic in &self.list { + descriptions.push(intrinsic.describe()); + } + match descriptions.len() { + 0 => + unreachable!("describe() should never be called on an empty Intrinsics component."), + 1 => format!("It {}.", descriptions[0]), + _ => { + let last = descriptions.pop().unwrap(); + let joined = descriptions.join(", "); + format!("It {}, and {}.", joined, last) + } + } + } +} + +#[derive(Component, Serialize, Deserialize, Debug, Clone)] +pub struct IntrinsicChanged { + pub gained: HashSet, + pub lost: HashSet, +} + #[derive(Component, Debug, ConvertSaveload, Clone)] pub struct InflictsDamage { pub damage_type: DamageType, @@ -576,3 +648,20 @@ pub struct EntityMoved {} #[derive(Component, Debug, Serialize, Deserialize, Clone)] pub struct MultiAttack {} + +#[derive(Component, Debug, Serialize, Deserialize, Clone)] +pub struct Stackable {} + +#[derive(Component, Debug, Serialize, Deserialize, Clone)] +pub struct WantsToRemoveKey {} + +#[derive(Component, Debug, Serialize, Deserialize, Clone)] +pub struct WantsToDelete {} + +#[derive(Component, Debug, Serialize, Deserialize, Clone)] +pub struct Key { + pub idx: usize, +} + +#[derive(Component, Debug, Serialize, Deserialize, Clone)] +pub struct WantsToAssignKey {} diff --git a/src/damage_system.rs b/src/damage_system.rs index a4224a7..b0cc566 100644 --- a/src/damage_system.rs +++ b/src/damage_system.rs @@ -11,6 +11,8 @@ use super::{ Position, Renderable, RunState, + WantsToRemoveKey, + WantsToDelete, }; use bracket_lib::prelude::*; use specs::prelude::*; @@ -65,7 +67,17 @@ pub fn delete_the_dead(ecs: &mut World) { } } } - let (items_to_delete, loot_to_spawn) = handle_dead_entity_items(ecs, &dead); + let (mut items_to_delete, loot_to_spawn) = handle_dead_entity_items(ecs, &dead); + { + let entities = ecs.entities(); + let removekeys = ecs.read_storage::(); + let delete = ecs.read_storage::(); + // Add items marked for deletion to the list, but only if they've already had their + // key assignments handled, to ensurew we don't leave any dangling references behind. + for (e, _d, _r) in (&entities, &delete, !&removekeys).join() { + items_to_delete.push(e); + } + } for loot in loot_to_spawn { crate::raws::spawn_named_entity( &crate::raws::RAWS.lock().unwrap(), @@ -82,6 +94,7 @@ pub fn delete_the_dead(ecs: &mut World) { // For everything that died, increment the event log, and delete. for victim in dead { gamelog::record_event(events::EVENT::Turn(1)); + // TODO: Delete stuff from inventory? This should be handled elsewhere. ecs.delete_entity(victim).expect("Unable to delete."); } } diff --git a/src/data/messages.rs b/src/data/messages.rs index 89e39c8..7175b2a 100644 --- a/src/data/messages.rs +++ b/src/data/messages.rs @@ -25,6 +25,7 @@ pub const NUTRITION_BLESSED: &str = "Delicious"; pub const LEVELUP_PLAYER: &str = "Welcome to experience level"; pub const YOU_PICKUP_ITEM: &str = "You pick up the"; +pub const NO_MORE_KEYS: &str = "Your backpack cannot accomodate any more items"; pub const YOU_DROP_ITEM: &str = "You drop the"; pub const YOU_EQUIP_ITEM: &str = "You equip the"; pub const YOU_REMOVE_ITEM: &str = "You unequip your"; diff --git a/src/data/mod.rs b/src/data/mod.rs index cefe83f..8abda34 100644 --- a/src/data/mod.rs +++ b/src/data/mod.rs @@ -5,8 +5,3 @@ pub mod char_create; pub mod events; pub mod ids; pub mod names; -pub mod sprites; - -pub mod prelude { - pub use super::visuals::{ TILE_LAYER, ENTITY_LAYER, TEXT_LAYER, HP_BAR_LAYER }; -} diff --git a/src/data/sprites.rs b/src/data/sprites.rs deleted file mode 100644 index 1b9d7bf..0000000 --- a/src/data/sprites.rs +++ /dev/null @@ -1,119 +0,0 @@ -// Row 1 -pub const UNKN: usize = 0; -pub const UNKN2: usize = 1; -pub const UNKN3: usize = 2; -pub const CANDLE: usize = 3; -pub const CANDLE2: usize = 4; -pub const CANDLE3: usize = 5; -pub const CANDLE4: usize = 6; -pub const CANDLE5: usize = 7; -pub const CANDLE6: usize = 8; -pub const CAULDRON: usize = 9; -pub const CAULDRON2: usize = 10; -pub const POTS: usize = 11; -pub const POTS2: usize = 12; -pub const POT: usize = 13; -pub const SPIKES: usize = 14; -pub const SPIKES2: usize = 15; -// Row 2 -pub const WINDOW: usize = 16; -pub const DOOR: usize = 17; -pub const DOOR_OPEN: usize = 18; -pub const ROOF_BASE: usize = 19; -pub const ROOF_BASE2: usize = 20; -pub const ROOF: usize = 21; -pub const ROOF2: usize = 22; -pub const ROOF_CHIMNEY: usize = 23; -pub const SIGN: usize = 24; -pub const SIGN_BLACKSMITH: usize = 25; -pub const SIGN_POTION: usize = 26; -pub const SIGN_FURNITURE: usize = 27; -pub const WINDOW_LIT: usize = 28; -pub const STATUE_ANGEL: usize = 29; -pub const STATUE: usize = 30; -pub const STATUE_SPIDER: usize = 31; -// Row 3 -pub const UNKN4: usize = 32; -pub const UNKN5: usize = 33; -pub const UNKN6: usize = 34; -pub const UNKN7: usize = 35; -pub const UNKN8: usize = 36; -pub const TREE: usize = 37; -pub const TREE2: usize = 38; -pub const PATH_GRASS: usize = 39; -pub const PATH_GRASS_QUAD: usize = 40; -pub const PATH_GRASS_QUAD2: usize = 41; -pub const PATH_GRASS_QUAD3: usize = 42; -pub const CAMPFIRE: usize = 43; -pub const CAMPFIRE_LIT: usize = 44; -pub const CAMPFIRE_LIT2: usize = 45; // ANIMATE WITH % 2 AND SOMETHING TO DO WITH FRAME TIME -pub const THRONE: usize = 46; -pub const THRONE2: usize = 47; -// Row 4 -pub const BOOKSHELF: usize = 48; -pub const BOOKSHELF_EMPTY: usize = 49; -pub const BED: usize = 50; -pub const CHAIR: usize = 51; -pub const TABLE: usize = 52; -pub const TABLE_L: usize = 53; -pub const TABLE_M: usize = 54; -pub const TABLE_R: usize = 55; -pub const CHAIR_AT_TABLE_L: usize = 56; -pub const TABLE_M_PARCHMENT: usize = 57; -pub const CHAIR_AT_TABLE_R: usize = 58; -pub const TABLE_DARK: usize = 59; -pub const TABLE_DARK_SKULL: usize = 60; -pub const TABLE_DARK_L: usize = 61; -pub const TABLE_DARK_M: usize = 62; -pub const TABLE_DARK_R: usize = 63; -// Row 5 -pub const GRASS: usize = 64; -pub const GRASS2: usize = 65; -pub const GRASS3: usize = 66; -pub const GRASS4: usize = 67; -pub const GRASS5: usize = 68; -pub const MUSHROOM: usize = 69; -pub const MUSHROOM_PURPLE: usize = 70; -pub const MUSHROOM_ORANGE: usize = 71; -pub const LILYPAD: usize = 72; -pub const LILYPAD2: usize = 73; -pub const LILYPAD3: usize = 74; -pub const LILYPAD4: usize = 75; -pub const LILYPAD5: usize = 76; -pub const LILYPAD6: usize = 77; -pub const LILYPAD7: usize = 78; -pub const LILYPAD8: usize = 79; -// Row 6 (80-95) -// Row 7 (96-111) -// Row 8 (112-127) -pub const FLOOR_WOOD: usize = 124; -// Row 9 (128-143) -// Row 10 (144-159) -// Row 11 (160-175) -pub const WATER_DEEP: usize = 164; -// Row 12 (176-191) -// Row 13 (192-207) -// Row 14 (208-223) -pub const FLOOR_GRASS: usize = 216; -// Row 15 (224-239) -pub const FLOOR: usize = 224; -// Row 16 (240-255) -// Row 17 (256-271) -// Row 18 (272-287) -// Row 19 (288-303) -pub const WALL_BASE: usize = 288; -pub const WALL_BASE2: usize = 289; -pub const WALL_BASE3: usize = 290; -pub const WALL_BASE4: usize = 291; -pub const WALL_CLOTH_BASE: usize = 292; -pub const WALL_CRACKED_BASE: usize = 293; -pub const WALL: usize = 294; -pub const WALL2: usize = 295; -pub const WALL3: usize = 296; -pub const WALL4: usize = 297; -pub const WALL_CRACKED: usize = 298; -pub const WALL_CLOTH_H: usize = 299; -pub const STAIR_D: usize = 300; -pub const STAIR_A: usize = 301; -pub const BASIN: usize = 302; -pub const BASIN_EMPTY: usize = 303; diff --git a/src/data/visuals.rs b/src/data/visuals.rs index 26fa5ee..8f59a24 100644 --- a/src/data/visuals.rs +++ b/src/data/visuals.rs @@ -2,13 +2,6 @@ use bracket_lib::prelude::*; // POST-PROCESSING pub const WITH_DARKEN_BY_DISTANCE: bool = true; // If further away tiles should get darkened, instead of a harsh transition to non-visible. -pub const VIEWPORT_W: i32 = 69; -pub const VIEWPORT_H: i32 = 41; - -pub const TILE_LAYER: usize = 1; -pub const ENTITY_LAYER: usize = 2; -pub const TEXT_LAYER: usize = 3; -pub const HP_BAR_LAYER: usize = 4; pub const BRIGHTEN_FG_COLOUR_BY: i32 = 16; pub const GLOBAL_OFFSET_MIN_CLAMP: f32 = -0.5; diff --git a/src/effects/damage.rs b/src/effects/damage.rs index 74d1178..80885e2 100644 --- a/src/effects/damage.rs +++ b/src/effects/damage.rs @@ -184,7 +184,7 @@ fn get_death_message(ecs: &World, source: Entity) -> String { result.push_str(format!("{}", PLAYER_DIED_SUICIDE).as_str()); } else if let Some(name) = ecs.read_storage::().get(source) { result.push_str( - format!("{} {}", PLAYER_DIED_NAMED_ATTACKER, with_article(&name.name)).as_str() + format!("{} {}", PLAYER_DIED_NAMED_ATTACKER, with_article(name.name.clone())).as_str() ); } else { result.push_str(format!("{}", PLAYER_DIED_UNKNOWN).as_str()); diff --git a/src/effects/intrinsics.rs b/src/effects/intrinsics.rs new file mode 100644 index 0000000..01776e1 --- /dev/null +++ b/src/effects/intrinsics.rs @@ -0,0 +1,11 @@ +use super::{ EffectSpawner, EffectType }; +use specs::prelude::*; + +pub fn add_intrinsic(ecs: &mut World, effect: &EffectSpawner, target: Entity) { + let intrinsic = if let EffectType::AddIntrinsic { intrinsic } = &effect.effect_type { + intrinsic + } else { + unreachable!("add_intrinsic() called with the wrong EffectType") + }; + add_intr!(ecs, target, *intrinsic); +} diff --git a/src/effects/mod.rs b/src/effects/mod.rs index c23b52b..5552f5a 100644 --- a/src/effects/mod.rs +++ b/src/effects/mod.rs @@ -4,13 +4,14 @@ use bracket_lib::prelude::*; use specs::prelude::*; use std::collections::VecDeque; use std::sync::Mutex; -use crate::components::DamageType; +use crate::components::*; mod damage; mod hunger; mod particles; mod targeting; mod triggers; +mod intrinsics; pub use targeting::aoe_tiles; @@ -51,6 +52,9 @@ pub enum EffectType { ModifyNutrition { amount: i32, }, + AddIntrinsic { + intrinsic: Intrinsic, + }, TriggerFire { trigger: Entity, }, @@ -153,6 +157,7 @@ fn tile_effect_hits_entities(effect: &EffectType) -> bool { EffectType::Healing { .. } => true, EffectType::ModifyNutrition { .. } => true, EffectType::Confusion { .. } => true, + EffectType::AddIntrinsic { .. } => true, _ => false, } } @@ -175,6 +180,7 @@ fn affect_entity(ecs: &mut World, effect: &EffectSpawner, target: Entity) { } EffectType::EntityDeath => damage::entity_death(ecs, effect, target), EffectType::ModifyNutrition { .. } => hunger::modify_nutrition(ecs, effect, target), + EffectType::AddIntrinsic { .. } => intrinsics::add_intrinsic(ecs, effect, target), _ => {} } } diff --git a/src/effects/triggers.rs b/src/effects/triggers.rs index ac38ccb..cb4e5d3 100644 --- a/src/effects/triggers.rs +++ b/src/effects/triggers.rs @@ -1,4 +1,4 @@ -use super::{ add_effect, get_noncursed, particles, spatial, EffectType, Entity, Targets, World }; +use super::{ add_effect, particles, spatial, EffectType, Entity, Targets, World }; use crate::{ gamelog, gui::item_colour_ecs, @@ -33,6 +33,8 @@ use crate::{ KnownSpells, Position, Viewshed, + WantsToRemoveKey, + WantsToDelete, }; use crate::data::messages::*; use bracket_lib::prelude::*; @@ -57,7 +59,10 @@ pub fn item_trigger(source: Option, item: Entity, target: &Targets, ecs: let did_something = event_trigger(source, item, target, ecs); // If it's a consumable, delete it if did_something && ecs.read_storage::().get(item).is_some() { - ecs.entities().delete(item).expect("Failed to delete item"); + let mut removekey = ecs.write_storage::(); + removekey.insert(item, WantsToRemoveKey {}).expect("Unable to insert WantsToRemoveKey"); + let mut delete = ecs.write_storage::(); + delete.insert(item, WantsToDelete {}).expect("Unable to insert WantsToDelete"); } } @@ -205,7 +210,7 @@ fn handle_healing( healing_item.modifier; add_effect( event.source, - EffectType::Healing { amount: roll, increment_max: get_noncursed(&event.buc) }, + EffectType::Healing { amount: roll, increment_max: event.buc.noncursed() }, event.target.clone() ); for target in get_entity_targets(&event.target) { @@ -218,9 +223,7 @@ fn handle_healing( let renderables = ecs.read_storage::(); if ecs.read_storage::().get(target).is_some() { logger = logger - .colour(renderable_colour(&renderables, target)) .append("You") - .colour(WHITE) .append(HEAL_PLAYER_HIT) .buc(event.buc.clone(), None, Some(HEAL_PLAYER_HIT_BLESSED)); } else { @@ -262,9 +265,7 @@ fn handle_damage( let player_viewshed = viewsheds.get(*ecs.fetch::()).unwrap(); if ecs.read_storage::().get(target).is_some() { logger = logger - .colour(renderable_colour(&renderables, target)) .append("You") - .colour(WHITE) .append(DAMAGE_PLAYER_HIT); event.log = true; } else if diff --git a/src/gamelog/events.rs b/src/gamelog/events.rs index bef5ff6..3e0006f 100644 --- a/src/gamelog/events.rs +++ b/src/gamelog/events.rs @@ -126,7 +126,7 @@ pub fn record_event(event: EVENT) { new_event = format!("Discovered {}", name); } EVENT::Identified(name) => { - new_event = format!("Identified {}", name); + new_event = format!("Identified {}", crate::gui::with_article(name)); } EVENT::PlayerDied(str) => { // Generating the String is handled in the death effect, to avoid passing the ecs here. diff --git a/src/gui/character_creation.rs b/src/gui/character_creation.rs index bc6e68e..da1ecdb 100644 --- a/src/gui/character_creation.rs +++ b/src/gui/character_creation.rs @@ -28,7 +28,6 @@ use bracket_lib::prelude::*; use serde::{ Deserialize, Serialize }; use specs::prelude::*; use std::collections::HashMap; -use crate::data::prelude::*; #[derive(Serialize, Deserialize, Copy, Clone, PartialEq)] pub enum Ancestry { @@ -113,7 +112,6 @@ pub enum CharCreateResult { /// Handles the player character creation screen. pub fn character_creation(gs: &mut State, ctx: &mut BTerm) -> CharCreateResult { - ctx.set_active_console(TEXT_LAYER); let runstate = gs.ecs.fetch::(); let mut x = 2; @@ -247,7 +245,6 @@ pub fn character_creation(gs: &mut State, ctx: &mut BTerm) -> CharCreateResult { } } } - ctx.set_active_console(TILE_LAYER); return CharCreateResult::NoSelection { ancestry: Ancestry::Human, class: Class::Fighter }; } @@ -273,7 +270,6 @@ pub fn setup_player_ancestry(ecs: &mut World, ancestry: Ancestry) { renderables .insert(*player, Renderable { glyph: to_cp437(DWARF_GLYPH), - sprite: None, // TODO: Dwarf sprite fg: RGB::named(DWARF_COLOUR), bg: RGB::named(BLACK), render_order: 0, @@ -285,7 +281,6 @@ pub fn setup_player_ancestry(ecs: &mut World, ancestry: Ancestry) { renderables .insert(*player, Renderable { glyph: to_cp437(ELF_GLYPH), - sprite: None, // TODO: Elf sprite fg: RGB::named(ELF_COLOUR), bg: RGB::named(BLACK), render_order: 0, @@ -311,7 +306,6 @@ pub fn setup_player_ancestry(ecs: &mut World, ancestry: Ancestry) { renderables .insert(*player, Renderable { glyph: to_cp437(CATFOLK_GLYPH), - sprite: None, // TODO: Catfolk sprite fg: RGB::named(CATFOLK_COLOUR), bg: RGB::named(BLACK), render_order: 0, diff --git a/src/gui/farlook.rs b/src/gui/farlook.rs index 045b172..c8f6312 100644 --- a/src/gui/farlook.rs +++ b/src/gui/farlook.rs @@ -1,11 +1,4 @@ -use super::{ - State, - RunState, - tooltip::draw_tooltips, - camera::get_screen_bounds, - VIEWPORT_H, - VIEWPORT_W, -}; +use super::{ State, RunState, tooltip::draw_tooltips, camera::get_screen_bounds }; use bracket_lib::prelude::*; #[derive(PartialEq, Copy, Clone)] @@ -30,8 +23,9 @@ pub fn show_farlook(gs: &mut State, ctx: &mut BTerm) -> FarlookResult { ); if let RunState::Farlook { x, y } = *runstate { - let x = x.clamp(x_offset, x_offset - 1 + VIEWPORT_W); - let y = y.clamp(y_offset, y_offset - 1 + VIEWPORT_H); + let (screen_x, screen_y) = (69, 41); + let x = x.clamp(x_offset, x_offset - 1 + (screen_x as i32)); + let y = y.clamp(y_offset, y_offset - 1 + (screen_y as i32)); ctx.set(x, y, RGB::named(WHITE), RGB::named(BLACK), to_cp437('X')); draw_tooltips(&gs.ecs, ctx, Some((x, y))); diff --git a/src/gui/identify_menu.rs b/src/gui/identify_menu.rs index 14e0686..31ce8d7 100644 --- a/src/gui/identify_menu.rs +++ b/src/gui/identify_menu.rs @@ -3,10 +3,10 @@ use super::{ item_colour_ecs, obfuscate_name_ecs, print_options, - renderable_colour, + unique_ecs, + check_key, + letter_to_option, ItemMenuResult, - UniqueInventoryItem, - BUC, }; use crate::{ gamelog, @@ -19,11 +19,12 @@ use crate::{ Name, ObfuscatedName, Renderable, + Key, states::state::*, }; use bracket_lib::prelude::*; use specs::prelude::*; -use std::collections::BTreeMap; +use std::collections::HashMap; /// Handles the Identify menu. pub fn identify(gs: &mut State, ctx: &mut BTerm) -> (ItemMenuResult, Option) { @@ -37,38 +38,41 @@ pub fn identify(gs: &mut State, ctx: &mut BTerm) -> (ItemMenuResult, Option(); let renderables = gs.ecs.read_storage::(); let beatitudes = gs.ecs.read_storage::(); + let keys = gs.ecs.read_storage::(); let build_identify_iterator = || { - (&entities, &items, &renderables, &names).join().filter(|(item_entity, _i, _r, n)| { - // If not owned by the player, return false. - let mut keep = false; - if let Some(bp) = backpack.get(*item_entity) { - if bp.owner == *player_entity { - keep = true; + (&entities, &items, &renderables, &names, &keys) + .join() + .filter(|(item_entity, _i, _r, n, _k)| { + // If not owned by the player, return false. + let mut keep = false; + if let Some(bp) = backpack.get(*item_entity) { + if bp.owner == *player_entity { + keep = true; + } } - } - // If not equipped by the player, return false. - if let Some(equip) = equipped.get(*item_entity) { - if equip.owner == *player_entity { - keep = true; + // If not equipped by the player, return false. + if let Some(equip) = equipped.get(*item_entity) { + if equip.owner == *player_entity { + keep = true; + } } - } - if !keep { - return false; - } - // If not obfuscated, or already identified, return false. - if - (!obfuscated.get(*item_entity).is_some() || - dm.identified_items.contains(&n.name)) && - beatitudes - .get(*item_entity) - .map(|beatitude| beatitude.known) - .unwrap_or(true) - { - return false; - } - return true; - }) + if !keep { + return false; + } + // If not obfuscated, or already identified, return false. + if + (!obfuscated.get(*item_entity).is_some() || + dm.identified_items.contains(&n.name)) && + beatitudes + .get(*item_entity) + .map(|beatitude| beatitude.known) + .unwrap_or(true) + { + return false; + } + return true; + }) }; // Build list of items to display @@ -91,34 +95,15 @@ pub fn identify(gs: &mut State, ctx: &mut BTerm) -> (ItemMenuResult, Option().get(entity) - { - match beatitude.buc { - BUC::Blessed => 1, - BUC::Uncursed => 2, - BUC::Cursed => 3, - } - } else { - 0 - }; - let unique_item = UniqueInventoryItem { - display_name: super::DisplayName { singular: singular.clone(), plural: plural.clone() }, - rgb: item_colour_ecs(&gs.ecs, entity), - renderables: renderable_colour(&renderables, entity), - glyph: renderable.glyph, - beatitude_status: beatitude_status, - name: name.name.clone(), - }; + let mut player_inventory: super::PlayerInventory = HashMap::new(); + for (entity, _i, _r, _n, key) in build_identify_iterator() { + let unique_item = unique_ecs(&gs.ecs, entity); player_inventory .entry(unique_item) - .and_modify(|(_e, count)| { - *count += 1; + .and_modify(|slot| { + slot.count += 1; }) - .or_insert((entity, 1)); + .or_insert(super::InventorySlot { item: entity, count: 1, idx: key.idx }); } // Get display args let width = get_max_inventory_width(&player_inventory); @@ -133,7 +118,7 @@ pub fn identify(gs: &mut State, ctx: &mut BTerm) -> (ItemMenuResult, Option (ItemMenuResult::NoResponse, None), @@ -141,21 +126,17 @@ pub fn identify(gs: &mut State, ctx: &mut BTerm) -> (ItemMenuResult, Option (ItemMenuResult::Cancel, None), _ => { - let selection = letter_to_option(key); - if selection > -1 && selection < (count as i32) { - let item = player_inventory - .iter() - .nth(selection as usize) - .unwrap().1.0; - gamelog::Logger - ::new() - .append("You identify the") - .colour(item_colour_ecs(&gs.ecs, item)) - .append_n(obfuscate_name_ecs(&gs.ecs, item).0) - .colour(WHITE) - .append("!") - .log(); - return (ItemMenuResult::Selected, Some(item)); + let selection = letter_to_option::letter_to_option(key, ctx.shift); + if selection != -1 && check_key(selection as usize) { + // Get the first entity with a Key {} component that has an idx matching "selection". + let entities = gs.ecs.entities(); + let keyed_items = gs.ecs.read_storage::(); + let backpack = gs.ecs.read_storage::(); + for (e, key, _b) in (&entities, &keyed_items, &backpack).join() { + if key.idx == (selection as usize) { + return (ItemMenuResult::Selected, Some(e)); + } + } } (ItemMenuResult::NoResponse, None) } diff --git a/src/gui/mod.rs b/src/gui/mod.rs index 65482af..7604527 100644 --- a/src/gui/mod.rs +++ b/src/gui/mod.rs @@ -32,21 +32,23 @@ use super::{ Skills, Viewshed, BUC, + Key, + Item, + ItemType, data::ids::get_local_col, }; -use crate::data::prelude::*; use crate::data::entity::CARRY_CAPACITY_PER_STRENGTH; use crate::data::visuals::{ TARGETING_LINE_COL, TARGETING_CURSOR_COL, TARGETING_AOE_COL, TARGETING_VALID_COL, - VIEWPORT_W, - VIEWPORT_H, }; use bracket_lib::prelude::*; use specs::prelude::*; -use std::collections::BTreeMap; +use std::collections::HashMap; +use crate::invkeys::check_key; + mod character_creation; mod cheat_menu; mod letter_to_option; @@ -85,33 +87,121 @@ pub fn draw_lerping_bar( n: i32, max: i32, full_colour: RGB, - empty_colour: RGB, - with_text: bool, - with_bg: bool + empty_colour: RGB ) { let percent = (n as f32) / (max as f32); let fill_width = (percent * (width as f32)) as i32; let bg = empty_colour.lerp(full_colour, percent); - let black = RGB::named(BLACK); + let fg = RGB::named(BLACK); for x in 0..width { if x <= fill_width { - ctx.print_color(sx + x, sy, black, bg, ' '); - } else if with_bg { - ctx.print_color(sx + x, sy, black, black, ' '); + ctx.print_color(sx + x, sy, fg, bg, " "); + } else { + ctx.print_color(sx + x, sy, RGB::named(BLACK), RGB::named(BLACK), " "); } } - if with_text { - ctx.print(sx - 1, sy, "["); - let health = format!("{}/{}", n, max); - ctx.print_color(sx + 1, sy, black, bg, health); - ctx.print(sx + width, sy, "]"); + ctx.print(sx - 1, sy, "["); + let health = format!("{}/{}", n, max); + ctx.print_color(sx + 1, sy, fg, bg, health); + ctx.print(sx + width, sy, "]"); +} + +fn draw_xp(ctx: &mut BTerm, pt: Point, pool: &Pools) { + ctx.print_color( + pt.x, + pt.y, + RGB::named(WHITE), + RGB::named(BLACK), + format!("XP{}/{}", pool.level, pool.xp) + ); +} + +fn calc_ac(ecs: &World, skills: &Skills, stats: &Pools, attr: &Attributes) -> i32 { + let skill_ac_bonus = gamesystem::skill_bonus(Skill::Defence, skills); + let mut armour_ac_bonus = 0; + let equipped = ecs.read_storage::(); + let ac = ecs.read_storage::(); + let player_entity = ecs.fetch::(); + for (wielded, ac) in (&equipped, &ac).join() { + if wielded.owner == *player_entity { + armour_ac_bonus += ac.amount; + } + } + stats.bac - attr.dexterity.bonus / 2 - skill_ac_bonus - armour_ac_bonus +} + +fn draw_ac(ctx: &mut BTerm, pt: Point, ac: i32) { + ctx.print_color(pt.x, pt.y, RGB::named(PINK), RGB::named(BLACK), "AC"); + ctx.print_color(pt.x + 2, pt.y, RGB::named(WHITE), RGB::named(BLACK), ac); +} + +fn draw_attributes(ctx: &mut BTerm, pt: Point, a: &Attributes) { + ctx.print_color(pt.x, pt.y, RGB::named(RED), RGB::named(BLACK), "STR"); + ctx.print_color(pt.x + 3, pt.y, RGB::named(WHITE), RGB::named(BLACK), a.strength.base); + ctx.print_color(pt.x + 7, pt.y, RGB::named(GREEN), RGB::named(BLACK), "DEX"); + ctx.print_color(pt.x + 10, pt.y, RGB::named(WHITE), RGB::named(BLACK), a.dexterity.base); + ctx.print_color(pt.x + 14, pt.y, RGB::named(ORANGE), RGB::named(BLACK), "CON"); + ctx.print_color(pt.x + 17, pt.y, RGB::named(WHITE), RGB::named(BLACK), a.constitution.base); + ctx.print_color(pt.x, 54, RGB::named(CYAN), RGB::named(BLACK), "INT"); + ctx.print_color(pt.x + 3, pt.y + 1, RGB::named(WHITE), RGB::named(BLACK), a.intelligence.base); + ctx.print_color(pt.x + 7, pt.y + 1, RGB::named(YELLOW), RGB::named(BLACK), "WIS"); + ctx.print_color(pt.x + 10, pt.y + 1, RGB::named(WHITE), RGB::named(BLACK), a.wisdom.base); + ctx.print_color(pt.x + 14, pt.y + 1, RGB::named(PURPLE), RGB::named(BLACK), "CHA"); + ctx.print_color(pt.x + 17, pt.y + 1, RGB::named(WHITE), RGB::named(BLACK), a.charisma.base); +} + +fn draw_hunger(ctx: &mut BTerm, pt: Point, hunger: &HungerClock) { + match hunger.state { + HungerState::Satiated => { + ctx.print_color_right( + pt.x, + pt.y, + get_hunger_colour(hunger.state), + RGB::named(BLACK), + "Satiated" + ); + } + HungerState::Normal => {} + HungerState::Hungry => { + ctx.print_color_right( + pt.x, + pt.y, + get_hunger_colour(hunger.state), + RGB::named(BLACK), + "Hungry" + ); + } + HungerState::Weak => { + ctx.print_color_right( + pt.x, + pt.y, + get_hunger_colour(hunger.state), + RGB::named(BLACK), + "Weak" + ); + } + HungerState::Fainting => { + ctx.print_color_right( + pt.x, + pt.y, + get_hunger_colour(hunger.state), + RGB::named(BLACK), + "Fainting" + ); + } + HungerState::Starving => { + ctx.print_color_right( + pt.x, + pt.y, + get_hunger_colour(hunger.state), + RGB::named(BLACK), + "Starving" + ); + } } } -pub const TEXT_FONT_MOD: i32 = 2; - pub fn draw_ui(ecs: &World, ctx: &mut BTerm) { - ctx.set_active_console(TEXT_LAYER); // Render stats let pools = ecs.read_storage::(); let attributes = ecs.read_storage::(); @@ -129,138 +219,35 @@ pub fn draw_ui(ecs: &World, ctx: &mut BTerm) { // Draw hp/mana bars draw_lerping_bar( ctx, - 2 * TEXT_FONT_MOD, + 2, 53, - 22 * TEXT_FONT_MOD, + 22, stats.hit_points.current, stats.hit_points.max, RGB::from_u8(0, 255, 0), - RGB::from_u8(255, 0, 0), - true, - true + RGB::from_u8(255, 0, 0) ); draw_lerping_bar( ctx, - 2 * TEXT_FONT_MOD, + 2, 54, - 22 * TEXT_FONT_MOD, + 22, stats.mana.current, stats.mana.max, RGB::named(BLUE), - RGB::named(BLACK), - true, - true + RGB::named(BLACK) ); - // Draw AC - let skill_ac_bonus = gamesystem::skill_bonus(Skill::Defence, &*skills); - let mut armour_ac_bonus = 0; - let equipped = ecs.read_storage::(); - let ac = ecs.read_storage::(); - let player_entity = ecs.fetch::(); - for (wielded, ac) in (&equipped, &ac).join() { - if wielded.owner == *player_entity { - armour_ac_bonus += ac.amount; - } - } - let armour_class = - stats.bac - attributes.dexterity.bonus / 2 - skill_ac_bonus - armour_ac_bonus; - ctx.print_color(26 * TEXT_FONT_MOD, 53, RGB::named(PINK), RGB::named(BLACK), "AC"); - ctx.print_color(28 * TEXT_FONT_MOD, 53, RGB::named(WHITE), RGB::named(BLACK), armour_class); - // Draw level - ctx.print_color( - 26 * TEXT_FONT_MOD, - 54, - RGB::named(WHITE), - RGB::named(BLACK), - format!("XP{}/{}", stats.level, stats.xp) - ); - // Draw attributes - let x = 38 * TEXT_FONT_MOD; - ctx.print_color(x, 53, RGB::named(RED), RGB::named(BLACK), "STR"); - ctx.print_color(x + 3, 53, RGB::named(WHITE), RGB::named(BLACK), attributes.strength.base); - ctx.print_color(x + 7, 53, RGB::named(GREEN), RGB::named(BLACK), "DEX"); - ctx.print_color( - x + 10, - 53, - RGB::named(WHITE), - RGB::named(BLACK), - attributes.dexterity.base - ); - ctx.print_color(x + 14, 53, RGB::named(ORANGE), RGB::named(BLACK), "CON"); - ctx.print_color( - x + 17, - 53, - RGB::named(WHITE), - RGB::named(BLACK), - attributes.constitution.base - ); - ctx.print_color(x, 54, RGB::named(CYAN), RGB::named(BLACK), "INT"); - ctx.print_color( - x + 3, - 54, - RGB::named(WHITE), - RGB::named(BLACK), - attributes.intelligence.base - ); - ctx.print_color(x + 7, 54, RGB::named(YELLOW), RGB::named(BLACK), "WIS"); - ctx.print_color(x + 10, 54, RGB::named(WHITE), RGB::named(BLACK), attributes.wisdom.base); - ctx.print_color(x + 14, 54, RGB::named(PURPLE), RGB::named(BLACK), "CHA"); - ctx.print_color(x + 17, 54, RGB::named(WHITE), RGB::named(BLACK), attributes.charisma.base); - // Draw hunger - match hunger.state { - HungerState::Satiated => { - ctx.print_color_right( - (VIEWPORT_W + 1) * TEXT_FONT_MOD, - 53, - get_hunger_colour(hunger.state), - RGB::named(BLACK), - "Satiated" - ); - } - HungerState::Normal => {} - HungerState::Hungry => { - ctx.print_color_right( - (VIEWPORT_W + 1) * TEXT_FONT_MOD, - 53, - get_hunger_colour(hunger.state), - RGB::named(BLACK), - "Hungry" - ); - } - HungerState::Weak => { - ctx.print_color_right( - (VIEWPORT_W + 1) * TEXT_FONT_MOD, - 53, - get_hunger_colour(hunger.state), - RGB::named(BLACK), - "Weak" - ); - } - HungerState::Fainting => { - ctx.print_color_right( - (VIEWPORT_W + 1) * TEXT_FONT_MOD, - 53, - get_hunger_colour(hunger.state), - RGB::named(BLACK), - "Fainting" - ); - } - HungerState::Starving => { - ctx.print_color_right( - (VIEWPORT_W + 1) * TEXT_FONT_MOD, - 53, - get_hunger_colour(hunger.state), - RGB::named(BLACK), - "Starving" - ); - } - } + draw_ac(ctx, Point::new(26, 53), calc_ac(ecs, skills, stats, attributes)); + draw_xp(ctx, Point::new(26, 54), stats); + draw_attributes(ctx, Point::new(38, 53), attributes); + draw_hunger(ctx, Point::new(70, 53), hunger); // Burden + let player_entity = ecs.fetch::(); if let Some(burden) = burden.get(*player_entity) { match burden.level { crate::BurdenLevel::Burdened => { ctx.print_color_right( - (VIEWPORT_W + 1) * TEXT_FONT_MOD, + 70, 50, RGB::named(BROWN1), RGB::named(BLACK), @@ -269,7 +256,7 @@ pub fn draw_ui(ecs: &World, ctx: &mut BTerm) { } crate::BurdenLevel::Strained => { ctx.print_color_right( - (VIEWPORT_W + 1) * TEXT_FONT_MOD, + 70, 50, RGB::named(ORANGE), RGB::named(BLACK), @@ -277,88 +264,27 @@ pub fn draw_ui(ecs: &World, ctx: &mut BTerm) { ); } crate::BurdenLevel::Overloaded => { - ctx.print_color_right( - (VIEWPORT_W + 1) * TEXT_FONT_MOD, - 50, - RGB::named(RED), - RGB::named(BLACK), - "Overloaded" - ); + ctx.print_color_right(70, 50, RGB::named(RED), RGB::named(BLACK), "Overloaded"); } } } if stats.god { - ctx.print_color( - 20 * TEXT_FONT_MOD, - 20, - RGB::named(YELLOW), - RGB::named(BLACK), - "--- GODMODE: ON ---" - ); + ctx.print_color(20, 20, RGB::named(YELLOW), RGB::named(BLACK), "--- GODMODE: ON ---"); } // Draw equipment - let renderables = ecs.read_storage::(); - let mut equipment: Vec<(String, RGB, RGB, FontCharType)> = Vec::new(); - let entities = ecs.entities(); - for (entity, _equipped, renderable) in (&entities, &equipped, &renderables) - .join() - .filter(|item| item.1.owner == *player_entity) { - equipment.push(( - obfuscate_name_ecs(ecs, entity).0, - RGB::named(item_colour_ecs(ecs, entity)), - renderable.fg, - renderable.glyph, - )); - } let mut y = 1; + let equipment = items(&ecs, Filter::Equipped); if !equipment.is_empty() { - ctx.print_color( - (VIEWPORT_W + 3) * TEXT_FONT_MOD, - y, - RGB::named(BLACK), - RGB::named(WHITE), - "Equipment" - ); - let mut j = 0; - for item in equipment { - y += 1; - ctx.set( - (VIEWPORT_W + 3) * TEXT_FONT_MOD, - y, - RGB::named(YELLOW), - RGB::named(BLACK), - 97 + (j as FontCharType) - ); - j += 1; - ctx.set((VIEWPORT_W + 3) * TEXT_FONT_MOD + 2, y, item.2, RGB::named(BLACK), item.3); - ctx.print_color( - (VIEWPORT_W + 3) * TEXT_FONT_MOD + 4, - y, - item.1, - RGB::named(BLACK), - &item.0 - ); - ctx.print_color( - (VIEWPORT_W + 3) * TEXT_FONT_MOD + 4 + (item.0.len() as i32) + 1, - y, - RGB::named(WHITE), - RGB::named(BLACK), - "(worn)" - ); - } - y += 2; + ctx.print_color(72, y, RGB::named(BLACK), RGB::named(WHITE), "Equipment"); + y += 1; + y = print_options(&ecs, &equipment, 72, y, ctx); + y += 1; } - // Draw consumables + // Draw backpack + ctx.print_color(72, y, RGB::named(BLACK), RGB::named(WHITE), "Backpack"); ctx.print_color( - (VIEWPORT_W + 3) * TEXT_FONT_MOD, - y, - RGB::named(BLACK), - RGB::named(WHITE), - "Backpack" - ); - ctx.print_color( - (VIEWPORT_W + 12) * TEXT_FONT_MOD, + 81, y, RGB::named(WHITE), RGB::named(BLACK), @@ -370,32 +296,26 @@ pub fn draw_ui(ecs: &World, ctx: &mut BTerm) { ) ); y += 1; - let player_inventory = get_player_inventory(&ecs); - y = print_options(&player_inventory, (VIEWPORT_W + 3) * TEXT_FONT_MOD, y, ctx).0; + let backpack = items(&ecs, Filter::Backpack); + y = print_options(&ecs, &backpack, 72, y, ctx); // Draw spells - if we have any -- NYI! if let Some(known_spells) = ecs.read_storage::().get(*player_entity) { y += 1; // Draw known spells - ctx.print_color( - (VIEWPORT_W + 3) * TEXT_FONT_MOD, - y, - RGB::named(BLACK), - RGB::named(WHITE), - "Known Spells" - ); + ctx.print_color(72, y, RGB::named(BLACK), RGB::named(WHITE), "Known Spells"); y += 1; let mut index = 1; for spell in known_spells.list.iter() { ctx.print_color( - (VIEWPORT_W + 3) * TEXT_FONT_MOD, + 72, y, RGB::named(YELLOW), RGB::named(BLACK), &format!("{}", index) ); ctx.print_color( - (VIEWPORT_W + 3) * TEXT_FONT_MOD + 2, + 74, y, RGB::named(CYAN), RGB::named(BLACK), @@ -452,34 +372,22 @@ pub fn draw_ui(ecs: &World, ctx: &mut BTerm) { if !seen_entities.is_empty() { y += 1; - ctx.print_color( - (VIEWPORT_W + 3) * TEXT_FONT_MOD, - y, - RGB::named(BLACK), - RGB::named(WHITE), - "In View" - ); + ctx.print_color(72, y, RGB::named(BLACK), RGB::named(WHITE), "In View"); for entity in seen_entities { y += 1; - ctx.set((VIEWPORT_W + 3) * TEXT_FONT_MOD, y, entity.2, RGB::named(BLACK), entity.3); - ctx.print_color( - (VIEWPORT_W + 3) * TEXT_FONT_MOD + 2, - y, - entity.1, - RGB::named(BLACK), - entity.0 - ); + ctx.set(72, y, entity.2, RGB::named(BLACK), entity.3); + ctx.print_color(74, y, entity.1, RGB::named(BLACK), entity.0); } } } // Render the message log at [1, 7], ascending, with 7 lines and a max width of 68. gamelog::print_log( - &mut BACKEND_INTERNAL.lock().consoles[TEXT_LAYER].console, - Point::new(1 * TEXT_FONT_MOD, 7), + &mut BACKEND_INTERNAL.lock().consoles[0].console, + Point::new(1, 7), false, 7, - (VIEWPORT_W - 1) * TEXT_FONT_MOD + 68 ); // Render id @@ -489,18 +397,12 @@ pub fn draw_ui(ecs: &World, ctx: &mut BTerm) { } else { format!("{}", map.short_name) }; - ctx.print_color_right( - (VIEWPORT_W + 1) * TEXT_FONT_MOD, - 54, - get_local_col(map.id), - RGB::named(BLACK), - &id - ); + ctx.print_color_right(70, 54, get_local_col(map.id), RGB::named(BLACK), &id); // Render turn let turns = crate::gamelog::get_event_count(EVENT::COUNT_TURN); ctx.print_color_right( - VIEWPORT_W * TEXT_FONT_MOD - (id.len() as i32), + 69 - id.len(), 54, RGB::named(YELLOW), RGB::named(BLACK), @@ -508,39 +410,10 @@ pub fn draw_ui(ecs: &World, ctx: &mut BTerm) { ); // Boxes and tooltips last, so they draw over everything else. - ctx.draw_hollow_box( - 0 * TEXT_FONT_MOD, - 0, - (VIEWPORT_W + 1) * TEXT_FONT_MOD, - 8, - RGB::named(WHITE), - RGB::named(BLACK) - ); // Log box - ctx.draw_hollow_box( - 0 * TEXT_FONT_MOD, - 9, - (VIEWPORT_W + 1) * TEXT_FONT_MOD, - 42, - RGB::named(WHITE), - RGB::named(BLACK) - ); // Camera box - ctx.draw_hollow_box( - 0 * TEXT_FONT_MOD, - 52, - (VIEWPORT_W + 1) * TEXT_FONT_MOD, - 3, - RGB::named(WHITE), - RGB::named(BLACK) - ); // Stats box - ctx.draw_hollow_box( - (VIEWPORT_W + 2) * TEXT_FONT_MOD, - 0, - 33 * TEXT_FONT_MOD, - 55, - RGB::named(WHITE), - RGB::named(BLACK) - ); // Side box - ctx.set_active_console(TILE_LAYER); + ctx.draw_hollow_box(0, 0, 70, 8, RGB::named(WHITE), RGB::named(BLACK)); // Log box + ctx.draw_hollow_box(0, 9, 70, 42, RGB::named(WHITE), RGB::named(BLACK)); // Camera box + ctx.draw_hollow_box(0, 52, 70, 3, RGB::named(WHITE), RGB::named(BLACK)); // Stats box + ctx.draw_hollow_box(71, 0, 33, 55, RGB::named(WHITE), RGB::named(BLACK)); // Side box tooltip::draw_tooltips(ecs, ctx, None); } @@ -608,46 +481,46 @@ pub enum ItemMenuResult { } pub fn print_options( + _ecs: &World, inventory: &PlayerInventory, mut x: i32, mut y: i32, ctx: &mut BTerm -) -> (i32, i32) { - let mut j = 0; +) -> i32 { let initial_x: i32 = x; - let mut width: i32 = -1; - for (item, (_e, item_count)) in inventory { + let mut sorted: Vec<_> = inventory.iter().collect(); + sorted.sort_by(|a, b| a.1.idx.cmp(&b.1.idx)); + + for (info, slot) in sorted { x = initial_x; // Print the character required to access this item. i.e. (a) - if j < 26 { - ctx.set(x, y, RGB::named(YELLOW), RGB::named(BLACK), 97 + (j as FontCharType)); + if slot.idx < 26 { + ctx.set(x, y, RGB::named(YELLOW), RGB::named(BLACK), 97 + slot.idx); } else { // If we somehow have more than 26, start using capitals - ctx.set(x, y, RGB::named(YELLOW), RGB::named(BLACK), 65 - 26 + (j as FontCharType)); + ctx.set(x, y, RGB::named(YELLOW), RGB::named(BLACK), 65 - 26 + slot.idx); } x += 2; - let fg = RGB::from_u8(item.renderables.0, item.renderables.1, item.renderables.2); - ctx.set(x, y, fg, RGB::named(BLACK), item.glyph); + let fg = RGB::from_u8(info.renderables.0, info.renderables.1, info.renderables.2); + ctx.set(x, y, fg, RGB::named(BLACK), info.glyph); x += 2; - let fg = RGB::from_u8(item.rgb.0, item.rgb.1, item.rgb.2); - if item_count > &1 { + let fg = RGB::from_u8(info.rgb.0, info.rgb.1, info.rgb.2); + if slot.count > 1 { // If more than one, print the number and pluralise // i.e. (a) 3 daggers - ctx.print_color(x, y, fg, RGB::named(BLACK), item_count); + ctx.print_color(x, y, fg, RGB::named(BLACK), slot.count); x += 2; - ctx.print_color(x, y, fg, RGB::named(BLACK), item.display_name.plural.to_string()); - let this_width = x - initial_x + (item.display_name.plural.len() as i32); - width = if width > this_width { width } else { this_width }; + ctx.print_color(x, y, fg, RGB::named(BLACK), info.display_name.plural.to_string()); } else { - if item.display_name.singular.to_lowercase().ends_with("s") { + if info.display_name.singular.to_lowercase().ends_with("s") { ctx.print_color(x, y, fg, RGB::named(BLACK), "some"); x += 5; } else if ['a', 'e', 'i', 'o', 'u'] .iter() - .any(|&v| item.display_name.singular.to_lowercase().starts_with(v)) + .any(|&v| info.display_name.singular.to_lowercase().starts_with(v)) { // If one and starts with a vowel, print 'an' // i.e. (a) an apple @@ -659,40 +532,54 @@ pub fn print_options( ctx.print_color(x, y, fg, RGB::named(BLACK), "a"); x += 2; } - ctx.print_color(x, y, fg, RGB::named(BLACK), item.display_name.singular.to_string()); - let this_width = x - initial_x + (item.display_name.singular.len() as i32); - width = if width > this_width { width } else { this_width }; + /* + let text = if let Some(worn) = ecs.read_storage::().get(slot.item) { + use crate::EquipmentSlot; + let text = match worn.slot { + EquipmentSlot::Melee | EquipmentSlot::Shield => "being held", + _ => "being worn", + }; + format!("{} ({})", info.display_name.singular.to_string(), text) + } else { + info.display_name.singular.to_string() + }; + */ + let text = info.display_name.singular.to_string(); + ctx.print_color(x, y, fg, RGB::named(BLACK), text); } y += 1; - j += 1; } - return (y, width); + return y; } +const PADDING: i32 = 4; +const SOME: i32 = 4; +const AN: i32 = 2; +const A: i32 = 1; + pub fn get_max_inventory_width(inventory: &PlayerInventory) -> i32 { let mut width: i32 = 0; - for (item, (_e, count)) in inventory { - let mut this_width = 4; // The spaces before and after the character to select this item, etc. - if count <= &1 { - this_width += item.display_name.singular.len() as i32; + for (item, slot) in inventory { + let mut this_width = item.display_name.singular.len() as i32; + if slot.count <= 1 { if item.display_name.singular == item.display_name.plural { - this_width += 4; // "some".len + this_width += SOME; } else if ['a', 'e', 'i', 'o', 'u'].iter().any(|&v| item.display_name.singular.starts_with(v)) { - this_width += 2; // "an".len + this_width += AN; } else { - this_width += 1; // "a".len + this_width += A; } } else { - this_width += item.display_name.plural.len() as i32; - this_width += count.to_string().len() as i32; // i.e. "12".len + this_width = + (item.display_name.plural.len() as i32) + (slot.count.to_string().len() as i32); // i.e. "12".len } width = if width > this_width { width } else { this_width }; } - return width; + return width + PADDING; } // Inside the ECS @@ -739,7 +626,7 @@ pub fn obfuscate_name( if has_beatitude.known { let prefix = match has_beatitude.buc { BUC::Cursed => Some("cursed "), - BUC::Uncursed => None, + BUC::Uncursed => Some("uncursed "), BUC::Blessed => Some("blessed "), }; if prefix.is_some() { @@ -934,13 +821,13 @@ pub fn show_help(ctx: &mut BTerm) -> YesNoResult { } } -#[derive(PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] struct DisplayName { singular: String, plural: String, } -#[derive(PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct UniqueInventoryItem { display_name: DisplayName, rgb: (u8, u8, u8), @@ -950,62 +837,74 @@ pub struct UniqueInventoryItem { name: String, } -pub type PlayerInventory = BTreeMap; +pub struct InventorySlot { + pub item: Entity, + pub count: i32, + pub idx: usize, +} -pub fn get_player_inventory(ecs: &World) -> PlayerInventory { - let player_entity = ecs.fetch::(); - let names = ecs.read_storage::(); - let backpack = ecs.read_storage::(); - let entities = ecs.entities(); - let renderables = ecs.read_storage::(); +pub type PlayerInventory = HashMap; - let mut player_inventory: BTreeMap = BTreeMap::new(); - for (entity, _pack, name, renderable) in (&entities, &backpack, &names, &renderables) - .join() - .filter(|item| item.1.owner == *player_entity) { - // RGB can't be used as a key. This is converting the RGB (tuple of f32) into a tuple of u8s. - let item_colour = item_colour_ecs(ecs, entity); - let renderables = ( - (renderable.fg.r * 255.0) as u8, - (renderable.fg.g * 255.0) as u8, - (renderable.fg.b * 255.0) as u8, - ); - let (singular, plural) = obfuscate_name_ecs(ecs, entity); - let beatitude_status = if let Some(beatitude) = ecs.read_storage::().get(entity) { - match beatitude.buc { - BUC::Blessed => 1, - BUC::Uncursed => 2, - BUC::Cursed => 3, - } - } else { - 0 - }; - let unique_item = UniqueInventoryItem { - display_name: DisplayName { singular: singular.clone(), plural: plural }, - rgb: item_colour, - renderables: renderables, - glyph: renderable.glyph, - beatitude_status: beatitude_status, - name: name.name.clone(), - }; - player_inventory - .entry(unique_item) - .and_modify(|(_e, count)| { - *count += 1; +pub enum Filter { + All, + Backpack, + Equipped, + Category(ItemType), +} + +macro_rules! includeitem { + ($inv:expr, $ecs:expr, $e:expr, $k:expr) => { + $inv.entry(unique_ecs($ecs, $e)) + .and_modify(|slot| { + slot.count += 1; }) - .or_insert((entity, 1)); - } + .or_insert(InventorySlot { + item: $e, + count: 1, + idx: $k.idx, + }); + }; +} - return player_inventory; +pub fn items(ecs: &World, filter: Filter) -> PlayerInventory { + let entities = ecs.entities(); + let keys = ecs.read_storage::(); + let mut inv: PlayerInventory = HashMap::new(); + match filter { + Filter::All => { + for (e, k) in (&entities, &keys).join() { + includeitem!(inv, ecs, e, k); + } + } + Filter::Backpack => { + let backpack = ecs.read_storage::(); + for (e, k, _b) in (&entities, &keys, &backpack).join() { + includeitem!(inv, ecs, e, k); + } + } + Filter::Equipped => { + let equipped = ecs.read_storage::(); + for (e, k, _e) in (&entities, &keys, &equipped).join() { + includeitem!(inv, ecs, e, k); + } + } + Filter::Category(itemtype) => { + let items = ecs.read_storage::(); + for (e, k, _i) in (&entities, &keys, &items) + .join() + .filter(|e| e.2.category == itemtype) { + includeitem!(inv, ecs, e, k); + } + } + } + inv } pub fn show_inventory(gs: &mut State, ctx: &mut BTerm) -> (ItemMenuResult, Option) { - ctx.set_active_console(TEXT_LAYER); - - let player_inventory = get_player_inventory(&gs.ecs); + let player_inventory = items(&gs.ecs, Filter::Backpack); let count = player_inventory.len(); - let (x_offset, y_offset) = (1 * TEXT_FONT_MOD, 10); + let (x_offset, y_offset) = (1, 10); let on_overmap = gs.ecs.fetch::().overmap; let message = if !on_overmap { @@ -1020,9 +919,7 @@ pub fn show_inventory(gs: &mut State, ctx: &mut BTerm) -> (ItemMenuResult, Optio let y = 3 + y_offset; let width = get_max_inventory_width(&player_inventory); ctx.draw_box(x, y, width + 2, (count + 1) as i32, RGB::named(WHITE), RGB::named(BLACK)); - print_options(&player_inventory, x + 1, y + 1, ctx); - - ctx.set_active_console(TILE_LAYER); + print_options(&gs.ecs, &player_inventory, x + 1, y + 1, ctx); match ctx.key { None => (ItemMenuResult::NoResponse, None), @@ -1031,22 +928,23 @@ pub fn show_inventory(gs: &mut State, ctx: &mut BTerm) -> (ItemMenuResult, Optio VirtualKeyCode::Escape => (ItemMenuResult::Cancel, None), _ => { let selection = letter_to_option::letter_to_option(key, ctx.shift); - if selection > -1 && selection < (count as i32) { + if selection != -1 && check_key(selection as usize) { if on_overmap { gamelog::Logger ::new() .append("You can't use items on the overmap.") .log(); } else { - return ( - ItemMenuResult::Selected, - Some( - player_inventory - .iter() - .nth(selection as usize) - .unwrap().1.0 - ), - ); + // Get the first entity with a Key {} component that has idx matching selection + let entities = gs.ecs.entities(); + let keyed_items = gs.ecs.read_storage::(); + let backpack = gs.ecs.read_storage::(); + for (e, key, _b) in (&entities, &keyed_items, &backpack).join() { + if key.idx == (selection as usize) { + return (ItemMenuResult::Selected, Some(e)); + } + } + // TODO: Gamelog about not having selected item? } } (ItemMenuResult::NoResponse, None) @@ -1056,7 +954,7 @@ pub fn show_inventory(gs: &mut State, ctx: &mut BTerm) -> (ItemMenuResult, Optio } pub fn drop_item_menu(gs: &mut State, ctx: &mut BTerm) -> (ItemMenuResult, Option) { - let player_inventory = get_player_inventory(&gs.ecs); + let player_inventory = items(&gs.ecs, Filter::Backpack); let count = player_inventory.len(); let (x_offset, y_offset) = (1, 10); @@ -1074,7 +972,7 @@ pub fn drop_item_menu(gs: &mut State, ctx: &mut BTerm) -> (ItemMenuResult, Optio let y = 3 + y_offset; let width = get_max_inventory_width(&player_inventory); ctx.draw_box(x, y, width + 2, (count + 1) as i32, RGB::named(WHITE), RGB::named(BLACK)); - print_options(&player_inventory, x + 1, y + 1, ctx); + print_options(&gs.ecs, &player_inventory, x + 1, y + 1, ctx); match ctx.key { None => (ItemMenuResult::NoResponse, None), @@ -1082,23 +980,23 @@ pub fn drop_item_menu(gs: &mut State, ctx: &mut BTerm) -> (ItemMenuResult, Optio match key { VirtualKeyCode::Escape => (ItemMenuResult::Cancel, None), _ => { - let selection = letter_to_option(key); - if selection > -1 && selection < (count as i32) { + let selection = letter_to_option::letter_to_option(key, ctx.shift); + if selection != -1 && check_key(selection as usize) { if on_overmap { gamelog::Logger ::new() .append("You can't drop items on the overmap.") .log(); } else { - return ( - ItemMenuResult::Selected, - Some( - player_inventory - .iter() - .nth(selection as usize) - .unwrap().1.0 - ), - ); + // Get the first entity with a Key {} component that has an idx matching "selection". + let entities = gs.ecs.entities(); + let keyed_items = gs.ecs.read_storage::(); + let backpack = gs.ecs.read_storage::(); + for (e, key, _b) in (&entities, &keyed_items, &backpack).join() { + if key.idx == (selection as usize) { + return (ItemMenuResult::Selected, Some(e)); + } + } } } (ItemMenuResult::NoResponse, None) @@ -1108,11 +1006,8 @@ pub fn drop_item_menu(gs: &mut State, ctx: &mut BTerm) -> (ItemMenuResult, Optio } pub fn remove_item_menu(gs: &mut State, ctx: &mut BTerm) -> (ItemMenuResult, Option) { - let player_entity = gs.ecs.fetch::(); - let backpack = gs.ecs.read_storage::(); - let entities = gs.ecs.entities(); - let inventory = (&backpack).join().filter(|item| item.owner == *player_entity); - let count = inventory.count(); + let player_inventory = items(&gs.ecs, Filter::Equipped); + let count = player_inventory.len(); let (x_offset, y_offset) = (1, 10); @@ -1124,38 +1019,11 @@ pub fn remove_item_menu(gs: &mut State, ctx: &mut BTerm) -> (ItemMenuResult, Opt "Unequip what? [aA-zZ][Esc.]" ); - let mut equippable: Vec<(Entity, String)> = Vec::new(); - let mut width = 2; - for (entity, _pack) in (&entities, &backpack) - .join() - .filter(|item| item.1.owner == *player_entity) { - let this_name = &obfuscate_name_ecs(&gs.ecs, entity).0; - let this_width = 5 + this_name.len(); - width = if width > this_width { width } else { this_width }; - equippable.push((entity, this_name.to_string())); - } - let x = 1 + x_offset; - let mut y = 3 + y_offset; - - ctx.draw_box(x, y, width, (count + 1) as i32, RGB::named(WHITE), RGB::named(BLACK)); - y += 1; - - let mut j = 0; - let renderables = gs.ecs.read_storage::(); - for (e, name) in &equippable { - let (mut fg, glyph) = if let Some(renderable) = renderables.get(*e) { - (renderable.fg, renderable.glyph) - } else { - (RGB::named(WHITE), to_cp437('-')) - }; - ctx.set(x + 1, y, RGB::named(YELLOW), RGB::named(BLACK), 97 + (j as FontCharType)); - ctx.set(x + 3, y, fg, RGB::named(BLACK), glyph); - fg = RGB::named(item_colour_ecs(&gs.ecs, *e)); - ctx.print_color(x + 5, y, fg, RGB::named(BLACK), name); - y += 1; - j += 1; - } + let y = 3 + y_offset; + let width = get_max_inventory_width(&player_inventory); + ctx.draw_box(x, y, width + 2, (count + 1) as i32, RGB::named(WHITE), RGB::named(BLACK)); + print_options(&gs.ecs, &player_inventory, x + 1, y + 1, ctx); match ctx.key { None => (ItemMenuResult::NoResponse, None), @@ -1163,9 +1031,17 @@ pub fn remove_item_menu(gs: &mut State, ctx: &mut BTerm) -> (ItemMenuResult, Opt match key { VirtualKeyCode::Escape => (ItemMenuResult::Cancel, None), _ => { - let selection = letter_to_option(key); - if selection > -1 && selection < (count as i32) { - return (ItemMenuResult::Selected, Some(equippable[selection as usize].0)); + let selection = letter_to_option::letter_to_option(key, ctx.shift); + if selection != -1 && check_key(selection as usize) { + // Get the first entity with a Key {} component that has an idx matching "selection". + let entities = gs.ecs.entities(); + let keyed_items = gs.ecs.read_storage::(); + let equipped = gs.ecs.read_storage::(); + for (e, key, _e) in (&entities, &keyed_items, &equipped).join() { + if key.idx == (selection as usize) { + return (ItemMenuResult::Selected, Some(e)); + } + } } (ItemMenuResult::NoResponse, None) } @@ -1235,8 +1111,9 @@ pub fn ranged_target( &gs.ecs, ctx ); - let x = x.clamp(x_offset, x_offset - 1 + VIEWPORT_W); - let y = y.clamp(y_offset, y_offset - 1 + VIEWPORT_H); + let (screen_x, screen_y) = (69, 41); + let x = x.clamp(x_offset, x_offset - 1 + (screen_x as i32)); + let y = y.clamp(y_offset, y_offset - 1 + (screen_y as i32)); let mut mouse_pos_adjusted = mouse_pos; mouse_pos_adjusted.0 += min_x - x_offset; @@ -1552,7 +1429,7 @@ pub fn game_over(ctx: &mut BTerm) -> YesNoResult { } } -pub fn with_article(name: &String) -> String { +pub fn with_article(name: String) -> String { // If first letter is a capital if name.chars().nth(0).unwrap().is_uppercase() { return format!("{}", name); @@ -1564,3 +1441,72 @@ pub fn with_article(name: &String) -> String { } format!("a {}", name) } + +pub fn unique( + entity: Entity, + names: &ReadStorage, + obfuscated_names: &ReadStorage, + renderables: &ReadStorage, + beatitudes: &ReadStorage, + magic_items: &ReadStorage, + charges: Option<&ReadStorage>, + dm: &MasterDungeonMap +) -> UniqueInventoryItem { + let item_colour = item_colour(entity, beatitudes); + let (singular, plural) = obfuscate_name( + entity, + names, + magic_items, + obfuscated_names, + beatitudes, + dm, + charges + ); + let (renderables, glyph) = if let Some(renderable) = renderables.get(entity) { + ( + ( + (renderable.fg.r * 255.0) as u8, + (renderable.fg.g * 255.0) as u8, + (renderable.fg.b * 255.0) as u8, + ), + renderable.glyph, + ) + } else { + unreachable!("Item has no renderable component.") + }; + let name = if let Some(name) = names.get(entity) { + name + } else { + unreachable!("Item has no name component.") + }; + let beatitude_status = if let Some(beatitude) = beatitudes.get(entity) { + match beatitude.buc { + BUC::Blessed => 1, + BUC::Uncursed => 2, + BUC::Cursed => 3, + } + } else { + 0 + }; + UniqueInventoryItem { + display_name: DisplayName { singular: singular.clone(), plural }, + rgb: item_colour, + renderables, + glyph, + beatitude_status, + name: name.name.clone(), + } +} + +pub fn unique_ecs(ecs: &World, entity: Entity) -> UniqueInventoryItem { + return unique( + entity, + &ecs.read_storage::(), + &ecs.read_storage::(), + &ecs.read_storage::(), + &ecs.read_storage::(), + &ecs.read_storage::(), + Some(&ecs.read_storage::()), + &ecs.fetch::() + ); +} diff --git a/src/gui/remove_curse_menu.rs b/src/gui/remove_curse_menu.rs index f8d1f14..68cea65 100644 --- a/src/gui/remove_curse_menu.rs +++ b/src/gui/remove_curse_menu.rs @@ -3,9 +3,11 @@ use super::{ item_colour_ecs, obfuscate_name_ecs, print_options, - renderable_colour, + unique_ecs, + check_key, + letter_to_option, ItemMenuResult, - UniqueInventoryItem, + InventorySlot, }; use crate::{ gamelog, @@ -18,10 +20,11 @@ use crate::{ Renderable, states::state::*, BUC, + Key, }; use bracket_lib::prelude::*; use specs::prelude::*; -use std::collections::BTreeMap; +use std::collections::HashMap; /// Handles the Remove Curse menu. pub fn remove_curse(gs: &mut State, ctx: &mut BTerm) -> (ItemMenuResult, Option) { @@ -33,11 +36,12 @@ pub fn remove_curse(gs: &mut State, ctx: &mut BTerm) -> (ItemMenuResult, Option< let beatitudes = gs.ecs.read_storage::(); let names = gs.ecs.read_storage::(); let renderables = gs.ecs.read_storage::(); + let keys = gs.ecs.read_storage::(); let build_cursed_iterator = || { - (&entities, &items, &beatitudes, &renderables, &names) + (&entities, &items, &beatitudes, &renderables, &names, &keys) .join() - .filter(|(item_entity, _i, b, _r, _n)| { + .filter(|(item_entity, _i, b, _r, _n, _k)| { // Set all items to FALSE initially. let mut keep = false; // If found in the player's backpack, set to TRUE @@ -86,34 +90,19 @@ pub fn remove_curse(gs: &mut State, ctx: &mut BTerm) -> (ItemMenuResult, Option< .log(); return (ItemMenuResult::Selected, Some(item)); } - let mut player_inventory: super::PlayerInventory = BTreeMap::new(); - for (entity, _i, _b, renderable, name) in build_cursed_iterator() { - let (singular, plural) = obfuscate_name_ecs(&gs.ecs, entity); - let beatitude_status = if - let Some(beatitude) = gs.ecs.read_storage::().get(entity) - { - match beatitude.buc { - BUC::Blessed => 1, - BUC::Uncursed => 2, - BUC::Cursed => 3, - } - } else { - 0 - }; - let unique_item = UniqueInventoryItem { - display_name: super::DisplayName { singular: singular.clone(), plural: plural.clone() }, - rgb: item_colour_ecs(&gs.ecs, entity), - renderables: renderable_colour(&renderables, entity), - glyph: renderable.glyph, - beatitude_status: beatitude_status, - name: name.name.clone(), - }; + let mut player_inventory: super::PlayerInventory = HashMap::new(); + for (entity, _i, _b, _r, _n, key) in build_cursed_iterator() { + let unique_item = unique_ecs(&gs.ecs, entity); player_inventory .entry(unique_item) - .and_modify(|(_e, count)| { - *count += 1; + .and_modify(|slot| { + slot.count += 1; }) - .or_insert((entity, 1)); + .or_insert(InventorySlot { + item: entity, + count: 1, + idx: key.idx, + }); } // Get display args let width = get_max_inventory_width(&player_inventory); @@ -128,7 +117,7 @@ pub fn remove_curse(gs: &mut State, ctx: &mut BTerm) -> (ItemMenuResult, Option< "Decurse which item? [aA-zZ][Esc.]" ); ctx.draw_box(x, y, width + 2, count + 1, RGB::named(WHITE), RGB::named(BLACK)); - print_options(&player_inventory, x + 1, y + 1, ctx); + print_options(&gs.ecs, &player_inventory, x + 1, y + 1, ctx); // Input match ctx.key { None => (ItemMenuResult::NoResponse, None), @@ -136,21 +125,17 @@ pub fn remove_curse(gs: &mut State, ctx: &mut BTerm) -> (ItemMenuResult, Option< match key { VirtualKeyCode::Escape => (ItemMenuResult::Cancel, None), _ => { - let selection = letter_to_option(key); - if selection > -1 && selection < (count as i32) { - let item = player_inventory - .iter() - .nth(selection as usize) - .unwrap().1.0; - gamelog::Logger - ::new() - .append("You decurse the") - .colour(item_colour_ecs(&gs.ecs, item)) - .append_n(obfuscate_name_ecs(&gs.ecs, item).0) - .colour(WHITE) - .append("!") - .log(); - return (ItemMenuResult::Selected, Some(item)); + let selection = letter_to_option::letter_to_option(key, ctx.shift); + if selection != -1 && check_key(selection as usize) { + // Get the first entity with a Key {} component that has an idx matching "selection". + let entities = gs.ecs.entities(); + let keyed_items = gs.ecs.read_storage::(); + let backpack = gs.ecs.read_storage::(); + for (e, key, _b) in (&entities, &keyed_items, &backpack).join() { + if key.idx == (selection as usize) { + return (ItemMenuResult::Selected, Some(e)); + } + } } (ItemMenuResult::NoResponse, None) } diff --git a/src/gui/tooltip.rs b/src/gui/tooltip.rs index 1aebed0..94c3f97 100644 --- a/src/gui/tooltip.rs +++ b/src/gui/tooltip.rs @@ -12,7 +12,6 @@ use super::{ }; use crate::TileType; use crate::data::ids::*; -use crate::data::prelude::*; use bracket_lib::prelude::*; use specs::prelude::*; @@ -46,7 +45,6 @@ impl Tooltip { return (self.lines.len() as i32) + 2i32; } fn render(&self, ctx: &mut BTerm, x: i32, y: i32) { - ctx.set_active_console(TEXT_LAYER); ctx.draw_box( x, y, @@ -58,7 +56,6 @@ impl Tooltip { for (i, s) in self.lines.iter().enumerate() { ctx.print_color(x + 1, y + (i as i32) + 1, s.1, RGB::named(BLACK), &s.0); } - ctx.set_active_console(TILE_LAYER); } } @@ -114,6 +111,12 @@ pub fn draw_tooltips(ecs: &World, ctx: &mut BTerm, xy: Option<(i32, i32)>) { if position.x == mouse_pos_adjusted.0 && position.y == mouse_pos_adjusted.1 { let mut tip = Tooltip::new(); tip.add(crate::gui::obfuscate_name_ecs(ecs, entity).0, renderable.fg); + let intrinsics = ecs.read_storage::(); + if let Some(intrinsics) = intrinsics.get(entity) { + if !intrinsics.list.is_empty() { + tip.add(intrinsics.describe(), RGB::named(WHITE)); + } + } // Attributes let attr = attributes.get(entity); if let Some(a) = attr { @@ -172,15 +175,13 @@ pub fn draw_tooltips(ecs: &World, ctx: &mut BTerm, xy: Option<(i32, i32)>) { if mouse_pos.0 > 35 { // Render to the left arrow = to_cp437('→'); - arrow_x = mouse_pos.0 * 2 - 1; + arrow_x = mouse_pos.0 - 1; } else { // Render to the right arrow = to_cp437('←'); - arrow_x = (mouse_pos.0 + 1) * 2; + arrow_x = mouse_pos.0 + 1; } - ctx.set_active_console(TEXT_LAYER); ctx.set(arrow_x, arrow_y, white, RGB::named(BLACK), arrow); - ctx.set_active_console(TILE_LAYER); let mut total_height = 0; for t in tooltips.iter() { @@ -194,9 +195,9 @@ pub fn draw_tooltips(ecs: &World, ctx: &mut BTerm, xy: Option<(i32, i32)>) { for t in tooltips.iter() { let x = if mouse_pos.0 > 35 { - (mouse_pos.0 * 2) - (1 + t.width()) + mouse_pos.0 - (1 + t.width()) } else { - (mouse_pos.0 * 2) + 2 + 1 + mouse_pos.0 + (1 + 1) }; t.render(ctx, x, y); y += t.height(); diff --git a/src/inventory/collection_system.rs b/src/inventory/collection_system.rs index 2fb7276..70fb25c 100644 --- a/src/inventory/collection_system.rs +++ b/src/inventory/collection_system.rs @@ -12,6 +12,7 @@ use crate::{ ObfuscatedName, Position, WantsToPickupItem, + WantsToAssignKey, }; use specs::prelude::*; use crate::data::messages; @@ -33,6 +34,7 @@ impl<'a> System<'a> for ItemCollectionSystem { ReadStorage<'a, Beatitude>, ReadExpect<'a, MasterDungeonMap>, ReadStorage<'a, Charges>, + ReadStorage<'a, WantsToAssignKey>, ); fn run(&mut self, data: Self::SystemData) { @@ -48,17 +50,11 @@ impl<'a> System<'a> for ItemCollectionSystem { beatitudes, dm, wands, + wants_key, ) = data; - - for pickup in wants_pickup.join() { - positions.remove(pickup.item); - backpack - .insert(pickup.item, InBackpack { owner: pickup.collected_by }) - .expect("Unable to pickup item."); - equipment_changed - .insert(pickup.collected_by, EquipmentChanged {}) - .expect("Unable to insert EquipmentChanged."); - + let mut to_remove: Vec = Vec::new(); + // For every item that wants to be picked up that *isn't* waiting on a key assignment. + for (pickup, _key) in (&wants_pickup, !&wants_key).join() { if pickup.collected_by == *player_entity { gamelog::Logger ::new() @@ -82,8 +78,17 @@ impl<'a> System<'a> for ItemCollectionSystem { .period() .log(); } + positions.remove(pickup.item); + backpack + .insert(pickup.item, InBackpack { owner: pickup.collected_by }) + .expect("Unable to pickup item"); + equipment_changed + .insert(pickup.collected_by, EquipmentChanged {}) + .expect("Unable to insert EquipmentChanged"); + to_remove.push(pickup.collected_by); + } + for item in to_remove.iter() { + wants_pickup.remove(*item); } - - wants_pickup.clear(); } } diff --git a/src/inventory/drop_system.rs b/src/inventory/drop_system.rs index 34084b4..af2d8a2 100644 --- a/src/inventory/drop_system.rs +++ b/src/inventory/drop_system.rs @@ -12,6 +12,7 @@ use crate::{ ObfuscatedName, Position, WantsToDropItem, + WantsToRemoveKey, }; use specs::prelude::*; use crate::data::messages; @@ -34,6 +35,7 @@ impl<'a> System<'a> for ItemDropSystem { ReadStorage<'a, ObfuscatedName>, ReadExpect<'a, MasterDungeonMap>, ReadStorage<'a, Charges>, + WriteStorage<'a, WantsToRemoveKey>, ); fn run(&mut self, data: Self::SystemData) { @@ -50,6 +52,7 @@ impl<'a> System<'a> for ItemDropSystem { obfuscated_names, dm, wands, + mut keys, ) = data; for (entity, to_drop) in (&entities, &wants_drop).join() { @@ -68,6 +71,9 @@ impl<'a> System<'a> for ItemDropSystem { backpack.remove(to_drop.item); if entity == *player_entity { + keys.insert(to_drop.item, WantsToRemoveKey {}).expect( + "Unable to insert WantsToRemoveKey" + ); gamelog::Logger ::new() .append(messages::YOU_DROP_ITEM) diff --git a/src/inventory/keyhandling.rs b/src/inventory/keyhandling.rs new file mode 100644 index 0000000..7194a18 --- /dev/null +++ b/src/inventory/keyhandling.rs @@ -0,0 +1,153 @@ +use crate::{ + gamelog, + gui::unique, + Beatitude, + Charges, + MagicItem, + MasterDungeonMap, + Name, + ObfuscatedName, + Stackable, + Renderable, + WantsToAssignKey, + WantsToRemoveKey, + Key, +}; +use specs::prelude::*; +use crate::data::messages; +use bracket_lib::prelude::*; +use crate::invkeys::*; + +pub struct KeyHandling {} + +const DEBUG_KEYHANDLING: bool = true; + +impl<'a> System<'a> for KeyHandling { + #[allow(clippy::type_complexity)] + type SystemData = ( + Entities<'a>, + WriteStorage<'a, WantsToAssignKey>, + WriteStorage<'a, WantsToRemoveKey>, + WriteStorage<'a, Key>, + ReadStorage<'a, Stackable>, + ReadStorage<'a, Name>, + ReadStorage<'a, ObfuscatedName>, + ReadStorage<'a, Renderable>, + ReadStorage<'a, Beatitude>, + ReadStorage<'a, MagicItem>, + ReadStorage<'a, Charges>, + ReadExpect<'a, MasterDungeonMap>, + ); + + fn run(&mut self, data: Self::SystemData) { + let ( + entities, + mut wants_keys, + mut wants_removekey, + mut keys, + stackable, + names, + obfuscated_names, + renderables, + beatitudes, + magic_items, + wands, + dm, + ) = data; + + // For every entity that wants to be picked up, that still needs a key assigned. + for (e, _wants_key) in (&entities, &wants_keys).join() { + if DEBUG_KEYHANDLING { + console::log(&format!("KEYHANDLING: Assigning key to {:?}", e)); + } + let (stacks, mut handled, unique) = ( + if let Some(_) = stackable.get(e) { true } else { false }, + false, + unique( + e, + &names, + &obfuscated_names, + &renderables, + &beatitudes, + &magic_items, + Some(&wands), + &dm + ), + ); + if stacks { + console::log(&format!("KEYHANDLING: Item is stackable.")); + let maybe_key = item_exists(&unique); + if maybe_key.is_some() { + console::log(&format!("KEYHANDLING: Existing stack found for this item.")); + let key = maybe_key.unwrap(); + keys.insert(e, Key { idx: key }).expect("Unable to insert Key."); + console::log(&format!("KEYHANDLING: Assigned key idx {} to item.", key)); + handled = true; + } + } + if !handled { + console::log( + &format!("KEYHANDLING: Item is not stackable, or no existing stack found.") + ); + if let Some(idx) = assign_next_available() { + console::log( + &format!("KEYHANDLING: Assigned next available index {} to item.", idx) + ); + keys.insert(e, Key { idx }).expect("Unable to insert Key."); + register_stackable(stacks, unique, idx); + } else { + console::log(&format!("KEYHANDLING: No more keys available.")); + gamelog::Logger + ::new() + .append(messages::NO_MORE_KEYS) + .colour(WHITE) + .period() + .log(); + } + } + } + for (e, _wants_key) in (&entities, &wants_removekey).join() { + let idx = keys.get(e).unwrap().idx; + if DEBUG_KEYHANDLING { + console::log(&format!("KEYHANDLING: Removing key from {:?}", e)); + } + // If the item is *not* stackable, then we can just remove the key and clear the index. + if let None = stackable.get(e) { + console::log( + &format!("KEYHANDLING: Item is not stackable, clearing index {}.", idx) + ); + clear_idx(idx); + keys.remove(e); + continue; + } + // If the item *is* stackable, then we need to check if there are any other items that + // share this key assignment, before clearing the index. + console::log( + &format!( + "KEYHANDLING: Item is stackable, checking if any other items share this key." + ) + ); + let mut sole_item_with_key = true; + for (entity, key) in (&entities, &keys).join() { + if entity != e && key.idx == idx { + console::log(&format!("KEYHANDLING: Another item shares index {}", idx)); + sole_item_with_key = false; + break; + } + } + // If no other items shared this key, free up the index. + if sole_item_with_key { + console::log( + &format!("KEYHANDLING: No other items found, clearing index {}.", idx) + ); + clear_idx(idx); + } + // Either way, remove the key component from this item, because we're dropping it. + console::log(&format!("KEYHANDLING: Removing key component from item.")); + keys.remove(e); + } + + wants_removekey.clear(); + wants_keys.clear(); + } +} diff --git a/src/inventory/mod.rs b/src/inventory/mod.rs index eceaccb..76748e0 100644 --- a/src/inventory/mod.rs +++ b/src/inventory/mod.rs @@ -4,6 +4,7 @@ mod equip_system; mod identification_system; mod remove_system; mod use_system; +mod keyhandling; pub use self::{ collection_system::ItemCollectionSystem, @@ -12,4 +13,5 @@ pub use self::{ identification_system::ItemIdentificationSystem, remove_system::ItemRemoveSystem, use_system::ItemUseSystem, + keyhandling::KeyHandling, }; diff --git a/src/invkeys.rs b/src/invkeys.rs new file mode 100644 index 0000000..2cee2f4 --- /dev/null +++ b/src/invkeys.rs @@ -0,0 +1,59 @@ +use std::sync::Mutex; +use std::collections::HashMap; +use crate::gui::UniqueInventoryItem; + +lazy_static! { + pub static ref INVKEYS: Mutex> = Mutex::new(HashMap::new()); + pub static ref ASSIGNEDKEYS: Mutex> = Mutex::new(vec![false; 52]); +} + +/// For (de)serialization. +pub fn clone_invkeys() -> HashMap { + let invkeys = INVKEYS.lock().unwrap(); + invkeys.clone() +} +pub fn restore_invkeys(invkeys: HashMap) { + INVKEYS.lock().unwrap().clear(); + INVKEYS.lock().unwrap().extend(invkeys); +} + +pub fn check_key(idx: usize) -> bool { + let lock = ASSIGNEDKEYS.lock().unwrap(); + lock[idx] +} + +pub fn item_exists(item: &UniqueInventoryItem) -> Option { + let invkeys = INVKEYS.lock().unwrap(); + use bracket_lib::prelude::*; + console::log(&format!("{:?}", item)); + if invkeys.contains_key(item) { + Some(*invkeys.get(item).unwrap()) + } else { + None + } +} + +pub fn assign_next_available() -> Option { + let mut lock = ASSIGNEDKEYS.lock().unwrap(); + for (i, key) in lock.iter_mut().enumerate() { + if !*key { + *key = true; + return Some(i); + } + } + None +} + +pub fn register_stackable(stacks: bool, item: UniqueInventoryItem, idx: usize) { + if stacks { + let mut invkeys = INVKEYS.lock().unwrap(); + invkeys.insert(item, idx); + } +} + +pub fn clear_idx(idx: usize) { + let mut lock = ASSIGNEDKEYS.lock().unwrap(); + lock[idx] = false; + let mut invkeys = INVKEYS.lock().unwrap(); + invkeys.retain(|_k, v| *v != idx); +} diff --git a/src/lib.rs b/src/lib.rs index 812c7be..e184a58 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,6 +8,9 @@ extern crate serde; #[macro_use] extern crate lazy_static; +#[macro_use] +pub mod macros; + pub mod camera; pub mod components; pub mod raws; @@ -35,6 +38,7 @@ pub mod rex_assets; pub mod spatial; pub mod morgue; pub mod states; +pub mod invkeys; pub use components::*; use particle_system::ParticleBuilder; diff --git a/src/macros/mod.rs b/src/macros/mod.rs new file mode 100644 index 0000000..a064f44 --- /dev/null +++ b/src/macros/mod.rs @@ -0,0 +1,93 @@ +// macros/mod.rs + +#[macro_export] +/// Used to check if the player has a given component. +macro_rules! player_has_component { + ($ecs:expr, $component:ty) => { + { + let player = $ecs.fetch::(); + let component = $ecs.read_storage::<$component>(); + if let Some(player_component) = component.get(*player) { + true + } else { + false + } + } + }; +} + +#[macro_export] +/// Used to check if a given entity has a given Intrinsic. +macro_rules! has { + ($ecs:expr, $entity:expr, $intrinsic:expr) => { + { + let intrinsics = $ecs.read_storage::(); + if let Some(has_intrinsics) = intrinsics.get($entity) { + has_intrinsics.list.contains(&$intrinsic) + } else { + false + } + } + }; +} + +#[macro_export] +/// Used to check if the player has a given Intrinsic. +macro_rules! player_has { + ($ecs:expr, $intrinsic:expr) => { + { + let player = $ecs.fetch::(); + let intrinsics = $ecs.read_storage::(); + if let Some(player_intrinsics) = intrinsics.get(*player) { + player_intrinsics.list.contains(&$intrinsic) + } else { + false + } + } + }; +} + +#[macro_export] +/// Handles adding an Intrinsic to the player, and adding it to the IntrinsicChanged component. +macro_rules! add_intr { + ($ecs:expr, $entity:expr, $intrinsic:expr) => { + { + let mut intrinsics = $ecs.write_storage::(); + if let Some(player_intrinsics) = intrinsics.get_mut($entity) { + if !player_intrinsics.list.contains(&$intrinsic) { + player_intrinsics.list.insert($intrinsic); + let mut intrinsic_changed = $ecs.write_storage::(); + if let Some(this_intrinsic_changed) = intrinsic_changed.get_mut($entity) { + this_intrinsic_changed.gained.insert($intrinsic); + } else { + intrinsic_changed.insert($entity, crate::IntrinsicChanged { + gained: { + let mut m = std::collections::HashSet::new(); + m.insert($intrinsic); + m + }, + lost: std::collections::HashSet::new() + }).expect("Failed to insert IntrinsicChanged component."); + } + } + } else { + intrinsics.insert($entity, crate::Intrinsics { + list: { + let mut m = std::collections::HashSet::new(); + m.insert($intrinsic); + m + } + }).expect("Failed to insert Intrinsics component."); + let mut intrinsic_changed = $ecs.write_storage::(); + intrinsic_changed.insert($entity, crate::IntrinsicChanged { + gained: { + let mut m = std::collections::HashSet::new(); + m.insert($intrinsic); + m + }, + lost: std::collections::HashSet::new() + }).expect("Failed to insert IntrinsicChanged component."); + } + } + }; +} diff --git a/src/main.rs b/src/main.rs index 3cdaa0a..fc2c72b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,43 +3,22 @@ use specs::prelude::*; use specs::saveload::{ SimpleMarker, SimpleMarkerAllocator }; use bracket_lib::prelude::*; -const DISPLAYWIDTH: i32 = 100; +const DISPLAYWIDTH: i32 = 105; const DISPLAYHEIGHT: i32 = 56; fn main() -> BError { // Embedded resources for use in wasm build - { - const WORLD_16_16_BYTES: &[u8] = include_bytes!("../resources/world16x16.png"); - const CURSES_16_16_BYTES: &[u8] = include_bytes!("../resources/curses16x16.png"); - const CURSES_8_16_BYTES: &[u8] = include_bytes!("../resources/curses8x16.png"); - const SINGLE_1_1_BYTES: &[u8] = include_bytes!("../resources/healthbar22x2.png"); - let mut lock = bracket_lib::terminal::EMBED.lock(); - lock.add_resource("resources/world16x16.png".to_string(), WORLD_16_16_BYTES); - lock.add_resource("resources/curses16x16.png".to_string(), CURSES_16_16_BYTES); - lock.add_resource("resources/curses8x16.png".to_string(), CURSES_8_16_BYTES); - lock.add_resource("resources/healthbar22x2.png".to_string(), SINGLE_1_1_BYTES); - } + const CURSES_14_16_BYTES: &[u8] = include_bytes!("../resources/curses14x16.png"); + EMBED.lock().add_resource("resources/curses14x16.png".to_string(), CURSES_14_16_BYTES); - let world_sheet = SpriteSheet { - filename: "resources/world16x16.png".to_string(), - sprites: register_spritesheet(16, 16, 19, 16), - backing: None, - }; + //link_resource!(CURSES14X16, "../resources/curses_14x16.png"); let mut context = BTermBuilder::new() .with_title("rust-rl") .with_dimensions(DISPLAYWIDTH, DISPLAYHEIGHT) - .with_font("curses16x16.png", 16, 16) - .with_font("curses8x16.png", 8, 16) - .with_font("healthbar22x2.png", 1, 1) - .with_tile_dimensions(16, 16) - .with_gutter(2) - .with_sprite_console(DISPLAYWIDTH * 16, DISPLAYHEIGHT * 16, 0) - .with_sprite_sheet(world_sheet) - .with_simple_console_no_bg(DISPLAYWIDTH, DISPLAYHEIGHT, "curses16x16.png") - .with_simple_console_no_bg(DISPLAYWIDTH, DISPLAYHEIGHT, "curses16x16.png") - .with_sparse_console(DISPLAYWIDTH * 2, DISPLAYHEIGHT, "curses8x16.png") - .with_sparse_console(DISPLAYWIDTH * 16, DISPLAYHEIGHT * 16, "healthbar22x2.png") + .with_font("curses14x16.png", 14, 16) + .with_tile_dimensions(14, 16) + .with_simple_console(DISPLAYWIDTH, DISPLAYHEIGHT, "curses14x16.png") .build()?; if config::CONFIG.visuals.with_scanlines { context.with_post_scanlines(config::CONFIG.visuals.with_screen_burn); @@ -132,6 +111,12 @@ fn main() -> BError { gs.ecs.register::(); gs.ecs.register::(); gs.ecs.register::(); + gs.ecs.register::(); + gs.ecs.register::(); + gs.ecs.register::(); + gs.ecs.register::(); + gs.ecs.register::(); + gs.ecs.register::(); gs.ecs.register::>(); gs.ecs.register::(); gs.ecs.register::(); @@ -157,15 +142,3 @@ fn main() -> BError { main_loop(context, gs) } - -fn register_spritesheet(width: i32, height: i32, rows: i32, columns: i32) -> Vec { - let mut sprites: Vec = Vec::new(); - for y in 0..rows { - for x in 0..columns { - sprites.push( - Sprite::new(Rect::with_size(x * width + 1, y * height + 1, width, height)) - ); - } - } - sprites -} diff --git a/src/map/dungeon.rs b/src/map/dungeon.rs index ed0bf91..4407efa 100644 --- a/src/map/dungeon.rs +++ b/src/map/dungeon.rs @@ -112,7 +112,26 @@ fn make_scroll_name(rng: &mut RandomNumberGenerator) -> String { return name; } -const POTION_COLOURS: &[&str] = &["blue", "red", "green", "yellow", "black"]; +const POTION_COLOURS: &[&str] = &[ + "red", + "orange", + "yellow", + "green", + "blue", + "indigo", + "violet", + "black", + "white", + "silver", + "gold", + "rainbow", + "blood", + "purple", + "cyan", + "brown", + "grey", + "octarine", +]; const POTION_ADJECTIVES: &[&str] = &[ "swirling", "viscous", diff --git a/src/map/mod.rs b/src/map/mod.rs index 9bcacca..99a0c6a 100644 --- a/src/map/mod.rs +++ b/src/map/mod.rs @@ -2,15 +2,7 @@ use bracket_lib::prelude::*; use serde::{ Deserialize, Serialize }; use std::collections::{ HashSet, HashMap }; mod tiletype; -pub use tiletype::{ - tile_cost, - tile_opaque, - tile_walkable, - tile_blocks_telepathy, - TileType, - get_dest, - Destination, -}; +pub use tiletype::{ tile_cost, tile_opaque, tile_walkable, TileType, get_dest, Destination }; mod interval_spawning_system; pub use interval_spawning_system::{ maybe_map_message, try_spawn_interval }; pub mod dungeon; diff --git a/src/map/themes.rs b/src/map/themes.rs index bd6fcf3..8ddcc2a 100644 --- a/src/map/themes.rs +++ b/src/map/themes.rs @@ -5,22 +5,6 @@ use crate::data::ids::*; use bracket_lib::prelude::*; use std::ops::{ Add, Mul }; -pub fn get_sprite_for_id(idx: usize, map: &Map, other_pos: Option) -> (usize, RGBA) { - let x = (idx as i32) % map.width; - let y = (idx as i32) / map.width; - let tile = map.tiles[idx]; - let base = match tile { - TileType::Wall => wall_sprite(tile.sprite(), map, x, y), - _ => tile.sprite(), - }; - let sprite_id = pick_variant(base, tile.variants(), idx, map); - let tint = if !map.visible_tiles[idx] { - RGBA::from_f32(0.75, 0.75, 0.75, 1.0) - } else { - RGBA::named(WHITE) - }; - return (sprite_id, tint); -} /// Gets the renderables for a tile, with darkening/offset/post-processing/etc. Passing a val for "debug" will ignore viewshed. pub fn get_tile_renderables_for_id( idx: usize, @@ -158,20 +142,6 @@ fn is_revealed_and_wall(map: &Map, x: i32, y: i32, debug: Option) -> bool (if debug.is_none() { map.revealed_tiles[idx] } else { true }) } -fn wall_sprite(id: usize, map: &Map, x: i32, y: i32) -> usize { - if y > map.height - (2 as i32) { - return id; - } - if is_revealed_and_wall(map, x, y + 1, None) { - return id + 6; - } - return id; -} - -fn pick_variant(base: usize, variants: usize, idx: usize, map: &Map) -> usize { - return base + ((map.colour_offset[idx].0.0 * (variants as f32)) as usize); -} - fn wall_glyph(map: &Map, x: i32, y: i32, debug: Option) -> FontCharType { if x < 1 || diff --git a/src/map/tiletype.rs b/src/map/tiletype.rs index beb483c..f451c9b 100644 --- a/src/map/tiletype.rs +++ b/src/map/tiletype.rs @@ -1,5 +1,4 @@ use serde::{ Deserialize, Serialize }; -use crate::data::sprites::*; #[derive(PartialEq, Eq, Hash, Copy, Clone, Serialize, Deserialize, Debug)] pub enum TileType { @@ -28,64 +27,9 @@ pub enum TileType { ToOvermap(i32), ToLocal(i32), } - -impl TileType { - pub fn sprite(&self) -> usize { - match self { - TileType::ImpassableMountain => STATUE, - TileType::Wall => WALL_BASE, - TileType::DeepWater => WATER_DEEP, - TileType::Fence => WALL_BASE, - TileType::Bars => WALL_BASE, - TileType::Floor => FLOOR, - TileType::WoodFloor => FLOOR_WOOD, - TileType::Gravel => FLOOR, - TileType::Road => PATH_GRASS, - TileType::Grass => FLOOR_GRASS, - TileType::Foliage => FLOOR_GRASS, - TileType::HeavyFoliage => FLOOR_GRASS, - TileType::Sand => FLOOR, - TileType::ShallowWater => WATER_DEEP, - TileType::Bridge => FLOOR, - TileType::DownStair => STAIR_D, - TileType::UpStair => STAIR_A, - TileType::ToLocal(_) => MUSHROOM, - TileType::ToOvermap(_) => MUSHROOM_ORANGE, - } - } - - pub fn variants(&self) -> usize { - match self { - TileType::ImpassableMountain => 1, - TileType::Wall => 4, - TileType::DeepWater => 2, - TileType::Fence => 1, - TileType::Bars => 1, - TileType::Floor => 6, - TileType::WoodFloor => 3, - TileType::Gravel => 1, - TileType::Road => 4, - TileType::Grass => 6, - TileType::Foliage => 1, - TileType::HeavyFoliage => 1, - TileType::Sand => 1, - TileType::ShallowWater => 2, - TileType::Bridge => 1, - TileType::DownStair => 1, - TileType::UpStair => 1, - TileType::ToLocal(_) => 1, - TileType::ToOvermap(_) => 1, - } - } -} - pub fn tile_walkable(tt: TileType) -> bool { match tt { - | TileType::ImpassableMountain - | TileType::Wall - | TileType::DeepWater - | TileType::Fence - | TileType::Bars => false, + TileType::ImpassableMountain | TileType::Wall | TileType::DeepWater | TileType::Fence | TileType::Bars => false, _ => true, } } @@ -96,11 +40,6 @@ pub fn tile_opaque(tt: TileType) -> bool { _ => false, } } -pub fn tile_blocks_telepathy(tt: TileType) -> bool { - match tt { - _ => false, - } -} pub fn tile_cost(tt: TileType) -> f32 { match tt { TileType::Road => 0.75, diff --git a/src/particle_system.rs b/src/particle_system.rs index b576984..69e12b7 100644 --- a/src/particle_system.rs +++ b/src/particle_system.rs @@ -81,7 +81,6 @@ fn create_delayed_particles(ecs: &mut World, ctx: &BTerm) { .expect("Could not insert position"); renderables .insert(p, Renderable { - sprite: None, // TODO: Particle sprite fg: handled.fg, bg: handled.bg, glyph: handled.glyph, @@ -307,7 +306,6 @@ impl<'a> System<'a> for ParticleSpawnSystem { .expect("Could not insert position"); renderables .insert(p, Renderable { - sprite: None, // TODO: Particle sprite fg: new_particle.fg, bg: new_particle.bg, glyph: new_particle.glyph, diff --git a/src/player.rs b/src/player.rs index d91ba3b..36af74b 100644 --- a/src/player.rs +++ b/src/player.rs @@ -30,6 +30,7 @@ use super::{ Viewshed, WantsToMelee, WantsToPickupItem, + WantsToAssignKey, get_dest, Destination, DamageType, @@ -39,7 +40,6 @@ use specs::prelude::*; use std::cmp::{ max, min }; use crate::data::events::*; use crate::data::ids::*; -use crate::gui::with_article; pub fn try_door(i: i32, j: i32, ecs: &mut World) -> RunState { let mut positions = ecs.write_storage::(); @@ -134,7 +134,6 @@ pub fn try_door(i: i32, j: i32, ecs: &mut World) -> RunState { let mut renderables = ecs.write_storage::(); let render_data = renderables.get_mut(potential_target).unwrap(); render_data.glyph = to_cp437('+'); // Nethack open door, maybe just use '/' instead. - render_data.sprite = Some(17); // TODO: Enum door_pos = Some(Point::new(pos.x + delta_x, pos.y + delta_y)); } result = RunState::Ticking; @@ -232,7 +231,6 @@ pub fn open(i: i32, j: i32, ecs: &mut World) -> RunState { let mut renderables = ecs.write_storage::(); let render_data = renderables.get_mut(potential_target).unwrap(); render_data.glyph = to_cp437('▓'); // Nethack open door, maybe just use '/' instead. - render_data.sprite = Some(18); // TODO: Enum door_pos = Some(Point::new(pos.x + delta_x, pos.y + delta_y)); } result = RunState::Ticking; @@ -563,11 +561,11 @@ pub fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World) -> RunState let mut logger = gamelog::Logger::new().append("You see"); for i in 0..seen_items.len() { if i > 0 && i < seen_items.len() { - logger = logger.append(", "); + logger = logger.append(", a"); } logger = logger .colour(seen_items[i].1) - .append_n(with_article(&seen_items[i].0)) + .append_n(&seen_items[i].0) .colour(WHITE); } logger.period().log(); @@ -636,7 +634,9 @@ fn get_item(ecs: &mut World) -> RunState { return RunState::AwaitingInput; } Some(item) => { + let mut assignkey = ecs.write_storage::(); let mut pickup = ecs.write_storage::(); + assignkey.insert(item, WantsToAssignKey {}).expect("Unable to insert WantsToAssignKey"); pickup .insert(*player_entity, WantsToPickupItem { collected_by: *player_entity, item }) .expect("Unable to insert want to pickup item."); diff --git a/src/raws/item_structs.rs b/src/raws/item_structs.rs index 1bd1a39..c670e54 100644 --- a/src/raws/item_structs.rs +++ b/src/raws/item_structs.rs @@ -6,6 +6,7 @@ pub struct Item { pub id: String, pub name: Name, pub renderable: Option, + pub class: String, pub weight: Option, pub value: Option, pub equip: Option, @@ -30,7 +31,6 @@ pub struct Equippable { #[derive(Deserialize, Debug)] pub struct Renderable { pub glyph: String, - pub sprite: Option, pub fg: String, pub bg: String, pub order: i32, diff --git a/src/raws/rawmaster.rs b/src/raws/rawmaster.rs index d15b7c7..0e2b227 100644 --- a/src/raws/rawmaster.rs +++ b/src/raws/rawmaster.rs @@ -66,6 +66,7 @@ macro_rules! apply_flags { "IDENTIFY" => $eb = $eb.with(ProvidesIdentify {}), "DIGGER" => $eb = $eb.with(Digger {}), "MAGICMAP" => $eb = $eb.with(MagicMapper {}), + "STACKABLE" => $eb = $eb.with(Stackable {}), // CAN BE DESTROYED BY DAMAGE "DESTRUCTIBLE" => $eb = $eb.with(Destructible {}), // --- EQUIP SLOTS --- @@ -281,6 +282,7 @@ pub fn spawn_named_item( if known_beatitude && !identified_items.contains(&item_template.name.name) { dm.identified_items.insert(item_template.name.name.clone()); } + let needs_key = is_player_owned(&player_entity, &pos); std::mem::drop(player_entity); std::mem::drop(dm); // -- DROP EVERYTHING THAT INVOLVES THE ECS BEFORE THIS POINT --- @@ -293,9 +295,23 @@ pub fn spawn_named_item( eb = eb.with(Item { weight: item_template.weight.unwrap_or(0.0), value: item_template.value.unwrap_or(0.0), + category: match item_template.class.as_str() { + "amulet" => ItemType::Amulet, + "weapon" => ItemType::Weapon, + "armour" => ItemType::Armour, + "comestible" => ItemType::Comestible, + "scroll" => ItemType::Scroll, + "spellbook" => ItemType::Spellbook, + "potion" => ItemType::Potion, + "ring" => ItemType::Ring, + "wand" => ItemType::Wand, + _ => unreachable!("Unknown item type."), + }, }); eb = spawn_position(pos, eb, key, raws); - + if needs_key { + eb = eb.with(WantsToAssignKey {}); + } if let Some(renderable) = &item_template.renderable { eb = eb.with(get_renderable_component(renderable)); } @@ -392,6 +408,7 @@ pub fn spawn_named_mob( if raws.mob_index.contains_key(key) { let mob_template = &raws.raws.mobs[raws.mob_index[key]]; let mut player_level = 1; + let needs_key; { let pools = ecs.read_storage::(); let player_entity = ecs.fetch::(); @@ -399,12 +416,15 @@ pub fn spawn_named_mob( if let Some(pool) = player_pool { player_level = pool.level; } + needs_key = is_player_owned(&player_entity, &pos); } - let mut eb; // New entity with a position, name, combatstats, and viewshed eb = ecs.create_entity().marked::>(); eb = spawn_position(pos, eb, key, raws); + if needs_key { + eb = eb.with(WantsToAssignKey {}); + } eb = eb.with(Name { name: mob_template.name.clone(), plural: mob_template.name.clone() }); eb = eb.with(Viewshed { visible_tiles: Vec::new(), @@ -632,10 +652,18 @@ pub fn spawn_named_prop( pos: SpawnType ) -> Option { if raws.prop_index.contains_key(key) { + let needs_key; + { + let player_entity = ecs.fetch::(); + needs_key = is_player_owned(&player_entity, &pos); + } // ENTITY BUILDER PREP let prop_template = &raws.raws.props[raws.prop_index[key]]; let mut eb = ecs.create_entity().marked::>(); eb = spawn_position(pos, eb, key, raws); + if needs_key { + eb = eb.with(WantsToAssignKey {}); + } // APPLY MANDATORY COMPONENTS FOR A PROP: // - Name // - Prop {} @@ -686,16 +714,28 @@ fn spawn_position<'a>( eb } +fn is_player_owned(player: &Entity, pos: &SpawnType) -> bool { + match pos { + SpawnType::Carried { by } => { + if by == player { + return true; + } + } + SpawnType::Equipped { by } => { + if by == player { + return true; + } + } + _ => {} + } + false +} + fn get_renderable_component( renderable: &super::item_structs::Renderable ) -> crate::components::Renderable { crate::components::Renderable { glyph: to_cp437(renderable.glyph.chars().next().unwrap()), - sprite: if let Some(sprite) = &renderable.sprite { - Some(sprite.clone()) - } else { - None - }, fg: RGB::from_hex(&renderable.fg).expect("Invalid RGB"), bg: RGB::from_hex(&renderable.bg).expect("Invalid RGB"), render_order: renderable.order, diff --git a/src/saveload_system.rs b/src/saveload_system.rs index 894e4ff..f3b284d 100644 --- a/src/saveload_system.rs +++ b/src/saveload_system.rs @@ -9,6 +9,7 @@ use specs::saveload::{ SimpleMarker, SimpleMarkerAllocator, }; + use std::fs; use std::fs::File; use std::path::Path; @@ -95,8 +96,10 @@ pub fn save_game(ecs: &mut World) { IdentifiedItem, InBackpack, InflictsDamage, + IntrinsicChanged, Intrinsics, Item, + Key, KnownSpells, LootTable, MagicItem, @@ -126,17 +129,21 @@ pub fn save_game(ecs: &mut World) { SpawnParticleBurst, SpawnParticleLine, SpawnParticleSimple, + Stackable, TakingTurn, Telepath, ToHitBonus, Viewshed, Charges, WantsToApproach, + WantsToAssignKey, + WantsToDelete, WantsToDropItem, WantsToFlee, WantsToMelee, WantsToPickupItem, WantsToRemoveItem, + WantsToRemoveKey, WantsToUseItem, SerializationHelper, DMSerializationHelper @@ -227,8 +234,10 @@ pub fn load_game(ecs: &mut World) { IdentifiedItem, InBackpack, InflictsDamage, + IntrinsicChanged, Intrinsics, Item, + Key, KnownSpells, LootTable, MagicItem, @@ -258,17 +267,21 @@ pub fn load_game(ecs: &mut World) { SpawnParticleBurst, SpawnParticleLine, SpawnParticleSimple, + Stackable, TakingTurn, Telepath, ToHitBonus, Viewshed, Charges, WantsToApproach, + WantsToAssignKey, + WantsToDelete, WantsToDropItem, WantsToFlee, WantsToMelee, WantsToPickupItem, WantsToRemoveItem, + WantsToRemoveKey, WantsToUseItem, SerializationHelper, DMSerializationHelper diff --git a/src/spawner.rs b/src/spawner.rs index 21a68b1..3fa673c 100644 --- a/src/spawner.rs +++ b/src/spawner.rs @@ -54,7 +54,6 @@ pub fn player(ecs: &mut World, player_x: i32, player_y: i32) -> Entity { .with(BlocksTile {}) .with(Renderable { glyph: to_cp437('@'), - sprite: None, // TODO: Player sprite fg: RGB::named(YELLOW), bg: RGB::named(BLACK), render_order: 0, diff --git a/src/states/state.rs b/src/states/state.rs index ed4cd58..3dde32b 100644 --- a/src/states/state.rs +++ b/src/states/state.rs @@ -23,7 +23,6 @@ use crate::camera; use crate::saveload_system; use crate::morgue; use crate::damage_system; -use crate::data::prelude::*; pub struct State { pub ecs: World, @@ -65,12 +64,13 @@ impl State { fn resolve_entity_decisions(&mut self) { let mut trigger_system = trigger_system::TriggerSystem {}; - let mut inventory_system = inventory::ItemCollectionSystem {}; let mut item_equip_system = inventory::ItemEquipSystem {}; let mut item_use_system = inventory::ItemUseSystem {}; let mut item_drop_system = inventory::ItemDropSystem {}; let mut item_remove_system = inventory::ItemRemoveSystem {}; + let mut inventory_system = inventory::ItemCollectionSystem {}; let mut item_id_system = inventory::ItemIdentificationSystem {}; + let mut key_system = inventory::KeyHandling {}; let mut melee_system = MeleeCombatSystem {}; trigger_system.run_now(&self.ecs); inventory_system.run_now(&self.ecs); @@ -79,6 +79,7 @@ impl State { item_drop_system.run_now(&self.ecs); item_remove_system.run_now(&self.ecs); item_id_system.run_now(&self.ecs); + key_system.run_now(&self.ecs); melee_system.run_now(&self.ecs); effects::run_effects_queue(&mut self.ecs); @@ -165,15 +166,6 @@ impl GameState for State { new_runstate = *runstate; } // Clear screen - ctx.set_active_console(0); - ctx.cls(); - ctx.set_active_console(HP_BAR_LAYER); - ctx.cls(); - ctx.set_active_console(TEXT_LAYER); - ctx.cls(); - ctx.set_active_console(ENTITY_LAYER); - ctx.cls(); - ctx.set_active_console(TILE_LAYER); ctx.cls(); particle_system::particle_ticker(&mut self.ecs, ctx); @@ -352,7 +344,11 @@ impl GameState for State { gui::ItemMenuResult::NoResponse => {} gui::ItemMenuResult::Selected => { let item_entity = result.1.unwrap(); + let mut removekey = self.ecs.write_storage::(); let mut intent = self.ecs.write_storage::(); + removekey + .insert(item_entity, WantsToRemoveKey {}) + .expect("Unable to insert WantsToRemoveKey"); intent .insert(*self.ecs.fetch::(), WantsToDropItem { item: item_entity, @@ -569,15 +565,6 @@ impl GameState for State { new_runstate = self.mapgen_next_state.unwrap(); } if self.mapgen_history.len() != 0 { - ctx.set_active_console(0); - ctx.cls(); - ctx.set_active_console(HP_BAR_LAYER); - ctx.cls(); - ctx.set_active_console(TEXT_LAYER); - ctx.cls(); - ctx.set_active_console(ENTITY_LAYER); - ctx.cls(); - ctx.set_active_console(TILE_LAYER); ctx.cls(); camera::render_debug_map(&self.mapgen_history[self.mapgen_index], ctx); diff --git a/src/visibility_system.rs b/src/visibility_system.rs index 521eecd..e53b0e1 100644 --- a/src/visibility_system.rs +++ b/src/visibility_system.rs @@ -11,7 +11,6 @@ use super::{ Viewshed, Renderable, gui::renderable_colour, - tile_blocks_telepathy, }; use bracket_lib::prelude::*; use bracket_lib::pathfinding::FieldOfViewAlg::SymmetricShadowcasting; @@ -121,7 +120,7 @@ impl<'a> System<'a> for VisibilitySystem { if let Some(_is_blind) = blind_entities.get(ent) { range *= BLIND_TELEPATHY_RANGE_MULTIPLIER; } - telepath.telepath_tiles = fast_fov(pos.x, pos.y, range, &map); + telepath.telepath_tiles = fast_fov(pos.x, pos.y, range); telepath.telepath_tiles.retain( |p| p.x >= 0 && p.x < map.width && p.y >= 0 && p.y < map.height ); @@ -142,7 +141,7 @@ impl<'a> System<'a> for VisibilitySystem { } } -pub fn fast_fov(p_x: i32, p_y: i32, r: i32, map: &WriteExpect) -> Vec { +pub fn fast_fov(p_x: i32, p_y: i32, r: i32) -> Vec { let mut visible_tiles: Vec = Vec::new(); let mut i = 0; @@ -153,17 +152,7 @@ pub fn fast_fov(p_x: i32, p_y: i32, r: i32, map: &WriteExpect) -> Vec= 0 && - ox_i32 < map.width && - oy_i32 >= 0 && - oy_i32 < map.height && - tile_blocks_telepathy(map.tiles[map.xy_idx(ox_i32, oy_i32)]) - { - break; - } + visible_tiles.push(Point::new(ox as i32, oy as i32)); ox += x; oy += y; } diff --git a/wasm/rust-rl.js b/wasm/rust-rl.js index 7036263..ffbe20e 100644 --- a/wasm/rust-rl.js +++ b/wasm/rust-rl.js @@ -212,11 +212,11 @@ function makeMutClosure(arg0, arg1, dtor, f) { return real; } function __wbg_adapter_20(arg0, arg1) { - wasm._dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h66b665bcfa5ccc10(arg0, arg1); + wasm._dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hb6c6b1cd103d974c(arg0, arg1); } function __wbg_adapter_23(arg0, arg1, arg2) { - wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h7f980deb71f217f3(arg0, arg1, addHeapObject(arg2)); + wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h02b9f16709be0849(arg0, arg1, addHeapObject(arg2)); } function handleError(f, args) { @@ -817,16 +817,16 @@ function __wbg_get_imports() { const ret = wasm.memory; return addHeapObject(ret); }; - imports.wbg.__wbindgen_closure_wrapper257 = function(arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 14, __wbg_adapter_20); + imports.wbg.__wbindgen_closure_wrapper258 = function(arg0, arg1, arg2) { + const ret = makeMutClosure(arg0, arg1, 15, __wbg_adapter_20); return addHeapObject(ret); }; - imports.wbg.__wbindgen_closure_wrapper2960 = function(arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 698, __wbg_adapter_23); + imports.wbg.__wbindgen_closure_wrapper2954 = function(arg0, arg1, arg2) { + const ret = makeMutClosure(arg0, arg1, 696, __wbg_adapter_23); return addHeapObject(ret); }; - imports.wbg.__wbindgen_closure_wrapper2962 = function(arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 698, __wbg_adapter_23); + imports.wbg.__wbindgen_closure_wrapper2956 = function(arg0, arg1, arg2) { + const ret = makeMutClosure(arg0, arg1, 696, __wbg_adapter_23); return addHeapObject(ret); }; diff --git a/wasm/rust-rl_bg.wasm b/wasm/rust-rl_bg.wasm index 79ebb75..f48ccb7 100644 Binary files a/wasm/rust-rl_bg.wasm and b/wasm/rust-rl_bg.wasm differ diff --git a/web/rust-rl.js b/web/rust-rl.js deleted file mode 100644 index 7036263..0000000 --- a/web/rust-rl.js +++ /dev/null @@ -1,887 +0,0 @@ -let wasm_bindgen; -(function() { - const __exports = {}; - let script_src; - if (typeof document !== 'undefined' && document.currentScript !== null) { - script_src = new URL(document.currentScript.src, location.href).toString(); - } - let wasm = undefined; - - const heap = new Array(128).fill(undefined); - - heap.push(undefined, null, true, false); - -function getObject(idx) { return heap[idx]; } - -let heap_next = heap.length; - -function dropObject(idx) { - if (idx < 132) return; - heap[idx] = heap_next; - heap_next = idx; -} - -function takeObject(idx) { - const ret = getObject(idx); - dropObject(idx); - return ret; -} - -function addHeapObject(obj) { - if (heap_next === heap.length) heap.push(heap.length + 1); - const idx = heap_next; - heap_next = heap[idx]; - - heap[idx] = obj; - return idx; -} - -let WASM_VECTOR_LEN = 0; - -let cachedUint8Memory0 = null; - -function getUint8Memory0() { - if (cachedUint8Memory0 === null || cachedUint8Memory0.byteLength === 0) { - cachedUint8Memory0 = new Uint8Array(wasm.memory.buffer); - } - return cachedUint8Memory0; -} - -const cachedTextEncoder = (typeof TextEncoder !== 'undefined' ? new TextEncoder('utf-8') : { encode: () => { throw Error('TextEncoder not available') } } ); - -const encodeString = (typeof cachedTextEncoder.encodeInto === 'function' - ? function (arg, view) { - return cachedTextEncoder.encodeInto(arg, view); -} - : function (arg, view) { - const buf = cachedTextEncoder.encode(arg); - view.set(buf); - return { - read: arg.length, - written: buf.length - }; -}); - -function passStringToWasm0(arg, malloc, realloc) { - - if (realloc === undefined) { - const buf = cachedTextEncoder.encode(arg); - const ptr = malloc(buf.length, 1) >>> 0; - getUint8Memory0().subarray(ptr, ptr + buf.length).set(buf); - WASM_VECTOR_LEN = buf.length; - return ptr; - } - - let len = arg.length; - let ptr = malloc(len, 1) >>> 0; - - const mem = getUint8Memory0(); - - let offset = 0; - - for (; offset < len; offset++) { - const code = arg.charCodeAt(offset); - if (code > 0x7F) break; - mem[ptr + offset] = code; - } - - if (offset !== len) { - if (offset !== 0) { - arg = arg.slice(offset); - } - ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0; - const view = getUint8Memory0().subarray(ptr + offset, ptr + len); - const ret = encodeString(arg, view); - - offset += ret.written; - } - - WASM_VECTOR_LEN = offset; - return ptr; -} - -function isLikeNone(x) { - return x === undefined || x === null; -} - -let cachedInt32Memory0 = null; - -function getInt32Memory0() { - if (cachedInt32Memory0 === null || cachedInt32Memory0.byteLength === 0) { - cachedInt32Memory0 = new Int32Array(wasm.memory.buffer); - } - return cachedInt32Memory0; -} - -function debugString(val) { - // primitive types - const type = typeof val; - if (type == 'number' || type == 'boolean' || val == null) { - return `${val}`; - } - if (type == 'string') { - return `"${val}"`; - } - if (type == 'symbol') { - const description = val.description; - if (description == null) { - return 'Symbol'; - } else { - return `Symbol(${description})`; - } - } - if (type == 'function') { - const name = val.name; - if (typeof name == 'string' && name.length > 0) { - return `Function(${name})`; - } else { - return 'Function'; - } - } - // objects - if (Array.isArray(val)) { - const length = val.length; - let debug = '['; - if (length > 0) { - debug += debugString(val[0]); - } - for(let i = 1; i < length; i++) { - debug += ', ' + debugString(val[i]); - } - debug += ']'; - return debug; - } - // Test for built-in - const builtInMatches = /\[object ([^\]]+)\]/.exec(toString.call(val)); - let className; - if (builtInMatches.length > 1) { - className = builtInMatches[1]; - } else { - // Failed to match the standard '[object ClassName]' - return toString.call(val); - } - if (className == 'Object') { - // we're a user defined class or Object - // JSON.stringify avoids problems with cycles, and is generally much - // easier than looping through ownProperties of `val`. - try { - return 'Object(' + JSON.stringify(val) + ')'; - } catch (_) { - return 'Object'; - } - } - // errors - if (val instanceof Error) { - return `${val.name}: ${val.message}\n${val.stack}`; - } - // TODO we could test for more things here, like `Set`s and `Map`s. - return className; -} - -const cachedTextDecoder = (typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }) : { decode: () => { throw Error('TextDecoder not available') } } ); - -if (typeof TextDecoder !== 'undefined') { cachedTextDecoder.decode(); }; - -function getStringFromWasm0(ptr, len) { - ptr = ptr >>> 0; - return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len)); -} - -function makeMutClosure(arg0, arg1, dtor, f) { - const state = { a: arg0, b: arg1, cnt: 1, dtor }; - const real = (...args) => { - // First up with a closure we increment the internal reference - // count. This ensures that the Rust closure environment won't - // be deallocated while we're invoking it. - state.cnt++; - const a = state.a; - state.a = 0; - try { - return f(a, state.b, ...args); - } finally { - if (--state.cnt === 0) { - wasm.__wbindgen_export_2.get(state.dtor)(a, state.b); - - } else { - state.a = a; - } - } - }; - real.original = state; - - return real; -} -function __wbg_adapter_20(arg0, arg1) { - wasm._dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h66b665bcfa5ccc10(arg0, arg1); -} - -function __wbg_adapter_23(arg0, arg1, arg2) { - wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h7f980deb71f217f3(arg0, arg1, addHeapObject(arg2)); -} - -function handleError(f, args) { - try { - return f.apply(this, args); - } catch (e) { - wasm.__wbindgen_exn_store(addHeapObject(e)); - } -} - -function getArrayU8FromWasm0(ptr, len) { - ptr = ptr >>> 0; - return getUint8Memory0().subarray(ptr / 1, ptr / 1 + len); -} - -async function __wbg_load(module, imports) { - if (typeof Response === 'function' && module instanceof Response) { - if (typeof WebAssembly.instantiateStreaming === 'function') { - try { - return await WebAssembly.instantiateStreaming(module, imports); - - } catch (e) { - if (module.headers.get('Content-Type') != 'application/wasm') { - console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e); - - } else { - throw e; - } - } - } - - const bytes = await module.arrayBuffer(); - return await WebAssembly.instantiate(bytes, imports); - - } else { - const instance = await WebAssembly.instantiate(module, imports); - - if (instance instanceof WebAssembly.Instance) { - return { instance, module }; - - } else { - return instance; - } - } -} - -function __wbg_get_imports() { - const imports = {}; - imports.wbg = {}; - imports.wbg.__wbindgen_cb_drop = function(arg0) { - const obj = takeObject(arg0).original; - if (obj.cnt-- == 1) { - obj.a = 0; - return true; - } - const ret = false; - return ret; - }; - imports.wbg.__wbindgen_object_drop_ref = function(arg0) { - takeObject(arg0); - }; - imports.wbg.__wbg_log_0e24d345b14995ec = function(arg0, arg1) { - console.log(getStringFromWasm0(arg0, arg1)); - }; - imports.wbg.__wbindgen_object_clone_ref = function(arg0) { - const ret = getObject(arg0); - return addHeapObject(ret); - }; - imports.wbg.__wbg_new_abda76e883ba8a5f = function() { - const ret = new Error(); - return addHeapObject(ret); - }; - imports.wbg.__wbg_stack_658279fe44541cf6 = function(arg0, arg1) { - const ret = getObject(arg1).stack; - const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); - const len1 = WASM_VECTOR_LEN; - getInt32Memory0()[arg0 / 4 + 1] = len1; - getInt32Memory0()[arg0 / 4 + 0] = ptr1; - }; - imports.wbg.__wbg_error_f851667af71bcfc6 = function(arg0, arg1) { - let deferred0_0; - let deferred0_1; - try { - deferred0_0 = arg0; - deferred0_1 = arg1; - console.error(getStringFromWasm0(arg0, arg1)); - } finally { - wasm.__wbindgen_free(deferred0_0, deferred0_1, 1); - } - }; - imports.wbg.__wbindgen_string_get = function(arg0, arg1) { - const obj = getObject(arg1); - const ret = typeof(obj) === 'string' ? obj : undefined; - var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); - var len1 = WASM_VECTOR_LEN; - getInt32Memory0()[arg0 / 4 + 1] = len1; - getInt32Memory0()[arg0 / 4 + 0] = ptr1; - }; - imports.wbg.__wbindgen_boolean_get = function(arg0) { - const v = getObject(arg0); - const ret = typeof(v) === 'boolean' ? (v ? 1 : 0) : 2; - return ret; - }; - imports.wbg.__wbg_instanceof_WebGl2RenderingContext_f921526c513bf717 = function(arg0) { - let result; - try { - result = getObject(arg0) instanceof WebGL2RenderingContext; - } catch { - result = false; - } - const ret = result; - return ret; - }; - imports.wbg.__wbg_bindVertexArray_8863a216d7b0a339 = function(arg0, arg1) { - getObject(arg0).bindVertexArray(getObject(arg1)); - }; - imports.wbg.__wbg_bufferData_21334671c4ba6004 = function(arg0, arg1, arg2, arg3) { - getObject(arg0).bufferData(arg1 >>> 0, getObject(arg2), arg3 >>> 0); - }; - imports.wbg.__wbg_createVertexArray_51d51e1e1e13e9f6 = function(arg0) { - const ret = getObject(arg0).createVertexArray(); - return isLikeNone(ret) ? 0 : addHeapObject(ret); - }; - imports.wbg.__wbg_texImage2D_07240affd06971e9 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) { - getObject(arg0).texImage2D(arg1 >>> 0, arg2, arg3, arg4, arg5, arg6, arg7 >>> 0, arg8 >>> 0, getObject(arg9)); - }, arguments) }; - imports.wbg.__wbg_attachShader_47256b6b3d42a22e = function(arg0, arg1, arg2) { - getObject(arg0).attachShader(getObject(arg1), getObject(arg2)); - }; - imports.wbg.__wbg_bindBuffer_24f6010e273fa400 = function(arg0, arg1, arg2) { - getObject(arg0).bindBuffer(arg1 >>> 0, getObject(arg2)); - }; - imports.wbg.__wbg_bindFramebuffer_a9573e340dab20fe = function(arg0, arg1, arg2) { - getObject(arg0).bindFramebuffer(arg1 >>> 0, getObject(arg2)); - }; - imports.wbg.__wbg_bindTexture_92d6d7f8bff9531e = function(arg0, arg1, arg2) { - getObject(arg0).bindTexture(arg1 >>> 0, getObject(arg2)); - }; - imports.wbg.__wbg_blendFunc_533de6de45b80a09 = function(arg0, arg1, arg2) { - getObject(arg0).blendFunc(arg1 >>> 0, arg2 >>> 0); - }; - imports.wbg.__wbg_clear_2db2efe323bfdf68 = function(arg0, arg1) { - getObject(arg0).clear(arg1 >>> 0); - }; - imports.wbg.__wbg_clearColor_7a7d04702f7e38e5 = function(arg0, arg1, arg2, arg3, arg4) { - getObject(arg0).clearColor(arg1, arg2, arg3, arg4); - }; - imports.wbg.__wbg_compileShader_6bf78b425d5c98e1 = function(arg0, arg1) { - getObject(arg0).compileShader(getObject(arg1)); - }; - imports.wbg.__wbg_createBuffer_323425af422748ac = function(arg0) { - const ret = getObject(arg0).createBuffer(); - return isLikeNone(ret) ? 0 : addHeapObject(ret); - }; - imports.wbg.__wbg_createFramebuffer_1684a99697ac9563 = function(arg0) { - const ret = getObject(arg0).createFramebuffer(); - return isLikeNone(ret) ? 0 : addHeapObject(ret); - }; - imports.wbg.__wbg_createProgram_4eaf3b97b5747a62 = function(arg0) { - const ret = getObject(arg0).createProgram(); - return isLikeNone(ret) ? 0 : addHeapObject(ret); - }; - imports.wbg.__wbg_createShader_429776c9dd6fb87b = function(arg0, arg1) { - const ret = getObject(arg0).createShader(arg1 >>> 0); - return isLikeNone(ret) ? 0 : addHeapObject(ret); - }; - imports.wbg.__wbg_createTexture_1bf4d6fec570124b = function(arg0) { - const ret = getObject(arg0).createTexture(); - return isLikeNone(ret) ? 0 : addHeapObject(ret); - }; - imports.wbg.__wbg_disable_e02106ca6c7002d6 = function(arg0, arg1) { - getObject(arg0).disable(arg1 >>> 0); - }; - imports.wbg.__wbg_drawArrays_c91ce3f736bf1f2a = function(arg0, arg1, arg2, arg3) { - getObject(arg0).drawArrays(arg1 >>> 0, arg2, arg3); - }; - imports.wbg.__wbg_drawElements_a9529eefaf2008bd = function(arg0, arg1, arg2, arg3, arg4) { - getObject(arg0).drawElements(arg1 >>> 0, arg2, arg3 >>> 0, arg4); - }; - imports.wbg.__wbg_enable_195891416c520019 = function(arg0, arg1) { - getObject(arg0).enable(arg1 >>> 0); - }; - imports.wbg.__wbg_enableVertexAttribArray_8804480c2ea0bb72 = function(arg0, arg1) { - getObject(arg0).enableVertexAttribArray(arg1 >>> 0); - }; - imports.wbg.__wbg_framebufferTexture2D_e88fcbd7f8523bb8 = function(arg0, arg1, arg2, arg3, arg4, arg5) { - getObject(arg0).framebufferTexture2D(arg1 >>> 0, arg2 >>> 0, arg3 >>> 0, getObject(arg4), arg5); - }; - imports.wbg.__wbg_getError_7191ad6ea53607fe = function(arg0) { - const ret = getObject(arg0).getError(); - return ret; - }; - imports.wbg.__wbg_getExtension_77909f6d51d49d4d = function() { return handleError(function (arg0, arg1, arg2) { - const ret = getObject(arg0).getExtension(getStringFromWasm0(arg1, arg2)); - return isLikeNone(ret) ? 0 : addHeapObject(ret); - }, arguments) }; - imports.wbg.__wbg_getParameter_55b36a787dbbfb74 = function() { return handleError(function (arg0, arg1) { - const ret = getObject(arg0).getParameter(arg1 >>> 0); - return addHeapObject(ret); - }, arguments) }; - imports.wbg.__wbg_getProgramInfoLog_b81bc53188e286fa = function(arg0, arg1, arg2) { - const ret = getObject(arg1).getProgramInfoLog(getObject(arg2)); - var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); - var len1 = WASM_VECTOR_LEN; - getInt32Memory0()[arg0 / 4 + 1] = len1; - getInt32Memory0()[arg0 / 4 + 0] = ptr1; - }; - imports.wbg.__wbg_getProgramParameter_35522a0bfdfaad27 = function(arg0, arg1, arg2) { - const ret = getObject(arg0).getProgramParameter(getObject(arg1), arg2 >>> 0); - return addHeapObject(ret); - }; - imports.wbg.__wbg_getShaderInfoLog_968b93e75477d725 = function(arg0, arg1, arg2) { - const ret = getObject(arg1).getShaderInfoLog(getObject(arg2)); - var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); - var len1 = WASM_VECTOR_LEN; - getInt32Memory0()[arg0 / 4 + 1] = len1; - getInt32Memory0()[arg0 / 4 + 0] = ptr1; - }; - imports.wbg.__wbg_getShaderParameter_ac2727ae4fe7648e = function(arg0, arg1, arg2) { - const ret = getObject(arg0).getShaderParameter(getObject(arg1), arg2 >>> 0); - return addHeapObject(ret); - }; - imports.wbg.__wbg_getSupportedExtensions_fafc31aab913037d = function(arg0) { - const ret = getObject(arg0).getSupportedExtensions(); - return isLikeNone(ret) ? 0 : addHeapObject(ret); - }; - imports.wbg.__wbg_getUniformLocation_9f6eb60c560a347b = function(arg0, arg1, arg2, arg3) { - const ret = getObject(arg0).getUniformLocation(getObject(arg1), getStringFromWasm0(arg2, arg3)); - return isLikeNone(ret) ? 0 : addHeapObject(ret); - }; - imports.wbg.__wbg_linkProgram_33998194075d71fb = function(arg0, arg1) { - getObject(arg0).linkProgram(getObject(arg1)); - }; - imports.wbg.__wbg_shaderSource_1cb7c64dc7d1a500 = function(arg0, arg1, arg2, arg3) { - getObject(arg0).shaderSource(getObject(arg1), getStringFromWasm0(arg2, arg3)); - }; - imports.wbg.__wbg_texParameteri_85dad939f62a15aa = function(arg0, arg1, arg2, arg3) { - getObject(arg0).texParameteri(arg1 >>> 0, arg2 >>> 0, arg3); - }; - imports.wbg.__wbg_uniform1i_d2e61a6a43889648 = function(arg0, arg1, arg2) { - getObject(arg0).uniform1i(getObject(arg1), arg2); - }; - imports.wbg.__wbg_uniform3f_8364a0959b6c1570 = function(arg0, arg1, arg2, arg3, arg4) { - getObject(arg0).uniform3f(getObject(arg1), arg2, arg3, arg4); - }; - imports.wbg.__wbg_useProgram_3683cf6f60939dcd = function(arg0, arg1) { - getObject(arg0).useProgram(getObject(arg1)); - }; - imports.wbg.__wbg_vertexAttribPointer_316ffe2f0458fde7 = function(arg0, arg1, arg2, arg3, arg4, arg5, arg6) { - getObject(arg0).vertexAttribPointer(arg1 >>> 0, arg2, arg3 >>> 0, arg4 !== 0, arg5, arg6); - }; - imports.wbg.__wbg_getElementById_cc0e0d931b0d9a28 = function(arg0, arg1, arg2) { - const ret = getObject(arg0).getElementById(getStringFromWasm0(arg1, arg2)); - return isLikeNone(ret) ? 0 : addHeapObject(ret); - }; - imports.wbg.__wbg_instanceof_HtmlCanvasElement_da5f9efa0688cf6d = function(arg0) { - let result; - try { - result = getObject(arg0) instanceof HTMLCanvasElement; - } catch { - result = false; - } - const ret = result; - return ret; - }; - imports.wbg.__wbg_setwidth_a667a942dba6656e = function(arg0, arg1) { - getObject(arg0).width = arg1 >>> 0; - }; - imports.wbg.__wbg_setheight_a747d440760fe5aa = function(arg0, arg1) { - getObject(arg0).height = arg1 >>> 0; - }; - imports.wbg.__wbg_getContext_7c5944ea807bf5d3 = function() { return handleError(function (arg0, arg1, arg2) { - const ret = getObject(arg0).getContext(getStringFromWasm0(arg1, arg2)); - return isLikeNone(ret) ? 0 : addHeapObject(ret); - }, arguments) }; - imports.wbg.__wbg_offsetX_5a58f16f6c3a41b6 = function(arg0) { - const ret = getObject(arg0).offsetX; - return ret; - }; - imports.wbg.__wbg_offsetY_c45b4956f6429a95 = function(arg0) { - const ret = getObject(arg0).offsetY; - return ret; - }; - imports.wbg.__wbg_now_0cfdc90c97d0c24b = function(arg0) { - const ret = getObject(arg0).now(); - return ret; - }; - imports.wbg.__wbg_instanceof_Window_9029196b662bc42a = function(arg0) { - let result; - try { - result = getObject(arg0) instanceof Window; - } catch { - result = false; - } - const ret = result; - return ret; - }; - imports.wbg.__wbg_charCode_75cea1a3a6d66388 = function(arg0) { - const ret = getObject(arg0).charCode; - return ret; - }; - imports.wbg.__wbg_keyCode_dfa86be31f5ef90c = function(arg0) { - const ret = getObject(arg0).keyCode; - return ret; - }; - imports.wbg.__wbg_code_96d6322b968b2d17 = function(arg0, arg1) { - const ret = getObject(arg1).code; - const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); - const len1 = WASM_VECTOR_LEN; - getInt32Memory0()[arg0 / 4 + 1] = len1; - getInt32Memory0()[arg0 / 4 + 0] = ptr1; - }; - imports.wbg.__wbg_getModifierState_5102ee8843516d2f = function(arg0, arg1, arg2) { - const ret = getObject(arg0).getModifierState(getStringFromWasm0(arg1, arg2)); - return ret; - }; - imports.wbg.__wbg_document_f7ace2b956f30a4f = function(arg0) { - const ret = getObject(arg0).document; - return isLikeNone(ret) ? 0 : addHeapObject(ret); - }; - imports.wbg.__wbg_performance_2c295061c8b01e0b = function(arg0) { - const ret = getObject(arg0).performance; - return isLikeNone(ret) ? 0 : addHeapObject(ret); - }; - imports.wbg.__wbg_setonkeydown_933cca3c9000a932 = function(arg0, arg1) { - getObject(arg0).onkeydown = getObject(arg1); - }; - imports.wbg.__wbg_setonkeyup_0dfb23e81d0afdde = function(arg0, arg1) { - getObject(arg0).onkeyup = getObject(arg1); - }; - imports.wbg.__wbg_requestAnimationFrame_d082200514b6674d = function() { return handleError(function (arg0, arg1) { - const ret = getObject(arg0).requestAnimationFrame(getObject(arg1)); - return ret; - }, arguments) }; - imports.wbg.__wbg_setonmousedown_4f38d9c057bbfcbd = function(arg0, arg1) { - getObject(arg0).onmousedown = getObject(arg1); - }; - imports.wbg.__wbg_setonmousemove_c0b17753786f3544 = function(arg0, arg1) { - getObject(arg0).onmousemove = getObject(arg1); - }; - imports.wbg.__wbg_setonmouseup_4b447fa380e33802 = function(arg0, arg1) { - getObject(arg0).onmouseup = getObject(arg1); - }; - imports.wbg.__wbg_bufferData_a11a9f65f31e7256 = function(arg0, arg1, arg2, arg3) { - getObject(arg0).bufferData(arg1 >>> 0, getObject(arg2), arg3 >>> 0); - }; - imports.wbg.__wbg_texImage2D_6175916e58c59bc7 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) { - getObject(arg0).texImage2D(arg1 >>> 0, arg2, arg3, arg4, arg5, arg6, arg7 >>> 0, arg8 >>> 0, getObject(arg9)); - }, arguments) }; - imports.wbg.__wbg_attachShader_b65b695055670cb5 = function(arg0, arg1, arg2) { - getObject(arg0).attachShader(getObject(arg1), getObject(arg2)); - }; - imports.wbg.__wbg_bindBuffer_313561e5bc0e533f = function(arg0, arg1, arg2) { - getObject(arg0).bindBuffer(arg1 >>> 0, getObject(arg2)); - }; - imports.wbg.__wbg_bindFramebuffer_56bf6536a4ced0ec = function(arg0, arg1, arg2) { - getObject(arg0).bindFramebuffer(arg1 >>> 0, getObject(arg2)); - }; - imports.wbg.__wbg_bindTexture_9cb5c770d1ba2cca = function(arg0, arg1, arg2) { - getObject(arg0).bindTexture(arg1 >>> 0, getObject(arg2)); - }; - imports.wbg.__wbg_blendFunc_fbe9d3a688fe71c3 = function(arg0, arg1, arg2) { - getObject(arg0).blendFunc(arg1 >>> 0, arg2 >>> 0); - }; - imports.wbg.__wbg_clear_2ccea1f65b510c97 = function(arg0, arg1) { - getObject(arg0).clear(arg1 >>> 0); - }; - imports.wbg.__wbg_clearColor_de587608b28bc7ed = function(arg0, arg1, arg2, arg3, arg4) { - getObject(arg0).clearColor(arg1, arg2, arg3, arg4); - }; - imports.wbg.__wbg_compileShader_d88d0a8cd9b72b4d = function(arg0, arg1) { - getObject(arg0).compileShader(getObject(arg1)); - }; - imports.wbg.__wbg_createBuffer_59051f4461e7c5e2 = function(arg0) { - const ret = getObject(arg0).createBuffer(); - return isLikeNone(ret) ? 0 : addHeapObject(ret); - }; - imports.wbg.__wbg_createFramebuffer_223c1212ad76affc = function(arg0) { - const ret = getObject(arg0).createFramebuffer(); - return isLikeNone(ret) ? 0 : addHeapObject(ret); - }; - imports.wbg.__wbg_createProgram_88dbe21c0b682e1a = function(arg0) { - const ret = getObject(arg0).createProgram(); - return isLikeNone(ret) ? 0 : addHeapObject(ret); - }; - imports.wbg.__wbg_createShader_9d7d388633caad18 = function(arg0, arg1) { - const ret = getObject(arg0).createShader(arg1 >>> 0); - return isLikeNone(ret) ? 0 : addHeapObject(ret); - }; - imports.wbg.__wbg_createTexture_9d0bb4d741b8ad76 = function(arg0) { - const ret = getObject(arg0).createTexture(); - return isLikeNone(ret) ? 0 : addHeapObject(ret); - }; - imports.wbg.__wbg_disable_5cf2070641fa2ed7 = function(arg0, arg1) { - getObject(arg0).disable(arg1 >>> 0); - }; - imports.wbg.__wbg_drawArrays_d5c7dc2b2376c85a = function(arg0, arg1, arg2, arg3) { - getObject(arg0).drawArrays(arg1 >>> 0, arg2, arg3); - }; - imports.wbg.__wbg_drawElements_3316ee0cd1117c2a = function(arg0, arg1, arg2, arg3, arg4) { - getObject(arg0).drawElements(arg1 >>> 0, arg2, arg3 >>> 0, arg4); - }; - imports.wbg.__wbg_enable_8965e69c596f0a94 = function(arg0, arg1) { - getObject(arg0).enable(arg1 >>> 0); - }; - imports.wbg.__wbg_enableVertexAttribArray_2b0475db43533cf2 = function(arg0, arg1) { - getObject(arg0).enableVertexAttribArray(arg1 >>> 0); - }; - imports.wbg.__wbg_framebufferTexture2D_953e69a8bec22fa9 = function(arg0, arg1, arg2, arg3, arg4, arg5) { - getObject(arg0).framebufferTexture2D(arg1 >>> 0, arg2 >>> 0, arg3 >>> 0, getObject(arg4), arg5); - }; - imports.wbg.__wbg_getError_1e5ec1ec9e58b323 = function(arg0) { - const ret = getObject(arg0).getError(); - return ret; - }; - imports.wbg.__wbg_getProgramInfoLog_0b7af4ad85fa52a4 = function(arg0, arg1, arg2) { - const ret = getObject(arg1).getProgramInfoLog(getObject(arg2)); - var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); - var len1 = WASM_VECTOR_LEN; - getInt32Memory0()[arg0 / 4 + 1] = len1; - getInt32Memory0()[arg0 / 4 + 0] = ptr1; - }; - imports.wbg.__wbg_getProgramParameter_2a3735278367f8bc = function(arg0, arg1, arg2) { - const ret = getObject(arg0).getProgramParameter(getObject(arg1), arg2 >>> 0); - return addHeapObject(ret); - }; - imports.wbg.__wbg_getShaderInfoLog_979aafa403ffb252 = function(arg0, arg1, arg2) { - const ret = getObject(arg1).getShaderInfoLog(getObject(arg2)); - var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); - var len1 = WASM_VECTOR_LEN; - getInt32Memory0()[arg0 / 4 + 1] = len1; - getInt32Memory0()[arg0 / 4 + 0] = ptr1; - }; - imports.wbg.__wbg_getShaderParameter_e8054f1d9026fb70 = function(arg0, arg1, arg2) { - const ret = getObject(arg0).getShaderParameter(getObject(arg1), arg2 >>> 0); - return addHeapObject(ret); - }; - imports.wbg.__wbg_getUniformLocation_688976233799a45a = function(arg0, arg1, arg2, arg3) { - const ret = getObject(arg0).getUniformLocation(getObject(arg1), getStringFromWasm0(arg2, arg3)); - return isLikeNone(ret) ? 0 : addHeapObject(ret); - }; - imports.wbg.__wbg_linkProgram_9a2d12d120d99917 = function(arg0, arg1) { - getObject(arg0).linkProgram(getObject(arg1)); - }; - imports.wbg.__wbg_shaderSource_f435f9b74440bb54 = function(arg0, arg1, arg2, arg3) { - getObject(arg0).shaderSource(getObject(arg1), getStringFromWasm0(arg2, arg3)); - }; - imports.wbg.__wbg_texParameteri_1f17358e51eb8069 = function(arg0, arg1, arg2, arg3) { - getObject(arg0).texParameteri(arg1 >>> 0, arg2 >>> 0, arg3); - }; - imports.wbg.__wbg_uniform1i_9f94ef0ba6b3cc66 = function(arg0, arg1, arg2) { - getObject(arg0).uniform1i(getObject(arg1), arg2); - }; - imports.wbg.__wbg_uniform3f_c682f4b32f713d1a = function(arg0, arg1, arg2, arg3, arg4) { - getObject(arg0).uniform3f(getObject(arg1), arg2, arg3, arg4); - }; - imports.wbg.__wbg_useProgram_019eb6df066fabf5 = function(arg0, arg1) { - getObject(arg0).useProgram(getObject(arg1)); - }; - imports.wbg.__wbg_vertexAttribPointer_ca11984ee8843c0a = function(arg0, arg1, arg2, arg3, arg4, arg5, arg6) { - getObject(arg0).vertexAttribPointer(arg1 >>> 0, arg2, arg3 >>> 0, arg4 !== 0, arg5, arg6); - }; - imports.wbg.__wbg_bindVertexArrayOES_b7d9da7e073aa6b5 = function(arg0, arg1) { - getObject(arg0).bindVertexArrayOES(getObject(arg1)); - }; - imports.wbg.__wbg_createVertexArrayOES_6a3c3a5a68201f8f = function(arg0) { - const ret = getObject(arg0).createVertexArrayOES(); - return isLikeNone(ret) ? 0 : addHeapObject(ret); - }; - imports.wbg.__wbg_self_1c2814d86e6e51e3 = function() { return handleError(function () { - const ret = self.self; - return addHeapObject(ret); - }, arguments) }; - imports.wbg.__wbg_crypto_70532d614bc7e028 = function(arg0) { - const ret = getObject(arg0).crypto; - return addHeapObject(ret); - }; - imports.wbg.__wbg_msCrypto_4e9b4dd0e1abade6 = function(arg0) { - const ret = getObject(arg0).msCrypto; - return addHeapObject(ret); - }; - imports.wbg.__wbindgen_is_undefined = function(arg0) { - const ret = getObject(arg0) === undefined; - return ret; - }; - imports.wbg.__wbg_static_accessor_MODULE_7781e47b50010688 = function() { - const ret = module; - return addHeapObject(ret); - }; - imports.wbg.__wbg_require_9ace3ae680954e98 = function() { return handleError(function (arg0, arg1, arg2) { - const ret = getObject(arg0).require(getStringFromWasm0(arg1, arg2)); - return addHeapObject(ret); - }, arguments) }; - imports.wbg.__wbg_getRandomValues_f6c9b08ef5448767 = function() { return handleError(function (arg0, arg1) { - getObject(arg0).getRandomValues(getObject(arg1)); - }, arguments) }; - imports.wbg.__wbg_randomFillSync_bf67eeddb65b346b = function() { return handleError(function (arg0, arg1, arg2) { - getObject(arg0).randomFillSync(getArrayU8FromWasm0(arg1, arg2)); - }, arguments) }; - imports.wbg.__wbg_get_44be0491f933a435 = function(arg0, arg1) { - const ret = getObject(arg0)[arg1 >>> 0]; - return addHeapObject(ret); - }; - imports.wbg.__wbg_length_fff51ee6522a1a18 = function(arg0) { - const ret = getObject(arg0).length; - return ret; - }; - imports.wbg.__wbg_newnoargs_581967eacc0e2604 = function(arg0, arg1) { - const ret = new Function(getStringFromWasm0(arg0, arg1)); - return addHeapObject(ret); - }; - imports.wbg.__wbg_call_cb65541d95d71282 = function() { return handleError(function (arg0, arg1) { - const ret = getObject(arg0).call(getObject(arg1)); - return addHeapObject(ret); - }, arguments) }; - imports.wbg.__wbg_self_1ff1d729e9aae938 = function() { return handleError(function () { - const ret = self.self; - return addHeapObject(ret); - }, arguments) }; - imports.wbg.__wbg_window_5f4faef6c12b79ec = function() { return handleError(function () { - const ret = window.window; - return addHeapObject(ret); - }, arguments) }; - imports.wbg.__wbg_globalThis_1d39714405582d3c = function() { return handleError(function () { - const ret = globalThis.globalThis; - return addHeapObject(ret); - }, arguments) }; - imports.wbg.__wbg_global_651f05c6a0944d1c = function() { return handleError(function () { - const ret = global.global; - return addHeapObject(ret); - }, arguments) }; - imports.wbg.__wbg_now_9c5990bda04c7e53 = function() { - const ret = Date.now(); - return ret; - }; - imports.wbg.__wbg_buffer_085ec1f694018c4f = function(arg0) { - const ret = getObject(arg0).buffer; - return addHeapObject(ret); - }; - imports.wbg.__wbg_newwithbyteoffsetandlength_828b952f0e692245 = function(arg0, arg1, arg2) { - const ret = new Int8Array(getObject(arg0), arg1 >>> 0, arg2 >>> 0); - return addHeapObject(ret); - }; - imports.wbg.__wbg_newwithbyteoffsetandlength_735ed5ea2ae07fe9 = function(arg0, arg1, arg2) { - const ret = new Int16Array(getObject(arg0), arg1 >>> 0, arg2 >>> 0); - return addHeapObject(ret); - }; - imports.wbg.__wbg_newwithbyteoffsetandlength_9f43b22ab631d1d6 = function(arg0, arg1, arg2) { - const ret = new Int32Array(getObject(arg0), arg1 >>> 0, arg2 >>> 0); - return addHeapObject(ret); - }; - imports.wbg.__wbg_newwithbyteoffsetandlength_6da8e527659b86aa = function(arg0, arg1, arg2) { - const ret = new Uint8Array(getObject(arg0), arg1 >>> 0, arg2 >>> 0); - return addHeapObject(ret); - }; - imports.wbg.__wbg_new_8125e318e6245eed = function(arg0) { - const ret = new Uint8Array(getObject(arg0)); - return addHeapObject(ret); - }; - imports.wbg.__wbg_set_5cf90238115182c3 = function(arg0, arg1, arg2) { - getObject(arg0).set(getObject(arg1), arg2 >>> 0); - }; - imports.wbg.__wbg_length_72e2208bbc0efc61 = function(arg0) { - const ret = getObject(arg0).length; - return ret; - }; - imports.wbg.__wbg_newwithbyteoffsetandlength_31ff1024ef0c63c7 = function(arg0, arg1, arg2) { - const ret = new Uint16Array(getObject(arg0), arg1 >>> 0, arg2 >>> 0); - return addHeapObject(ret); - }; - imports.wbg.__wbg_newwithbyteoffsetandlength_6df0e8c3efd2a5d3 = function(arg0, arg1, arg2) { - const ret = new Uint32Array(getObject(arg0), arg1 >>> 0, arg2 >>> 0); - return addHeapObject(ret); - }; - imports.wbg.__wbg_newwithbyteoffsetandlength_69193e31c844b792 = function(arg0, arg1, arg2) { - const ret = new Float32Array(getObject(arg0), arg1 >>> 0, arg2 >>> 0); - return addHeapObject(ret); - }; - imports.wbg.__wbg_newwithlength_e5d69174d6984cd7 = function(arg0) { - const ret = new Uint8Array(arg0 >>> 0); - return addHeapObject(ret); - }; - imports.wbg.__wbg_subarray_13db269f57aa838d = function(arg0, arg1, arg2) { - const ret = getObject(arg0).subarray(arg1 >>> 0, arg2 >>> 0); - return addHeapObject(ret); - }; - imports.wbg.__wbindgen_debug_string = function(arg0, arg1) { - const ret = debugString(getObject(arg1)); - const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); - const len1 = WASM_VECTOR_LEN; - getInt32Memory0()[arg0 / 4 + 1] = len1; - getInt32Memory0()[arg0 / 4 + 0] = ptr1; - }; - imports.wbg.__wbindgen_throw = function(arg0, arg1) { - throw new Error(getStringFromWasm0(arg0, arg1)); - }; - imports.wbg.__wbindgen_memory = function() { - const ret = wasm.memory; - return addHeapObject(ret); - }; - imports.wbg.__wbindgen_closure_wrapper257 = function(arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 14, __wbg_adapter_20); - return addHeapObject(ret); - }; - imports.wbg.__wbindgen_closure_wrapper2960 = function(arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 698, __wbg_adapter_23); - return addHeapObject(ret); - }; - imports.wbg.__wbindgen_closure_wrapper2962 = function(arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, 698, __wbg_adapter_23); - return addHeapObject(ret); - }; - - return imports; -} - -function __wbg_init_memory(imports, maybe_memory) { - -} - -function __wbg_finalize_init(instance, module) { - wasm = instance.exports; - __wbg_init.__wbindgen_wasm_module = module; - cachedInt32Memory0 = null; - cachedUint8Memory0 = null; - - wasm.__wbindgen_start(); - return wasm; -} - -function initSync(module) { - if (wasm !== undefined) return wasm; - - const imports = __wbg_get_imports(); - - __wbg_init_memory(imports); - - if (!(module instanceof WebAssembly.Module)) { - module = new WebAssembly.Module(module); - } - - const instance = new WebAssembly.Instance(module, imports); - - return __wbg_finalize_init(instance, module); -} - -async function __wbg_init(input) { - if (wasm !== undefined) return wasm; - - if (typeof input === 'undefined' && script_src !== 'undefined') { - input = script_src.replace(/\.js$/, '_bg.wasm'); - } - const imports = __wbg_get_imports(); - - if (typeof input === 'string' || (typeof Request === 'function' && input instanceof Request) || (typeof URL === 'function' && input instanceof URL)) { - input = fetch(input); - } - - __wbg_init_memory(imports); - - const { instance, module } = await __wbg_load(await input, imports); - - return __wbg_finalize_init(instance, module); -} - -wasm_bindgen = Object.assign(__wbg_init, { initSync }, __exports); - -})(); diff --git a/web/rust-rl_bg.wasm b/web/rust-rl_bg.wasm deleted file mode 100644 index 79ebb75..0000000 Binary files a/web/rust-rl_bg.wasm and /dev/null differ