Compare commits

..

28 commits

Author SHA1 Message Date
Llywelwyn
c29b93337c
Update README.md 2025-03-09 11:12:11 +00:00
Llywelwyn
0584d07a1f
Update cargo-build-test.yml to use ubuntu-22.04 2025-03-09 11:04:32 +00:00
Llywelwyn
45b9b33039
Update cargo-build-test.yml 2025-03-09 11:02:16 +00:00
Lewis Wynne
bdcd55c8a5 Fixes miscoloured logs (fixes #26) 2025-03-09 10:50:35 +00:00
Llywelwyn
99c17f8521 draw hunger uses Point 2024-06-17 23:22:30 +01:00
Llywelwyn
6324449c16 draw_hunger() 2024-06-17 23:19:20 +01:00
Llywelwyn
d465592c0f abstracts ui drawing 2024-06-16 10:31:06 +01:00
Llywelwyn
f494efbf3f bump ver 2024-06-15 20:41:21 +01:00
Llywelwyn
ba5d120fef fix warns, bump ver 2024-06-15 20:40:51 +01:00
Llywelwyn
c5106a63b5 static inventory keys - items remember their slots
this is the biggest refactor of my entire life
2024-06-15 20:14:38 +01:00
Llywelwyn
9719ebbe88 docs tldr 2024-06-15 17:35:40 +01:00
Llywelwyn
2eaf431942 disable show_mapgen for default config 2024-06-15 17:24:37 +01:00
Llywelwyn
a7c5d2167c back to serde_json 2024-06-15 16:46:15 +01:00
Llywelwyn
678636c57d Revert "Infallible -> NoError"
This reverts commit 9c8f301491.
2024-06-15 16:44:13 +01:00
Llywelwyn
30697a98bb rm room_accretion for now 2024-06-15 16:43:17 +01:00
Llywelwyn
c73f9a5458 Revert "cherry pick -> serde_json saves to bincode"
This reverts commit 180532ee3e.
2024-06-15 16:42:59 +01:00
Llywelwyn
9c8f301491 Infallible -> NoError 2023-10-24 23:32:42 +01:00
Llywelwyn
180532ee3e cherry pick -> serde_json saves to bincode 2023-10-24 11:13:43 +01:00
Llywelwyn
46bbe14bea added effects for adding intrinsics 2023-10-02 23:02:46 +01:00
Llywelwyn
fa4612cf1f changed get_noncursed() to helper on BUC struct 2023-10-02 23:02:34 +01:00
Llywelwyn
4d21bd46d4 add_intr!() macro for adding intrinsics to the Player
If needed, player can just be replaced by another arg to the macro so this works on every other entity - but right now the player is the only thing to gain/lose intrinsics.
2023-10-02 22:14:00 +01:00
Llywelwyn
b5743819ec .describe() for Intrinsics, for use in tooltips later 2023-10-02 21:11:12 +01:00
Llywelwyn
190543a361 move all doors to the ends of corridors 2023-10-02 07:39:45 +01:00
Llywelwyn
7a27321bec initial tweaks - starting room w/ corridors + doors 2023-10-02 07:00:28 +01:00
Llywelwyn
97ca3a25e3 doors and door directions - RA 2023-10-02 04:43:01 +01:00
Llywelwyn
1fa7432dfe room accretion - initial 2023-10-01 20:56:46 +01:00
Llywelwyn
fa3b906dce adds article to ID morgue msg 2023-09-23 11:21:34 +01:00
Llywelwyn
2d33c90af8 fixes infini-dungeon difficulty 2023-09-23 11:12:28 +01:00
64 changed files with 1157 additions and 1928 deletions

View file

@ -12,7 +12,7 @@ env:
jobs:
build:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3

View file

@ -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

View file

@ -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.
---
<details>
<summary>boring details about the sprint where this project started</summary>
<details>
<summary>week 1</summary>
@ -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)
</details>
</details>

View file

@ -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.

View file

@ -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"]
}
]

View file

@ -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": []
},
{

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 337 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

View file

@ -45,7 +45,6 @@ impl<'a> System<'a> for ApproachAI {
continue;
};
let mut path: Option<NavigationPath> = 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;
}
}
}
}

View file

@ -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));

View file

@ -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::<Point>();
let map = ecs.fetch::<Map>();
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::<Point>()),
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::<Point>())
);
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::<Point>()),
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::<Position>();
let renderables = ecs.read_storage::<Renderable>();
let pools = ecs.read_storage::<Pools>();
let minds = ecs.read_storage::<Mind>();
let hidden = ecs.read_storage::<Hidden>();
let props = ecs.write_storage::<Prop>();
@ -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::<Point>()),
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);
}
}

View file

@ -41,7 +41,6 @@ pub struct OtherLevelPosition {
#[derive(Component, ConvertSaveload, Clone)]
pub struct Renderable {
pub glyph: FontCharType,
pub sprite: Option<usize>,
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<Intrinsic>,
}
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<Intrinsic>,
pub lost: HashSet<Intrinsic>,
}
#[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 {}

View file

@ -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::<WantsToRemoveKey>();
let delete = ecs.read_storage::<WantsToDelete>();
// 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.");
}
}

View file

@ -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";

View file

@ -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 };
}

View file

@ -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;

View file

@ -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;

View file

@ -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::<Name>().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());

11
src/effects/intrinsics.rs Normal file
View file

@ -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);
}

View file

@ -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),
_ => {}
}
}

View file

@ -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<Entity>, 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::<Consumable>().get(item).is_some() {
ecs.entities().delete(item).expect("Failed to delete item");
let mut removekey = ecs.write_storage::<WantsToRemoveKey>();
removekey.insert(item, WantsToRemoveKey {}).expect("Unable to insert WantsToRemoveKey");
let mut delete = ecs.write_storage::<WantsToDelete>();
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::<Renderable>();
if ecs.read_storage::<Player>().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::<Entity>()).unwrap();
if ecs.read_storage::<Player>().get(target).is_some() {
logger = logger
.colour(renderable_colour(&renderables, target))
.append("You")
.colour(WHITE)
.append(DAMAGE_PLAYER_HIT);
event.log = true;
} else if

View file

@ -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.

View file

@ -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::<RunState>();
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,

View file

@ -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)));

View file

@ -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<Entity>) {
@ -37,38 +38,41 @@ pub fn identify(gs: &mut State, ctx: &mut BTerm) -> (ItemMenuResult, Option<Enti
let names = gs.ecs.read_storage::<Name>();
let renderables = gs.ecs.read_storage::<Renderable>();
let beatitudes = gs.ecs.read_storage::<Beatitude>();
let keys = gs.ecs.read_storage::<Key>();
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<Enti
.log();
return (ItemMenuResult::Selected, Some(build_identify_iterator().nth(0).unwrap().0));
}
let mut player_inventory: super::PlayerInventory = BTreeMap::new();
for (entity, _i, renderable, name) in build_identify_iterator() {
let (singular, plural) = obfuscate_name_ecs(&gs.ecs, entity);
let beatitude_status = if
let Some(beatitude) = gs.ecs.read_storage::<Beatitude>().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<Enti
"Identify 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),
@ -141,21 +126,17 @@ pub fn identify(gs: &mut State, ctx: &mut BTerm) -> (ItemMenuResult, Option<Enti
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 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::<Key>();
let backpack = gs.ecs.read_storage::<InBackpack>();
for (e, key, _b) in (&entities, &keyed_items, &backpack).join() {
if key.idx == (selection as usize) {
return (ItemMenuResult::Selected, Some(e));
}
}
}
(ItemMenuResult::NoResponse, None)
}

File diff suppressed because it is too large Load diff

View file

@ -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<Entity>) {
@ -33,11 +36,12 @@ pub fn remove_curse(gs: &mut State, ctx: &mut BTerm) -> (ItemMenuResult, Option<
let beatitudes = gs.ecs.read_storage::<Beatitude>();
let names = gs.ecs.read_storage::<Name>();
let renderables = gs.ecs.read_storage::<Renderable>();
let keys = gs.ecs.read_storage::<Key>();
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::<Beatitude>().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::<Key>();
let backpack = gs.ecs.read_storage::<InBackpack>();
for (e, key, _b) in (&entities, &keyed_items, &backpack).join() {
if key.idx == (selection as usize) {
return (ItemMenuResult::Selected, Some(e));
}
}
}
(ItemMenuResult::NoResponse, None)
}

View file

@ -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::<crate::components::Intrinsics>();
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();

View file

@ -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<Entity> = 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();
}
}

View file

@ -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)

View file

@ -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();
}
}

View file

@ -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,
};

59
src/invkeys.rs Normal file
View file

@ -0,0 +1,59 @@
use std::sync::Mutex;
use std::collections::HashMap;
use crate::gui::UniqueInventoryItem;
lazy_static! {
pub static ref INVKEYS: Mutex<HashMap<UniqueInventoryItem, usize>> = Mutex::new(HashMap::new());
pub static ref ASSIGNEDKEYS: Mutex<Vec<bool>> = Mutex::new(vec![false; 52]);
}
/// For (de)serialization.
pub fn clone_invkeys() -> HashMap<UniqueInventoryItem, usize> {
let invkeys = INVKEYS.lock().unwrap();
invkeys.clone()
}
pub fn restore_invkeys(invkeys: HashMap<UniqueInventoryItem, usize>) {
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<usize> {
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<usize> {
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);
}

View file

@ -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;

93
src/macros/mod.rs Normal file
View file

@ -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::<Entity>();
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::<crate::Intrinsics>();
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::<Entity>();
let intrinsics = $ecs.read_storage::<crate::Intrinsics>();
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::<crate::Intrinsics>();
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::<crate::IntrinsicChanged>();
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::<crate::IntrinsicChanged>();
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.");
}
}
};
}

View file

@ -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::<SpawnParticleLine>();
gs.ecs.register::<HasDamageModifiers>();
gs.ecs.register::<Intrinsics>();
gs.ecs.register::<IntrinsicChanged>();
gs.ecs.register::<Stackable>();
gs.ecs.register::<WantsToAssignKey>();
gs.ecs.register::<Key>();
gs.ecs.register::<WantsToRemoveKey>();
gs.ecs.register::<WantsToDelete>();
gs.ecs.register::<SimpleMarker<SerializeMe>>();
gs.ecs.register::<SerializationHelper>();
gs.ecs.register::<DMSerializationHelper>();
@ -157,15 +142,3 @@ fn main() -> BError {
main_loop(context, gs)
}
fn register_spritesheet(width: i32, height: i32, rows: i32, columns: i32) -> Vec<Sprite> {
let mut sprites: Vec<Sprite> = 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
}

View file

@ -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",

View file

@ -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;

View file

@ -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<Point>) -> (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>) -> 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<bool>) -> FontCharType {
if
x < 1 ||

View file

@ -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,

View file

@ -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,

View file

@ -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::<Position>();
@ -134,7 +134,6 @@ pub fn try_door(i: i32, j: i32, ecs: &mut World) -> RunState {
let mut renderables = ecs.write_storage::<Renderable>();
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::<Renderable>();
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::<WantsToAssignKey>();
let mut pickup = ecs.write_storage::<WantsToPickupItem>();
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.");

View file

@ -6,6 +6,7 @@ pub struct Item {
pub id: String,
pub name: Name,
pub renderable: Option<Renderable>,
pub class: String,
pub weight: Option<f32>,
pub value: Option<f32>,
pub equip: Option<Equippable>,
@ -30,7 +31,6 @@ pub struct Equippable {
#[derive(Deserialize, Debug)]
pub struct Renderable {
pub glyph: String,
pub sprite: Option<usize>,
pub fg: String,
pub bg: String,
pub order: i32,

View file

@ -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::<Pools>();
let player_entity = ecs.fetch::<Entity>();
@ -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::<SimpleMarker<SerializeMe>>();
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<Entity> {
if raws.prop_index.contains_key(key) {
let needs_key;
{
let player_entity = ecs.fetch::<Entity>();
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::<SimpleMarker<SerializeMe>>();
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,

View file

@ -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

View file

@ -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,

View file

@ -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::<WantsToRemoveKey>();
let mut intent = self.ecs.write_storage::<WantsToDropItem>();
removekey
.insert(item_entity, WantsToRemoveKey {})
.expect("Unable to insert WantsToRemoveKey");
intent
.insert(*self.ecs.fetch::<Entity>(), 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);

View file

@ -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<Map>) -> Vec<Point> {
pub fn fast_fov(p_x: i32, p_y: i32, r: i32) -> Vec<Point> {
let mut visible_tiles: Vec<Point> = Vec::new();
let mut i = 0;
@ -153,17 +152,7 @@ pub fn fast_fov(p_x: i32, p_y: i32, r: i32, map: &WriteExpect<Map>) -> Vec<Point
let mut ox: f32 = (p_x as f32) + (0.5 as f32);
let mut oy: f32 = (p_y as f32) + (0.5 as f32);
for _i in 0..r {
let (ox_i32, oy_i32) = (ox as i32, oy as i32);
visible_tiles.push(Point::new(ox_i32, oy_i32));
if
ox_i32 >= 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;
}

View file

@ -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);
};

Binary file not shown.

View file

@ -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);
})();

Binary file not shown.