Compare commits
10 commits
cbff127b40
...
1777a6bbf2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1777a6bbf2 | ||
|
|
aa83417ba3 | ||
|
|
dfc86452fc | ||
|
|
d22eaa554d | ||
|
|
cbd4b858ac | ||
|
|
ae0d205037 | ||
|
|
36a49ef768 | ||
|
|
db60f75bd9 | ||
|
|
8073997eb3 | ||
|
|
e742b8772d |
6
Makefile
|
|
@ -37,7 +37,7 @@ tracy_build:
|
|||
meson compile -j 10 -C builddir
|
||||
|
||||
test: build
|
||||
./builddir/runtests -d yes "[systems-engine]"
|
||||
./builddir/runtests -d yes
|
||||
|
||||
run: build test
|
||||
ifeq '$(OS)' 'Windows_NT'
|
||||
|
|
@ -48,7 +48,7 @@ else
|
|||
endif
|
||||
|
||||
debug: build
|
||||
gdb --nx -x .gdbinit --ex run --args builddir/runtests "[systems-engine]"
|
||||
gdb --nx -x .gdbinit --ex run --args builddir/runtests
|
||||
|
||||
debug_run: build
|
||||
gdb --nx -x .gdbinit --batch --ex run --ex bt --ex q --args builddir/zedcaster
|
||||
|
|
@ -60,7 +60,7 @@ clean:
|
|||
meson compile --clean -C builddir
|
||||
|
||||
debug_test: build
|
||||
gdb --nx -x .gdbinit --ex run --ex bt --ex q --args builddir/runtests "[systems-engine]"
|
||||
gdb --nx -x .gdbinit --ex run --ex bt --ex q --args builddir/runtests
|
||||
|
||||
win_installer:
|
||||
powershell 'start "C:\Program Files (x86)\solicus\InstallForge\bin\ifbuilderenvx86.exe" scripts\win_installer.ifp'
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@
|
|||
"close": []
|
||||
}
|
||||
},
|
||||
"rat_with_sword": {
|
||||
"spider_bot": {
|
||||
"sheet": {
|
||||
"frames": 1,
|
||||
"frame_width": 256,
|
||||
|
|
@ -98,14 +98,14 @@
|
|||
"close": []
|
||||
}
|
||||
},
|
||||
"female_hand": {
|
||||
"hands_sword_attack": {
|
||||
"sheet": {
|
||||
"frames": 3,
|
||||
"frame_width": 900,
|
||||
"frame_height": 600
|
||||
"frame_width": 512,
|
||||
"frame_height": 341
|
||||
},
|
||||
"sequences": {
|
||||
"idle": {"frames": [0, 1, 2], "durations": [10, 10, 20] }
|
||||
"idle": {"frames": [0, 1, 2], "durations": [25, 5, 20] }
|
||||
},
|
||||
"transforms": {
|
||||
"basic": {
|
||||
|
|
@ -115,7 +115,7 @@
|
|||
"max_y": 1.0,
|
||||
"flipped": false,
|
||||
"scaled": false,
|
||||
"toggled": true,
|
||||
"toggled": false,
|
||||
"looped": false,
|
||||
"relative": false,
|
||||
"easing": "none",
|
||||
|
|
|
|||
|
|
@ -1,62 +1,29 @@
|
|||
{
|
||||
"sounds": {
|
||||
"Sword_Hit_1": "assets/sounds/Creature_Sounds-Sword_Hit_1.ogg",
|
||||
"Evil_Eye_Sound_1": "assets/sounds/Creature_Sounds-Evil_Eye_Sound_1.ogg",
|
||||
"Evil_Eye_Sound_2": "assets/sounds/Creature_Sounds-Evil_Eye_Sound_2.ogg",
|
||||
"Giant_Voice_1": "assets/sounds/Creature_Sounds-Giant_Voice_1.ogg",
|
||||
"Medium_Rat": "assets/sounds/Creature_Sounds-Medium_Rat.ogg",
|
||||
"Ranger_1": "assets/sounds/Creature_Sounds-Ranger_1.ogg",
|
||||
"Small_Rat": "assets/sounds/Creature_Sounds-Small_Rat.ogg",
|
||||
"Spider_1": "assets/sounds/Creature_Sounds-Spider_1.ogg",
|
||||
"Spider_2": "assets/sounds/Creature_Sounds-Spider_2.ogg",
|
||||
"Sword_Hit_1": "assets/sounds/Creature_Sounds-Sword_Hit_1.ogg",
|
||||
"Sword_Hit_2": "assets/sounds/Creature_Sounds-Sword_Hit_2.ogg",
|
||||
"walk": "assets/sounds/Creature_Sounds-Walk.ogg",
|
||||
"Creature_Death_1": "assets/sounds/Creature_Sounds-Creature_Death_1.ogg",
|
||||
"Humanoid_Death_1": "assets/sounds/Creature_Sounds-Humanoid_Death_1.ogg",
|
||||
"Marmot_Scream_1": "assets/sounds/Creature_Sounds-Marmot_Scream_1.ogg",
|
||||
"blank": "assets/sounds/blank.ogg",
|
||||
"pickup": "assets/sounds/pickup.ogg",
|
||||
"ambient_1": "assets/sounds/ambient_1.ogg",
|
||||
"ui_click": "assets/sounds/ui_click.ogg",
|
||||
"ui_hover": "assets/sounds/ui_hover.ogg",
|
||||
"punch_cartoony": "assets/sounds/punch_cartoony.ogg",
|
||||
"electric_shock_01": "assets/sounds/electric_shock_01.ogg",
|
||||
"fireball_01": "assets/sounds/fireball_01.ogg",
|
||||
"hp_status_80": "assets/sounds/hp_status_80.ogg",
|
||||
"hp_status_60": "assets/sounds/hp_status_60.ogg",
|
||||
"hp_status_30": "assets/sounds/hp_status_30.ogg",
|
||||
"hp_status_10": "assets/sounds/hp_status_10.ogg",
|
||||
"hp_status_00": "assets/sounds/hp_status_00.ogg"
|
||||
"walk": "assets/sounds/walk.ogg"
|
||||
},
|
||||
"sprites": {
|
||||
"rat_with_sword":
|
||||
{"path": "assets/sprites/rat_with_sword.png",
|
||||
"spider_bot":
|
||||
{"path": "assets/sprites/spider_bot.png",
|
||||
"frame_width": 256,
|
||||
"frame_height": 256
|
||||
},
|
||||
"torch_crappy":
|
||||
{"path": "assets/items/torch_crappy.png",
|
||||
"repair_kit":
|
||||
{"path": "assets/items/repair_kit.png",
|
||||
"frame_width": 256,
|
||||
"frame_height": 256
|
||||
},
|
||||
"torch_horizontal_floor":
|
||||
{"path": "assets/items/torch_horizontal_floor.png",
|
||||
"sword_1":
|
||||
{"path": "assets/items/sword_1_sprite.png",
|
||||
"frame_width": 256,
|
||||
"frame_height": 256
|
||||
},
|
||||
"peasant_girl":
|
||||
{"path": "assets/sprites/peasant_girl_2.png",
|
||||
"frame_width": 256,
|
||||
"frame_height": 256
|
||||
},
|
||||
"healing_potion_small":
|
||||
{"path": "assets/items/healing_potion_small.png",
|
||||
"frame_width": 256,
|
||||
"frame_height": 256
|
||||
},
|
||||
"well_down":
|
||||
{"path": "assets/sprites/well_down.png",
|
||||
"ladder_down":
|
||||
{"path": "assets/sprites/ladder_down.png",
|
||||
"frame_width": 256,
|
||||
"frame_height": 256
|
||||
},
|
||||
|
|
@ -75,13 +42,8 @@
|
|||
"frame_width": 256,
|
||||
"frame_height": 256
|
||||
},
|
||||
"peasant_girl":
|
||||
{"path": "assets/sprites/peasant_girl_2.png",
|
||||
"frame_width": 256,
|
||||
"frame_height": 256
|
||||
},
|
||||
"female_hand":
|
||||
{"path": "assets/hands/female_hand.png",
|
||||
"hands_sword_attack":
|
||||
{"path": "assets/hands/hands_sword_attack.png",
|
||||
"frame_width": 900,
|
||||
"frame_height": 600
|
||||
}
|
||||
|
|
@ -109,9 +71,9 @@
|
|||
"border_px": 1,
|
||||
"text_size": 20,
|
||||
"label_size": 20,
|
||||
"font_file_name": "assets/text.otf"
|
||||
"font_file_name": "assets/text.ttf"
|
||||
},
|
||||
"player": {
|
||||
"hands": "female_hand"
|
||||
"hands": "hands_sword_attack"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
{"_type": "Device",
|
||||
"config": {},
|
||||
"events": ["STAIRS_DOWN"]},
|
||||
{"_type": "Sprite", "name": "well_down", "width": 256, "height": 256, "scale": 1.0}
|
||||
{"_type": "Sprite", "name": "ladder_down", "width": 256, "height": 256, "scale": 1.0}
|
||||
]
|
||||
},
|
||||
"DEAD_BODY_LOOTABLE": {
|
||||
|
|
|
|||
BIN
assets/doors/door_plain.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
|
|
@ -6,7 +6,7 @@
|
|||
"foreground": "enemies/fg:player",
|
||||
"background": "color:transparent"
|
||||
},
|
||||
{"_type": "Combat", "hp": 200, "max_hp": 200, "ap": 0, "max_ap": 12, "ap_delta": 6, "damage": 50, "dead": false},
|
||||
{"_type": "Combat", "ap": 0, "max_ap": 12, "ap_delta": 6, "damage": 50, "dead": false},
|
||||
{"_type": "Motion", "dx": 0, "dy": 0, "random": false},
|
||||
{"_type": "Collision", "has": true},
|
||||
{"_type": "EnemyConfig", "ai_script": "Host::actions", "ai_start_name": "Host::initial_state", "ai_goal_name": "Host::final_state"},
|
||||
|
|
@ -14,19 +14,18 @@
|
|||
{"_type": "LightSource", "strength": 35, "radius": 2.0}
|
||||
]
|
||||
},
|
||||
"RAT_GIANT": {
|
||||
"SPIDER_BOT": {
|
||||
"components": [
|
||||
{"_type": "Tile", "display": 2220,
|
||||
"foreground": "enemies/fg:rat_giant",
|
||||
"background": "color:transparent"
|
||||
},
|
||||
{"_type": "Combat", "hp": 50, "max_hp": 50, "ap": 0, "max_ap": 12, "ap_delta": 6,"damage": 2, "dead": false},
|
||||
{"_type": "Combat", "ap": 0, "max_ap": 12, "ap_delta": 6,"damage": 2, "dead": false},
|
||||
{"_type": "Collision", "has": true},
|
||||
{"_type": "Motion", "dx": 0, "dy": 0, "random": false},
|
||||
{"_type": "EnemyConfig", "ai_script": "Enemy::actions", "ai_start_name": "Enemy::initial_state", "ai_goal_name": "Enemy::final_state"},
|
||||
{"_type": "Personality", "hearing_distance": 5, "tough": false},
|
||||
{"_type": "Sprite", "name": "rat_with_sword", "scale": 1.0},
|
||||
{"_type": "Sound", "attack": "Small_Rat", "death": "Creature_Death_1"}
|
||||
{"_type": "Sprite", "name": "spider_bot", "scale": 1.0}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
BIN
assets/hands/hands_sword_attack.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"healing_potion_small":
|
||||
{"path": "assets/icons/healing_potion_small.png",
|
||||
"repair_kit":
|
||||
{"path": "assets/icons/repair_kit.png",
|
||||
"frame_width": 96,
|
||||
"frame_height": 96
|
||||
},
|
||||
"torch_horizontal_floor":
|
||||
{"path": "assets/icons/torch_horizontal_floor.png",
|
||||
"frame_width": 96,
|
||||
"frame_height": 96
|
||||
"sword_1":
|
||||
{"path": "assets/icons/sword_1_icon.png",
|
||||
"frame_width": 300,
|
||||
"frame_height": 100
|
||||
}
|
||||
}
|
||||
|
|
|
|||
BIN
assets/icons/repair_kit.png
Normal file
|
After Width: | Height: | Size: 912 B |
BIN
assets/icons/sword_1_icon.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
|
|
@ -1,23 +1,8 @@
|
|||
{
|
||||
"TORCH_BAD": {
|
||||
"id": "TORCH_BAD",
|
||||
"name": "Crappy Torch",
|
||||
"description": "A torch that barely lights the way. You wonder if it'd be better to not see the person who murders you.",
|
||||
"inventory_count": 1,
|
||||
"components": [
|
||||
{"_type": "LightSource", "strength": 50, "radius": 2.5},
|
||||
{"_type": "Tile", "display": 3848,
|
||||
"foreground": "items/fg:flame",
|
||||
"background": "color:transparent"
|
||||
},
|
||||
{"_type": "Sprite", "name": "torch_horizontal_floor", "width": 256, "height": 256, "scale": 1.0},
|
||||
{"_type": "Sound", "attack": "pickup", "death": "blank"}
|
||||
]
|
||||
},
|
||||
"POTION_HEALING_SMALL": {
|
||||
"id": "POTION_HEALING_SMALL",
|
||||
"name": "Small Healing Potion",
|
||||
"description": "A small healing potion.",
|
||||
"REPAIR_KIT": {
|
||||
"id": "REPAIR_KIT",
|
||||
"name": "Robot Repair Kit",
|
||||
"description": "A healing item for robots.",
|
||||
"inventory_count": 1,
|
||||
"components": [
|
||||
{"_type": "Tile", "display": 1003,
|
||||
|
|
@ -25,7 +10,21 @@
|
|||
"background": "color:transparent"
|
||||
},
|
||||
{"_type": "Curative", "hp": 20},
|
||||
{"_type": "Sprite", "name": "healing_potion_small", "width": 256, "height": 256, "scale": 1.0},
|
||||
{"_type": "Sprite", "name": "repair_kit", "width": 256, "height": 256, "scale": 1.0},
|
||||
{"_type": "Sound", "attack": "pickup", "death": "blank"}
|
||||
]
|
||||
},
|
||||
"SWORD_1": {
|
||||
"id": "SWORD_1",
|
||||
"name": "Robot Repair Kit",
|
||||
"description": "A healing item for robots.",
|
||||
"inventory_count": 1,
|
||||
"components": [
|
||||
{"_type": "Tile", "display": 1004,
|
||||
"foreground": "items/fg:potion",
|
||||
"background": "color:transparent"
|
||||
},
|
||||
{"_type": "Sprite", "name": "sword_1", "width": 300, "height": 100, "scale": 1.0},
|
||||
{"_type": "Sound", "attack": "pickup", "death": "blank"}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
BIN
assets/items/repair_kit.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
assets/items/sword_1_sprite.png
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
BIN
assets/items/torch_horizontal_floor.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
assets/map_tiles.png
Normal file
|
After Width: | Height: | Size: 9.5 KiB |
|
|
@ -5,17 +5,17 @@
|
|||
},
|
||||
"gui/theme": {
|
||||
"black": [0, 0, 0, 255],
|
||||
"dark_dark": [10, 10, 10, 255],
|
||||
"dark_mid": [30, 30, 30, 255],
|
||||
"dark_light": [60, 60, 60, 255],
|
||||
"mid": [100, 100, 100, 255],
|
||||
"light_dark": [150, 150, 150, 255],
|
||||
"light_mid": [200, 200, 200, 255],
|
||||
"light_light": [230, 230, 230, 255],
|
||||
"dark_dark": [22, 10, 7, 255],
|
||||
"dark_mid": [53, 25, 18, 255],
|
||||
"dark_light": [91, 42, 31, 255],
|
||||
"mid": [142, 65, 48, 255],
|
||||
"light_dark": [193, 89, 65, 255],
|
||||
"light_mid": [255, 117, 86, 255],
|
||||
"light_light": [255, 194, 181, 255],
|
||||
"white": [255, 255, 255, 255],
|
||||
"fill_color": "gui/theme:dark_mid",
|
||||
"text_color": "gui/theme:light_light",
|
||||
"bg_color": "gui/theme:mid",
|
||||
"fill_color": [28, 29, 33, 255],
|
||||
"text_color": [209, 209, 209, 255],
|
||||
"bg_color": "gui/theme:dark_light",
|
||||
"border_color": "gui/theme:dark_dark",
|
||||
"bg_color_dark": "gui/theme:black"
|
||||
},
|
||||
|
|
|
|||
BIN
assets/sounds/blank.ogg
Normal file
BIN
assets/sounds/pickup.ogg
Normal file
BIN
assets/sounds/ui_click.ogg
Normal file
BIN
assets/sounds/ui_hover.ogg
Normal file
BIN
assets/sounds/walk.ogg
Normal file
BIN
assets/sprites/dead_body.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
assets/sprites/dead_body_lootable.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
assets/sprites/ladder_down.png
Normal file
|
After Width: | Height: | Size: 2 KiB |
BIN
assets/sprites/rat_with_sword.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
assets/sprites/spider_bot.png
Normal file
|
After Width: | Height: | Size: 8.9 KiB |
BIN
assets/text.ttf
Normal file
BIN
assets/textures/ceiling_black.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
assets/textures/floor_gray_stone.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
assets/textures/wall_plain.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
|
|
@ -8,9 +8,30 @@ namespace components {
|
|||
|
||||
if(attack) {
|
||||
my_dmg = Random::uniform<int>(1, damage);
|
||||
target.hp -= my_dmg;
|
||||
target.hit_limb(my_dmg);
|
||||
}
|
||||
|
||||
return my_dmg;
|
||||
}
|
||||
|
||||
void Combat::hit_limb(int my_dmg) {
|
||||
body_parts["head"] -= my_dmg;
|
||||
}
|
||||
|
||||
bool Combat::is_dead() {
|
||||
return body_parts["head"] < 0;
|
||||
}
|
||||
|
||||
bool Combat::almost_dead() {
|
||||
return body_parts["head"] < 20;
|
||||
}
|
||||
|
||||
bool Combat::can_heal() {
|
||||
return body_parts["head"] < 50;
|
||||
}
|
||||
|
||||
void Combat::apply_healing(Curative& cure) {
|
||||
int new_hp = body_parts["head"] + cure.hp;
|
||||
body_parts["head"] = std::min(new_hp, 50);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,10 +83,6 @@ namespace components {
|
|||
std::string ai_goal_name;
|
||||
};
|
||||
|
||||
struct Curative {
|
||||
int hp = 10;
|
||||
};
|
||||
|
||||
struct Sprite {
|
||||
string name;
|
||||
float scale;
|
||||
|
|
@ -106,12 +102,17 @@ namespace components {
|
|||
std::vector<std::array<std::string, 4>> beats;
|
||||
};
|
||||
|
||||
struct Curative {
|
||||
int hp = 10;
|
||||
};
|
||||
|
||||
struct Combat {
|
||||
int hp;
|
||||
int max_hp;
|
||||
int ap_delta;
|
||||
int max_ap;
|
||||
int damage;
|
||||
std::unordered_map<std::string, int> body_parts{
|
||||
{"head", 50},
|
||||
};
|
||||
|
||||
// everyone starts at 0 but ap_delta is added each round
|
||||
int ap = 0;
|
||||
|
|
@ -120,6 +121,11 @@ namespace components {
|
|||
bool dead = false;
|
||||
|
||||
int attack(Combat &target);
|
||||
void hit_limb(int my_dmg);
|
||||
bool is_dead();
|
||||
bool almost_dead();
|
||||
bool can_heal();
|
||||
void apply_healing(Curative& cure);
|
||||
};
|
||||
|
||||
struct LightSource {
|
||||
|
|
@ -156,7 +162,7 @@ namespace components {
|
|||
ENROLL_COMPONENT(EnemyConfig, ai_script, ai_start_name, ai_goal_name);
|
||||
ENROLL_COMPONENT(Personality, hearing_distance, tough);
|
||||
ENROLL_COMPONENT(Motion, dx, dy, random);
|
||||
ENROLL_COMPONENT(Combat, hp, max_hp, ap_delta, max_ap, damage, dead);
|
||||
ENROLL_COMPONENT(Combat, ap_delta, max_ap, damage, dead);
|
||||
ENROLL_COMPONENT(Device, config, events);
|
||||
ENROLL_COMPONENT(Storyboard, image, audio, layout, beats);
|
||||
ENROLL_COMPONENT(Sound, attack, death);
|
||||
|
|
|
|||
82
src/game/registry.hpp
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include "game/components.hpp"
|
||||
|
||||
namespace System {
|
||||
using MovingFunc = std::function<void(components::Position& move_to)>;
|
||||
using CombatFunc = std::function<void(int attack_id)>;
|
||||
using RenderFunc = std::function<void()>;
|
||||
using UpdateFunc = std::function<void()>;
|
||||
using UseItemFunc = std::function<void(const std::string& slot_name)>;
|
||||
using PickupFunc = std::function<void()>;
|
||||
|
||||
struct Registry {
|
||||
std::vector<MovingFunc> $moving;
|
||||
std::vector<CombatFunc> $combat;
|
||||
std::vector<RenderFunc> $render;
|
||||
std::vector<UpdateFunc> $update;
|
||||
std::vector<UseItemFunc> $use_item;
|
||||
std::vector<PickupFunc> $pickup;
|
||||
|
||||
void addMoving(MovingFunc action) {
|
||||
$moving.emplace_back(action);
|
||||
}
|
||||
|
||||
void addCombat(CombatFunc action) {
|
||||
$combat.emplace_back(action);
|
||||
}
|
||||
|
||||
void addRender(RenderFunc action) {
|
||||
$render.emplace_back(action);
|
||||
}
|
||||
|
||||
void addUpdate(UpdateFunc action) {
|
||||
$update.emplace_back(action);
|
||||
}
|
||||
|
||||
void addUseItem(UseItemFunc action) {
|
||||
$use_item.emplace_back(action);
|
||||
}
|
||||
|
||||
void addPickup(PickupFunc action) {
|
||||
$pickup.emplace_back(action);
|
||||
}
|
||||
|
||||
void runMoving(components::Position move_to) {
|
||||
for(auto func : $moving) {
|
||||
func(move_to);
|
||||
}
|
||||
}
|
||||
|
||||
void runCombat(int attack_id) {
|
||||
for(auto func : $combat) {
|
||||
func(attack_id);
|
||||
}
|
||||
}
|
||||
|
||||
void runRender() {
|
||||
for(auto func : $render) {
|
||||
func();
|
||||
}
|
||||
}
|
||||
|
||||
void runUpdate() {
|
||||
for(auto func : $update) {
|
||||
func();
|
||||
}
|
||||
}
|
||||
|
||||
void runUseItem(const std::string& slot_name) {
|
||||
for(auto func : $use_item) {
|
||||
func(slot_name);
|
||||
}
|
||||
}
|
||||
|
||||
void runPickup() {
|
||||
for(auto func : $pickup) {
|
||||
func();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -167,15 +167,14 @@ void System::distribute_loot(Position target_pos) {
|
|||
auto loot_entity = world.entity();
|
||||
|
||||
if(inventory_count > 0) {
|
||||
auto& entity_data = config.devices["DEAD_BODY_LOOTABLE"];
|
||||
components::configure_entity(world, loot_entity, entity_data["components"]);
|
||||
// BUG: inventory_count here isn't really used to remove it
|
||||
world.set<InventoryItem>(loot_entity, {inventory_count, entity_data});
|
||||
} else {
|
||||
dbc::log("!!!!!!!!!!!!!!!! ============= LOOTING BODIES NOT READY");
|
||||
}
|
||||
|
||||
// NOTE: refer to the code in raycaster for this
|
||||
|
||||
// this creates a dead body on the ground
|
||||
auto& entity_data = config.devices["DEAD_BODY"];
|
||||
components::configure_entity(world, loot_entity, entity_data["components"]);
|
||||
}
|
||||
|
||||
set_position(world, *level.collision, loot_entity, target_pos);
|
||||
level.world->send<game::Event>(game::Event::ENTITY_SPAWN, loot_entity, {});
|
||||
|
|
@ -189,7 +188,7 @@ void System::death() {
|
|||
|
||||
world.query<Combat>([&](auto ent, auto &combat) {
|
||||
// bring out yer dead
|
||||
if(combat.hp <= 0 && !combat.dead) {
|
||||
if(combat.is_dead() && !combat.dead) {
|
||||
combat.dead = true;
|
||||
if(ent != player.entity) {
|
||||
// we won't change out the player's components later
|
||||
|
|
@ -197,7 +196,7 @@ void System::death() {
|
|||
}
|
||||
// we need to send this event for everything that dies
|
||||
world.send<game::Event>(game::Event::DEATH, ent, {});
|
||||
} else if(float(combat.hp) / float(combat.max_hp) < 0.5f) {
|
||||
} else if(combat.almost_dead()) {
|
||||
// if enemies are below 50% health they are marked with bad health
|
||||
if(world.has<ai::EntityAI>(ent)) {
|
||||
auto& enemy_ai = world.get<ai::EntityAI>(ent);
|
||||
|
|
@ -474,34 +473,23 @@ bool System::inventory_occupied(Entity container_id, const std::string& name) {
|
|||
return inventory.has(name);
|
||||
}
|
||||
|
||||
bool System::use_item(const string& slot_name) {
|
||||
void System::use_item(const string& slot_name) {
|
||||
auto& level = GameDB::current_level();
|
||||
auto& world = *level.world;
|
||||
auto& inventory = world.get<inventory::Model>(level.player);
|
||||
auto& player_combat = world.get<Combat>(level.player);
|
||||
|
||||
if(player_combat.hp >= player_combat.max_hp) return false;
|
||||
if(!inventory.has(slot_name)) return false;
|
||||
if(!player_combat.can_heal()) return;
|
||||
if(!inventory.has(slot_name)) return;
|
||||
|
||||
auto what = inventory.get(slot_name);
|
||||
|
||||
if(auto curative = world.get_if<Curative>(what)) {
|
||||
inventory.remove(what);
|
||||
|
||||
player_combat.hp += curative->hp;
|
||||
|
||||
if(player_combat.hp > player_combat.max_hp) {
|
||||
player_combat.hp = player_combat.max_hp;
|
||||
}
|
||||
|
||||
dbc::log($F("player health now {}",
|
||||
player_combat.hp));
|
||||
|
||||
player_combat.apply_healing(*curative);
|
||||
world.remove<Curative>(what);
|
||||
return true;
|
||||
} else {
|
||||
dbc::log($F("no usable item at {}", what));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -541,3 +529,19 @@ void System::clear_attack() {
|
|||
|
||||
void System::spawn_attack(World& world, int attack_id, DinkyECS::Entity enemy) {
|
||||
}
|
||||
|
||||
|
||||
void System::init(Registry& reg) {
|
||||
reg.addRender(System::clear_attack);
|
||||
reg.addUseItem(System::use_item);
|
||||
reg.addMoving(System::move_player);
|
||||
reg.addCombat(System::combat);
|
||||
reg.addPickup(System::pickup);
|
||||
reg.addUpdate(System::generate_paths);
|
||||
reg.addUpdate(System::enemy_ai_initialize);
|
||||
reg.addUpdate(System::enemy_pathing);
|
||||
reg.addUpdate(System::motion);
|
||||
reg.addUpdate(System::collision);
|
||||
reg.addUpdate(System::lighting);
|
||||
reg.addUpdate(System::death);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,8 +5,10 @@
|
|||
#include "algos/spatialmap.hpp"
|
||||
#include "game/level.hpp"
|
||||
#include "events.hpp"
|
||||
#include "game/registry.hpp"
|
||||
|
||||
namespace System {
|
||||
|
||||
using namespace components;
|
||||
using namespace DinkyECS;
|
||||
using std::string, matrix::Matrix;
|
||||
|
|
@ -32,15 +34,15 @@ namespace System {
|
|||
|
||||
void pickup();
|
||||
|
||||
// BUG: these might need to go somewhere else....
|
||||
bool place_in_container(Entity cont_id, const string& name, Entity world_entity);
|
||||
|
||||
void remove_from_container(Entity cont_id, const std::string& name);
|
||||
void remove_from_world(Entity entity);
|
||||
void inventory_swap(Entity container_id, const std::string& a_name, const std::string &b_name);
|
||||
bool inventory_occupied(Entity container_id, const std::string& name);
|
||||
|
||||
void set_position(DinkyECS::World& world, SpatialMap& collision, Entity entity, Position pos);
|
||||
bool use_item(const std::string& slot_name);
|
||||
void use_item(const std::string& slot_name);
|
||||
|
||||
game::Event shortest_rotate(Point player_at, Point aiming_at, Point turning_to);
|
||||
|
||||
|
|
@ -67,4 +69,6 @@ namespace System {
|
|||
|
||||
void clear_attack();
|
||||
void spawn_attack(World& world, int attack_id, DinkyECS::Entity enemy);
|
||||
|
||||
void init(Registry& reg);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -199,15 +199,14 @@ void WorldBuilder::place_stairs(DinkyECS::World& world, GameConfig& config) {
|
|||
|
||||
void WorldBuilder::configure_starting_items(DinkyECS::World &world) {
|
||||
auto& player = world.get_the<Player>();
|
||||
|
||||
auto torch_id = System::spawn_item(world, "TORCH_BAD");
|
||||
|
||||
auto &inventory = world.get<inventory::Model>(player.entity);
|
||||
inventory.add("hand_r", torch_id);
|
||||
world.make_constant(torch_id);
|
||||
|
||||
auto healing = System::spawn_item(world, "POTION_HEALING_SMALL");
|
||||
inventory.add("pocket_l", healing);
|
||||
auto healing = System::spawn_item(world, "REPAIR_KIT");
|
||||
inventory.add("inv0", healing);
|
||||
|
||||
auto sword = System::spawn_item(world, "SWORD_1");
|
||||
inventory.add("hand_main", sword);
|
||||
|
||||
world.make_constant(healing);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ inline void set_scale_position(sf::Sprite& sprite, sf::Vector2f& position, sf::V
|
|||
}
|
||||
|
||||
|
||||
void Raycaster::sprite_casting() {
|
||||
void Raycaster::sprite_casting(sf::RenderTarget& target) {
|
||||
auto& lights = $level.lights->lighting();
|
||||
auto world = $level.world;
|
||||
$level.collision->distance_sorted($sprite_order, {(size_t)$pos_x, (size_t)$pos_y}, RENDER_DISTANCE);
|
||||
|
|
@ -212,7 +212,6 @@ void Raycaster::sprite_casting() {
|
|||
sf::Vector2f scale{sprite_scale_w, sprite_scale_h};
|
||||
sf::Vector2f position{x + origin.x * scale.x, y + origin.y * scale.y};
|
||||
sf::IntRect in_texture{ {tex_x, tex_y}, {tex_render_width, texture_height}};
|
||||
|
||||
shared_ptr<sf::Shader> effect = System::sprite_effect(rec.entity);
|
||||
|
||||
if(effect) {
|
||||
|
|
@ -231,7 +230,7 @@ void Raycaster::sprite_casting() {
|
|||
set_scale_position(*sf_sprite, position, scale, in_texture, origin);
|
||||
}
|
||||
|
||||
$sprites_to_render.emplace_back(sf_sprite, effect);
|
||||
target.draw(*sf_sprite, effect.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -438,16 +437,12 @@ void Raycaster::update() {
|
|||
draw_ceiling_floor();
|
||||
cast_rays();
|
||||
draw_pixel_buffer();
|
||||
sprite_casting();
|
||||
}
|
||||
|
||||
// BUG: if target is a rendertarget then I can say it has to be the viewport only, then I can get rid of $screen_pos_x/y
|
||||
void Raycaster::render(sf::RenderTarget& target) {
|
||||
target.draw($view_sprite);
|
||||
|
||||
for(auto [sprite, effect] : $sprites_to_render) {
|
||||
target.draw(*sprite, effect.get());
|
||||
}
|
||||
sprite_casting(target);
|
||||
}
|
||||
|
||||
void Raycaster::update_sprite(DinkyECS::Entity ent, components::Sprite& sprite) {
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ struct CameraLOL {
|
|||
double target_plane_y = 0.0;
|
||||
};
|
||||
|
||||
using SpriteRender = std::pair<std::shared_ptr<sf::Sprite>, std::shared_ptr<sf::Shader>>;
|
||||
using SpriteRender = std::pair<sf::Sprite, std::shared_ptr<sf::Shader>>;
|
||||
|
||||
struct Raycaster {
|
||||
sf::Texture $view_texture;
|
||||
|
|
@ -64,7 +64,7 @@ struct Raycaster {
|
|||
void cast_rays();
|
||||
void draw_ceiling_floor();
|
||||
void draw_pixel_buffer();
|
||||
void sprite_casting();
|
||||
void sprite_casting(sf::RenderTarget& target);
|
||||
void update();
|
||||
void render(sf::RenderTarget& target);
|
||||
|
||||
|
|
|
|||
61
src/gui/body_ui.cpp
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
#include "gui/body_ui.hpp"
|
||||
#include "game/components.hpp"
|
||||
#include <guecs/ui.hpp>
|
||||
#include "algos/rand.hpp"
|
||||
#include <fmt/xchar.h>
|
||||
#include "gui/guecstra.hpp"
|
||||
#include "game/systems.hpp"
|
||||
#include "game/inventory.hpp"
|
||||
#include "game/level.hpp"
|
||||
|
||||
namespace gui {
|
||||
using namespace guecs;
|
||||
using std::any, std::any_cast, std::string, std::make_any;
|
||||
|
||||
void BodyUI::init(size_t x, size_t y, size_t width, size_t height) {
|
||||
$gui.position(x, y, width, height);
|
||||
$gui.layout(
|
||||
"[head]"
|
||||
"[chest]"
|
||||
"[right_arm]"
|
||||
"[left_arm]"
|
||||
"[stomach]"
|
||||
"[left_leg]"
|
||||
"[right_leg]");
|
||||
|
||||
$gui.set<Background>($gui.MAIN, {$gui.$parser, });
|
||||
|
||||
for(auto& [name, cell] : $gui.cells()) {
|
||||
auto gui_id = $gui.entity(name);
|
||||
|
||||
$gui.set<Text>(gui_id, {guecs::to_wstring(name)});
|
||||
$gui.set<Meter>(gui_id, {1.0f, THEME.DARK_MID, {}});
|
||||
}
|
||||
|
||||
$gui.init();
|
||||
update();
|
||||
}
|
||||
|
||||
bool BodyUI::mouse(float x, float y, guecs::Modifiers mods) {
|
||||
return $gui.mouse(x, y, mods);
|
||||
}
|
||||
|
||||
void BodyUI::update() {
|
||||
auto world = GameDB::current_world();
|
||||
auto& player = world->get_the<components::Player>();
|
||||
auto& player_combat = world->get<components::Combat>(player.entity);
|
||||
|
||||
for(auto& [key, value] : player_combat.body_parts) {
|
||||
auto gui_id = $gui.entity(key);
|
||||
|
||||
if(auto meter = $gui.get_if<Meter>(gui_id)) {
|
||||
meter->percent = float(value) / 50.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BodyUI::render(sf::RenderWindow &window) {
|
||||
$gui.render(window);
|
||||
// $gui.debug_layout(window);
|
||||
}
|
||||
}
|
||||
18
src/gui/body_ui.hpp
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#pragma once
|
||||
#include "constants.hpp"
|
||||
#include <deque>
|
||||
#include "graphics/textures.hpp"
|
||||
#include <guecs/ui.hpp>
|
||||
#include "gui/guecstra.hpp"
|
||||
|
||||
namespace gui {
|
||||
class BodyUI {
|
||||
public:
|
||||
guecs::UI $gui{};
|
||||
|
||||
void init(size_t x, size_t y, size_t width, size_t height);
|
||||
void render(sf::RenderWindow &window);
|
||||
void update();
|
||||
bool mouse(float x, float y, guecs::Modifiers mods);
|
||||
};
|
||||
}
|
||||
|
|
@ -19,7 +19,7 @@ namespace gui {
|
|||
"[spawn1|spawn2|spawn3]"
|
||||
"[spawn4|spawn5|spawn6]");
|
||||
|
||||
add_spawn_button("RAT_GIANT", "rat_with_sword", "spawn4");
|
||||
// add_spawn_button("RAT_GIANT", "rat_with_sword", "spawn4");
|
||||
|
||||
$gui.init();
|
||||
}
|
||||
|
|
@ -48,7 +48,6 @@ namespace gui {
|
|||
auto map = level.map;
|
||||
|
||||
std::wstring stats = $F(L"STATS\n"
|
||||
L"HP: {}\n"
|
||||
L"mean:{:>8.5}\n"
|
||||
L"sdev: {:>8.5}\n"
|
||||
L"min: {:>8.5}\n"
|
||||
|
|
@ -58,7 +57,7 @@ namespace gui {
|
|||
L"VSync? {}\n"
|
||||
L"FR Limit: {}\n"
|
||||
L"Debug? {}\n\n",
|
||||
player_combat.hp, $stats.mean(), $stats.stddev(), $stats.min,
|
||||
$stats.mean(), $stats.stddev(), $stats.min,
|
||||
$stats.max, $stats.n, level.index, map->width(), map->height(),
|
||||
VSYNC, FRAME_LIMIT, DEBUG_BUILD);
|
||||
|
||||
|
|
@ -74,9 +73,6 @@ namespace gui {
|
|||
if(active) {
|
||||
auto& level = GameDB::current_level();
|
||||
// it's on now, enable things
|
||||
auto player = level.world->get_the<components::Player>();
|
||||
auto& player_combat = level.world->get<components::Combat>(player.entity);
|
||||
player_combat.hp = player_combat.max_hp;
|
||||
$gui.show_text("debug_text", L"STATS");
|
||||
} else {
|
||||
// it's off now, close it
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ namespace gui {
|
|||
void FSM::MOVING(Event ) {
|
||||
// this should be an optional that returns a point
|
||||
if(auto move_to = $main_ui.play_move()) {
|
||||
System::move_player(*move_to);
|
||||
$systems.runMoving(*move_to);
|
||||
run_systems();
|
||||
$main_ui.dirty();
|
||||
state(State::IDLE);
|
||||
|
|
@ -70,7 +70,7 @@ namespace gui {
|
|||
switch(ev) {
|
||||
case TICK: {
|
||||
dbc::log("!!!!!! FIX System::combat(0) doesn't use any weapons, only first");
|
||||
System::combat(0);
|
||||
$systems.runCombat(0);
|
||||
run_systems();
|
||||
state(State::IN_COMBAT);
|
||||
} break;
|
||||
|
|
@ -79,7 +79,7 @@ namespace gui {
|
|||
break;
|
||||
case ATTACK: {
|
||||
int attack_id = std::any_cast<int>(data);
|
||||
System::combat(attack_id);
|
||||
$systems.runCombat(attack_id);
|
||||
run_systems();
|
||||
} break;
|
||||
default:
|
||||
|
|
@ -174,10 +174,8 @@ namespace gui {
|
|||
case USE_ITEM: {
|
||||
auto gui_id = std::any_cast<guecs::Entity>(data);
|
||||
auto& slot_name = $status_ui.$gui.name_for(gui_id);
|
||||
|
||||
if(System::use_item(slot_name)) {
|
||||
$systems.runUseItem(slot_name);
|
||||
$status_ui.update();
|
||||
}
|
||||
} break;
|
||||
case MOUSE_CLICK:
|
||||
mouse_action(guecs::NO_MODS);
|
||||
|
|
@ -186,7 +184,7 @@ namespace gui {
|
|||
mouse_action({1 << guecs::ModBit::hover});
|
||||
} break;
|
||||
case AIM_CLICK:
|
||||
System::pickup();
|
||||
$systems.runPickup();
|
||||
break;
|
||||
default:
|
||||
break; // ignore everything else
|
||||
|
|
@ -312,9 +310,6 @@ namespace gui {
|
|||
$debug_ui.debug();
|
||||
shaders::reload();
|
||||
break;
|
||||
case KEY::O:
|
||||
autowalking = true;
|
||||
break;
|
||||
case KEY::L:
|
||||
// This will go away as soon as containers work
|
||||
$loot_ui.set_target($loot_ui.$temp_loot);
|
||||
|
|
@ -360,10 +355,8 @@ namespace gui {
|
|||
}
|
||||
|
||||
void FSM::render() {
|
||||
$window.clear();
|
||||
|
||||
// this clears any attack animations, like fire
|
||||
System::clear_attack();
|
||||
$systems.runRender();
|
||||
// BUG: this is the render for this class, and where I add an update
|
||||
draw_gui();
|
||||
|
||||
|
|
@ -371,13 +364,7 @@ namespace gui {
|
|||
}
|
||||
|
||||
void FSM::run_systems() {
|
||||
System::generate_paths();
|
||||
System::enemy_ai_initialize();
|
||||
System::enemy_pathing();
|
||||
System::motion();
|
||||
System::collision();
|
||||
System::lighting();
|
||||
System::death();
|
||||
$systems.runUpdate();
|
||||
}
|
||||
|
||||
bool FSM::active() {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "constants.hpp"
|
||||
#include "game/registry.hpp"
|
||||
#include "algos/simplefsm.hpp"
|
||||
#include "gui/debug_ui.hpp"
|
||||
#include "gui/main_ui.hpp"
|
||||
|
|
@ -35,12 +36,11 @@ namespace gui {
|
|||
LootUI $loot_ui;
|
||||
gui::routing::Router $router;
|
||||
DNDLoot $dnd_loot;
|
||||
System::Registry $systems;
|
||||
|
||||
FSM();
|
||||
|
||||
void event(game::Event ev, std::any data={});
|
||||
void autowalk();
|
||||
void start_autowalk(double rot_speed);
|
||||
|
||||
void START(game::Event ev);
|
||||
void MOVING(game::Event ev);
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ namespace gui {
|
|||
dbc::check(world->has<components::Sprite>(item),
|
||||
"item in inventory UI doesn't exist in world. New level?");
|
||||
auto& sprite = world->get<components::Sprite>(item);
|
||||
fmt::println("!!!!!!!!!!! trying to load {}", sprite.name);
|
||||
$gui.set_init<guecs::Icon>(id, {sprite.name});
|
||||
|
||||
guecs::GrabSource grabber{
|
||||
|
|
|
|||
|
|
@ -17,9 +17,11 @@ namespace gui {
|
|||
$window.setFramerateLimit(FRAME_LIMIT);
|
||||
|
||||
auto config = settings::get("config");
|
||||
|
||||
$hand = textures::get_sprite(config["player"]["hands"]);
|
||||
$hand_anim = animation::load("assets/animation.json", config["player"]["hands"]);
|
||||
int width = $hand_anim.sheet.frame_width;
|
||||
int height = $hand_anim.sheet.frame_height;
|
||||
$hand.sprite->setPosition({float(RAY_VIEW_X + (RAY_VIEW_WIDTH - width) / 2), float(RAY_VIEW_HEIGHT - height)});
|
||||
}
|
||||
|
||||
void MainUI::dirty() {
|
||||
|
|
@ -148,7 +150,6 @@ namespace gui {
|
|||
if($hand_anim.playing) {
|
||||
$hand_anim.update();
|
||||
$hand_anim.apply(*$hand.sprite);
|
||||
$hand.sprite->setPosition({RAY_VIEW_X, RAY_VIEW_Y});
|
||||
$window.draw(*$hand.sprite);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,12 +18,13 @@ namespace gui {
|
|||
$gui.init();
|
||||
}
|
||||
|
||||
inline void make_clickable_area(guecs::UI &gui, const std::string &name) {
|
||||
inline void make_clickable_area(guecs::UI &gui, const std::string name) {
|
||||
auto area = gui.entity(name);
|
||||
|
||||
gui.set<Clickable>(area, {
|
||||
[&](auto) {
|
||||
[=](auto) {
|
||||
auto world = GameDB::current_world();
|
||||
fmt::println("CLICK {}", name);
|
||||
world->send<game::Event>(game::Event::AIM_CLICK, area, {});
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -16,10 +16,14 @@ namespace gui {
|
|||
{
|
||||
$gui.position(x, y, width, height);
|
||||
$gui.layout(
|
||||
"[=slot1]"
|
||||
"[=slot2]"
|
||||
"[=hand_r]"
|
||||
"[=pocket_l]");
|
||||
"[*%(100, 300)body_ui]"
|
||||
"[_]"
|
||||
"[_]"
|
||||
"[=inv0|=inv1|=inv2]"
|
||||
"[=inv3|=inv4|=inv5]"
|
||||
"[=inv6|=inv7|=inv8]"
|
||||
"[=hand_main]"
|
||||
"[=hand_off]");
|
||||
}
|
||||
|
||||
void StatusUI::init() {
|
||||
|
|
@ -28,9 +32,13 @@ namespace gui {
|
|||
for(auto& [name, cell] : $gui.cells()) {
|
||||
auto gui_id = $gui.entity(name);
|
||||
|
||||
$gui.set<Rectangle>(gui_id, {});
|
||||
|
||||
$gui.set<Text>(gui_id, {guecs::to_wstring(name)});
|
||||
|
||||
if(name.starts_with("body_")) {
|
||||
auto& cell = $gui.cell_for(name);
|
||||
$body_ui.init(cell.x, cell.y, cell.w, cell.h);
|
||||
} else {
|
||||
$gui.set<Rectangle>(gui_id, {});
|
||||
$gui.set<Clickable>(gui_id, {
|
||||
guecs::make_action(gui_id, game::Event::INV_SELECT, {gui_id})
|
||||
});
|
||||
|
|
@ -40,6 +48,7 @@ namespace gui {
|
|||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$gui.init();
|
||||
update();
|
||||
|
|
@ -54,6 +63,8 @@ namespace gui {
|
|||
auto player = world->get_the<components::Player>();
|
||||
auto& inventory = world->get<inventory::Model>(player.entity);
|
||||
|
||||
$body_ui.update();
|
||||
|
||||
for(const auto& [slot, cell] : $gui.cells()) {
|
||||
|
||||
if(inventory.has(slot)) {
|
||||
|
|
@ -79,6 +90,7 @@ namespace gui {
|
|||
|
||||
void StatusUI::render(sf::RenderWindow &window) {
|
||||
$gui.render(window);
|
||||
$body_ui.render(window);
|
||||
// $gui.debug_layout(window);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,11 +4,13 @@
|
|||
#include "graphics/textures.hpp"
|
||||
#include <guecs/ui.hpp>
|
||||
#include "gui/guecstra.hpp"
|
||||
#include "gui/body_ui.hpp"
|
||||
|
||||
namespace gui {
|
||||
class StatusUI {
|
||||
public:
|
||||
guecs::UI $gui;
|
||||
guecs::UI $gui{};
|
||||
BodyUI $body_ui{};
|
||||
|
||||
explicit StatusUI(size_t x, size_t y, size_t width, size_t height);
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include "gui/backend.hpp"
|
||||
#include "game/level.hpp"
|
||||
#include "graphics/camera.hpp"
|
||||
#include "game/systems.hpp"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
try {
|
||||
|
|
@ -21,6 +22,7 @@ int main(int argc, char* argv[]) {
|
|||
sound::mute(true);
|
||||
|
||||
gui::FSM main;
|
||||
System::init(main.$systems);
|
||||
main.event(game::Event::START);
|
||||
|
||||
sound::play("ambient_1", true);
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ sources = files(
|
|||
'gui/status_ui.cpp',
|
||||
'gui/main_ui.cpp',
|
||||
'gui/overlay_ui.cpp',
|
||||
'gui/body_ui.cpp',
|
||||
|
||||
# graphics
|
||||
'graphics/animation.cpp',
|
||||
|
|
|
|||
|
|
@ -25,20 +25,17 @@ TEST_CASE("battle operations fantasy", "[combat-battle]") {
|
|||
|
||||
DinkyECS::Entity host = 0;
|
||||
ai::EntityAI host_ai("Host::actions", host_start, host_goal);
|
||||
components::Combat host_combat{
|
||||
.hp=100, .max_hp=100, .ap_delta=6, .max_ap=12, .damage=20};
|
||||
components::Combat host_combat{.ap_delta=6, .max_ap=12, .damage=20};
|
||||
battle.add_enemy({host, &host_ai, &host_combat, true});
|
||||
|
||||
DinkyECS::Entity axe_ranger = 1;
|
||||
ai::EntityAI axe_ai("Enemy::actions", ai_start, ai_goal);
|
||||
components::Combat axe_combat{
|
||||
.hp=20, .max_hp=20, .ap_delta=8, .max_ap=12, .damage=20};
|
||||
components::Combat axe_combat{.ap_delta=8, .max_ap=12, .damage=20};
|
||||
battle.add_enemy({axe_ranger, &axe_ai, &axe_combat});
|
||||
|
||||
DinkyECS::Entity rat = 2;
|
||||
ai::EntityAI rat_ai("Enemy::actions", ai_start, ai_goal);
|
||||
components::Combat rat_combat{
|
||||
.hp=10, .max_hp=10, .ap_delta=2, .max_ap=10, .damage=10};
|
||||
components::Combat rat_combat{.ap_delta=2, .max_ap=10, .damage=10};
|
||||
battle.add_enemy({rat, &rat_ai, &rat_combat});
|
||||
|
||||
battle.set_all("enemy_found", true);
|
||||
|
|
@ -50,8 +47,8 @@ TEST_CASE("battle operations fantasy", "[combat-battle]") {
|
|||
battle.set(host, "have_healing", false);
|
||||
battle.set(host, "tough_personality", false);
|
||||
|
||||
while(host_combat.hp > 0) {
|
||||
battle.set(host, "health_good", host_combat.hp > 20);
|
||||
while(!host_combat.is_dead()) {
|
||||
battle.set(host, "health_good", host_combat.almost_dead());
|
||||
|
||||
battle.player_request("use_healing");
|
||||
battle.player_request("kill_enemy");
|
||||
|
|
@ -62,11 +59,6 @@ TEST_CASE("battle operations fantasy", "[combat-battle]") {
|
|||
while(auto act = battle.next()) {
|
||||
auto& [enemy, wants_to, cost, enemy_state] = *act;
|
||||
|
||||
// fmt::println(">>>>> entity: {} wants to {} cost={}; has {} HP; {} ap",
|
||||
// enemy.entity, wants_to,
|
||||
// cost, enemy.combat->hp,
|
||||
// enemy.combat->ap);
|
||||
|
||||
switch(enemy_state) {
|
||||
case BattleHostState::agree:
|
||||
// fmt::println("HOST and PLAYER requests match {}, doing it.", wants_to);
|
||||
|
|
|
|||
|
|
@ -10,12 +10,12 @@ using namespace components;
|
|||
TEST_CASE("test the loot ui", "[loot]") {
|
||||
auto items = settings::get("assets/items.json");
|
||||
DinkyECS::World world;
|
||||
auto torch = world.entity();
|
||||
auto& data = items["TORCH_BAD"];
|
||||
auto repair_kit = world.entity();
|
||||
auto& data = items["REPAIR_KIT"];
|
||||
|
||||
components::init();
|
||||
components::configure_entity(world, torch, data["components"]);
|
||||
components::configure_entity(world, repair_kit, data["components"]);
|
||||
|
||||
auto& torch_sprite = world.get<Sprite>(torch);
|
||||
REQUIRE(torch_sprite.name == "torch_horizontal_floor");
|
||||
auto& repair_kit_sprite = world.get<Sprite>(repair_kit);
|
||||
REQUIRE(repair_kit_sprite.name == "repair_kit");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,14 +11,8 @@ TEST_CASE("color palette test", "[color-palette]") {
|
|||
// confirm it's idempotent
|
||||
palette::init();
|
||||
|
||||
sf::Color expect{10, 10, 10, 255};
|
||||
|
||||
auto gui_text = palette::get("gui/theme:dark_dark");
|
||||
REQUIRE(gui_text == expect);
|
||||
|
||||
gui_text = palette::get("gui/theme", "mid");
|
||||
REQUIRE(gui_text != expect);
|
||||
|
||||
expect = {100, 100, 100, 255};
|
||||
REQUIRE(gui_text == expect);
|
||||
REQUIRE(gui_text.r > 0);
|
||||
REQUIRE(gui_text.g > 0);
|
||||
REQUIRE(gui_text.b > 0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@
|
|||
#include "game/systems.hpp"
|
||||
#include <cmath>
|
||||
#include <numbers>
|
||||
#include "game/registry.hpp"
|
||||
|
||||
using components::Position;
|
||||
|
||||
TEST_CASE("figure out best rotation direction", "[systems-rotate]") {
|
||||
Matrix map = matrix::make(3, 3);
|
||||
|
|
@ -35,104 +37,45 @@ TEST_CASE("figure out best rotation direction", "[systems-rotate]") {
|
|||
}
|
||||
}
|
||||
|
||||
using MovingFunc = std::function<void()>;
|
||||
using CombatFunc = std::function<void(bool)>;
|
||||
using RenderFunc = std::function<void()>;
|
||||
using UpdateFunc = std::function<void()>;
|
||||
using UseFunc = std::function<void()>;
|
||||
using PickupFunc = std::function<void()>;
|
||||
|
||||
struct Engine {
|
||||
std::vector<MovingFunc> $moving;
|
||||
std::vector<CombatFunc> $combat;
|
||||
std::vector<RenderFunc> $render;
|
||||
std::vector<UpdateFunc> $update;
|
||||
std::vector<UseFunc> $use;
|
||||
std::vector<PickupFunc> $pickup;
|
||||
|
||||
void addMoving(MovingFunc action) {
|
||||
$moving.emplace_back(action);
|
||||
}
|
||||
|
||||
void addCombat(CombatFunc action) {
|
||||
$combat.emplace_back(action);
|
||||
}
|
||||
|
||||
void addRender(RenderFunc action) {
|
||||
$render.emplace_back(action);
|
||||
}
|
||||
|
||||
void addUpdate(UpdateFunc action) {
|
||||
$update.emplace_back(action);
|
||||
}
|
||||
|
||||
void addUse(UseFunc action) {
|
||||
$use.emplace_back(action);
|
||||
}
|
||||
|
||||
void addPickup(PickupFunc action) {
|
||||
$pickup.emplace_back(action);
|
||||
}
|
||||
|
||||
void runMoving() {
|
||||
for(auto func : $moving) {
|
||||
func();
|
||||
}
|
||||
}
|
||||
|
||||
void runCombat(bool attr) {
|
||||
for(auto func : $combat) {
|
||||
func(attr);
|
||||
}
|
||||
}
|
||||
|
||||
void runRender() {
|
||||
for(auto func : $render) {
|
||||
func();
|
||||
}
|
||||
}
|
||||
|
||||
void runUpdate() {
|
||||
for(auto func : $update) {
|
||||
func();
|
||||
}
|
||||
}
|
||||
|
||||
void runUse() {
|
||||
for(auto func : $use) {
|
||||
func();
|
||||
}
|
||||
}
|
||||
|
||||
void runPickup() {
|
||||
for(auto func : $pickup) {
|
||||
func();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void test_system_1() {
|
||||
fmt::println("TEST 1");
|
||||
void test_moving(Position& move_to) {
|
||||
fmt::println("MOVING: {},{}", move_to.location.x, move_to.location.y);
|
||||
}
|
||||
|
||||
void test_combat(bool what) {
|
||||
fmt::println("TEST 2: {}", what);
|
||||
void test_combat(int attack_id) {
|
||||
fmt::println("ATTACK: {}", attack_id);
|
||||
}
|
||||
|
||||
void test_render() {
|
||||
fmt::println("RENDER");
|
||||
}
|
||||
|
||||
void test_update() {
|
||||
fmt::println("UPDATE");
|
||||
}
|
||||
|
||||
void test_use_item(const std::string& slot_name) {
|
||||
fmt::println("USE ITEM {}", slot_name);
|
||||
}
|
||||
|
||||
void test_pickup() {
|
||||
fmt::println("PICKUP");
|
||||
}
|
||||
|
||||
TEST_CASE("new system running engine thing", "[systems-engine]") {
|
||||
Engine systems;
|
||||
System::Registry systems;
|
||||
|
||||
systems.addMoving(test_system_1);
|
||||
systems.addMoving(test_moving);
|
||||
systems.addCombat(test_combat);
|
||||
systems.addRender(test_system_1);
|
||||
systems.addUpdate(test_system_1);
|
||||
systems.addUse(test_system_1);
|
||||
systems.addPickup(test_system_1);
|
||||
systems.addRender(test_render);
|
||||
systems.addUpdate(test_update);
|
||||
systems.addUseItem(test_use_item);
|
||||
systems.addPickup(test_pickup);
|
||||
|
||||
systems.runCombat(false);
|
||||
systems.runMoving();
|
||||
systems.runCombat(1);
|
||||
systems.runMoving({1,1});
|
||||
systems.runRender();
|
||||
systems.runUpdate();
|
||||
systems.runUse();
|
||||
systems.runUseItem("hand_l");
|
||||
systems.runPickup();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,13 +11,13 @@ TEST_CASE("test texture management", "[textures]") {
|
|||
components::init();
|
||||
textures::init();
|
||||
|
||||
auto spider = textures::get_sprite("rat_with_sword");
|
||||
auto spider = textures::get_sprite("spider_bot");
|
||||
REQUIRE(spider.sprite != nullptr);
|
||||
REQUIRE(spider.texture != nullptr);
|
||||
REQUIRE(spider.frame_size.x == TEXTURE_WIDTH);
|
||||
REQUIRE(spider.frame_size.y == TEXTURE_HEIGHT);
|
||||
|
||||
auto image = textures::load_image("assets/sprites/rat_with_sword.png");
|
||||
auto image = textures::load_image("assets/sprites/spider_bot.png");
|
||||
|
||||
size_t floor_tile = textures::get_id("floor_tile");
|
||||
size_t gray_stone = textures::get_id("door_plain");
|
||||
|
|
|
|||