From 4c42dfe0f8692a39992d40f149520098d046cb1d Mon Sep 17 00:00:00 2001 From: Shinthoras0815 Date: Tue, 27 Jan 2026 05:06:43 +0100 Subject: [PATCH 01/11] Add damage source info to Lua apply damage hook Propagates damage source info through spells, shots, and powers. --- config/fxdata/lua/triggers/Builtins.lua | 6 +++- src/console_cmd.c | 4 +-- src/creature_control.h | 1 + src/creature_states_pray.c | 2 +- src/lua_triggers.c | 11 +++++-- src/lua_triggers.h | 2 +- src/magic_powers.c | 4 +-- src/main.cpp | 6 ++-- src/power_process.c | 7 +++-- src/thing_creature.c | 40 +++++++++++++++---------- src/thing_creature.h | 10 +++---- src/thing_effects.c | 16 +++++----- src/thing_list.c | 2 +- src/thing_shots.c | 27 +++++++++-------- src/thing_stats.c | 30 +++++++++++++++++-- src/thing_stats.h | 2 +- 16 files changed, 109 insertions(+), 61 deletions(-) diff --git a/config/fxdata/lua/triggers/Builtins.lua b/config/fxdata/lua/triggers/Builtins.lua index 5f2c257297..a319f4d1fd 100644 --- a/config/fxdata/lua/triggers/Builtins.lua +++ b/config/fxdata/lua/triggers/Builtins.lua @@ -74,11 +74,15 @@ end ---@param thing Thing ---@param damage integer ---@param dealing_player Player -function OnApplyDamage(thing, damage, dealing_player) +---@param source_thing Thing|nil +---@param source_string string|nil +function OnApplyDamage(thing, damage, dealing_player, source_thing, source_string) local eventData = {} eventData.thing = thing eventData.damage = damage eventData.dealing_player = dealing_player + eventData.source_thing = source_thing + eventData.source_string = source_string ProcessEvent("ApplyDamage",eventData) end diff --git a/src/console_cmd.c b/src/console_cmd.c index bfd1541d24..bf80ee3a62 100644 --- a/src/console_cmd.c +++ b/src/console_cmd.c @@ -1839,7 +1839,7 @@ TbBool cmd_freeze_creature(PlayerNumber plyr_idx, char * args) } thing_play_sample(thing, 50, NORMAL_PITCH, 0, 3, 0, 4, FULL_LOUDNESS); // Not sure how to handle this yet, for now simply hardcode the intended spell kind with a number. - apply_spell_effect_to_thing(thing, 3, 8, plyr_idx); // 3 was 'SplK_Freeze' in the enum. + apply_spell_effect_to_thing(thing, 3, 8, plyr_idx, INVALID_THING, "COMMAND_FREEZE"); // 3 was 'SplK_Freeze' in the enum. return true; } @@ -1857,7 +1857,7 @@ TbBool cmd_slow_creature(PlayerNumber plyr_idx, char * args) } thing_play_sample(thing, 50, NORMAL_PITCH, 0, 3, 0, 4, FULL_LOUDNESS); // Not sure how to handle this yet, for now simply hardcode the intended spell kind with a number. - apply_spell_effect_to_thing(thing, 12, 8, plyr_idx); // 12 was 'SplK_Slow' in the enum. + apply_spell_effect_to_thing(thing, 12, 8, plyr_idx, INVALID_THING, "COMMAND_SLOW"); // 12 was 'SplK_Slow' in the enum. return true; } diff --git a/src/creature_control.h b/src/creature_control.h index deb97d4b50..fb6d2df3bb 100644 --- a/src/creature_control.h +++ b/src/creature_control.h @@ -133,6 +133,7 @@ struct CastedSpellData { GameTurnDelta duration; CrtrExpLevel caster_level; PlayerNumber caster_owner; + ThingIndex caster_thing_idx; }; struct CreatureControl { diff --git a/src/creature_states_pray.c b/src/creature_states_pray.c index 154d01a059..7f1f563c2d 100644 --- a/src/creature_states_pray.c +++ b/src/creature_states_pray.c @@ -377,7 +377,7 @@ void apply_spell_effect_to_players_creatures(PlayerNumber plyr_idx, ThingModel c // Thing list loop body if (creature_matches_model(thing,crmodel)) { - apply_spell_effect_to_thing(thing, spl_idx, overchrg, plyr_idx); + apply_spell_effect_to_thing(thing, spl_idx, overchrg, plyr_idx, INVALID_THING, NULL); } // Thing list loop body ends k++; diff --git a/src/lua_triggers.c b/src/lua_triggers.c index 619e04ae90..a0ec08e41b 100644 --- a/src/lua_triggers.c +++ b/src/lua_triggers.c @@ -103,7 +103,7 @@ void lua_on_power_cast(PlayerNumber plyr_idx, PowerKind pwkind, { lua_pushstring(Lvl_script,get_conf_parameter_text(power_desc,pwkind)); lua_pushPlayer(Lvl_script, plyr_idx); - lua_pushThing(Lvl_script, thing); + lua_pushThing(Lvl_script, thing); lua_pushinteger(Lvl_script, stl_x); lua_pushinteger(Lvl_script, stl_y); lua_pushinteger(Lvl_script, splevel + 1); // Lua is 1-based, so we add 1 to the level @@ -182,7 +182,7 @@ void lua_on_creature_rebirth(struct Thing* crtng) } -void lua_on_apply_damage_to_thing(struct Thing *thing, HitPoints dmg, PlayerNumber dealing_plyr_idx) +void lua_on_apply_damage_to_thing(struct Thing *thing, HitPoints dmg, PlayerNumber dealing_plyr_idx, struct Thing *tngsrc, const char *source_str) { SYNCDBG(6,"Starting"); lua_getglobal(Lvl_script, "OnApplyDamage"); @@ -191,8 +191,13 @@ void lua_on_apply_damage_to_thing(struct Thing *thing, HitPoints dmg, PlayerNumb lua_pushThing(Lvl_script, thing); lua_pushinteger(Lvl_script, dmg); lua_pushPlayer(Lvl_script, dealing_plyr_idx); + lua_pushThing(Lvl_script, tngsrc); + if (source_str) + lua_pushstring(Lvl_script, source_str); + else + lua_pushnil(Lvl_script); - CheckLua(Lvl_script, lua_pcall(Lvl_script, 3, 0, 0),"OnApplyDamage"); + CheckLua(Lvl_script, lua_pcall(Lvl_script, 5, 0, 0),"OnApplyDamage"); } else { diff --git a/src/lua_triggers.h b/src/lua_triggers.h index eabd6e7294..6d52160db9 100644 --- a/src/lua_triggers.h +++ b/src/lua_triggers.h @@ -35,7 +35,7 @@ void lua_on_dungeon_destroyed(PlayerNumber plyr_idx); void lua_on_creature_death(struct Thing *crtng); void lua_on_creature_rebirth(struct Thing* crtng); void lua_on_trap_placed(struct Thing *traptng); -void lua_on_apply_damage_to_thing(struct Thing *thing, HitPoints dmg, PlayerNumber dealing_plyr_idx); +void lua_on_apply_damage_to_thing(struct Thing *thing, HitPoints dmg, PlayerNumber dealing_plyr_idx, struct Thing *tngsrc, const char *source_str); void lua_on_level_up(struct Thing *thing); //void lua_on_room_claimed(PlayerNumber plyr_idx, struct Room *room); diff --git a/src/magic_powers.c b/src/magic_powers.c index 67007d26b1..57309b1033 100644 --- a/src/magic_powers.c +++ b/src/magic_powers.c @@ -613,7 +613,7 @@ void slap_creature(struct PlayerInfo *player, struct Thing *thing) if (crconf->slaps_to_kill > 0) { HitPoints slap_damage = calculate_correct_creature_max_health(thing) / crconf->slaps_to_kill; - apply_damage_to_thing_and_display_health(thing, slap_damage, player->id_number); + apply_damage_to_thing_and_display_health(thing, slap_damage, player->id_number, INVALID_THING, "POWER_SLAP"); } powerst = get_power_model_stats(PwrK_SLAP); i = cctrl->slap_turns; @@ -1386,7 +1386,7 @@ static TbResult magic_use_power_apply_spell(PowerKind power_kind, PlayerNumber p create_used_effect_or_element(&effpos, powerst->effect_id, thing->owner, 0); } thing_play_sample(thing, powerst->select_sound_idx, NORMAL_PITCH, 0, 3, 0, 2, FULL_LOUDNESS); - apply_spell_effect_to_thing(thing, powerst->spell_idx, power_level, plyr_idx); + apply_spell_effect_to_thing(thing, powerst->spell_idx, power_level, plyr_idx, INVALID_THING, NULL); // Special cases. if (flag_is_set(spconf->spell_flags, CSAfF_Disease)) { // Set disease_caster_plyridx if spell_idx has 'CSAfF_Disease'. diff --git a/src/main.cpp b/src/main.cpp index 508d3a7cf0..a508e447bf 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2511,7 +2511,7 @@ TngUpdateRet damage_creatures_with_physical_force(struct Thing *thing, ModTngFil } if (thing_is_creature(thing)) { - apply_damage_to_thing_and_display_health(thing, param->secondary_number, param->primary_number); + apply_damage_to_thing_and_display_health(thing, param->secondary_number, param->primary_number, INVALID_THING, "PHYSICALLY_FORCE"); if ((thing->health >= 0) && !creature_is_leaving_and_cannot_be_stopped(thing)) { if (((thing->alloc_flags & TAlF_IsControlled) == 0) && !creature_is_kept_in_custody(thing)) @@ -2531,7 +2531,7 @@ TngUpdateRet damage_creatures_with_physical_force(struct Thing *thing, ModTngFil } else if (thing_is_destructible_trap(thing) > 0) { - apply_damage_to_thing(thing, param->secondary_number, param->primary_number); + apply_damage_to_thing(thing, param->secondary_number, param->primary_number, INVALID_THING, "PHYSICALLY_FORCE"); return TUFRet_Modified; } return TUFRet_Unchanged; @@ -3546,7 +3546,7 @@ void gameplay_loop_timestep() exit_keeper = 1; } } - + frametime_end_measurement(Frametime_Sleep); } diff --git a/src/power_process.c b/src/power_process.c index 8cc416b847..bf710a75ff 100644 --- a/src/power_process.c +++ b/src/power_process.c @@ -32,6 +32,7 @@ #include "thing_objects.h" #include "thing_physics.h" #include "thing_effects.h" +#include "thing_creature.h" #include "thing_navigate.h" #include "creature_instances.h" #include "creature_states.h" @@ -214,7 +215,7 @@ void process_disease(struct Thing *creatng) && !creature_is_immune_to_spell_effect(thing, CSAfF_Disease) && (cctrl->disease_caster_plyridx != game.neutral_player_num)) { // Apply the spell kind stored in 'active_disease_spell'. - apply_spell_effect_to_thing(thing, cctrl->active_disease_spell, cctrl->exp_level, creatng->owner); + apply_spell_effect_to_thing(thing, cctrl->active_disease_spell, cctrl->exp_level, creatng->owner, creatng, "POWER_DISEASE"); tngcctrl->disease_caster_plyridx = cctrl->disease_caster_plyridx; } // Per thing code ends. @@ -230,7 +231,7 @@ void process_disease(struct Thing *creatng) } if (((game.play_gameturn - cctrl->disease_start_turn) % game.conf.rules[creatng->owner].magic.disease_lose_health_time) == 0) { - apply_damage_to_thing_and_display_health(creatng, game.conf.rules[creatng->owner].magic.disease_lose_percentage_health * cctrl->max_health / 100, cctrl->disease_caster_plyridx); + apply_damage_to_thing_and_display_health(creatng, game.conf.rules[creatng->owner].magic.disease_lose_percentage_health * cctrl->max_health / 100, cctrl->disease_caster_plyridx, INVALID_THING, "POWER_DISEASE"); } } @@ -302,7 +303,7 @@ void update_god_lightning_ball(struct Thing *thing) if (!thing_exists(target)) break; shotst = get_shot_model_stats(thing->model); - apply_damage_to_thing_and_display_health(target, shotst->damage, thing->owner); + apply_damage_to_thing_and_display_health(target, shotst->damage, thing->owner, INVALID_THING, "POWER_LIGHTNING"); if (target->health < 0) { struct CreatureControl* cctrl = creature_control_get_from_thing(target); diff --git a/src/thing_creature.c b/src/thing_creature.c index ba2b9d40c7..0bf2abbc60 100644 --- a/src/thing_creature.c +++ b/src/thing_creature.c @@ -854,7 +854,7 @@ long get_spell_slot(const struct Thing *thing, SpellKind spkind) return -1; } -TbBool fill_spell_slot(struct Thing *thing, SpellKind spell_idx, GameTurnDelta spell_power, CrtrExpLevel spell_level, PlayerNumber plyr_idx, int slot_idx) +TbBool fill_spell_slot(struct Thing *thing, SpellKind spell_idx, GameTurnDelta spell_power, CrtrExpLevel spell_level, PlayerNumber plyr_idx, int slot_idx, struct Thing *castertng) { if ((slot_idx < 0) || (slot_idx >= CREATURE_MAX_SPELLS_CASTED_AT)) return false; @@ -866,6 +866,10 @@ TbBool fill_spell_slot(struct Thing *thing, SpellKind spell_idx, GameTurnDelta s cspell->duration = spell_power; cspell->caster_level = spell_level; cspell->caster_owner = plyr_idx; + if (thing_exists(castertng)) + cspell->caster_thing_idx = castertng->index; + else + cspell->caster_thing_idx = INVALID_THING; return true; } @@ -881,6 +885,7 @@ TbBool free_spell_slot(struct Thing *thing, int slot_idx) cspell->duration = 0; cspell->caster_level = 0; cspell->caster_owner = 0; + cspell->caster_thing_idx = INVALID_THING; return true; } @@ -1412,7 +1417,7 @@ void update_aura_effect_to_thing(struct Thing *thing, SpellKind spell_idx) } } -void first_apply_spell_effect_to_thing(struct Thing *thing, SpellKind spell_idx, CrtrExpLevel spell_level, PlayerNumber plyr_idx) +void first_apply_spell_effect_to_thing(struct Thing *thing, SpellKind spell_idx, CrtrExpLevel spell_level, PlayerNumber plyr_idx, struct Thing *castertng, const char *source_str) { if (spell_level > SPELL_MAX_LEVEL) { @@ -1426,14 +1431,14 @@ void first_apply_spell_effect_to_thing(struct Thing *thing, SpellKind spell_idx, if (set_thing_spell_flags(thing, spell_idx, duration, spell_level) || spell_is_continuous(spell_idx, duration)) { - fill_spell_slot(thing, spell_idx, duration, spell_level, plyr_idx, i); + fill_spell_slot(thing, spell_idx, duration, spell_level, plyr_idx, i, castertng); update_aura_effect_to_thing(thing, spell_idx); } } return; } -void reapply_spell_effect_to_thing(struct Thing *thing, SpellKind spell_idx, CrtrExpLevel spell_level, PlayerNumber plyr_idx, int slot_idx) +void reapply_spell_effect_to_thing(struct Thing *thing, SpellKind spell_idx, CrtrExpLevel spell_level, PlayerNumber plyr_idx, int slot_idx, struct Thing *castertng, const char *source_str) { if (spell_level > SPELL_MAX_LEVEL) { @@ -1454,7 +1459,7 @@ void reapply_spell_effect_to_thing(struct Thing *thing, SpellKind spell_idx, Crt return; } -void apply_spell_effect_to_thing(struct Thing *thing, SpellKind spell_idx, CrtrExpLevel spell_level, PlayerNumber plyr_idx) +void apply_spell_effect_to_thing(struct Thing *thing, SpellKind spell_idx, CrtrExpLevel spell_level, PlayerNumber plyr_idx, struct Thing *castertng, const char *source_str) { struct CreatureControl *cctrl = creature_control_get_from_thing(thing); if (creature_control_invalid(cctrl)) @@ -1496,7 +1501,7 @@ void apply_spell_effect_to_thing(struct Thing *thing, SpellKind spell_idx, CrtrE // Check for damage/heal one-time effect. if ((spconf->damage != 0) && (spconf->damage_frequency == 0)) { - process_thing_spell_damage_or_heal_effects(thing, spell_idx, spell_level, plyr_idx); + process_thing_spell_damage_or_heal_effects(thing, spell_idx, spell_level, plyr_idx, castertng, source_str); if (spconf->spell_flags == 0 && !spell_is_continuous(spell_idx, duration)) { @@ -1522,11 +1527,11 @@ void apply_spell_effect_to_thing(struct Thing *thing, SpellKind spell_idx, CrtrE { if (cctrl->casted_spells[i].spkind == spell_idx) { - reapply_spell_effect_to_thing(thing, spell_idx, spell_level, plyr_idx, i); + reapply_spell_effect_to_thing(thing, spell_idx, spell_level, plyr_idx, i, castertng, source_str); return; // Exit the function, spell is already active. } } - first_apply_spell_effect_to_thing(thing, spell_idx, spell_level, plyr_idx); + first_apply_spell_effect_to_thing(thing, spell_idx, spell_level, plyr_idx, castertng, source_str); } void terminate_thing_spell_effect(struct Thing *thing, SpellKind spell_idx) @@ -1814,7 +1819,7 @@ void process_thing_spell_teleport_effects(struct Thing *thing, struct CastedSpel } } -void process_thing_spell_damage_or_heal_effects(struct Thing *thing, SpellKind spell_idx, CrtrExpLevel caster_level, PlayerNumber caster_owner) +void process_thing_spell_damage_or_heal_effects(struct Thing *thing, SpellKind spell_idx, CrtrExpLevel caster_level, PlayerNumber caster_owner, struct Thing *caster_tng, const char *source_str) { struct CreatureControl *cctrl = creature_control_get_from_thing(thing); struct SpellConfig *spconf = get_spell_config(spell_idx); @@ -1853,7 +1858,7 @@ void process_thing_spell_damage_or_heal_effects(struct Thing *thing, SpellKind s // Apply damage. if (damage >= 0) { - apply_damage_to_thing_and_display_health(thing, damage, caster_owner); + apply_damage_to_thing_and_display_health(thing, damage, caster_owner, caster_tng, source_str); } else // Or heal if damage is negative. { @@ -1892,7 +1897,10 @@ void process_thing_spell_effects(struct Thing *thing) { if (cspell->duration % spconf->damage_frequency == 0) { - process_thing_spell_damage_or_heal_effects(thing, cspell->spkind, cspell->caster_level, cspell->caster_owner); + struct Thing* caster_tng = thing_get(cspell->caster_thing_idx); + if (!thing_exists(caster_tng)) + caster_tng = INVALID_THING; + process_thing_spell_damage_or_heal_effects(thing, cspell->spkind, cspell->caster_level, cspell->caster_owner, caster_tng, "UNKNOWN_DOT"); } } // Process spell with teleport flag. @@ -2225,7 +2233,7 @@ void creature_cast_spell(struct Thing *castng, SpellKind spl_idx, CrtrExpLevel s { thing_play_sample(castng, spconf->caster_affect_sound + SOUND_RANDOM(spconf->caster_sounds_count), NORMAL_PITCH, 0, 3, 0, 4, FULL_LOUDNESS); } - apply_spell_effect_to_thing(castng, spl_idx, cctrl->exp_level, castng->owner); + apply_spell_effect_to_thing(castng, spl_idx, cctrl->exp_level, castng->owner, castng, NULL); } else if (spconf->shot_model > 0) { @@ -6039,12 +6047,12 @@ void process_creature_leave_footsteps(struct Thing *thing) * @param dmg * @param inflicting_plyr_idx */ -HitPoints apply_damage_to_thing_and_display_health(struct Thing *thing, HitPoints dmg, PlayerNumber inflicting_plyr_idx) +HitPoints apply_damage_to_thing_and_display_health(struct Thing *thing, HitPoints dmg, PlayerNumber inflicting_plyr_idx, struct Thing *tngsrc, const char *source_str) { HitPoints cdamage; if (dmg > 0) { - cdamage = apply_damage_to_thing(thing, dmg, inflicting_plyr_idx); + cdamage = apply_damage_to_thing(thing, dmg, inflicting_plyr_idx, tngsrc, source_str); } else { cdamage = 0; } @@ -6094,7 +6102,7 @@ void process_landscape_affecting_creature(struct Thing *thing) if (cube_is_lava(i)) { struct CreatureModelConfig* crconf = creature_stats_get_from_thing(thing); - apply_damage_to_thing_and_display_health(thing, crconf->hurt_by_lava, -1); + apply_damage_to_thing_and_display_health(thing, crconf->hurt_by_lava, -1, INVALID_THING, "LAVA"); thing->movement_flags |= TMvF_IsOnLava; } else if (cube_is_water(i)) @@ -7692,7 +7700,7 @@ TbResult script_use_spell_on_creature(PlayerNumber plyr_idx, struct Thing *thing { thing_play_sample(thing, spconf->caster_affect_sound + SOUND_RANDOM(spconf->caster_sounds_count), NORMAL_PITCH, 0, 3, 0, 4, FULL_LOUDNESS); } - apply_spell_effect_to_thing(thing, spkind, spell_level, plyr_idx); + apply_spell_effect_to_thing(thing, spkind, spell_level, plyr_idx, INVALID_THING, "SCRIPT_SPELL"); if (flag_is_set(spconf->spell_flags, CSAfF_Disease)) { struct CreatureControl *cctrl; diff --git a/src/thing_creature.h b/src/thing_creature.h index 657d912461..af590c9050 100644 --- a/src/thing_creature.h +++ b/src/thing_creature.h @@ -129,7 +129,7 @@ TbBool thing_can_be_eaten(struct Thing *thing); void food_eaten_by_creature(struct Thing *foodtng, struct Thing *creatng); void anger_apply_anger_to_creature_f(struct Thing *thing, long anger, AnnoyMotive reason, long a3, const char *func_name); #define anger_apply_anger_to_creature(thing, anger, reason, a3) anger_apply_anger_to_creature_f(thing, anger, reason, a3, __func__) -HitPoints apply_damage_to_thing_and_display_health(struct Thing *thing, HitPoints dmg, PlayerNumber inflicting_plyr_idx); +HitPoints apply_damage_to_thing_and_display_health(struct Thing *thing, HitPoints dmg, PlayerNumber inflicting_plyr_idx, struct Thing* tngsrc, const char *source_str); void process_creature_standing_on_corpses_at(struct Thing *thing, struct Coord3d *pos); long creature_instance_has_reset(const struct Thing *thing, long a2); void set_creature_instance(struct Thing *thing, CrInstance inst_idx, long targtng_idx, const struct Coord3d *pos); @@ -163,11 +163,11 @@ void clean_spell_effect_f(struct Thing *thing, unsigned long spell_flags, const TbResult script_use_spell_on_creature(PlayerNumber plyr_idx, struct Thing *thing, SpellKind spkind, CrtrExpLevel spell_level); TbResult script_use_spell_on_creature_with_criteria(PlayerNumber plyr_idx, ThingModel crmodel, short criteria, SpellKind spkind, CrtrExpLevel spell_level); -void apply_spell_effect_to_thing(struct Thing *thing, SpellKind spell_idx, CrtrExpLevel spell_level, PlayerNumber plyr_idx); -void first_apply_spell_effect_to_thing(struct Thing *thing, SpellKind spell_idx, CrtrExpLevel spell_level, PlayerNumber plyr_idx); -void reapply_spell_effect_to_thing(struct Thing *thing, SpellKind spell_idx, CrtrExpLevel spell_level, PlayerNumber plyr_idx, int slot_idx); +void apply_spell_effect_to_thing(struct Thing *thing, SpellKind spell_idx, CrtrExpLevel spell_level, PlayerNumber plyr_idx, struct Thing *castertng, const char *source_str); +void first_apply_spell_effect_to_thing(struct Thing *thing, SpellKind spell_idx, CrtrExpLevel spell_level, PlayerNumber plyr_idx, struct Thing *castertng, const char *source_str); +void reapply_spell_effect_to_thing(struct Thing *thing, SpellKind spell_idx, CrtrExpLevel spell_level, PlayerNumber plyr_idx, int slot_idx, struct Thing *castertng, const char *source_str); void terminate_thing_spell_effect(struct Thing *thing, SpellKind spell_idx); -void process_thing_spell_damage_or_heal_effects(struct Thing *thing, SpellKind spell_idx, CrtrExpLevel caster_level, PlayerNumber caster_owner); +void process_thing_spell_damage_or_heal_effects(struct Thing *thing, SpellKind spell_idx, CrtrExpLevel caster_level, PlayerNumber caster_owner, struct Thing *caster_tng, const char *source_str); void process_thing_spell_effects(struct Thing *thing); void process_thing_spell_effects_while_blocked(struct Thing *thing); void delete_armour_effects_attached_to_creature(struct Thing *thing); diff --git a/src/thing_effects.c b/src/thing_effects.c index 50b9e33cd6..9373f6b5dd 100644 --- a/src/thing_effects.c +++ b/src/thing_effects.c @@ -1012,7 +1012,7 @@ TbBool explosion_affecting_thing(struct Thing *tngsrc, struct Thing *tngdst, con { HitPoints damage = get_radially_decaying_value(max_damage, max_dist / 4, 3 * max_dist / 4, distance) + 1; SYNCDBG(7,"Causing %d damage to %s at distance %d",(int)damage,thing_model_name(tngdst),(int)distance); - apply_damage_to_thing_and_display_health(tngdst, damage, owner); + apply_damage_to_thing_and_display_health(tngdst, damage, owner, tngsrc, NULL); if (flag_is_set(shotst->model_flags,ShMF_LifeDrain)) { give_shooter_drained_health(origtng, damage / 2); @@ -1038,7 +1038,7 @@ TbBool explosion_affecting_thing(struct Thing *tngsrc, struct Thing *tngdst, con { spell_level = scctrl->exp_level; } - apply_spell_effect_to_thing(tngdst, shotst->cast_spell_kind, spell_level, owner); + apply_spell_effect_to_thing(tngdst, shotst->cast_spell_kind, spell_level, owner, origtng, NULL); struct SpellConfig *spconf = get_spell_config(shotst->cast_spell_kind); if (flag_is_set(spconf->spell_flags, CSAfF_Disease)) { @@ -1066,7 +1066,7 @@ TbBool explosion_affecting_thing(struct Thing *tngsrc, struct Thing *tngdst, con { HitPoints damage = get_radially_decaying_value(max_damage, max_dist / 4, 3 * max_dist / 4, distance) + 1; SYNCDBG(7,"Causing %d damage to %s at distance %d",(int)damage,thing_model_name(tngdst),(int)distance); - apply_damage_to_thing(tngdst, damage, -1); + apply_damage_to_thing(tngdst, damage, -1, tngsrc, NULL); affected = true; event_create_event_or_update_nearby_existing_event(tngdst->mappos.x.val, tngdst->mappos.y.val,EvKind_HeartAttacked, tngdst->owner, 0); if (is_my_player_number(tngdst->owner)) @@ -1136,7 +1136,7 @@ TbBool explosion_affecting_door(struct Thing *tngsrc, struct Thing *tngdst, cons } } SYNCDBG(7,"Causing %d damage to %s at distance %d",(int)damage,thing_model_name(tngdst),(int)distance); - apply_damage_to_thing(tngdst, damage, -1); + apply_damage_to_thing(tngdst, damage, -1, tngsrc, NULL); affected = true; } } @@ -1446,7 +1446,7 @@ TbBool poison_cloud_affecting_thing(struct Thing *tngsrc, struct Thing *tngdst, HitPoints damage; damage = get_radially_decaying_value(max_damage, max_dist / 4, 3 * max_dist / 4, distance) + 1; SYNCDBG(7, "Causing %d damage to %s at distance %d", (int)damage, thing_model_name(tngdst), (int)distance); - apply_damage_to_thing_and_display_health(tngdst, damage, tngsrc->owner); + apply_damage_to_thing_and_display_health(tngdst, damage, tngsrc->owner, tngsrc, NULL); } break; case AAffT_GasDamageEffect: @@ -1455,14 +1455,14 @@ TbBool poison_cloud_affecting_thing(struct Thing *tngsrc, struct Thing *tngdst, HitPoints damage; damage = get_radially_decaying_value(max_damage, 3 * max_dist / 4, max_dist / 4, distance) + 1; SYNCDBG(7, "Causing %d damage to %s at distance %d", (int)damage, thing_model_name(tngdst), (int)distance); - apply_damage_to_thing_and_display_health(tngdst, damage, tngsrc->owner); + apply_damage_to_thing_and_display_health(tngdst, damage, tngsrc->owner, tngsrc, NULL); } spconf = get_spell_config(spell_idx); if ((!creature_under_spell_effect(tngdst, spconf->spell_flags)) && (!creature_is_immune_to_spell_effect(tngdst, spconf->spell_flags))) { struct CreatureControl *srcctrl; srcctrl = creature_control_get_from_thing(tngsrc); - apply_spell_effect_to_thing(tngdst, spell_idx, srcctrl->exp_level, tngsrc->owner); + apply_spell_effect_to_thing(tngdst, spell_idx, srcctrl->exp_level, tngsrc->owner, tngsrc, NULL); } break; case AAffT_GasEffect: @@ -1471,7 +1471,7 @@ TbBool poison_cloud_affecting_thing(struct Thing *tngsrc, struct Thing *tngdst, { struct CreatureControl *srcctrl; srcctrl = creature_control_get_from_thing(tngsrc); - apply_spell_effect_to_thing(tngdst, spell_idx, srcctrl->exp_level, tngsrc->owner); + apply_spell_effect_to_thing(tngdst, spell_idx, srcctrl->exp_level, tngsrc->owner, tngsrc, NULL); } break; default: diff --git a/src/thing_list.c b/src/thing_list.c index 4e03ed8481..23ee6ff2dc 100644 --- a/src/thing_list.c +++ b/src/thing_list.c @@ -2077,7 +2077,7 @@ TbBool electricity_affecting_thing(struct Thing *tngsrc, struct Thing *tngdst, c HitPoints damage = get_radially_decaying_value(max_damage, max_dist / 2, max_dist / 2, distance); if (damage != 0) { - apply_damage_to_thing_and_display_health(tngdst, damage, owner); + apply_damage_to_thing_and_display_health(tngdst, damage, owner, tngsrc, NULL); affected = true; } } diff --git a/src/thing_shots.c b/src/thing_shots.c index 822b44e654..3131e104a3 100644 --- a/src/thing_shots.c +++ b/src/thing_shots.c @@ -429,6 +429,7 @@ TbBool shot_hit_wall_at(struct Thing *shotng, struct Coord3d *pos) TbBool destroy_shot = 0; struct ShotConfigStats* shotst = get_shot_model_stats(shotng->model); long blocked_flags = get_thing_blocked_flags_at(shotng, pos); + struct Thing* damage_source = get_parent_thing(shotng); TbBool digging = (shotst->model_flags & ShMF_Digging); HitPoints old_health = 0; EffectOrEffElModel eff_kind; @@ -538,7 +539,7 @@ TbBool shot_hit_wall_at(struct Thing *shotng, struct Coord3d *pos) if (!shotst->hit_door.withstand) destroy_shot = 1; i = calculate_shot_real_damage_to_door(doortng, shotng); - apply_damage_to_thing(doortng, i, -1); + apply_damage_to_thing(doortng, i, -1, damage_source, NULL); reveal_secret_door_to_player(doortng,shotng->owner); } else if (cube_is_water(cube_id)) @@ -599,7 +600,7 @@ TbBool shot_hit_wall_at(struct Thing *shotng, struct Coord3d *pos) if (!shotst->hit_door.withstand) destroy_shot = 1; i = calculate_shot_real_damage_to_door(doortng, shotng); - apply_damage_to_thing(doortng, i, -1); + apply_damage_to_thing(doortng, i, -1, damage_source, NULL); reveal_secret_door_to_player(doortng,shotng->owner); } else { @@ -662,6 +663,7 @@ long shot_hit_door_at(struct Thing *shotng, struct Coord3d *pos) TbBool shot_explodes = false; struct ShotConfigStats* shotst = get_shot_model_stats(shotng->model); struct Thing* efftng = INVALID_THING; + struct Thing* damage_source = get_parent_thing(shotng); long blocked_flags = get_thing_blocked_flags_at(shotng, pos); if (blocked_flags != 0) { @@ -692,7 +694,7 @@ long shot_hit_door_at(struct Thing *shotng, struct Coord3d *pos) } // Apply damage to the door i = calculate_shot_real_damage_to_door(doortng, shotng); - apply_damage_to_thing(doortng, i, -1); + apply_damage_to_thing(doortng, i, -1, damage_source, NULL); reveal_secret_door_to_player(doortng,shotng->owner); } } @@ -791,6 +793,7 @@ static TbBool shot_hit_trap_at(struct Thing* shotng, struct Thing* target, struc if (shotng->parent_idx != shotng->index) { shootertng = thing_get(shotng->parent_idx); } + struct Thing* damage_source = shootertng; int i = shotst->hit_generic.sndsample_idx; if (i > 0) { thing_play_sample(target, i, NORMAL_PITCH, 0, 3, 0, 3, FULL_LOUDNESS); @@ -802,7 +805,7 @@ static TbBool shot_hit_trap_at(struct Thing* shotng, struct Thing* target, struc if ((thing_is_destructible_trap(target) > 0) || ((thing_is_destructible_trap(target) > -1) && (shotst->model_flags & ShMF_Disarming))) { - damage_done = apply_damage_to_thing(target, shotng->shot.damage, -1); + damage_done = apply_damage_to_thing(target, shotng->shot.damage, -1, damage_source, NULL); // Drain allows caster to regain half of damage if ((shotst->model_flags & ShMF_LifeDrain) && thing_is_creature(shootertng)) @@ -887,7 +890,7 @@ static TbBool shot_hit_object_at(struct Thing *shotng, struct Thing *target, str { if (object_can_be_damaged(target)) // do not damage objects that cannot be destroyed { - damage_done = apply_damage_to_thing(target, shotng->shot.damage, -1); + damage_done = apply_damage_to_thing(target, shotng->shot.damage, -1, shootertng, NULL); // Drain allows caster to regain half of damage if ((shotst->model_flags & ShMF_LifeDrain) && thing_is_creature(shootertng)) @@ -1068,9 +1071,9 @@ long melee_shot_hit_creature_at(struct Thing *shotng, struct Thing *trgtng, stru } create_relevant_effect_for_shot_hitting_thing(shotng, trgtng); if (!thing_is_invalid(shooter)) { - damage = apply_damage_to_thing_and_display_health(trgtng, damage, shooter->owner); + damage = apply_damage_to_thing_and_display_health(trgtng, damage, shooter->owner, shooter, NULL); } else { - damage = apply_damage_to_thing_and_display_health(trgtng, damage, -1); + damage = apply_damage_to_thing_and_display_health(trgtng, damage, -1, shooter, NULL); } if (shotst->model_flags & ShMF_LifeDrain) { @@ -1084,7 +1087,7 @@ long melee_shot_hit_creature_at(struct Thing *shotng, struct Thing *trgtng, stru { spell_level = scctrl->exp_level; } - apply_spell_effect_to_thing(trgtng, shotst->cast_spell_kind, spell_level, shotng->owner); + apply_spell_effect_to_thing(trgtng, shotst->cast_spell_kind, spell_level, shotng->owner, shooter, NULL); struct SpellConfig *spconf = get_spell_config(shotst->cast_spell_kind); if (flag_is_set(spconf->spell_flags, CSAfF_Disease)) { @@ -1252,9 +1255,9 @@ long shot_hit_creature_at(struct Thing *shotng, struct Thing *trgtng, struct Coo { HitPoints damage_done; if (thing_exists(shooter)) { - damage_done = apply_damage_to_thing_and_display_health(trgtng, shotng->shot.damage, shooter->owner); + damage_done = apply_damage_to_thing_and_display_health(trgtng, shotng->shot.damage, shooter->owner, shooter, NULL); } else { - damage_done = apply_damage_to_thing_and_display_health(trgtng, shotng->shot.damage, -1); + damage_done = apply_damage_to_thing_and_display_health(trgtng, shotng->shot.damage, -1, shooter, NULL); } if (shotst->model_flags & ShMF_LifeDrain) { @@ -1276,7 +1279,7 @@ long shot_hit_creature_at(struct Thing *shotng, struct Thing *trgtng, struct Coo { spell_level = scctrl->exp_level; } - apply_spell_effect_to_thing(trgtng, shotst->cast_spell_kind, spell_level, shotng->owner); + apply_spell_effect_to_thing(trgtng, shotst->cast_spell_kind, spell_level, shotng->owner, shooter, NULL); struct SpellConfig *spconf = get_spell_config(shotst->cast_spell_kind); if (flag_is_set(spconf->spell_flags, CSAfF_Disease)) { @@ -1740,7 +1743,7 @@ TngUpdateRet update_shot(struct Thing *thing) { shotst = get_shot_model_stats(ShM_GodLightBall); draw_lightning(&thing->mappos,&target->mappos, shotst->effect_spacing, shotst->effect_id); - apply_damage_to_thing_and_display_health(target, shotst->damage, thing->owner); + apply_damage_to_thing_and_display_health(target, shotst->damage, thing->owner, thing, NULL); } } break; diff --git a/src/thing_stats.c b/src/thing_stats.c index fc2c2c467a..c17d27abde 100644 --- a/src/thing_stats.c +++ b/src/thing_stats.c @@ -1067,6 +1067,28 @@ HitPoints calculate_shot_real_damage_to_door(const struct Thing *doortng, const return dmg; } + +static const char *default_src_string(ThingClass class_id, const char *source_str) +{ + if ((source_str != NULL) && (source_str[0] != '\0')) + { + return source_str; + } + switch (class_id) + { + case TCls_Creature: + return "CREATURE"; + case TCls_Trap: + return "TRAP"; + case TCls_Object: + return "OBJECT"; + case TCls_Door: + return "DOOR"; + default: + return source_str; + } +} + /** * Applies given damage points to a thing. * In case of targeting creature, uses its defense values to compute the actual damage. @@ -1076,7 +1098,7 @@ HitPoints calculate_shot_real_damage_to_door(const struct Thing *doortng, const * @param inflicting_plyr_idx * @return Amount of damage really inflicted. */ -HitPoints apply_damage_to_thing(struct Thing *thing, HitPoints dmg, PlayerNumber dealing_plyr_idx) +HitPoints apply_damage_to_thing(struct Thing *thing, HitPoints dmg, PlayerNumber dealing_plyr_idx, struct Thing* scrtng, const char *source_str) { // We're here to damage, not to heal. SYNCDBG(19, "Dealing %d damage to %s by player %d", (int)dmg, thing_model_name(thing), (int)dealing_plyr_idx); @@ -1085,7 +1107,9 @@ HitPoints apply_damage_to_thing(struct Thing *thing, HitPoints dmg, PlayerNumber // If it's already dead, then don't interfere. if (thing->health < 0) return 0; - lua_on_apply_damage_to_thing(thing, dmg, dealing_plyr_idx); + + source_str = default_src_string(thing->class_id, source_str); + lua_on_apply_damage_to_thing(thing, dmg, dealing_plyr_idx, scrtng, source_str); HitPoints cdamage; switch (thing->class_id) @@ -1102,6 +1126,8 @@ HitPoints apply_damage_to_thing(struct Thing *thing, HitPoints dmg, PlayerNumber } break; case TCls_Trap: + cdamage = apply_damage_to_object(thing, dmg); + break; case TCls_Object: cdamage = apply_damage_to_object(thing, dmg); break; diff --git a/src/thing_stats.h b/src/thing_stats.h index 772479ab09..878d13cfd8 100644 --- a/src/thing_stats.h +++ b/src/thing_stats.h @@ -130,7 +130,7 @@ TbBool update_relative_creature_health(struct Thing *creatng); TbBool set_creature_health_to_max_with_heal_effect(struct Thing *thing); TbBool apply_health_to_thing(struct Thing *thing, HitPoints amount); void apply_health_to_thing_and_display_health(struct Thing *thing, HitPoints amount); -HitPoints apply_damage_to_thing(struct Thing *thing, HitPoints dmg, PlayerNumber dealing_plyr_idx); +HitPoints apply_damage_to_thing(struct Thing *thing, HitPoints dmg, PlayerNumber dealing_plyr_idx, struct Thing* scrtng, const char *source_str); HitPoints get_thing_max_health(const struct Thing *thing); /******************************************************************************/ #ifdef __cplusplus From 36a439e86883e654c00bd911592c96fd89754725 Mon Sep 17 00:00:00 2001 From: Shinthoras0815 Date: Tue, 27 Jan 2026 13:30:32 +0100 Subject: [PATCH 02/11] Misc fixes --- src/main.cpp | 4 ++-- src/thing_creature.c | 8 ++++++-- src/thing_creature.h | 2 +- src/thing_stats.c | 4 ++-- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index a508e447bf..60b88c002d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2511,7 +2511,7 @@ TngUpdateRet damage_creatures_with_physical_force(struct Thing *thing, ModTngFil } if (thing_is_creature(thing)) { - apply_damage_to_thing_and_display_health(thing, param->secondary_number, param->primary_number, INVALID_THING, "PHYSICALLY_FORCE"); + apply_damage_to_thing_and_display_health(thing, param->secondary_number, param->primary_number, INVALID_THING, "PHYSICAL_FORCE"); if ((thing->health >= 0) && !creature_is_leaving_and_cannot_be_stopped(thing)) { if (((thing->alloc_flags & TAlF_IsControlled) == 0) && !creature_is_kept_in_custody(thing)) @@ -2531,7 +2531,7 @@ TngUpdateRet damage_creatures_with_physical_force(struct Thing *thing, ModTngFil } else if (thing_is_destructible_trap(thing) > 0) { - apply_damage_to_thing(thing, param->secondary_number, param->primary_number, INVALID_THING, "PHYSICALLY_FORCE"); + apply_damage_to_thing(thing, param->secondary_number, param->primary_number, INVALID_THING, "PHYSICAL_FORCE"); return TUFRet_Modified; } return TUFRet_Unchanged; diff --git a/src/thing_creature.c b/src/thing_creature.c index 0bf2abbc60..32d9edeb02 100644 --- a/src/thing_creature.c +++ b/src/thing_creature.c @@ -1454,6 +1454,10 @@ void reapply_spell_effect_to_thing(struct Thing *thing, SpellKind spell_idx, Crt cspell->duration = duration; cspell->caster_level = spell_level; cspell->caster_owner = plyr_idx; + if (thing_exists(castertng)) + cspell->caster_thing_idx = castertng->index; + else + cspell->caster_thing_idx = INVALID_THING; update_aura_effect_to_thing(thing, spell_idx); } return; @@ -6047,12 +6051,12 @@ void process_creature_leave_footsteps(struct Thing *thing) * @param dmg * @param inflicting_plyr_idx */ -HitPoints apply_damage_to_thing_and_display_health(struct Thing *thing, HitPoints dmg, PlayerNumber inflicting_plyr_idx, struct Thing *tngsrc, const char *source_str) +HitPoints apply_damage_to_thing_and_display_health(struct Thing *thing, HitPoints dmg, PlayerNumber inflicting_plyr_idx, struct Thing *scrtng, const char *source_str) { HitPoints cdamage; if (dmg > 0) { - cdamage = apply_damage_to_thing(thing, dmg, inflicting_plyr_idx, tngsrc, source_str); + cdamage = apply_damage_to_thing(thing, dmg, inflicting_plyr_idx, scrtng, source_str); } else { cdamage = 0; } diff --git a/src/thing_creature.h b/src/thing_creature.h index af590c9050..13a557ae9d 100644 --- a/src/thing_creature.h +++ b/src/thing_creature.h @@ -129,7 +129,7 @@ TbBool thing_can_be_eaten(struct Thing *thing); void food_eaten_by_creature(struct Thing *foodtng, struct Thing *creatng); void anger_apply_anger_to_creature_f(struct Thing *thing, long anger, AnnoyMotive reason, long a3, const char *func_name); #define anger_apply_anger_to_creature(thing, anger, reason, a3) anger_apply_anger_to_creature_f(thing, anger, reason, a3, __func__) -HitPoints apply_damage_to_thing_and_display_health(struct Thing *thing, HitPoints dmg, PlayerNumber inflicting_plyr_idx, struct Thing* tngsrc, const char *source_str); +HitPoints apply_damage_to_thing_and_display_health(struct Thing *thing, HitPoints dmg, PlayerNumber inflicting_plyr_idx, struct Thing* scrtng, const char *source_str); void process_creature_standing_on_corpses_at(struct Thing *thing, struct Coord3d *pos); long creature_instance_has_reset(const struct Thing *thing, long a2); void set_creature_instance(struct Thing *thing, CrInstance inst_idx, long targtng_idx, const struct Coord3d *pos); diff --git a/src/thing_stats.c b/src/thing_stats.c index c17d27abde..92b49e27b5 100644 --- a/src/thing_stats.c +++ b/src/thing_stats.c @@ -1085,7 +1085,7 @@ static const char *default_src_string(ThingClass class_id, const char *source_st case TCls_Door: return "DOOR"; default: - return source_str; + return "UNKNOWN"; } } @@ -1108,7 +1108,7 @@ HitPoints apply_damage_to_thing(struct Thing *thing, HitPoints dmg, PlayerNumber if (thing->health < 0) return 0; - source_str = default_src_string(thing->class_id, source_str); + source_str = default_src_string(scrtng->class_id, source_str); lua_on_apply_damage_to_thing(thing, dmg, dealing_plyr_idx, scrtng, source_str); HitPoints cdamage; From 6c4ac80fc076a3afa723c7af4f4334612afd28fd Mon Sep 17 00:00:00 2001 From: Shinthoras0815 Date: Tue, 27 Jan 2026 13:37:49 +0100 Subject: [PATCH 03/11] thing_class_code_name instead of switch --- src/thing_stats.c | 25 ++----------------------- 1 file changed, 2 insertions(+), 23 deletions(-) diff --git a/src/thing_stats.c b/src/thing_stats.c index 92b49e27b5..395875348b 100644 --- a/src/thing_stats.c +++ b/src/thing_stats.c @@ -1067,28 +1067,6 @@ HitPoints calculate_shot_real_damage_to_door(const struct Thing *doortng, const return dmg; } - -static const char *default_src_string(ThingClass class_id, const char *source_str) -{ - if ((source_str != NULL) && (source_str[0] != '\0')) - { - return source_str; - } - switch (class_id) - { - case TCls_Creature: - return "CREATURE"; - case TCls_Trap: - return "TRAP"; - case TCls_Object: - return "OBJECT"; - case TCls_Door: - return "DOOR"; - default: - return "UNKNOWN"; - } -} - /** * Applies given damage points to a thing. * In case of targeting creature, uses its defense values to compute the actual damage. @@ -1108,7 +1086,8 @@ HitPoints apply_damage_to_thing(struct Thing *thing, HitPoints dmg, PlayerNumber if (thing->health < 0) return 0; - source_str = default_src_string(scrtng->class_id, source_str); + if (source_str == NULL || source_str[0] == '\0') + source_str = thing_class_code_name(thing->class_id); lua_on_apply_damage_to_thing(thing, dmg, dealing_plyr_idx, scrtng, source_str); HitPoints cdamage; From f1954780aa5d21df5a25c312de07fda581990539 Mon Sep 17 00:00:00 2001 From: Shinthoras0815 Date: Tue, 27 Jan 2026 17:23:11 +0100 Subject: [PATCH 04/11] enum --- src/console_cmd.c | 4 +-- src/creature_states_pray.c | 2 +- src/lua_triggers.c | 3 ++- src/lua_triggers.h | 3 ++- src/magic_powers.c | 4 +-- src/main.cpp | 4 +-- src/power_process.c | 6 ++--- src/thing_creature.c | 28 +++++++++---------- src/thing_creature.h | 10 +++---- src/thing_effects.c | 16 +++++------ src/thing_list.c | 2 +- src/thing_shots.c | 24 ++++++++--------- src/thing_stats.c | 55 ++++++++++++++++++++++++++++++++++---- src/thing_stats.h | 20 +++++++++++++- 14 files changed, 123 insertions(+), 58 deletions(-) diff --git a/src/console_cmd.c b/src/console_cmd.c index bf80ee3a62..27cdfa78c6 100644 --- a/src/console_cmd.c +++ b/src/console_cmd.c @@ -1839,7 +1839,7 @@ TbBool cmd_freeze_creature(PlayerNumber plyr_idx, char * args) } thing_play_sample(thing, 50, NORMAL_PITCH, 0, 3, 0, 4, FULL_LOUDNESS); // Not sure how to handle this yet, for now simply hardcode the intended spell kind with a number. - apply_spell_effect_to_thing(thing, 3, 8, plyr_idx, INVALID_THING, "COMMAND_FREEZE"); // 3 was 'SplK_Freeze' in the enum. + apply_spell_effect_to_thing(thing, 3, 8, plyr_idx, INVALID_THING, DSK_CommandFreeze); // 3 was 'SplK_Freeze' in the enum. return true; } @@ -1857,7 +1857,7 @@ TbBool cmd_slow_creature(PlayerNumber plyr_idx, char * args) } thing_play_sample(thing, 50, NORMAL_PITCH, 0, 3, 0, 4, FULL_LOUDNESS); // Not sure how to handle this yet, for now simply hardcode the intended spell kind with a number. - apply_spell_effect_to_thing(thing, 12, 8, plyr_idx, INVALID_THING, "COMMAND_SLOW"); // 12 was 'SplK_Slow' in the enum. + apply_spell_effect_to_thing(thing, 12, 8, plyr_idx, INVALID_THING, DSK_CommandSlow); // 12 was 'SplK_Slow' in the enum. return true; } diff --git a/src/creature_states_pray.c b/src/creature_states_pray.c index 7f1f563c2d..9464964652 100644 --- a/src/creature_states_pray.c +++ b/src/creature_states_pray.c @@ -377,7 +377,7 @@ void apply_spell_effect_to_players_creatures(PlayerNumber plyr_idx, ThingModel c // Thing list loop body if (creature_matches_model(thing,crmodel)) { - apply_spell_effect_to_thing(thing, spl_idx, overchrg, plyr_idx, INVALID_THING, NULL); + apply_spell_effect_to_thing(thing, spl_idx, overchrg, plyr_idx, INVALID_THING, DSK_NONE); } // Thing list loop body ends k++; diff --git a/src/lua_triggers.c b/src/lua_triggers.c index a0ec08e41b..c56ce9e64a 100644 --- a/src/lua_triggers.c +++ b/src/lua_triggers.c @@ -182,7 +182,7 @@ void lua_on_creature_rebirth(struct Thing* crtng) } -void lua_on_apply_damage_to_thing(struct Thing *thing, HitPoints dmg, PlayerNumber dealing_plyr_idx, struct Thing *tngsrc, const char *source_str) +void lua_on_apply_damage_to_thing(struct Thing *thing, HitPoints dmg, PlayerNumber dealing_plyr_idx, struct Thing *tngsrc, DamageSourceKind source_kind) { SYNCDBG(6,"Starting"); lua_getglobal(Lvl_script, "OnApplyDamage"); @@ -192,6 +192,7 @@ void lua_on_apply_damage_to_thing(struct Thing *thing, HitPoints dmg, PlayerNumb lua_pushinteger(Lvl_script, dmg); lua_pushPlayer(Lvl_script, dealing_plyr_idx); lua_pushThing(Lvl_script, tngsrc); + const char *source_str = damage_source_kind_name(source_kind); if (source_str) lua_pushstring(Lvl_script, source_str); else diff --git a/src/lua_triggers.h b/src/lua_triggers.h index 6d52160db9..53bfaa6b7f 100644 --- a/src/lua_triggers.h +++ b/src/lua_triggers.h @@ -19,6 +19,7 @@ #include "globals.h" #include "bflib_basics.h" +#include "thing_stats.h" #ifdef __cplusplus extern "C" { @@ -35,7 +36,7 @@ void lua_on_dungeon_destroyed(PlayerNumber plyr_idx); void lua_on_creature_death(struct Thing *crtng); void lua_on_creature_rebirth(struct Thing* crtng); void lua_on_trap_placed(struct Thing *traptng); -void lua_on_apply_damage_to_thing(struct Thing *thing, HitPoints dmg, PlayerNumber dealing_plyr_idx, struct Thing *tngsrc, const char *source_str); +void lua_on_apply_damage_to_thing(struct Thing *thing, HitPoints dmg, PlayerNumber dealing_plyr_idx, struct Thing *tngsrc, DamageSourceKind source_kind); void lua_on_level_up(struct Thing *thing); //void lua_on_room_claimed(PlayerNumber plyr_idx, struct Room *room); diff --git a/src/magic_powers.c b/src/magic_powers.c index 57309b1033..96d91d6123 100644 --- a/src/magic_powers.c +++ b/src/magic_powers.c @@ -613,7 +613,7 @@ void slap_creature(struct PlayerInfo *player, struct Thing *thing) if (crconf->slaps_to_kill > 0) { HitPoints slap_damage = calculate_correct_creature_max_health(thing) / crconf->slaps_to_kill; - apply_damage_to_thing_and_display_health(thing, slap_damage, player->id_number, INVALID_THING, "POWER_SLAP"); + apply_damage_to_thing_and_display_health(thing, slap_damage, player->id_number, INVALID_THING, DSK_PowerSlap); } powerst = get_power_model_stats(PwrK_SLAP); i = cctrl->slap_turns; @@ -1386,7 +1386,7 @@ static TbResult magic_use_power_apply_spell(PowerKind power_kind, PlayerNumber p create_used_effect_or_element(&effpos, powerst->effect_id, thing->owner, 0); } thing_play_sample(thing, powerst->select_sound_idx, NORMAL_PITCH, 0, 3, 0, 2, FULL_LOUDNESS); - apply_spell_effect_to_thing(thing, powerst->spell_idx, power_level, plyr_idx, INVALID_THING, NULL); + apply_spell_effect_to_thing(thing, powerst->spell_idx, power_level, plyr_idx, INVALID_THING, DSK_NONE); // Special cases. if (flag_is_set(spconf->spell_flags, CSAfF_Disease)) { // Set disease_caster_plyridx if spell_idx has 'CSAfF_Disease'. diff --git a/src/main.cpp b/src/main.cpp index 60b88c002d..d4a9d8e3bc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2511,7 +2511,7 @@ TngUpdateRet damage_creatures_with_physical_force(struct Thing *thing, ModTngFil } if (thing_is_creature(thing)) { - apply_damage_to_thing_and_display_health(thing, param->secondary_number, param->primary_number, INVALID_THING, "PHYSICAL_FORCE"); + apply_damage_to_thing_and_display_health(thing, param->secondary_number, param->primary_number, INVALID_THING, DSK_PhysicalForce); if ((thing->health >= 0) && !creature_is_leaving_and_cannot_be_stopped(thing)) { if (((thing->alloc_flags & TAlF_IsControlled) == 0) && !creature_is_kept_in_custody(thing)) @@ -2531,7 +2531,7 @@ TngUpdateRet damage_creatures_with_physical_force(struct Thing *thing, ModTngFil } else if (thing_is_destructible_trap(thing) > 0) { - apply_damage_to_thing(thing, param->secondary_number, param->primary_number, INVALID_THING, "PHYSICAL_FORCE"); + apply_damage_to_thing(thing, param->secondary_number, param->primary_number, INVALID_THING, DSK_PhysicalForce); return TUFRet_Modified; } return TUFRet_Unchanged; diff --git a/src/power_process.c b/src/power_process.c index bf710a75ff..a707ec1d2b 100644 --- a/src/power_process.c +++ b/src/power_process.c @@ -215,7 +215,7 @@ void process_disease(struct Thing *creatng) && !creature_is_immune_to_spell_effect(thing, CSAfF_Disease) && (cctrl->disease_caster_plyridx != game.neutral_player_num)) { // Apply the spell kind stored in 'active_disease_spell'. - apply_spell_effect_to_thing(thing, cctrl->active_disease_spell, cctrl->exp_level, creatng->owner, creatng, "POWER_DISEASE"); + apply_spell_effect_to_thing(thing, cctrl->active_disease_spell, cctrl->exp_level, creatng->owner, creatng, DSK_PowerDisease); tngcctrl->disease_caster_plyridx = cctrl->disease_caster_plyridx; } // Per thing code ends. @@ -231,7 +231,7 @@ void process_disease(struct Thing *creatng) } if (((game.play_gameturn - cctrl->disease_start_turn) % game.conf.rules[creatng->owner].magic.disease_lose_health_time) == 0) { - apply_damage_to_thing_and_display_health(creatng, game.conf.rules[creatng->owner].magic.disease_lose_percentage_health * cctrl->max_health / 100, cctrl->disease_caster_plyridx, INVALID_THING, "POWER_DISEASE"); + apply_damage_to_thing_and_display_health(creatng, game.conf.rules[creatng->owner].magic.disease_lose_percentage_health * cctrl->max_health / 100, cctrl->disease_caster_plyridx, INVALID_THING, DSK_PowerDisease); } } @@ -303,7 +303,7 @@ void update_god_lightning_ball(struct Thing *thing) if (!thing_exists(target)) break; shotst = get_shot_model_stats(thing->model); - apply_damage_to_thing_and_display_health(target, shotst->damage, thing->owner, INVALID_THING, "POWER_LIGHTNING"); + apply_damage_to_thing_and_display_health(target, shotst->damage, thing->owner, INVALID_THING, DSK_PowerLightning); if (target->health < 0) { struct CreatureControl* cctrl = creature_control_get_from_thing(target); diff --git a/src/thing_creature.c b/src/thing_creature.c index 32d9edeb02..74b6c022bb 100644 --- a/src/thing_creature.c +++ b/src/thing_creature.c @@ -1417,7 +1417,7 @@ void update_aura_effect_to_thing(struct Thing *thing, SpellKind spell_idx) } } -void first_apply_spell_effect_to_thing(struct Thing *thing, SpellKind spell_idx, CrtrExpLevel spell_level, PlayerNumber plyr_idx, struct Thing *castertng, const char *source_str) +void first_apply_spell_effect_to_thing(struct Thing *thing, SpellKind spell_idx, CrtrExpLevel spell_level, PlayerNumber plyr_idx, struct Thing *castertng, DamageSourceKind source_kind) { if (spell_level > SPELL_MAX_LEVEL) { @@ -1438,7 +1438,7 @@ void first_apply_spell_effect_to_thing(struct Thing *thing, SpellKind spell_idx, return; } -void reapply_spell_effect_to_thing(struct Thing *thing, SpellKind spell_idx, CrtrExpLevel spell_level, PlayerNumber plyr_idx, int slot_idx, struct Thing *castertng, const char *source_str) +void reapply_spell_effect_to_thing(struct Thing *thing, SpellKind spell_idx, CrtrExpLevel spell_level, PlayerNumber plyr_idx, int slot_idx, struct Thing *castertng, DamageSourceKind source_kind) { if (spell_level > SPELL_MAX_LEVEL) { @@ -1463,7 +1463,7 @@ void reapply_spell_effect_to_thing(struct Thing *thing, SpellKind spell_idx, Crt return; } -void apply_spell_effect_to_thing(struct Thing *thing, SpellKind spell_idx, CrtrExpLevel spell_level, PlayerNumber plyr_idx, struct Thing *castertng, const char *source_str) +void apply_spell_effect_to_thing(struct Thing *thing, SpellKind spell_idx, CrtrExpLevel spell_level, PlayerNumber plyr_idx, struct Thing *castertng, DamageSourceKind source_kind) { struct CreatureControl *cctrl = creature_control_get_from_thing(thing); if (creature_control_invalid(cctrl)) @@ -1505,7 +1505,7 @@ void apply_spell_effect_to_thing(struct Thing *thing, SpellKind spell_idx, CrtrE // Check for damage/heal one-time effect. if ((spconf->damage != 0) && (spconf->damage_frequency == 0)) { - process_thing_spell_damage_or_heal_effects(thing, spell_idx, spell_level, plyr_idx, castertng, source_str); + process_thing_spell_damage_or_heal_effects(thing, spell_idx, spell_level, plyr_idx, castertng, source_kind); if (spconf->spell_flags == 0 && !spell_is_continuous(spell_idx, duration)) { @@ -1531,11 +1531,11 @@ void apply_spell_effect_to_thing(struct Thing *thing, SpellKind spell_idx, CrtrE { if (cctrl->casted_spells[i].spkind == spell_idx) { - reapply_spell_effect_to_thing(thing, spell_idx, spell_level, plyr_idx, i, castertng, source_str); + reapply_spell_effect_to_thing(thing, spell_idx, spell_level, plyr_idx, i, castertng, source_kind); return; // Exit the function, spell is already active. } } - first_apply_spell_effect_to_thing(thing, spell_idx, spell_level, plyr_idx, castertng, source_str); + first_apply_spell_effect_to_thing(thing, spell_idx, spell_level, plyr_idx, castertng, source_kind); } void terminate_thing_spell_effect(struct Thing *thing, SpellKind spell_idx) @@ -1823,7 +1823,7 @@ void process_thing_spell_teleport_effects(struct Thing *thing, struct CastedSpel } } -void process_thing_spell_damage_or_heal_effects(struct Thing *thing, SpellKind spell_idx, CrtrExpLevel caster_level, PlayerNumber caster_owner, struct Thing *caster_tng, const char *source_str) +void process_thing_spell_damage_or_heal_effects(struct Thing *thing, SpellKind spell_idx, CrtrExpLevel caster_level, PlayerNumber caster_owner, struct Thing *caster_tng, DamageSourceKind source_kind) { struct CreatureControl *cctrl = creature_control_get_from_thing(thing); struct SpellConfig *spconf = get_spell_config(spell_idx); @@ -1862,7 +1862,7 @@ void process_thing_spell_damage_or_heal_effects(struct Thing *thing, SpellKind s // Apply damage. if (damage >= 0) { - apply_damage_to_thing_and_display_health(thing, damage, caster_owner, caster_tng, source_str); + apply_damage_to_thing_and_display_health(thing, damage, caster_owner, caster_tng, source_kind); } else // Or heal if damage is negative. { @@ -1904,7 +1904,7 @@ void process_thing_spell_effects(struct Thing *thing) struct Thing* caster_tng = thing_get(cspell->caster_thing_idx); if (!thing_exists(caster_tng)) caster_tng = INVALID_THING; - process_thing_spell_damage_or_heal_effects(thing, cspell->spkind, cspell->caster_level, cspell->caster_owner, caster_tng, "UNKNOWN_DOT"); + process_thing_spell_damage_or_heal_effects(thing, cspell->spkind, cspell->caster_level, cspell->caster_owner, caster_tng, DSK_DOTSpell); } } // Process spell with teleport flag. @@ -2237,7 +2237,7 @@ void creature_cast_spell(struct Thing *castng, SpellKind spl_idx, CrtrExpLevel s { thing_play_sample(castng, spconf->caster_affect_sound + SOUND_RANDOM(spconf->caster_sounds_count), NORMAL_PITCH, 0, 3, 0, 4, FULL_LOUDNESS); } - apply_spell_effect_to_thing(castng, spl_idx, cctrl->exp_level, castng->owner, castng, NULL); + apply_spell_effect_to_thing(castng, spl_idx, cctrl->exp_level, castng->owner, castng, DSK_NONE); } else if (spconf->shot_model > 0) { @@ -6051,12 +6051,12 @@ void process_creature_leave_footsteps(struct Thing *thing) * @param dmg * @param inflicting_plyr_idx */ -HitPoints apply_damage_to_thing_and_display_health(struct Thing *thing, HitPoints dmg, PlayerNumber inflicting_plyr_idx, struct Thing *scrtng, const char *source_str) +HitPoints apply_damage_to_thing_and_display_health(struct Thing *thing, HitPoints dmg, PlayerNumber inflicting_plyr_idx, struct Thing *scrtng, DamageSourceKind source_kind) { HitPoints cdamage; if (dmg > 0) { - cdamage = apply_damage_to_thing(thing, dmg, inflicting_plyr_idx, scrtng, source_str); + cdamage = apply_damage_to_thing(thing, dmg, inflicting_plyr_idx, scrtng, source_kind); } else { cdamage = 0; } @@ -6106,7 +6106,7 @@ void process_landscape_affecting_creature(struct Thing *thing) if (cube_is_lava(i)) { struct CreatureModelConfig* crconf = creature_stats_get_from_thing(thing); - apply_damage_to_thing_and_display_health(thing, crconf->hurt_by_lava, -1, INVALID_THING, "LAVA"); + apply_damage_to_thing_and_display_health(thing, crconf->hurt_by_lava, -1, INVALID_THING, DSK_Lava); thing->movement_flags |= TMvF_IsOnLava; } else if (cube_is_water(i)) @@ -7704,7 +7704,7 @@ TbResult script_use_spell_on_creature(PlayerNumber plyr_idx, struct Thing *thing { thing_play_sample(thing, spconf->caster_affect_sound + SOUND_RANDOM(spconf->caster_sounds_count), NORMAL_PITCH, 0, 3, 0, 4, FULL_LOUDNESS); } - apply_spell_effect_to_thing(thing, spkind, spell_level, plyr_idx, INVALID_THING, "SCRIPT_SPELL"); + apply_spell_effect_to_thing(thing, spkind, spell_level, plyr_idx, INVALID_THING, DSK_ScriptSpell); if (flag_is_set(spconf->spell_flags, CSAfF_Disease)) { struct CreatureControl *cctrl; diff --git a/src/thing_creature.h b/src/thing_creature.h index 13a557ae9d..68de992efc 100644 --- a/src/thing_creature.h +++ b/src/thing_creature.h @@ -129,7 +129,7 @@ TbBool thing_can_be_eaten(struct Thing *thing); void food_eaten_by_creature(struct Thing *foodtng, struct Thing *creatng); void anger_apply_anger_to_creature_f(struct Thing *thing, long anger, AnnoyMotive reason, long a3, const char *func_name); #define anger_apply_anger_to_creature(thing, anger, reason, a3) anger_apply_anger_to_creature_f(thing, anger, reason, a3, __func__) -HitPoints apply_damage_to_thing_and_display_health(struct Thing *thing, HitPoints dmg, PlayerNumber inflicting_plyr_idx, struct Thing* scrtng, const char *source_str); +HitPoints apply_damage_to_thing_and_display_health(struct Thing *thing, HitPoints dmg, PlayerNumber inflicting_plyr_idx, struct Thing* scrtng, DamageSourceKind source_kind); void process_creature_standing_on_corpses_at(struct Thing *thing, struct Coord3d *pos); long creature_instance_has_reset(const struct Thing *thing, long a2); void set_creature_instance(struct Thing *thing, CrInstance inst_idx, long targtng_idx, const struct Coord3d *pos); @@ -163,11 +163,11 @@ void clean_spell_effect_f(struct Thing *thing, unsigned long spell_flags, const TbResult script_use_spell_on_creature(PlayerNumber plyr_idx, struct Thing *thing, SpellKind spkind, CrtrExpLevel spell_level); TbResult script_use_spell_on_creature_with_criteria(PlayerNumber plyr_idx, ThingModel crmodel, short criteria, SpellKind spkind, CrtrExpLevel spell_level); -void apply_spell_effect_to_thing(struct Thing *thing, SpellKind spell_idx, CrtrExpLevel spell_level, PlayerNumber plyr_idx, struct Thing *castertng, const char *source_str); -void first_apply_spell_effect_to_thing(struct Thing *thing, SpellKind spell_idx, CrtrExpLevel spell_level, PlayerNumber plyr_idx, struct Thing *castertng, const char *source_str); -void reapply_spell_effect_to_thing(struct Thing *thing, SpellKind spell_idx, CrtrExpLevel spell_level, PlayerNumber plyr_idx, int slot_idx, struct Thing *castertng, const char *source_str); +void apply_spell_effect_to_thing(struct Thing *thing, SpellKind spell_idx, CrtrExpLevel spell_level, PlayerNumber plyr_idx, struct Thing *castertng, DamageSourceKind source_kind); +void first_apply_spell_effect_to_thing(struct Thing *thing, SpellKind spell_idx, CrtrExpLevel spell_level, PlayerNumber plyr_idx, struct Thing *castertng, DamageSourceKind source_kind); +void reapply_spell_effect_to_thing(struct Thing *thing, SpellKind spell_idx, CrtrExpLevel spell_level, PlayerNumber plyr_idx, int slot_idx, struct Thing *castertng, DamageSourceKind source_kind); void terminate_thing_spell_effect(struct Thing *thing, SpellKind spell_idx); -void process_thing_spell_damage_or_heal_effects(struct Thing *thing, SpellKind spell_idx, CrtrExpLevel caster_level, PlayerNumber caster_owner, struct Thing *caster_tng, const char *source_str); +void process_thing_spell_damage_or_heal_effects(struct Thing *thing, SpellKind spell_idx, CrtrExpLevel caster_level, PlayerNumber caster_owner, struct Thing *caster_tng, DamageSourceKind source_kind); void process_thing_spell_effects(struct Thing *thing); void process_thing_spell_effects_while_blocked(struct Thing *thing); void delete_armour_effects_attached_to_creature(struct Thing *thing); diff --git a/src/thing_effects.c b/src/thing_effects.c index 9373f6b5dd..54581cbb8e 100644 --- a/src/thing_effects.c +++ b/src/thing_effects.c @@ -1012,7 +1012,7 @@ TbBool explosion_affecting_thing(struct Thing *tngsrc, struct Thing *tngdst, con { HitPoints damage = get_radially_decaying_value(max_damage, max_dist / 4, 3 * max_dist / 4, distance) + 1; SYNCDBG(7,"Causing %d damage to %s at distance %d",(int)damage,thing_model_name(tngdst),(int)distance); - apply_damage_to_thing_and_display_health(tngdst, damage, owner, tngsrc, NULL); + apply_damage_to_thing_and_display_health(tngdst, damage, owner, tngsrc, DSK_NONE); if (flag_is_set(shotst->model_flags,ShMF_LifeDrain)) { give_shooter_drained_health(origtng, damage / 2); @@ -1038,7 +1038,7 @@ TbBool explosion_affecting_thing(struct Thing *tngsrc, struct Thing *tngdst, con { spell_level = scctrl->exp_level; } - apply_spell_effect_to_thing(tngdst, shotst->cast_spell_kind, spell_level, owner, origtng, NULL); + apply_spell_effect_to_thing(tngdst, shotst->cast_spell_kind, spell_level, owner, origtng, DSK_NONE); struct SpellConfig *spconf = get_spell_config(shotst->cast_spell_kind); if (flag_is_set(spconf->spell_flags, CSAfF_Disease)) { @@ -1066,7 +1066,7 @@ TbBool explosion_affecting_thing(struct Thing *tngsrc, struct Thing *tngdst, con { HitPoints damage = get_radially_decaying_value(max_damage, max_dist / 4, 3 * max_dist / 4, distance) + 1; SYNCDBG(7,"Causing %d damage to %s at distance %d",(int)damage,thing_model_name(tngdst),(int)distance); - apply_damage_to_thing(tngdst, damage, -1, tngsrc, NULL); + apply_damage_to_thing(tngdst, damage, -1, tngsrc, DSK_NONE); affected = true; event_create_event_or_update_nearby_existing_event(tngdst->mappos.x.val, tngdst->mappos.y.val,EvKind_HeartAttacked, tngdst->owner, 0); if (is_my_player_number(tngdst->owner)) @@ -1136,7 +1136,7 @@ TbBool explosion_affecting_door(struct Thing *tngsrc, struct Thing *tngdst, cons } } SYNCDBG(7,"Causing %d damage to %s at distance %d",(int)damage,thing_model_name(tngdst),(int)distance); - apply_damage_to_thing(tngdst, damage, -1, tngsrc, NULL); + apply_damage_to_thing(tngdst, damage, -1, tngsrc, DSK_NONE); affected = true; } } @@ -1446,7 +1446,7 @@ TbBool poison_cloud_affecting_thing(struct Thing *tngsrc, struct Thing *tngdst, HitPoints damage; damage = get_radially_decaying_value(max_damage, max_dist / 4, 3 * max_dist / 4, distance) + 1; SYNCDBG(7, "Causing %d damage to %s at distance %d", (int)damage, thing_model_name(tngdst), (int)distance); - apply_damage_to_thing_and_display_health(tngdst, damage, tngsrc->owner, tngsrc, NULL); + apply_damage_to_thing_and_display_health(tngdst, damage, tngsrc->owner, tngsrc, DSK_NONE); } break; case AAffT_GasDamageEffect: @@ -1455,14 +1455,14 @@ TbBool poison_cloud_affecting_thing(struct Thing *tngsrc, struct Thing *tngdst, HitPoints damage; damage = get_radially_decaying_value(max_damage, 3 * max_dist / 4, max_dist / 4, distance) + 1; SYNCDBG(7, "Causing %d damage to %s at distance %d", (int)damage, thing_model_name(tngdst), (int)distance); - apply_damage_to_thing_and_display_health(tngdst, damage, tngsrc->owner, tngsrc, NULL); + apply_damage_to_thing_and_display_health(tngdst, damage, tngsrc->owner, tngsrc, DSK_NONE); } spconf = get_spell_config(spell_idx); if ((!creature_under_spell_effect(tngdst, spconf->spell_flags)) && (!creature_is_immune_to_spell_effect(tngdst, spconf->spell_flags))) { struct CreatureControl *srcctrl; srcctrl = creature_control_get_from_thing(tngsrc); - apply_spell_effect_to_thing(tngdst, spell_idx, srcctrl->exp_level, tngsrc->owner, tngsrc, NULL); + apply_spell_effect_to_thing(tngdst, spell_idx, srcctrl->exp_level, tngsrc->owner, tngsrc, DSK_NONE); } break; case AAffT_GasEffect: @@ -1471,7 +1471,7 @@ TbBool poison_cloud_affecting_thing(struct Thing *tngsrc, struct Thing *tngdst, { struct CreatureControl *srcctrl; srcctrl = creature_control_get_from_thing(tngsrc); - apply_spell_effect_to_thing(tngdst, spell_idx, srcctrl->exp_level, tngsrc->owner, tngsrc, NULL); + apply_spell_effect_to_thing(tngdst, spell_idx, srcctrl->exp_level, tngsrc->owner, tngsrc, DSK_NONE); } break; default: diff --git a/src/thing_list.c b/src/thing_list.c index 23ee6ff2dc..080c4ee40a 100644 --- a/src/thing_list.c +++ b/src/thing_list.c @@ -2077,7 +2077,7 @@ TbBool electricity_affecting_thing(struct Thing *tngsrc, struct Thing *tngdst, c HitPoints damage = get_radially_decaying_value(max_damage, max_dist / 2, max_dist / 2, distance); if (damage != 0) { - apply_damage_to_thing_and_display_health(tngdst, damage, owner, tngsrc, NULL); + apply_damage_to_thing_and_display_health(tngdst, damage, owner, tngsrc, DSK_NONE); affected = true; } } diff --git a/src/thing_shots.c b/src/thing_shots.c index 3131e104a3..81a9252abf 100644 --- a/src/thing_shots.c +++ b/src/thing_shots.c @@ -539,7 +539,7 @@ TbBool shot_hit_wall_at(struct Thing *shotng, struct Coord3d *pos) if (!shotst->hit_door.withstand) destroy_shot = 1; i = calculate_shot_real_damage_to_door(doortng, shotng); - apply_damage_to_thing(doortng, i, -1, damage_source, NULL); + apply_damage_to_thing(doortng, i, -1, damage_source, DSK_NONE); reveal_secret_door_to_player(doortng,shotng->owner); } else if (cube_is_water(cube_id)) @@ -600,7 +600,7 @@ TbBool shot_hit_wall_at(struct Thing *shotng, struct Coord3d *pos) if (!shotst->hit_door.withstand) destroy_shot = 1; i = calculate_shot_real_damage_to_door(doortng, shotng); - apply_damage_to_thing(doortng, i, -1, damage_source, NULL); + apply_damage_to_thing(doortng, i, -1, damage_source, DSK_NONE); reveal_secret_door_to_player(doortng,shotng->owner); } else { @@ -694,7 +694,7 @@ long shot_hit_door_at(struct Thing *shotng, struct Coord3d *pos) } // Apply damage to the door i = calculate_shot_real_damage_to_door(doortng, shotng); - apply_damage_to_thing(doortng, i, -1, damage_source, NULL); + apply_damage_to_thing(doortng, i, -1, damage_source, DSK_NONE); reveal_secret_door_to_player(doortng,shotng->owner); } } @@ -805,7 +805,7 @@ static TbBool shot_hit_trap_at(struct Thing* shotng, struct Thing* target, struc if ((thing_is_destructible_trap(target) > 0) || ((thing_is_destructible_trap(target) > -1) && (shotst->model_flags & ShMF_Disarming))) { - damage_done = apply_damage_to_thing(target, shotng->shot.damage, -1, damage_source, NULL); + damage_done = apply_damage_to_thing(target, shotng->shot.damage, -1, damage_source, DSK_NONE); // Drain allows caster to regain half of damage if ((shotst->model_flags & ShMF_LifeDrain) && thing_is_creature(shootertng)) @@ -890,7 +890,7 @@ static TbBool shot_hit_object_at(struct Thing *shotng, struct Thing *target, str { if (object_can_be_damaged(target)) // do not damage objects that cannot be destroyed { - damage_done = apply_damage_to_thing(target, shotng->shot.damage, -1, shootertng, NULL); + damage_done = apply_damage_to_thing(target, shotng->shot.damage, -1, shootertng, DSK_NONE); // Drain allows caster to regain half of damage if ((shotst->model_flags & ShMF_LifeDrain) && thing_is_creature(shootertng)) @@ -1071,9 +1071,9 @@ long melee_shot_hit_creature_at(struct Thing *shotng, struct Thing *trgtng, stru } create_relevant_effect_for_shot_hitting_thing(shotng, trgtng); if (!thing_is_invalid(shooter)) { - damage = apply_damage_to_thing_and_display_health(trgtng, damage, shooter->owner, shooter, NULL); + damage = apply_damage_to_thing_and_display_health(trgtng, damage, shooter->owner, shooter, DSK_NONE); } else { - damage = apply_damage_to_thing_and_display_health(trgtng, damage, -1, shooter, NULL); + damage = apply_damage_to_thing_and_display_health(trgtng, damage, -1, shooter, DSK_NONE); } if (shotst->model_flags & ShMF_LifeDrain) { @@ -1087,7 +1087,7 @@ long melee_shot_hit_creature_at(struct Thing *shotng, struct Thing *trgtng, stru { spell_level = scctrl->exp_level; } - apply_spell_effect_to_thing(trgtng, shotst->cast_spell_kind, spell_level, shotng->owner, shooter, NULL); + apply_spell_effect_to_thing(trgtng, shotst->cast_spell_kind, spell_level, shotng->owner, shooter, DSK_NONE); struct SpellConfig *spconf = get_spell_config(shotst->cast_spell_kind); if (flag_is_set(spconf->spell_flags, CSAfF_Disease)) { @@ -1255,9 +1255,9 @@ long shot_hit_creature_at(struct Thing *shotng, struct Thing *trgtng, struct Coo { HitPoints damage_done; if (thing_exists(shooter)) { - damage_done = apply_damage_to_thing_and_display_health(trgtng, shotng->shot.damage, shooter->owner, shooter, NULL); + damage_done = apply_damage_to_thing_and_display_health(trgtng, shotng->shot.damage, shooter->owner, shooter, DSK_NONE); } else { - damage_done = apply_damage_to_thing_and_display_health(trgtng, shotng->shot.damage, -1, shooter, NULL); + damage_done = apply_damage_to_thing_and_display_health(trgtng, shotng->shot.damage, -1, shooter, DSK_NONE); } if (shotst->model_flags & ShMF_LifeDrain) { @@ -1279,7 +1279,7 @@ long shot_hit_creature_at(struct Thing *shotng, struct Thing *trgtng, struct Coo { spell_level = scctrl->exp_level; } - apply_spell_effect_to_thing(trgtng, shotst->cast_spell_kind, spell_level, shotng->owner, shooter, NULL); + apply_spell_effect_to_thing(trgtng, shotst->cast_spell_kind, spell_level, shotng->owner, shooter, DSK_NONE); struct SpellConfig *spconf = get_spell_config(shotst->cast_spell_kind); if (flag_is_set(spconf->spell_flags, CSAfF_Disease)) { @@ -1743,7 +1743,7 @@ TngUpdateRet update_shot(struct Thing *thing) { shotst = get_shot_model_stats(ShM_GodLightBall); draw_lightning(&thing->mappos,&target->mappos, shotst->effect_spacing, shotst->effect_id); - apply_damage_to_thing_and_display_health(target, shotst->damage, thing->owner, thing, NULL); + apply_damage_to_thing_and_display_health(target, shotst->damage, thing->owner, thing, DSK_NONE); } } break; diff --git a/src/thing_stats.c b/src/thing_stats.c index 395875348b..4a8ec7fbb4 100644 --- a/src/thing_stats.c +++ b/src/thing_stats.c @@ -1067,6 +1067,53 @@ HitPoints calculate_shot_real_damage_to_door(const struct Thing *doortng, const return dmg; } +DamageSourceKind check_dmg_src_kind(struct Thing* scrtng, DamageSourceKind source_kind) +{ + if ((source_kind == DSK_NONE) && (scrtng != NULL && !thing_is_invalid(scrtng))) + { + switch(scrtng->class_id) + { + case TCls_Creature: + source_kind = DSK_Creature; + break; + case TCls_Trap: + source_kind = DSK_Trap; + break; + case TCls_Object: + source_kind = DSK_Object; + break; + case TCls_Door: + source_kind = DSK_Door; + break; + default: + source_kind = DSK_NONE; + break; + } + } + return source_kind; +} + +const char *damage_source_kind_name(DamageSourceKind kind) +{ + switch (kind) + { + case DSK_Lava: return "LAVA"; + case DSK_PowerSlap: return "POWER_SLAP"; + case DSK_PowerDisease: return "POWER_DISEASE"; + case DSK_PowerLightning: return "POWER_LIGHTNING"; + case DSK_PhysicalForce: return "PHYSICAL_FORCE"; + case DSK_CommandFreeze: return "COMMAND_FREEZE"; + case DSK_CommandSlow: return "COMMAND_SLOW"; + case DSK_ScriptSpell: return "SCRIPT_SPELL"; + case DSK_DOTSpell: return "UNKNOWN_DOT"; + case DSK_Creature: return "CREATURE"; + case DSK_Trap: return "TRAP"; + case DSK_Object: return "OBJECT"; + case DSK_Door: return "DOOR"; + default: return NULL; + } +} + /** * Applies given damage points to a thing. * In case of targeting creature, uses its defense values to compute the actual damage. @@ -1076,7 +1123,7 @@ HitPoints calculate_shot_real_damage_to_door(const struct Thing *doortng, const * @param inflicting_plyr_idx * @return Amount of damage really inflicted. */ -HitPoints apply_damage_to_thing(struct Thing *thing, HitPoints dmg, PlayerNumber dealing_plyr_idx, struct Thing* scrtng, const char *source_str) +HitPoints apply_damage_to_thing(struct Thing *thing, HitPoints dmg, PlayerNumber dealing_plyr_idx, struct Thing* scrtng, DamageSourceKind source_kind) { // We're here to damage, not to heal. SYNCDBG(19, "Dealing %d damage to %s by player %d", (int)dmg, thing_model_name(thing), (int)dealing_plyr_idx); @@ -1085,10 +1132,8 @@ HitPoints apply_damage_to_thing(struct Thing *thing, HitPoints dmg, PlayerNumber // If it's already dead, then don't interfere. if (thing->health < 0) return 0; - - if (source_str == NULL || source_str[0] == '\0') - source_str = thing_class_code_name(thing->class_id); - lua_on_apply_damage_to_thing(thing, dmg, dealing_plyr_idx, scrtng, source_str); + DamageSourceKind damagesource = check_dmg_src_kind(scrtng, source_kind); + lua_on_apply_damage_to_thing(thing, dmg, dealing_plyr_idx, scrtng, damagesource); HitPoints cdamage; switch (thing->class_id) diff --git a/src/thing_stats.h b/src/thing_stats.h index 878d13cfd8..8628a08924 100644 --- a/src/thing_stats.h +++ b/src/thing_stats.h @@ -57,6 +57,24 @@ enum CreatureLiveStatistics { CrLStat_Score, }; +typedef enum DamageSourceKind { + DSK_NONE = 0, + DSK_Lava, + DSK_PowerSlap, + DSK_PowerDisease, + DSK_PowerLightning, + DSK_PhysicalForce, + DSK_CommandFreeze, + DSK_CommandSlow, + DSK_ScriptSpell, + DSK_DOTSpell, + DSK_Creature, + DSK_Trap, + DSK_Object, + DSK_Door, +} DamageSourceKind; + +const char *damage_source_kind_name(DamageSourceKind kind); /******************************************************************************/ #pragma pack(1) @@ -130,7 +148,7 @@ TbBool update_relative_creature_health(struct Thing *creatng); TbBool set_creature_health_to_max_with_heal_effect(struct Thing *thing); TbBool apply_health_to_thing(struct Thing *thing, HitPoints amount); void apply_health_to_thing_and_display_health(struct Thing *thing, HitPoints amount); -HitPoints apply_damage_to_thing(struct Thing *thing, HitPoints dmg, PlayerNumber dealing_plyr_idx, struct Thing* scrtng, const char *source_str); +HitPoints apply_damage_to_thing(struct Thing *thing, HitPoints dmg, PlayerNumber dealing_plyr_idx, struct Thing* scrtng, DamageSourceKind source_kind); HitPoints get_thing_max_health(const struct Thing *thing); /******************************************************************************/ #ifdef __cplusplus From 16e1d66b06c6013cb370aa054edd2151c7d57795 Mon Sep 17 00:00:00 2001 From: Shinthoras0815 Date: Tue, 27 Jan 2026 18:03:51 +0100 Subject: [PATCH 05/11] damage source enum in Lua --- config/fxdata/lua/aliases.lua | 23 +++++++++- config/fxdata/lua/triggers/Builtins.lua | 16 +++---- src/lua_api.c | 1 + src/lua_api_things.c | 59 +++++++++++++++++++++++-- src/lua_triggers.c | 6 +-- 5 files changed, 88 insertions(+), 17 deletions(-) diff --git a/config/fxdata/lua/aliases.lua b/config/fxdata/lua/aliases.lua index fa3335ca77..875805aecb 100644 --- a/config/fxdata/lua/aliases.lua +++ b/config/fxdata/lua/aliases.lua @@ -26,5 +26,26 @@ ---@alias actionpoint integer ---@alias location playersingle|actionpoint|"LAST_EVENT"|"COMBAT"|Pos3d ---@alias thing_class "Object"|"Shot"|"EffectElem"|"DeadCreature"|"Creature"|"Effect"|"EffectGen"|"Trap"|"Door"|"AmbientSnd"|"CaveIn" ----@alias effect_or_effelem_type integer|string|effect_type|effect_element_type -- I allow string here because there's to many entries for, the language server to handle +---@alias effect_or_effelem_type integer|string|effect_type|effect_element_type -- I allow string here because there's to many entries for, the language server to handle +---@alias damage_source_kind integer + +---@class DamageSourceKindTable +---@field NONE integer Unspecified damage source (0) +---@field LAVA integer Damage from lava terrain (1) +---@field POWER_SLAP integer Damage from player slap power (2) +---@field POWER_DISEASE integer Damage from disease spell (3) +---@field POWER_LIGHTNING integer Damage from lightning spell (4) +---@field PHYSICAL_FORCE integer Physical damage (5) +---@field COMMAND_FREEZE integer Damage from freeze command/spell (6) +---@field COMMAND_SLOW integer Damage from slow command/spell (7) +---@field SCRIPT_SPELL integer Damage from script-triggered spell (8) +---@field DOT_SPELL integer Damage from damage-over-time spell effects (9) +---@field CREATURE integer Damage from creature attack (10) +---@field TRAP integer Damage from trap activation (11) +---@field OBJECT integer Damage from object interaction (12) +---@field DOOR integer Damage from door (13) + +--- Global table containing damage source kind constants +---@type DamageSourceKindTable +DamageSourceKind = {} diff --git a/config/fxdata/lua/triggers/Builtins.lua b/config/fxdata/lua/triggers/Builtins.lua index a319f4d1fd..7367154033 100644 --- a/config/fxdata/lua/triggers/Builtins.lua +++ b/config/fxdata/lua/triggers/Builtins.lua @@ -70,19 +70,19 @@ function OnDungeonDestroyed(player) ProcessEvent("DungeonDestroyed",eventData) end ---- Called when a thing taked damage ----@param thing Thing ----@param damage integer ----@param dealing_player Player ----@param source_thing Thing|nil ----@param source_string string|nil -function OnApplyDamage(thing, damage, dealing_player, source_thing, source_string) +--- Called when a thing takes damage +---@param thing Thing The thing receiving damage +---@param damage integer Amount of damage dealt +---@param dealing_player Player Player responsible for the damage +---@param source_thing Thing|nil The thing that caused the damage (e.g., attacking creature, trap) +---@param source_kind damage_source_kind Integer enum value from DamageSourceKind (e.g., DamageSourceKind.LAVA) +function OnApplyDamage(thing, damage, dealing_player, source_thing, source_kind) local eventData = {} eventData.thing = thing eventData.damage = damage eventData.dealing_player = dealing_player eventData.source_thing = source_thing - eventData.source_string = source_string + eventData.source_kind = source_kind ProcessEvent("ApplyDamage",eventData) end diff --git a/src/lua_api.c b/src/lua_api.c index 3932869eff..ea9a7d734b 100644 --- a/src/lua_api.c +++ b/src/lua_api.c @@ -2256,4 +2256,5 @@ void reg_host_functions(lua_State *L) Thing_register(L); Slab_register(L); room_register(L); + DamageSourceKind_register(L); } diff --git a/src/lua_api_things.c b/src/lua_api_things.c index 2141af30fe..f1fc736aa6 100644 --- a/src/lua_api_things.c +++ b/src/lua_api_things.c @@ -210,7 +210,7 @@ static int thing_set_field(lua_State *L) { } else if (strcmp(key, "health") == 0) { thing->health = luaL_checkinteger(L, 3); - } else if (strcmp(key, "pos") == 0) + } else if (strcmp(key, "pos") == 0) { struct Coord3d pos; luaL_checkCoord3d(L, 3, &pos); @@ -566,7 +566,7 @@ static const struct luaL_Reg thing_methods[] = { {"stun", lua_stun_creature}, {"delete", lua_delete_thing}, {"isValid", lua_is_valid}, - + {"transfer" ,lua_Transfer_creature }, {"level_up" ,lua_Level_up_creature }, {"teleport" ,lua_Teleport_creature }, @@ -611,4 +611,57 @@ void Thing_register(lua_State *L) { // Pop the metatable lua_pop(L, 1); -} \ No newline at end of file +} + +// In lua_api.c oder lua_api_things.c + +void DamageSourceKind_register(lua_State *L) { + // Create global table "DamageSourceKind" + lua_newtable(L); + + // Add enum values as fields + lua_pushinteger(L, DSK_NONE); + lua_setfield(L, -2, "NONE"); + + lua_pushinteger(L, DSK_Lava); + lua_setfield(L, -2, "LAVA"); + + lua_pushinteger(L, DSK_PowerSlap); + lua_setfield(L, -2, "POWER_SLAP"); + + lua_pushinteger(L, DSK_PowerDisease); + lua_setfield(L, -2, "POWER_DISEASE"); + + lua_pushinteger(L, DSK_PowerLightning); + lua_setfield(L, -2, "POWER_LIGHTNING"); + + lua_pushinteger(L, DSK_PhysicalForce); + lua_setfield(L, -2, "PHYSICAL_FORCE"); + + lua_pushinteger(L, DSK_CommandFreeze); + lua_setfield(L, -2, "COMMAND_FREEZE"); + + lua_pushinteger(L, DSK_CommandSlow); + lua_setfield(L, -2, "COMMAND_SLOW"); + + lua_pushinteger(L, DSK_ScriptSpell); + lua_setfield(L, -2, "SCRIPT_SPELL"); + + lua_pushinteger(L, DSK_DOTSpell); + lua_setfield(L, -2, "DOT_SPELL"); + + lua_pushinteger(L, DSK_Creature); + lua_setfield(L, -2, "CREATURE"); + + lua_pushinteger(L, DSK_Trap); + lua_setfield(L, -2, "TRAP"); + + lua_pushinteger(L, DSK_Object); + lua_setfield(L, -2, "OBJECT"); + + lua_pushinteger(L, DSK_Door); + lua_setfield(L, -2, "DOOR"); + + // Set as global "DamageSourceKind" + lua_setglobal(L, "DamageSourceKind"); +} diff --git a/src/lua_triggers.c b/src/lua_triggers.c index c56ce9e64a..59ad6277d4 100644 --- a/src/lua_triggers.c +++ b/src/lua_triggers.c @@ -192,11 +192,7 @@ void lua_on_apply_damage_to_thing(struct Thing *thing, HitPoints dmg, PlayerNumb lua_pushinteger(Lvl_script, dmg); lua_pushPlayer(Lvl_script, dealing_plyr_idx); lua_pushThing(Lvl_script, tngsrc); - const char *source_str = damage_source_kind_name(source_kind); - if (source_str) - lua_pushstring(Lvl_script, source_str); - else - lua_pushnil(Lvl_script); + lua_pushinteger(Lvl_script, source_kind); CheckLua(Lvl_script, lua_pcall(Lvl_script, 5, 0, 0),"OnApplyDamage"); } From 4797a20386518f12e19ea9d0a0e8ba506459b27a Mon Sep 17 00:00:00 2001 From: Shinthoras0815 Date: Tue, 27 Jan 2026 18:10:02 +0100 Subject: [PATCH 06/11] Update thing_creature.h --- src/thing_creature.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/thing_creature.h b/src/thing_creature.h index 68de992efc..23d97e4789 100644 --- a/src/thing_creature.h +++ b/src/thing_creature.h @@ -25,6 +25,7 @@ #include "bflib_filelst.h" #include "bflib_sprite.h" #include "thing_list.h" +#include "thing_stats.h" #include "map_locations.h" #include "packets.h" From 7d4d19a433187834f23fc3e940bb00af57c81f07 Mon Sep 17 00:00:00 2001 From: Shinthoras0815 Date: Tue, 27 Jan 2026 18:28:31 +0100 Subject: [PATCH 07/11] Update console_cmd.h --- src/console_cmd.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/console_cmd.h b/src/console_cmd.h index 483454fb07..653502cbef 100644 --- a/src/console_cmd.h +++ b/src/console_cmd.h @@ -21,6 +21,7 @@ #include "globals.h" #include "bflib_basics.h" +#include "thing_stats.h" #ifdef __cplusplus extern "C" { From c58b55dbb4fc246de548f2cc38925d385d7b102d Mon Sep 17 00:00:00 2001 From: Shinthoras0815 Date: Tue, 27 Jan 2026 18:56:40 +0100 Subject: [PATCH 08/11] Add missing includes --- src/console_cmd.c | 1 + src/console_cmd.h | 1 - src/lua_api.c | 1 + src/lua_api.h | 1 + src/thing_creature.c | 6 +++--- 5 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/console_cmd.c b/src/console_cmd.c index 27cdfa78c6..f8735c7bac 100644 --- a/src/console_cmd.c +++ b/src/console_cmd.c @@ -65,6 +65,7 @@ #include "thing_objects.h" #include "thing_navigate.h" #include "thing_physics.h" +#include "thing_creature.h" #include "version.h" #include "frontmenu_ingame_map.h" #include diff --git a/src/console_cmd.h b/src/console_cmd.h index 653502cbef..483454fb07 100644 --- a/src/console_cmd.h +++ b/src/console_cmd.h @@ -21,7 +21,6 @@ #include "globals.h" #include "bflib_basics.h" -#include "thing_stats.h" #ifdef __cplusplus extern "C" { diff --git a/src/lua_api.c b/src/lua_api.c index ea9a7d734b..62b8d8a608 100644 --- a/src/lua_api.c +++ b/src/lua_api.c @@ -25,6 +25,7 @@ #include "thing_effects.h" #include "magic_powers.h" +#include "lua_api.h" #include "lua_base.h" #include "lua_params.h" diff --git a/src/lua_api.h b/src/lua_api.h index d5a2cee23b..e353e3eec8 100644 --- a/src/lua_api.h +++ b/src/lua_api.h @@ -25,6 +25,7 @@ extern "C" { #endif void reg_host_functions(lua_State *L); +void DamageSourceKind_register(lua_State *L); #ifdef __cplusplus } diff --git a/src/thing_creature.c b/src/thing_creature.c index 74b6c022bb..93732f164a 100644 --- a/src/thing_creature.c +++ b/src/thing_creature.c @@ -869,7 +869,7 @@ TbBool fill_spell_slot(struct Thing *thing, SpellKind spell_idx, GameTurnDelta s if (thing_exists(castertng)) cspell->caster_thing_idx = castertng->index; else - cspell->caster_thing_idx = INVALID_THING; + cspell->caster_thing_idx = 0; return true; } @@ -885,7 +885,7 @@ TbBool free_spell_slot(struct Thing *thing, int slot_idx) cspell->duration = 0; cspell->caster_level = 0; cspell->caster_owner = 0; - cspell->caster_thing_idx = INVALID_THING; + cspell->caster_thing_idx = 0; return true; } @@ -1457,7 +1457,7 @@ void reapply_spell_effect_to_thing(struct Thing *thing, SpellKind spell_idx, Crt if (thing_exists(castertng)) cspell->caster_thing_idx = castertng->index; else - cspell->caster_thing_idx = INVALID_THING; + cspell->caster_thing_idx = 0; update_aura_effect_to_thing(thing, spell_idx); } return; From be49212de90199bb8be092d242ab6c5f222d005a Mon Sep 17 00:00:00 2001 From: Shinthoras0815 Date: Wed, 28 Jan 2026 01:36:24 +0100 Subject: [PATCH 09/11] fix lightning and gas damage source --- src/power_process.c | 2 +- src/thing_list.c | 2 +- src/thing_shots.c | 50 +++++++++++++++++++++++++----- src/thing_stats.c | 75 ++++++++++++++++++++++++++++++++------------- 4 files changed, 98 insertions(+), 31 deletions(-) diff --git a/src/power_process.c b/src/power_process.c index a707ec1d2b..c9715ddf36 100644 --- a/src/power_process.c +++ b/src/power_process.c @@ -303,7 +303,7 @@ void update_god_lightning_ball(struct Thing *thing) if (!thing_exists(target)) break; shotst = get_shot_model_stats(thing->model); - apply_damage_to_thing_and_display_health(target, shotst->damage, thing->owner, INVALID_THING, DSK_PowerLightning); + apply_damage_to_thing_and_display_health(target, shotst->damage, thing->owner, thing, DSK_PowerLightning); if (target->health < 0) { struct CreatureControl* cctrl = creature_control_get_from_thing(target); diff --git a/src/thing_list.c b/src/thing_list.c index 080c4ee40a..a3313ce7cb 100644 --- a/src/thing_list.c +++ b/src/thing_list.c @@ -2077,7 +2077,7 @@ TbBool electricity_affecting_thing(struct Thing *tngsrc, struct Thing *tngdst, c HitPoints damage = get_radially_decaying_value(max_damage, max_dist / 2, max_dist / 2, distance); if (damage != 0) { - apply_damage_to_thing_and_display_health(tngdst, damage, owner, tngsrc, DSK_NONE); + apply_damage_to_thing_and_display_health(tngdst, damage, owner, tngsrc, DSK_PowerLightning); affected = true; } } diff --git a/src/thing_shots.c b/src/thing_shots.c index 81a9252abf..e82631b069 100644 --- a/src/thing_shots.c +++ b/src/thing_shots.c @@ -56,6 +56,20 @@ extern "C" { #endif /******************************************************************************/ /******************************************************************************/ +static TbBool effect_model_is_gas(EffectOrEffElModel eff_kind) +{ + return (eff_kind == TngEff_Gas1) || (eff_kind == TngEff_Gas2) || (eff_kind == TngEff_Gas3); +} + +static ThingIndex get_shot_hit_effect_parent(const struct Thing *shotng, EffectOrEffElModel eff_kind) +{ + if (effect_model_is_gas(eff_kind) && (shotng->parent_idx > 0) && (shotng->parent_idx != shotng->index)) + { + return shotng->parent_idx; + } + return shotng->index; +} + TbBool thing_is_shot(const struct Thing *thing) { if (thing_is_invalid(thing)) @@ -627,8 +641,28 @@ TbBool shot_hit_wall_at(struct Thing *shotng, struct Coord3d *pos) } if (!thing_is_invalid(efftng)) { efftng->shot_effect.hit_type = shotst->area_hit_type; - efftng->shot_effect.parent_class_id = TCls_Shot; - efftng->shot_effect.parent_model = shotng->model; + if (effect_model_is_gas(efftng->model)) + { + ThingIndex parent_idx = get_shot_hit_effect_parent(shotng, efftng->model); + struct Thing* parent_tng = (parent_idx > 0) ? thing_get(parent_idx) : INVALID_THING; + if (thing_exists(parent_tng)) + { + efftng->shot_effect.parent_class_id = parent_tng->class_id; + efftng->shot_effect.parent_model = parent_tng->model; + efftng->parent_idx = parent_tng->index; + } + else + { + efftng->shot_effect.parent_class_id = TCls_Shot; + efftng->shot_effect.parent_model = shotng->model; + efftng->parent_idx = parent_idx; + } + } + else + { + efftng->shot_effect.parent_class_id = TCls_Shot; + efftng->shot_effect.parent_model = shotng->model; + } } if ( destroy_shot ) { @@ -674,7 +708,7 @@ long shot_hit_door_at(struct Thing *shotng, struct Coord3d *pos) // If the shot hit is supposed to create effect thing if (shotst->hit_door.effect_model != 0) { - efftng = create_used_effect_or_element(&shotng->mappos, shotst->hit_door.effect_model, shotng->owner, shotng->index); + efftng = create_used_effect_or_element(&shotng->mappos, shotst->hit_door.effect_model, shotng->owner, get_shot_hit_effect_parent(shotng, shotst->hit_door.effect_model)); } // If the shot hit is supposed to create sound int n = shotst->hit_door.sndsample_idx; @@ -863,7 +897,7 @@ static TbBool shot_hit_object_at(struct Thing *shotng, struct Thing *target, str { if (shotst->hit_heart.effect_model != 0) { - create_used_effect_or_element(&shotng->mappos, shotst->hit_heart.effect_model, shotng->owner, shotng->index); + create_used_effect_or_element(&shotng->mappos, shotst->hit_heart.effect_model, shotng->owner, get_shot_hit_effect_parent(shotng, shotst->hit_heart.effect_model)); } if (shotst->hit_heart.sndsample_idx > 0) { @@ -944,18 +978,18 @@ void create_relevant_effect_for_shot_hitting_thing(struct Thing *shotng, struct { thing_play_sample(target, shotst->hit_creature.sndsample_idx, NORMAL_PITCH, 0, 3, 0, 2, FULL_LOUDNESS); if (shotst->hit_creature.effect_model != 0) { - create_used_effect_or_element(&shotng->mappos, shotst->hit_creature.effect_model, shotng->owner, shotng->index); + create_used_effect_or_element(&shotng->mappos, shotst->hit_creature.effect_model, shotng->owner, get_shot_hit_effect_parent(shotng, shotst->hit_creature.effect_model)); } if (creature_under_spell_effect(target, CSAfF_Freeze)) { if (shotst->effect_frozen != 0) { - create_used_effect_or_element(&shotng->mappos, shotst->effect_frozen, shotng->owner, shotng->index); + create_used_effect_or_element(&shotng->mappos, shotst->effect_frozen, shotng->owner, get_shot_hit_effect_parent(shotng, shotst->effect_frozen)); } } else if (creature_model_bleeds(target->model)) { if (shotst->effect_bleeding != 0) { - create_used_effect_or_element(&shotng->mappos, shotst->effect_bleeding, shotng->owner, shotng->index); + create_used_effect_or_element(&shotng->mappos, shotst->effect_bleeding, shotng->owner, get_shot_hit_effect_parent(shotng, shotst->effect_bleeding)); } } } @@ -964,7 +998,7 @@ void create_relevant_effect_for_shot_hitting_thing(struct Thing *shotng, struct // TODO for a later PR: introduces trap/object hit, for now it uses the on hit creature sound and effect. thing_play_sample(target, shotst->hit_creature.sndsample_idx, NORMAL_PITCH, 0, 3, 0, 2, FULL_LOUDNESS); if (shotst->hit_creature.effect_model != 0) { - create_used_effect_or_element(&shotng->mappos, shotst->hit_creature.effect_model, shotng->owner, shotng->index); + create_used_effect_or_element(&shotng->mappos, shotst->hit_creature.effect_model, shotng->owner, get_shot_hit_effect_parent(shotng, shotst->hit_creature.effect_model)); } } } diff --git a/src/thing_stats.c b/src/thing_stats.c index 4a8ec7fbb4..6ed0a333f3 100644 --- a/src/thing_stats.c +++ b/src/thing_stats.c @@ -38,6 +38,7 @@ #include "player_utils.h" #include "thing_effects.h" #include "thing_list.h" +#include "thing_data.h" #include "thing_physics.h" #include "thing_stats.h" #include "vidfade.h" @@ -1067,30 +1068,51 @@ HitPoints calculate_shot_real_damage_to_door(const struct Thing *doortng, const return dmg; } -DamageSourceKind check_dmg_src_kind(struct Thing* scrtng, DamageSourceKind source_kind) +static struct Thing* resolve_damage_source_thing(struct Thing* scrtng) { - if ((source_kind == DSK_NONE) && (scrtng != NULL && !thing_is_invalid(scrtng))) + if ((scrtng == NULL) || thing_is_invalid(scrtng)) + return INVALID_THING; + + struct Thing* source_tng = scrtng; + switch (source_tng->class_id) { - switch(scrtng->class_id) + case TCls_Shot: + case TCls_Effect: + case TCls_EffectElem: { - case TCls_Creature: - source_kind = DSK_Creature; - break; - case TCls_Trap: - source_kind = DSK_Trap; - break; - case TCls_Object: - source_kind = DSK_Object; - break; - case TCls_Door: - source_kind = DSK_Door; - break; - default: - source_kind = DSK_NONE; - break; + struct Thing* parent_tng = get_parent_thing(source_tng); + if (thing_exists(parent_tng)) + source_tng = parent_tng; } + break; + default: + break; + } + return source_tng; +} + +DamageSourceKind check_dmg_src_kind(struct Thing* scrtng, DamageSourceKind source_kind) +{ + if (source_kind != DSK_NONE) + return source_kind; + + struct Thing* source_tng = resolve_damage_source_thing(scrtng); + if (!thing_exists(source_tng)) + return DSK_NONE; + + switch (source_tng->class_id) + { + case TCls_Creature: + return DSK_Creature; + case TCls_Trap: + return DSK_Trap; + case TCls_Object: + return DSK_Object; + case TCls_Door: + return DSK_Door; + default: + return DSK_NONE; } - return source_kind; } const char *damage_source_kind_name(DamageSourceKind kind) @@ -1127,13 +1149,24 @@ HitPoints apply_damage_to_thing(struct Thing *thing, HitPoints dmg, PlayerNumber { // We're here to damage, not to heal. SYNCDBG(19, "Dealing %d damage to %s by player %d", (int)dmg, thing_model_name(thing), (int)dealing_plyr_idx); + if ((scrtng != NULL) && !thing_is_invalid(scrtng)) { + SYNCDBG(8, "ApplyDamage: incoming kind=%d src=%s", (int)source_kind, thing_model_name(scrtng)); + } else { + SYNCDBG(8, "ApplyDamage: incoming kind=%d src=", (int)source_kind); + } if (dmg <= 0) return 0; // If it's already dead, then don't interfere. if (thing->health < 0) return 0; - DamageSourceKind damagesource = check_dmg_src_kind(scrtng, source_kind); - lua_on_apply_damage_to_thing(thing, dmg, dealing_plyr_idx, scrtng, damagesource); + struct Thing* src_tng = resolve_damage_source_thing(scrtng); + DamageSourceKind damagesource = check_dmg_src_kind(src_tng, source_kind); + if (thing_exists(src_tng)) { + SYNCDBG(8, "ApplyDamage: resolved kind=%d src=%s", (int)damagesource, thing_model_name(src_tng)); + } else { + SYNCDBG(8, "ApplyDamage: resolved kind=%d src=", (int)damagesource); + } + lua_on_apply_damage_to_thing(thing, dmg, dealing_plyr_idx, src_tng, damagesource); HitPoints cdamage; switch (thing->class_id) From 8ff1b5cd9e4a781f10466e2cd03a8e7d858e63ee Mon Sep 17 00:00:00 2001 From: Shinthoras0815 Date: Sun, 1 Mar 2026 23:55:43 +0100 Subject: [PATCH 10/11] Refactor DamageSourceKind to use strings and unify power types also unify power types extend RegisterThingDamageEvent --- config/fxdata/lua/aliases.lua | 22 +---------- config/fxdata/lua/triggers/Builtins.lua | 2 +- config/fxdata/lua/triggers/Events.lua | 14 +++++-- src/console_cmd.c | 4 +- src/lua_api.c | 1 - src/lua_api.h | 1 - src/lua_api_things.c | 52 ------------------------- src/lua_triggers.c | 2 +- src/main.cpp | 4 +- src/power_process.c | 6 +-- src/thing_creature.c | 2 +- src/thing_list.c | 2 +- src/thing_stats.c | 13 ++----- src/thing_stats.h | 7 +--- 14 files changed, 28 insertions(+), 104 deletions(-) diff --git a/config/fxdata/lua/aliases.lua b/config/fxdata/lua/aliases.lua index 875805aecb..5c7dae36b8 100644 --- a/config/fxdata/lua/aliases.lua +++ b/config/fxdata/lua/aliases.lua @@ -27,25 +27,5 @@ ---@alias location playersingle|actionpoint|"LAST_EVENT"|"COMBAT"|Pos3d ---@alias thing_class "Object"|"Shot"|"EffectElem"|"DeadCreature"|"Creature"|"Effect"|"EffectGen"|"Trap"|"Door"|"AmbientSnd"|"CaveIn" ---@alias effect_or_effelem_type integer|string|effect_type|effect_element_type -- I allow string here because there's to many entries for, the language server to handle ----@alias damage_source_kind integer - ----@class DamageSourceKindTable ----@field NONE integer Unspecified damage source (0) ----@field LAVA integer Damage from lava terrain (1) ----@field POWER_SLAP integer Damage from player slap power (2) ----@field POWER_DISEASE integer Damage from disease spell (3) ----@field POWER_LIGHTNING integer Damage from lightning spell (4) ----@field PHYSICAL_FORCE integer Physical damage (5) ----@field COMMAND_FREEZE integer Damage from freeze command/spell (6) ----@field COMMAND_SLOW integer Damage from slow command/spell (7) ----@field SCRIPT_SPELL integer Damage from script-triggered spell (8) ----@field DOT_SPELL integer Damage from damage-over-time spell effects (9) ----@field CREATURE integer Damage from creature attack (10) ----@field TRAP integer Damage from trap activation (11) ----@field OBJECT integer Damage from object interaction (12) ----@field DOOR integer Damage from door (13) - ---- Global table containing damage source kind constants ----@type DamageSourceKindTable -DamageSourceKind = {} +---@alias damage_source_kind "NONE"|"UNKNOWN"|"LAVA"|"POWER_SLAP"|"POWER"|"DOT_SPELL"|"CREATURE"|"TRAP"|"OBJECT"|"DOOR" diff --git a/config/fxdata/lua/triggers/Builtins.lua b/config/fxdata/lua/triggers/Builtins.lua index 7367154033..231d60e72f 100644 --- a/config/fxdata/lua/triggers/Builtins.lua +++ b/config/fxdata/lua/triggers/Builtins.lua @@ -75,7 +75,7 @@ end ---@param damage integer Amount of damage dealt ---@param dealing_player Player Player responsible for the damage ---@param source_thing Thing|nil The thing that caused the damage (e.g., attacking creature, trap) ----@param source_kind damage_source_kind Integer enum value from DamageSourceKind (e.g., DamageSourceKind.LAVA) +---@param source_kind damage_source_kind String identifying the damage source (e.g., "LAVA", "CREATURE", "TRAP") function OnApplyDamage(thing, damage, dealing_player, source_thing, source_kind) local eventData = {} eventData.thing = thing diff --git a/config/fxdata/lua/triggers/Events.lua b/config/fxdata/lua/triggers/Events.lua index 9f15db6a4f..fcc253589c 100644 --- a/config/fxdata/lua/triggers/Events.lua +++ b/config/fxdata/lua/triggers/Events.lua @@ -117,14 +117,22 @@ end ---Triggers when a thing takes damage ---@param action function|string the function to call when the event happens ---@param thing? Thing the unit that triggers the event +---@param source_thing? Thing the thing that cause the trigger +---@param source_kind? damage_source_kind kind of damage ---@return table -function RegisterThingDamageEvent(action, thing) - local trigData = {thing = thing} +function RegisterThingDamageEvent(action, thing, source_thing, source_kind) + local trigData = {thing = thing,source_thing = source_thing, source_kind = source_kind} local trigger = CreateTrigger("ApplyDamage",action,trigData) if thing then TriggerAddCondition(trigger, function(eventData,triggerData) return eventData.thing == triggerData.thing end) end + if source_thing then + TriggerAddCondition(trigger, function(eventData,triggerData) return eventData.source_thing == triggerData.source_thing end) + end + if source_kind then + TriggerAddCondition(trigger, function(eventData,triggerData) return eventData.source_kind == triggerData.source_kind end) + end return trigger end @@ -139,7 +147,7 @@ function RegisterOnActionPointEvent(action, actionPoint, player) local trigData = {Player = player,actionPoint = actionPoint, triggered = false} local trigger = CreateTrigger("GameTick",action,trigData) - TriggerAddCondition(trigger, function(eventData,triggerData) + TriggerAddCondition(trigger, function(eventData,triggerData) if triggerData.triggered == false then triggerData.triggered = IsActionpointActivatedByPlayer(triggerData.Player,triggerData.actionPoint) return triggerData.triggered diff --git a/src/console_cmd.c b/src/console_cmd.c index f8735c7bac..d4ad74cbef 100644 --- a/src/console_cmd.c +++ b/src/console_cmd.c @@ -1840,7 +1840,7 @@ TbBool cmd_freeze_creature(PlayerNumber plyr_idx, char * args) } thing_play_sample(thing, 50, NORMAL_PITCH, 0, 3, 0, 4, FULL_LOUDNESS); // Not sure how to handle this yet, for now simply hardcode the intended spell kind with a number. - apply_spell_effect_to_thing(thing, 3, 8, plyr_idx, INVALID_THING, DSK_CommandFreeze); // 3 was 'SplK_Freeze' in the enum. + apply_spell_effect_to_thing(thing, 3, 8, plyr_idx, INVALID_THING, DSK_Power); // 3 was 'SplK_Freeze' in the enum. return true; } @@ -1858,7 +1858,7 @@ TbBool cmd_slow_creature(PlayerNumber plyr_idx, char * args) } thing_play_sample(thing, 50, NORMAL_PITCH, 0, 3, 0, 4, FULL_LOUDNESS); // Not sure how to handle this yet, for now simply hardcode the intended spell kind with a number. - apply_spell_effect_to_thing(thing, 12, 8, plyr_idx, INVALID_THING, DSK_CommandSlow); // 12 was 'SplK_Slow' in the enum. + apply_spell_effect_to_thing(thing, 12, 8, plyr_idx, INVALID_THING, DSK_Power); // 12 was 'SplK_Slow' in the enum. return true; } diff --git a/src/lua_api.c b/src/lua_api.c index 8bbdce8816..1b2d4f5478 100644 --- a/src/lua_api.c +++ b/src/lua_api.c @@ -2259,6 +2259,5 @@ void reg_host_functions(lua_State *L) Thing_register(L); Slab_register(L); room_register(L); - DamageSourceKind_register(L); Lens_register(L); } diff --git a/src/lua_api.h b/src/lua_api.h index e353e3eec8..d5a2cee23b 100644 --- a/src/lua_api.h +++ b/src/lua_api.h @@ -25,7 +25,6 @@ extern "C" { #endif void reg_host_functions(lua_State *L); -void DamageSourceKind_register(lua_State *L); #ifdef __cplusplus } diff --git a/src/lua_api_things.c b/src/lua_api_things.c index 9014ececec..aef6fbdfd3 100644 --- a/src/lua_api_things.c +++ b/src/lua_api_things.c @@ -616,55 +616,3 @@ void Thing_register(lua_State *L) { lua_pop(L, 1); } -// In lua_api.c oder lua_api_things.c - -void DamageSourceKind_register(lua_State *L) { - // Create global table "DamageSourceKind" - lua_newtable(L); - - // Add enum values as fields - lua_pushinteger(L, DSK_NONE); - lua_setfield(L, -2, "NONE"); - - lua_pushinteger(L, DSK_Lava); - lua_setfield(L, -2, "LAVA"); - - lua_pushinteger(L, DSK_PowerSlap); - lua_setfield(L, -2, "POWER_SLAP"); - - lua_pushinteger(L, DSK_PowerDisease); - lua_setfield(L, -2, "POWER_DISEASE"); - - lua_pushinteger(L, DSK_PowerLightning); - lua_setfield(L, -2, "POWER_LIGHTNING"); - - lua_pushinteger(L, DSK_PhysicalForce); - lua_setfield(L, -2, "PHYSICAL_FORCE"); - - lua_pushinteger(L, DSK_CommandFreeze); - lua_setfield(L, -2, "COMMAND_FREEZE"); - - lua_pushinteger(L, DSK_CommandSlow); - lua_setfield(L, -2, "COMMAND_SLOW"); - - lua_pushinteger(L, DSK_ScriptSpell); - lua_setfield(L, -2, "SCRIPT_SPELL"); - - lua_pushinteger(L, DSK_DOTSpell); - lua_setfield(L, -2, "DOT_SPELL"); - - lua_pushinteger(L, DSK_Creature); - lua_setfield(L, -2, "CREATURE"); - - lua_pushinteger(L, DSK_Trap); - lua_setfield(L, -2, "TRAP"); - - lua_pushinteger(L, DSK_Object); - lua_setfield(L, -2, "OBJECT"); - - lua_pushinteger(L, DSK_Door); - lua_setfield(L, -2, "DOOR"); - - // Set as global "DamageSourceKind" - lua_setglobal(L, "DamageSourceKind"); -} diff --git a/src/lua_triggers.c b/src/lua_triggers.c index 59ad6277d4..cdb18ef2b8 100644 --- a/src/lua_triggers.c +++ b/src/lua_triggers.c @@ -192,7 +192,7 @@ void lua_on_apply_damage_to_thing(struct Thing *thing, HitPoints dmg, PlayerNumb lua_pushinteger(Lvl_script, dmg); lua_pushPlayer(Lvl_script, dealing_plyr_idx); lua_pushThing(Lvl_script, tngsrc); - lua_pushinteger(Lvl_script, source_kind); + lua_pushstring(Lvl_script, damage_source_kind_name(source_kind)); CheckLua(Lvl_script, lua_pcall(Lvl_script, 5, 0, 0),"OnApplyDamage"); } diff --git a/src/main.cpp b/src/main.cpp index 909abd6de6..5b37e46045 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2511,7 +2511,7 @@ TngUpdateRet damage_creatures_with_physical_force(struct Thing *thing, ModTngFil } if (thing_is_creature(thing)) { - apply_damage_to_thing_and_display_health(thing, param->secondary_number, param->primary_number, INVALID_THING, DSK_PhysicalForce); + apply_damage_to_thing_and_display_health(thing, param->secondary_number, param->primary_number, INVALID_THING, DSK_Power); if ((thing->health >= 0) && !creature_is_leaving_and_cannot_be_stopped(thing)) { if (((thing->alloc_flags & TAlF_IsControlled) == 0) && !creature_is_kept_in_custody(thing)) @@ -2531,7 +2531,7 @@ TngUpdateRet damage_creatures_with_physical_force(struct Thing *thing, ModTngFil } else if (thing_is_destructible_trap(thing) > 0) { - apply_damage_to_thing(thing, param->secondary_number, param->primary_number, INVALID_THING, DSK_PhysicalForce); + apply_damage_to_thing(thing, param->secondary_number, param->primary_number, INVALID_THING, DSK_Power); return TUFRet_Modified; } return TUFRet_Unchanged; diff --git a/src/power_process.c b/src/power_process.c index c9715ddf36..33f727f391 100644 --- a/src/power_process.c +++ b/src/power_process.c @@ -215,7 +215,7 @@ void process_disease(struct Thing *creatng) && !creature_is_immune_to_spell_effect(thing, CSAfF_Disease) && (cctrl->disease_caster_plyridx != game.neutral_player_num)) { // Apply the spell kind stored in 'active_disease_spell'. - apply_spell_effect_to_thing(thing, cctrl->active_disease_spell, cctrl->exp_level, creatng->owner, creatng, DSK_PowerDisease); + apply_spell_effect_to_thing(thing, cctrl->active_disease_spell, cctrl->exp_level, creatng->owner, creatng, DSK_Power); tngcctrl->disease_caster_plyridx = cctrl->disease_caster_plyridx; } // Per thing code ends. @@ -231,7 +231,7 @@ void process_disease(struct Thing *creatng) } if (((game.play_gameturn - cctrl->disease_start_turn) % game.conf.rules[creatng->owner].magic.disease_lose_health_time) == 0) { - apply_damage_to_thing_and_display_health(creatng, game.conf.rules[creatng->owner].magic.disease_lose_percentage_health * cctrl->max_health / 100, cctrl->disease_caster_plyridx, INVALID_THING, DSK_PowerDisease); + apply_damage_to_thing_and_display_health(creatng, game.conf.rules[creatng->owner].magic.disease_lose_percentage_health * cctrl->max_health / 100, cctrl->disease_caster_plyridx, INVALID_THING, DSK_Power); } } @@ -303,7 +303,7 @@ void update_god_lightning_ball(struct Thing *thing) if (!thing_exists(target)) break; shotst = get_shot_model_stats(thing->model); - apply_damage_to_thing_and_display_health(target, shotst->damage, thing->owner, thing, DSK_PowerLightning); + apply_damage_to_thing_and_display_health(target, shotst->damage, thing->owner, thing, DSK_Power); if (target->health < 0) { struct CreatureControl* cctrl = creature_control_get_from_thing(target); diff --git a/src/thing_creature.c b/src/thing_creature.c index 47a75e7089..9844f70c0e 100644 --- a/src/thing_creature.c +++ b/src/thing_creature.c @@ -7721,7 +7721,7 @@ TbResult script_use_spell_on_creature(PlayerNumber plyr_idx, struct Thing *thing { thing_play_sample(thing, spconf->caster_affect_sound + SOUND_RANDOM(spconf->caster_sounds_count), NORMAL_PITCH, 0, 3, 0, 4, FULL_LOUDNESS); } - apply_spell_effect_to_thing(thing, spkind, spell_level, plyr_idx, INVALID_THING, DSK_ScriptSpell); + apply_spell_effect_to_thing(thing, spkind, spell_level, plyr_idx, INVALID_THING, DSK_Power); if (flag_is_set(spconf->spell_flags, CSAfF_Disease)) { struct CreatureControl *cctrl; diff --git a/src/thing_list.c b/src/thing_list.c index a3313ce7cb..861d99cd79 100644 --- a/src/thing_list.c +++ b/src/thing_list.c @@ -2077,7 +2077,7 @@ TbBool electricity_affecting_thing(struct Thing *tngsrc, struct Thing *tngdst, c HitPoints damage = get_radially_decaying_value(max_damage, max_dist / 2, max_dist / 2, distance); if (damage != 0) { - apply_damage_to_thing_and_display_health(tngdst, damage, owner, tngsrc, DSK_PowerLightning); + apply_damage_to_thing_and_display_health(tngdst, damage, owner, tngsrc, DSK_Power); affected = true; } } diff --git a/src/thing_stats.c b/src/thing_stats.c index 6ed0a333f3..49fc9d3b44 100644 --- a/src/thing_stats.c +++ b/src/thing_stats.c @@ -1091,7 +1091,7 @@ static struct Thing* resolve_damage_source_thing(struct Thing* scrtng) return source_tng; } -DamageSourceKind check_dmg_src_kind(struct Thing* scrtng, DamageSourceKind source_kind) +static DamageSourceKind check_dmg_src_kind(struct Thing* scrtng, DamageSourceKind source_kind) { if (source_kind != DSK_NONE) return source_kind; @@ -1121,18 +1121,13 @@ const char *damage_source_kind_name(DamageSourceKind kind) { case DSK_Lava: return "LAVA"; case DSK_PowerSlap: return "POWER_SLAP"; - case DSK_PowerDisease: return "POWER_DISEASE"; - case DSK_PowerLightning: return "POWER_LIGHTNING"; - case DSK_PhysicalForce: return "PHYSICAL_FORCE"; - case DSK_CommandFreeze: return "COMMAND_FREEZE"; - case DSK_CommandSlow: return "COMMAND_SLOW"; - case DSK_ScriptSpell: return "SCRIPT_SPELL"; - case DSK_DOTSpell: return "UNKNOWN_DOT"; + case DSK_Power: return "POWER"; + case DSK_DOTSpell: return "DOT_SPELL"; case DSK_Creature: return "CREATURE"; case DSK_Trap: return "TRAP"; case DSK_Object: return "OBJECT"; case DSK_Door: return "DOOR"; - default: return NULL; + default: return "UNKNOWN"; } } diff --git a/src/thing_stats.h b/src/thing_stats.h index 8628a08924..c365e9eb2d 100644 --- a/src/thing_stats.h +++ b/src/thing_stats.h @@ -61,12 +61,7 @@ typedef enum DamageSourceKind { DSK_NONE = 0, DSK_Lava, DSK_PowerSlap, - DSK_PowerDisease, - DSK_PowerLightning, - DSK_PhysicalForce, - DSK_CommandFreeze, - DSK_CommandSlow, - DSK_ScriptSpell, + DSK_Power, DSK_DOTSpell, DSK_Creature, DSK_Trap, From 17f2689eee9d74ddc3198694c90c6266bafe3768 Mon Sep 17 00:00:00 2001 From: Shinthoras0815 Date: Tue, 10 Mar 2026 19:44:01 +0100 Subject: [PATCH 11/11] clean up --- config/fxdata/lua/aliases.lua | 2 +- src/creature_states_pray.c | 2 +- src/magic_powers.c | 2 +- src/thing_creature.c | 6 +++--- src/thing_effects.c | 16 ++++++++-------- src/thing_shots.c | 36 +++++++++++++++++++++++------------ src/thing_stats.c | 23 ++++++---------------- src/thing_stats.h | 2 +- 8 files changed, 45 insertions(+), 44 deletions(-) diff --git a/config/fxdata/lua/aliases.lua b/config/fxdata/lua/aliases.lua index 5c7dae36b8..2fe946b77a 100644 --- a/config/fxdata/lua/aliases.lua +++ b/config/fxdata/lua/aliases.lua @@ -27,5 +27,5 @@ ---@alias location playersingle|actionpoint|"LAST_EVENT"|"COMBAT"|Pos3d ---@alias thing_class "Object"|"Shot"|"EffectElem"|"DeadCreature"|"Creature"|"Effect"|"EffectGen"|"Trap"|"Door"|"AmbientSnd"|"CaveIn" ---@alias effect_or_effelem_type integer|string|effect_type|effect_element_type -- I allow string here because there's to many entries for, the language server to handle ----@alias damage_source_kind "NONE"|"UNKNOWN"|"LAVA"|"POWER_SLAP"|"POWER"|"DOT_SPELL"|"CREATURE"|"TRAP"|"OBJECT"|"DOOR" +---@alias damage_source_kind "UNKNOWN"|"LAVA"|"POWER_SLAP"|"POWER"|"DOT_SPELL"|"CREATURE"|"TRAP"|"OBJECT"|"DOOR" diff --git a/src/creature_states_pray.c b/src/creature_states_pray.c index 9464964652..5951628669 100644 --- a/src/creature_states_pray.c +++ b/src/creature_states_pray.c @@ -377,7 +377,7 @@ void apply_spell_effect_to_players_creatures(PlayerNumber plyr_idx, ThingModel c // Thing list loop body if (creature_matches_model(thing,crmodel)) { - apply_spell_effect_to_thing(thing, spl_idx, overchrg, plyr_idx, INVALID_THING, DSK_NONE); + apply_spell_effect_to_thing(thing, spl_idx, overchrg, plyr_idx, INVALID_THING, DSK_None); } // Thing list loop body ends k++; diff --git a/src/magic_powers.c b/src/magic_powers.c index 96d91d6123..fb1c9ee0cc 100644 --- a/src/magic_powers.c +++ b/src/magic_powers.c @@ -1386,7 +1386,7 @@ static TbResult magic_use_power_apply_spell(PowerKind power_kind, PlayerNumber p create_used_effect_or_element(&effpos, powerst->effect_id, thing->owner, 0); } thing_play_sample(thing, powerst->select_sound_idx, NORMAL_PITCH, 0, 3, 0, 2, FULL_LOUDNESS); - apply_spell_effect_to_thing(thing, powerst->spell_idx, power_level, plyr_idx, INVALID_THING, DSK_NONE); + apply_spell_effect_to_thing(thing, powerst->spell_idx, power_level, plyr_idx, INVALID_THING, DSK_None); // Special cases. if (flag_is_set(spconf->spell_flags, CSAfF_Disease)) { // Set disease_caster_plyridx if spell_idx has 'CSAfF_Disease'. diff --git a/src/thing_creature.c b/src/thing_creature.c index 9844f70c0e..0eba37a220 100644 --- a/src/thing_creature.c +++ b/src/thing_creature.c @@ -2238,7 +2238,7 @@ void creature_cast_spell(struct Thing *castng, SpellKind spl_idx, CrtrExpLevel s { thing_play_sample(castng, spconf->caster_affect_sound + SOUND_RANDOM(spconf->caster_sounds_count), NORMAL_PITCH, 0, 3, 0, 4, FULL_LOUDNESS); } - apply_spell_effect_to_thing(castng, spl_idx, cctrl->exp_level, castng->owner, castng, DSK_NONE); + apply_spell_effect_to_thing(castng, spl_idx, cctrl->exp_level, castng->owner, castng, DSK_None); } else if (spconf->shot_model > 0) { @@ -4275,7 +4275,7 @@ void draw_creature_view(struct Thing *thing) unsigned char* scrmem = lens_get_render_target(); unsigned int render_width = lens_get_render_target_width(); unsigned int render_height = lens_get_render_target_height(); - + // Store previous graphics settings unsigned char* wscr_cp = lbDisplay.WScreen; TbGraphicsWindow grwnd; @@ -4305,7 +4305,7 @@ void draw_creature_view(struct Thing *thing) // Pass full srcbuf so displacement map lookups work correctly // Calculate 2D viewport offset for destination buffer long dst_offset = view_y * lbDisplay.GraphicsScreenWidth + view_x; - draw_lens_effect(lbDisplay.WScreen + dst_offset, lbDisplay.GraphicsScreenWidth, + draw_lens_effect(lbDisplay.WScreen + dst_offset, lbDisplay.GraphicsScreenWidth, scrmem, render_width, view_width, view_height, view_x, game.applied_lens_type); } diff --git a/src/thing_effects.c b/src/thing_effects.c index 54581cbb8e..cedc59ce92 100644 --- a/src/thing_effects.c +++ b/src/thing_effects.c @@ -1012,7 +1012,7 @@ TbBool explosion_affecting_thing(struct Thing *tngsrc, struct Thing *tngdst, con { HitPoints damage = get_radially_decaying_value(max_damage, max_dist / 4, 3 * max_dist / 4, distance) + 1; SYNCDBG(7,"Causing %d damage to %s at distance %d",(int)damage,thing_model_name(tngdst),(int)distance); - apply_damage_to_thing_and_display_health(tngdst, damage, owner, tngsrc, DSK_NONE); + apply_damage_to_thing_and_display_health(tngdst, damage, owner, tngsrc, DSK_None); if (flag_is_set(shotst->model_flags,ShMF_LifeDrain)) { give_shooter_drained_health(origtng, damage / 2); @@ -1038,7 +1038,7 @@ TbBool explosion_affecting_thing(struct Thing *tngsrc, struct Thing *tngdst, con { spell_level = scctrl->exp_level; } - apply_spell_effect_to_thing(tngdst, shotst->cast_spell_kind, spell_level, owner, origtng, DSK_NONE); + apply_spell_effect_to_thing(tngdst, shotst->cast_spell_kind, spell_level, owner, origtng, DSK_None); struct SpellConfig *spconf = get_spell_config(shotst->cast_spell_kind); if (flag_is_set(spconf->spell_flags, CSAfF_Disease)) { @@ -1066,7 +1066,7 @@ TbBool explosion_affecting_thing(struct Thing *tngsrc, struct Thing *tngdst, con { HitPoints damage = get_radially_decaying_value(max_damage, max_dist / 4, 3 * max_dist / 4, distance) + 1; SYNCDBG(7,"Causing %d damage to %s at distance %d",(int)damage,thing_model_name(tngdst),(int)distance); - apply_damage_to_thing(tngdst, damage, -1, tngsrc, DSK_NONE); + apply_damage_to_thing(tngdst, damage, -1, tngsrc, DSK_None); affected = true; event_create_event_or_update_nearby_existing_event(tngdst->mappos.x.val, tngdst->mappos.y.val,EvKind_HeartAttacked, tngdst->owner, 0); if (is_my_player_number(tngdst->owner)) @@ -1136,7 +1136,7 @@ TbBool explosion_affecting_door(struct Thing *tngsrc, struct Thing *tngdst, cons } } SYNCDBG(7,"Causing %d damage to %s at distance %d",(int)damage,thing_model_name(tngdst),(int)distance); - apply_damage_to_thing(tngdst, damage, -1, tngsrc, DSK_NONE); + apply_damage_to_thing(tngdst, damage, -1, tngsrc, DSK_None); affected = true; } } @@ -1446,7 +1446,7 @@ TbBool poison_cloud_affecting_thing(struct Thing *tngsrc, struct Thing *tngdst, HitPoints damage; damage = get_radially_decaying_value(max_damage, max_dist / 4, 3 * max_dist / 4, distance) + 1; SYNCDBG(7, "Causing %d damage to %s at distance %d", (int)damage, thing_model_name(tngdst), (int)distance); - apply_damage_to_thing_and_display_health(tngdst, damage, tngsrc->owner, tngsrc, DSK_NONE); + apply_damage_to_thing_and_display_health(tngdst, damage, tngsrc->owner, tngsrc, DSK_None); } break; case AAffT_GasDamageEffect: @@ -1455,14 +1455,14 @@ TbBool poison_cloud_affecting_thing(struct Thing *tngsrc, struct Thing *tngdst, HitPoints damage; damage = get_radially_decaying_value(max_damage, 3 * max_dist / 4, max_dist / 4, distance) + 1; SYNCDBG(7, "Causing %d damage to %s at distance %d", (int)damage, thing_model_name(tngdst), (int)distance); - apply_damage_to_thing_and_display_health(tngdst, damage, tngsrc->owner, tngsrc, DSK_NONE); + apply_damage_to_thing_and_display_health(tngdst, damage, tngsrc->owner, tngsrc, DSK_None); } spconf = get_spell_config(spell_idx); if ((!creature_under_spell_effect(tngdst, spconf->spell_flags)) && (!creature_is_immune_to_spell_effect(tngdst, spconf->spell_flags))) { struct CreatureControl *srcctrl; srcctrl = creature_control_get_from_thing(tngsrc); - apply_spell_effect_to_thing(tngdst, spell_idx, srcctrl->exp_level, tngsrc->owner, tngsrc, DSK_NONE); + apply_spell_effect_to_thing(tngdst, spell_idx, srcctrl->exp_level, tngsrc->owner, tngsrc, DSK_None); } break; case AAffT_GasEffect: @@ -1471,7 +1471,7 @@ TbBool poison_cloud_affecting_thing(struct Thing *tngsrc, struct Thing *tngdst, { struct CreatureControl *srcctrl; srcctrl = creature_control_get_from_thing(tngsrc); - apply_spell_effect_to_thing(tngdst, spell_idx, srcctrl->exp_level, tngsrc->owner, tngsrc, DSK_NONE); + apply_spell_effect_to_thing(tngdst, spell_idx, srcctrl->exp_level, tngsrc->owner, tngsrc, DSK_None); } break; default: diff --git a/src/thing_shots.c b/src/thing_shots.c index e82631b069..375fcab4e6 100644 --- a/src/thing_shots.c +++ b/src/thing_shots.c @@ -56,11 +56,18 @@ extern "C" { #endif /******************************************************************************/ /******************************************************************************/ +/** Check if an effect model is a gas cloud (Gas1/Gas2/Gas3). */ static TbBool effect_model_is_gas(EffectOrEffElModel eff_kind) { return (eff_kind == TngEff_Gas1) || (eff_kind == TngEff_Gas2) || (eff_kind == TngEff_Gas3); } +/** + * Returns the parent index to assign to an effect spawned by a shot hit. + * Gas effects need to trace back to the original shooter (creature/trap) + * so that damage from lingering gas clouds is attributed to the correct source. + * Non-gas effects keep the shot itself as parent. + */ static ThingIndex get_shot_hit_effect_parent(const struct Thing *shotng, EffectOrEffElModel eff_kind) { if (effect_model_is_gas(eff_kind) && (shotng->parent_idx > 0) && (shotng->parent_idx != shotng->index)) @@ -553,7 +560,7 @@ TbBool shot_hit_wall_at(struct Thing *shotng, struct Coord3d *pos) if (!shotst->hit_door.withstand) destroy_shot = 1; i = calculate_shot_real_damage_to_door(doortng, shotng); - apply_damage_to_thing(doortng, i, -1, damage_source, DSK_NONE); + apply_damage_to_thing(doortng, i, -1, damage_source, DSK_None); reveal_secret_door_to_player(doortng,shotng->owner); } else if (cube_is_water(cube_id)) @@ -614,7 +621,7 @@ TbBool shot_hit_wall_at(struct Thing *shotng, struct Coord3d *pos) if (!shotst->hit_door.withstand) destroy_shot = 1; i = calculate_shot_real_damage_to_door(doortng, shotng); - apply_damage_to_thing(doortng, i, -1, damage_source, DSK_NONE); + apply_damage_to_thing(doortng, i, -1, damage_source, DSK_None); reveal_secret_door_to_player(doortng,shotng->owner); } else { @@ -641,6 +648,9 @@ TbBool shot_hit_wall_at(struct Thing *shotng, struct Coord3d *pos) } if (!thing_is_invalid(efftng)) { efftng->shot_effect.hit_type = shotst->area_hit_type; + // Gas effects persist after the shot is gone and deal damage over time. + // Set their parent to the original shooter (creature/trap) so that + // damage from the gas cloud can be traced back to the correct source. if (effect_model_is_gas(efftng->model)) { ThingIndex parent_idx = get_shot_hit_effect_parent(shotng, efftng->model); @@ -653,6 +663,7 @@ TbBool shot_hit_wall_at(struct Thing *shotng, struct Coord3d *pos) } else { + // Shooter no longer exists — fall back to shot as parent. efftng->shot_effect.parent_class_id = TCls_Shot; efftng->shot_effect.parent_model = shotng->model; efftng->parent_idx = parent_idx; @@ -660,6 +671,7 @@ TbBool shot_hit_wall_at(struct Thing *shotng, struct Coord3d *pos) } else { + // Non-gas effects are short-lived; the shot itself is sufficient as parent. efftng->shot_effect.parent_class_id = TCls_Shot; efftng->shot_effect.parent_model = shotng->model; } @@ -728,7 +740,7 @@ long shot_hit_door_at(struct Thing *shotng, struct Coord3d *pos) } // Apply damage to the door i = calculate_shot_real_damage_to_door(doortng, shotng); - apply_damage_to_thing(doortng, i, -1, damage_source, DSK_NONE); + apply_damage_to_thing(doortng, i, -1, damage_source, DSK_None); reveal_secret_door_to_player(doortng,shotng->owner); } } @@ -839,7 +851,7 @@ static TbBool shot_hit_trap_at(struct Thing* shotng, struct Thing* target, struc if ((thing_is_destructible_trap(target) > 0) || ((thing_is_destructible_trap(target) > -1) && (shotst->model_flags & ShMF_Disarming))) { - damage_done = apply_damage_to_thing(target, shotng->shot.damage, -1, damage_source, DSK_NONE); + damage_done = apply_damage_to_thing(target, shotng->shot.damage, -1, damage_source, DSK_None); // Drain allows caster to regain half of damage if ((shotst->model_flags & ShMF_LifeDrain) && thing_is_creature(shootertng)) @@ -924,7 +936,7 @@ static TbBool shot_hit_object_at(struct Thing *shotng, struct Thing *target, str { if (object_can_be_damaged(target)) // do not damage objects that cannot be destroyed { - damage_done = apply_damage_to_thing(target, shotng->shot.damage, -1, shootertng, DSK_NONE); + damage_done = apply_damage_to_thing(target, shotng->shot.damage, -1, shootertng, DSK_None); // Drain allows caster to regain half of damage if ((shotst->model_flags & ShMF_LifeDrain) && thing_is_creature(shootertng)) @@ -1105,9 +1117,9 @@ long melee_shot_hit_creature_at(struct Thing *shotng, struct Thing *trgtng, stru } create_relevant_effect_for_shot_hitting_thing(shotng, trgtng); if (!thing_is_invalid(shooter)) { - damage = apply_damage_to_thing_and_display_health(trgtng, damage, shooter->owner, shooter, DSK_NONE); + damage = apply_damage_to_thing_and_display_health(trgtng, damage, shooter->owner, shooter, DSK_None); } else { - damage = apply_damage_to_thing_and_display_health(trgtng, damage, -1, shooter, DSK_NONE); + damage = apply_damage_to_thing_and_display_health(trgtng, damage, -1, shooter, DSK_None); } if (shotst->model_flags & ShMF_LifeDrain) { @@ -1121,7 +1133,7 @@ long melee_shot_hit_creature_at(struct Thing *shotng, struct Thing *trgtng, stru { spell_level = scctrl->exp_level; } - apply_spell_effect_to_thing(trgtng, shotst->cast_spell_kind, spell_level, shotng->owner, shooter, DSK_NONE); + apply_spell_effect_to_thing(trgtng, shotst->cast_spell_kind, spell_level, shotng->owner, shooter, DSK_None); struct SpellConfig *spconf = get_spell_config(shotst->cast_spell_kind); if (flag_is_set(spconf->spell_flags, CSAfF_Disease)) { @@ -1289,9 +1301,9 @@ long shot_hit_creature_at(struct Thing *shotng, struct Thing *trgtng, struct Coo { HitPoints damage_done; if (thing_exists(shooter)) { - damage_done = apply_damage_to_thing_and_display_health(trgtng, shotng->shot.damage, shooter->owner, shooter, DSK_NONE); + damage_done = apply_damage_to_thing_and_display_health(trgtng, shotng->shot.damage, shooter->owner, shooter, DSK_None); } else { - damage_done = apply_damage_to_thing_and_display_health(trgtng, shotng->shot.damage, -1, shooter, DSK_NONE); + damage_done = apply_damage_to_thing_and_display_health(trgtng, shotng->shot.damage, -1, shooter, DSK_None); } if (shotst->model_flags & ShMF_LifeDrain) { @@ -1313,7 +1325,7 @@ long shot_hit_creature_at(struct Thing *shotng, struct Thing *trgtng, struct Coo { spell_level = scctrl->exp_level; } - apply_spell_effect_to_thing(trgtng, shotst->cast_spell_kind, spell_level, shotng->owner, shooter, DSK_NONE); + apply_spell_effect_to_thing(trgtng, shotst->cast_spell_kind, spell_level, shotng->owner, shooter, DSK_None); struct SpellConfig *spconf = get_spell_config(shotst->cast_spell_kind); if (flag_is_set(spconf->spell_flags, CSAfF_Disease)) { @@ -1777,7 +1789,7 @@ TngUpdateRet update_shot(struct Thing *thing) { shotst = get_shot_model_stats(ShM_GodLightBall); draw_lightning(&thing->mappos,&target->mappos, shotst->effect_spacing, shotst->effect_id); - apply_damage_to_thing_and_display_health(target, shotst->damage, thing->owner, thing, DSK_NONE); + apply_damage_to_thing_and_display_health(target, shotst->damage, thing->owner, thing, DSK_None); } } break; diff --git a/src/thing_stats.c b/src/thing_stats.c index 49fc9d3b44..642d2e93b9 100644 --- a/src/thing_stats.c +++ b/src/thing_stats.c @@ -38,7 +38,6 @@ #include "player_utils.h" #include "thing_effects.h" #include "thing_list.h" -#include "thing_data.h" #include "thing_physics.h" #include "thing_stats.h" #include "vidfade.h" @@ -1093,14 +1092,13 @@ static struct Thing* resolve_damage_source_thing(struct Thing* scrtng) static DamageSourceKind check_dmg_src_kind(struct Thing* scrtng, DamageSourceKind source_kind) { - if (source_kind != DSK_NONE) + if (source_kind != DSK_None) return source_kind; - struct Thing* source_tng = resolve_damage_source_thing(scrtng); - if (!thing_exists(source_tng)) - return DSK_NONE; + if (!thing_exists(scrtng)) + return DSK_None; - switch (source_tng->class_id) + switch (scrtng->class_id) { case TCls_Creature: return DSK_Creature; @@ -1111,7 +1109,7 @@ static DamageSourceKind check_dmg_src_kind(struct Thing* scrtng, DamageSourceKin case TCls_Door: return DSK_Door; default: - return DSK_NONE; + return DSK_None; } } @@ -1144,11 +1142,6 @@ HitPoints apply_damage_to_thing(struct Thing *thing, HitPoints dmg, PlayerNumber { // We're here to damage, not to heal. SYNCDBG(19, "Dealing %d damage to %s by player %d", (int)dmg, thing_model_name(thing), (int)dealing_plyr_idx); - if ((scrtng != NULL) && !thing_is_invalid(scrtng)) { - SYNCDBG(8, "ApplyDamage: incoming kind=%d src=%s", (int)source_kind, thing_model_name(scrtng)); - } else { - SYNCDBG(8, "ApplyDamage: incoming kind=%d src=", (int)source_kind); - } if (dmg <= 0) return 0; // If it's already dead, then don't interfere. @@ -1156,11 +1149,7 @@ HitPoints apply_damage_to_thing(struct Thing *thing, HitPoints dmg, PlayerNumber return 0; struct Thing* src_tng = resolve_damage_source_thing(scrtng); DamageSourceKind damagesource = check_dmg_src_kind(src_tng, source_kind); - if (thing_exists(src_tng)) { - SYNCDBG(8, "ApplyDamage: resolved kind=%d src=%s", (int)damagesource, thing_model_name(src_tng)); - } else { - SYNCDBG(8, "ApplyDamage: resolved kind=%d src=", (int)damagesource); - } + lua_on_apply_damage_to_thing(thing, dmg, dealing_plyr_idx, src_tng, damagesource); HitPoints cdamage; diff --git a/src/thing_stats.h b/src/thing_stats.h index c365e9eb2d..dd8471ef1c 100644 --- a/src/thing_stats.h +++ b/src/thing_stats.h @@ -58,7 +58,7 @@ enum CreatureLiveStatistics { }; typedef enum DamageSourceKind { - DSK_NONE = 0, + DSK_None = 0, DSK_Lava, DSK_PowerSlap, DSK_Power,