Now the body_ui handles the toughness and attack rating, and applies colors to show your body part status.

This commit is contained in:
Zed A. Shaw 2026-04-03 23:42:49 -04:00
parent 009c5c1cd2
commit 831b46fa3f
11 changed files with 92 additions and 20 deletions

View file

@ -30,6 +30,7 @@ namespace components {
components::enroll<Sprite>(MAP);
components::enroll<Sound>(MAP);
components::enroll<Collision>(MAP);
components::enroll<LearnByDoing>(MAP);
MAP_configured = true;
}
}

View file

@ -108,11 +108,21 @@ namespace components {
int hp = 10;
};
struct LearnByDoing {
int attacks=0;
int hits=0;
int next_attack_level=10;
int next_toughness_level=10;
};
struct Combat {
int max_hp=1;
int ap_delta=1;
int max_ap=1;
int damage=1;
float attack_rating=0.01;
float toughness_rating=0.01;
std::unordered_map<std::string, int> body_parts{
{"head", 10},
{"chest", 10},
@ -177,11 +187,12 @@ 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, max_hp, ap_delta, max_ap, damage, body_parts);
ENROLL_COMPONENT(Combat, max_hp, ap_delta, max_ap, damage, attack_rating, toughness_rating, body_parts);
ENROLL_COMPONENT(Device, config, events);
ENROLL_COMPONENT(Storyboard, image, audio, layout, beats);
ENROLL_COMPONENT(Sound, attack, death);
ENROLL_COMPONENT(Collision, has);
ENROLL_COMPONENT(LearnByDoing, attacks, hits, next_attack_level, next_toughness_level);
template<typename COMPONENT> COMPONENT convert(nlohmann::json &data) {
COMPONENT result;

View file

@ -270,6 +270,7 @@ void System::combat(int attack_id) {
// player shouldn't hit theirself
if(host_state != BattleHostState::not_host) continue;
// BUG: really this should be attacker and receiver so I don't need the above line
components::CombatResult result {
.attacker=enemy.entity,
.host_state=host_state,
@ -286,10 +287,38 @@ void System::combat(int attack_id) {
animation::animate_entity(world, enemy.entity);
}
System::learn_by_doing(result);
world.send<game::Event>(game::Event::COMBAT, enemy.entity, result);
}
}
void System::learn_by_doing(components::CombatResult& result) {
auto& level = GameDB::current_level();
auto& world = *level.world;
auto& combat = world.get<components::Combat>(level.player);
auto& lbd = world.get<components::LearnByDoing>(level.player);
if(result.player_did > 0) {
lbd.attacks++;
}
if(result.enemy_did > 0) {
lbd.hits++;
}
if(lbd.attacks > lbd.next_attack_level) {
// they leveled up
combat.attack_rating += 0.01;
lbd.next_attack_level = lbd.next_attack_level * 4;
}
if(lbd.hits > lbd.next_toughness_level) {
// they leveled up
combat.toughness_rating += 0.01;
lbd.next_toughness_level = lbd.next_toughness_level * 4;
}
}
void System::collision() {
auto& level = GameDB::current_level();

View file

@ -31,6 +31,7 @@ namespace System {
void enemy_ai();
void combat(int attack_id);
void learn_by_doing(components::CombatResult& result);
std::shared_ptr<sf::Shader> sprite_effect(Entity entity);
void distribute_loot(Position target_pos);

View file

@ -209,7 +209,7 @@ void WorldBuilder::configure_starting_items(DinkyECS::World &world) {
world.make_constant(healing);
auto sword = System::spawn_item(world, "SWORD_1");
inventory.add("hand_main", sword);
inventory.add("weapon", sword);
world.make_constant(sword);
}