Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rework hit types #3508

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion config/fxdata/magic.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,10 @@ DamageType = None
;6 - Affect all things.
;7 - Affect only dungeon hearts.
;8 - Affect only not own dungeon hearts.
;9 - Affect all creatures and all objects, also allow colliding with other shots
;11 - Affect only own creatures.
;12 - Affect own creatures, allied, and neutral creatures.
;13 - Affect hostile creatures.
HitType = 0
; For shots that can damage surrounding area - range, damage and blow.
; The damage and blow will be at its max only very near to the casting point at distance it will start decaying, until zero is reached at given range.
Expand Down Expand Up @@ -1249,7 +1253,7 @@ AnimationTransparency = 0
Health = 64
Damage = 16
DamageType =
HitType = 4
HitType = 13
Speed = 0
BaseExperienceGain = 256
DestroyOnHit = 0
Expand Down
2 changes: 1 addition & 1 deletion src/config_magic.c
Original file line number Diff line number Diff line change
Expand Up @@ -754,7 +754,7 @@ TbBool parse_magic_shot_blocks(char *buf, long len, const char *config_textname,
shot_desc[i].num = i;
}
shotst->model_flags = 0;
shotst->area_hit_type = THit_CrtrsOnly;
shotst->area_hit_type = THit_Creatures;
shotst->area_range = 0;
shotst->area_damage = 0;
shotst->area_blow = 0;
Expand Down
74 changes: 27 additions & 47 deletions src/creature_instances.c
Original file line number Diff line number Diff line change
Expand Up @@ -486,54 +486,26 @@ void process_creature_instance(struct Thing *thing)

long instf_creature_fire_shot(struct Thing *creatng, long *param)
{
struct Thing *target;
int hittype;
TRACE_THING(creatng);
struct Thing *target = NULL;
struct CreatureControl* cctrl = creature_control_get_from_thing(creatng);
if (cctrl->targtng_idx == 0)
{
if ((creatng->alloc_flags & TAlF_IsControlled) == 0)
hittype = THit_CrtrsOnlyNotOwn;
else
hittype = THit_CrtrsNObjcts;
}
else if ((creatng->alloc_flags & TAlF_IsControlled) != 0)
HitTargetFlags hit_targets_flags = 0;
TRACE_THING(creatng);

target = thing_get(cctrl->targtng_idx);
if (target == NULL || target == INVALID_THING)
{
target = thing_get(cctrl->targtng_idx);
TRACE_THING(target);
if (target->class_id == TCls_Object)
hittype = THit_CrtrsNObjcts;
else if (target->class_id == TCls_Trap)
hittype = THit_TrapsAll;
else
hittype = THit_CrtrsOnly;
SYNCDBG(8,"The %s(%d) fires %s",thing_model_name(creatng), creatng->index, shot_code_name(*param));
hit_targets_flags = get_hit_targets_for_shot(creatng, NULL, *param);
}
else
{
target = thing_get(cctrl->targtng_idx);
TRACE_THING(target);
if (target->class_id == TCls_Object)
hittype = THit_CrtrsNObjctsNotOwn;
else if (thing_is_destructible_trap(target) > 0)
hittype = THit_CrtrsNObjctsNotOwn;
else if (target->class_id == TCls_Trap)
hittype = THit_TrapsAll;
else if (target->owner == creatng->owner)
hittype = THit_CrtrsOnly;
else
hittype = THit_CrtrsOnlyNotOwn;
}
if (cctrl->targtng_idx > 0)
{
target = thing_get(cctrl->targtng_idx);
SYNCDBG(8,"The %s index %d fires %s at %s index %d",thing_model_name(creatng),(int)creatng->index,shot_code_name(*param),thing_model_name(target),(int)target->index);
SYNCDBG(8,"The %s(%d) fires %s at %s(%d)", thing_model_name(creatng), creatng->index,
shot_code_name(*param), thing_model_name(target), target->index);
TRACE_THING(target);
} else
{
target = NULL;
SYNCDBG(8,"The %s index %d fires %s",thing_model_name(creatng),(int)creatng->index,shot_code_name(*param));
hit_targets_flags = get_hit_targets_for_shot(creatng, target, *param);
}
thing_fire_shot(creatng, target, *param, 1, hittype);

thing_fire_shot(creatng, target, *param, 1, hit_targets_flags);
// Start cooldown after shot is fired
cctrl->instance_use_turn[cctrl->instance_id] = game.play_gameturn;
return 0;
Expand All @@ -550,12 +522,20 @@ long instf_creature_cast_spell(struct Thing *creatng, long *param)
SYNCDBG(8,"The %s(%d) casts %s at %d", thing_model_name(creatng), (int)creatng->index,
spell_code_name(spl_idx), cctrl->targtng_idx);

if (spconf->cast_at_thing && cctrl->targtng_idx != creatng->index)
// If the targtng_idx is jus the caster itself, we can call creature_cast_spell
// instead of creature_cast_spell_at_thing.
if (cctrl->targtng_idx != creatng->index)
{
// If the targtng_idx is just the caster itself, we can call creature_cast_spell
// instead of creature_cast_spell_at_thing.
target = thing_get(cctrl->targtng_idx);
if (thing_is_invalid(target)) target = NULL;
if (!spconf->cast_at_thing)
{
WARNLOG("The spell %s is casted on a thing(%d) but its CastAtThing property is false",
spell_code_name(spl_idx), cctrl->targtng_idx);
}
else
{
target = thing_get(cctrl->targtng_idx);
if (thing_is_invalid(target)) target = NULL;
}
}

if (target != NULL)
Expand Down Expand Up @@ -888,7 +868,7 @@ long instf_fart(struct Thing *creatng, long *param)
TRACE_THING(creatng);
struct Thing* efftng = create_effect(&creatng->mappos, TngEff_Gas3, creatng->owner);
if (!thing_is_invalid(efftng))
efftng->shot_effect.hit_type = THit_CrtrsOnlyNotOwn;
efftng->shot_effect.hit_type = THit_CreaturesNotOwn; // Consider using THit_CreaturesHostile.
thing_play_sample(creatng,94+UNSYNC_RANDOM(6), NORMAL_PITCH, 0, 3, 0, 4, FULL_LOUDNESS);
// Start cooldown after fart created
struct CreatureControl* cctrl = creature_control_get_from_thing(creatng);
Expand Down
4 changes: 2 additions & 2 deletions src/game_loop.c
Original file line number Diff line number Diff line change
Expand Up @@ -198,10 +198,10 @@ void process_dungeon_destroy(struct Thing* heartng)
struct Thing* efftng;
efftng = create_used_effect_or_element(central_pos, objst->effect.explosion1, plyr_idx);
if (!thing_is_invalid(efftng))
efftng->shot_effect.hit_type = THit_HeartOnlyNotOwn;
efftng->shot_effect.hit_type = THit_HeartNotOwn;
efftng = create_used_effect_or_element(central_pos, objst->effect.explosion2, plyr_idx);
if (!thing_is_invalid(efftng))
efftng->shot_effect.hit_type = THit_HeartOnlyNotOwn;
efftng->shot_effect.hit_type = THit_HeartNotOwn;
destroy_dungeon_heart_room(plyr_idx, heartng);
delete_thing_structure(heartng, 0);
}
Expand Down
2 changes: 1 addition & 1 deletion src/magic.c
Original file line number Diff line number Diff line change
Expand Up @@ -1473,7 +1473,7 @@ static TbResult magic_use_power_lightning(PowerKind power_kind, PlayerNumber ply
if (!thing_is_invalid(shtng))
{
shtng->mappos.z.val = get_thing_height_at(shtng, &shtng->mappos) + COORD_PER_STL/2;
shtng->shot.hit_type = THit_CrtrsOnly;
shtng->shot.hit_targets = hit_type_to_hit_targets(THit_Creatures);
shtng->shot.spell_level = splevel;
}
pwrdynst = get_power_dynamic_stats(power_kind);
Expand Down
55 changes: 23 additions & 32 deletions src/thing_creature.c
Original file line number Diff line number Diff line change
Expand Up @@ -1551,33 +1551,16 @@ short creature_take_wage_from_gold_pile(struct Thing *creatng,struct Thing *gold
*/
void creature_cast_spell_at_thing(struct Thing *castng, struct Thing *targetng, SpellKind spl_idx, long shot_lvl)
{
unsigned char hit_type;
if ((castng->alloc_flags & TAlF_IsControlled) != 0)
{
if ((targetng->class_id == TCls_Object) || (targetng->class_id == TCls_Trap))
hit_type = THit_CrtrsNObjcts;
else
hit_type = THit_CrtrsOnly;
} else
{
if ((targetng->class_id == TCls_Object) || (targetng->class_id == TCls_Trap))
hit_type = THit_CrtrsNObjctsNotOwn;
else
if (targetng->owner == castng->owner)
hit_type = THit_CrtrsOnly;
else
hit_type = THit_CrtrsOnlyNotOwn;
}
HitTargetFlags hit_targets = get_hit_targets_for_spell(castng, targetng, spl_idx);
const struct SpellConfig* spconf = get_spell_config(spl_idx);
if (spell_config_is_invalid(spconf))
{
ERRORLOG("The %s owned by player %d tried to cast invalid spell %d",thing_model_name(castng),(int)castng->owner,(int)spl_idx);
return;
}

SYNCDBG(12,"The %s(%u) fire shot(%s) at %s(%u) with shot level %ld, hit type: 0x%02X", thing_model_name(castng), castng->index,
shot_code_name(spconf->shot_model), thing_model_name(targetng), targetng->index, shot_lvl, hit_type);
thing_fire_shot(castng, targetng, spconf->shot_model, shot_lvl, hit_type);
SYNCDBG(12,"The %s(%u) fire shot(%s) at %s(%u) with shot level %ld, hit targets: 0x%02X", thing_model_name(castng), castng->index,
shot_code_name(spconf->shot_model), thing_model_name(targetng), targetng->index, shot_lvl, hit_targets);
thing_fire_shot(castng, targetng, spconf->shot_model, shot_lvl, hit_targets);
}

/**
Expand Down Expand Up @@ -1767,12 +1750,11 @@ void remove_creature_from_summon_list(struct Dungeon* dungeon, ThingIndex famlrt
* @param castng The caster creature.
* @param spl_idx Spell index to be casted.
* @param shot_lvl Spell level to be casted.
* @param trg_x
* @param trg_y
* @param trg_x Coordinate X of the target location
* @param trg_y Coordinate Y of the target location
*/
void creature_cast_spell(struct Thing *castng, SpellKind spl_idx, long shot_lvl, MapSubtlCoord trg_x, MapSubtlCoord trg_y)
{
long i;
const struct SpellConfig* spconf = get_spell_config(spl_idx);
struct CreatureControl* cctrl = creature_control_get_from_thing(castng);
if (creature_control_invalid(cctrl))
Expand All @@ -1785,7 +1767,19 @@ void creature_cast_spell(struct Thing *castng, SpellKind spl_idx, long shot_lvl,
cctrl->teleport_x = trg_x;
cctrl->teleport_y = trg_y;
}

if ((spconf->shot_model > 0) && (cctrl->targtng_idx != castng->index))
{
// If we reach here, it means that this spell cannot find a Thing as the target,
// either due to invalid target index or incorrect CastAtThing setting.
// Besides, this spell has a shot model. It means the caster want to fire a shot without
// locking on a target.
// In this case, it should use instf_creature_fire_shot, not instf_creature_cast_spell.
// This is a misuse.
WARNLOG("Consider using instf_creature_fire_shot for spell %s", spell_code_name(spl_idx));
HitTargetFlags hit_targets_flags = get_hit_targets_for_shot(castng, NULL, spconf->shot_model);
thing_fire_shot(castng, INVALID_THING, spconf->shot_model, shot_lvl, hit_targets_flags);
}
// Check if the spell can be self-casted
if (spconf->caster_affected)
{
if (spconf->caster_affect_sound > 0)
Expand Down Expand Up @@ -3090,7 +3084,7 @@ static void shot_set_start_pos(const struct Thing *firing, const struct ShotConf
}
}

void thing_fire_shot(struct Thing *firing, struct Thing *target, ThingModel shot_model, char shot_lvl, unsigned char hit_type)
void thing_fire_shot(struct Thing *firing, struct Thing *target, ThingModel shot_model, char shot_lvl, HitTargetFlags hit_targets)
{
struct Coord3d pos2;
struct Thing *tmptng;
Expand Down Expand Up @@ -3199,10 +3193,7 @@ void thing_fire_shot(struct Thing *firing, struct Thing *target, ThingModel shot
damage = calculate_shot_damage(firing, shot_model);
}
}
if ((shotst->model_flags & ShMF_Disarming) && thing_is_deployed_trap(target))
{
hit_type = THit_TrapsAll;
}

struct Thing* shotng = NULL;
long target_idx = 0;
// Set target index for navigating shots
Expand Down Expand Up @@ -3257,7 +3248,7 @@ void thing_fire_shot(struct Thing *firing, struct Thing *target, ThingModel shot
if (thing_is_invalid(tmptng))
break;
shotng = tmptng;
shotng->shot.hit_type = hit_type;
shotng->shot.hit_targets = hit_targets;
shotng->move_angle_xy = (short)((angle_xy + CREATURE_RANDOM(firing, 2 * shotst->spread_xy + 1) - shotst->spread_xy) & LbFPMath_AngleMask);
shotng->move_angle_z = (short)((angle_yz + CREATURE_RANDOM(firing, 2 * shotst->spread_z + 1) - shotst->spread_z) & LbFPMath_AngleMask);
angles_to_vector(shotng->move_angle_xy, shotng->move_angle_z, speed, &cvect);
Expand Down Expand Up @@ -3326,7 +3317,7 @@ void thing_fire_shot(struct Thing *firing, struct Thing *target, ThingModel shot
WARNLOG("Shot of type %d carries %d damage",(int)shot_model,(int)damage);
}
#endif
shotng->shot.hit_type = hit_type;
shotng->shot.hit_targets = hit_targets;
if (shotst->firing_sound > 0)
{
thing_play_sample(firing, shotst->firing_sound + UNSYNC_RANDOM(shotst->firing_sound_variants),
Expand Down
2 changes: 1 addition & 1 deletion src/thing_creature.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ long creature_available_for_combat_this_turn(struct Thing *thing);
TbBool set_creature_object_combat(struct Thing *crthing, struct Thing *obthing);
TbBool set_creature_object_snipe(struct Thing* crthing, struct Thing* obthing);
TbBool set_creature_door_combat(struct Thing *crthing, struct Thing *obthing);
void thing_fire_shot(struct Thing *firing,struct Thing *target, ThingModel shot_model, char shot_lvl, unsigned char hit_type);
void thing_fire_shot(struct Thing *firing,struct Thing *target, ThingModel shot_model, char shot_lvl, HitTargetFlags hit_targets);
void creature_cast_spell_at_thing(struct Thing *caster, struct Thing *target, SpellKind spl_idx, long shot_lvl);
void creature_cast_spell(struct Thing *caster, SpellKind spl_idx, long shot_lvl, MapSubtlCoord trg_x, MapSubtlCoord trg_y);

Expand Down
4 changes: 2 additions & 2 deletions src/thing_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -176,12 +176,12 @@ struct Thing {
short unused3;
long last_turn_drawn;
unsigned char display_timer;
}roomflag2; // both roomflag and roomflag2 are used in same function on same object but have 2 bytes overlapping between room_idx and last_turn_drawn
} roomflag2; // both roomflag and roomflag2 are used in same function on same object but have 2 bytes overlapping between room_idx and last_turn_drawn
//TCls_Shot
struct {
unsigned char dexterity;
short damage;
unsigned char hit_type;
HitTargetFlags hit_targets;
short target_idx;
unsigned char spell_level;
struct Coord3d originpos;
Expand Down
2 changes: 1 addition & 1 deletion src/thing_effects.c
Original file line number Diff line number Diff line change
Expand Up @@ -1158,7 +1158,7 @@ long explosion_effect_affecting_map_block(struct Thing *efftng, struct Thing *tn
}
i = thing->next_on_mapblk;
// Per thing processing block
if ((thing->class_id == TCls_Door) && (efftng->shot_effect.hit_type != THit_CrtrsOnlyNotOwn)) //TODO: Find pretty way to say that WoP traps should not destroy doors. And make it configurable through configs.
if ((thing->class_id == TCls_Door) && (efftng->shot_effect.hit_type != THit_CreaturesNotOwn)) //TODO: Find pretty way to say that WoP traps should not destroy doors. And make it configurable through configs.
{
if (explosion_affecting_door(tngsrc, thing, &efftng->mappos, max_dist, shotst->area_damage, shotst->area_blow, shotst->damage_type, owner))
{
Expand Down
24 changes: 15 additions & 9 deletions src/thing_effects.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,24 @@ extern "C" {
#endif

/******************************************************************************/

// This provides a convenient way to specify hit types in the cfg files.
// They will be converted to a combination of HitTargetFlags for further process.
enum ThingHitTypes {
THit_None = 0,
THit_CrtrsNObjcts, // Affect all creatures and all objects
THit_CrtrsOnly, // Affect only creatures
THit_CrtrsNObjctsNotOwn, // Affect not own creatures and objects
THit_CrtrsOnlyNotOwn, // Affect not own creatures
THit_CrtrsNotArmourNotOwn, // Affect not own creatures which are not protected by Armour spell
THit_CreaturesAndObjects, // Affect all creatures and all objects
THit_Creatures, // Affect only creatures
THit_CreaturesAndObjectsNotOwn, // Affect not own creatures and objects
THit_CreaturesNotOwn, // Affect not own creatures
THit_CreaturesHostileNotArmour, // Affect hostile creatures which are not protected by Armour spell
THit_All, // Affect all things
THit_HeartOnly, // Affect only dungeon hearts
THit_HeartOnlyNotOwn, // Affect only not own dungeon hearts
THit_CrtrsNObjctsNShot, // Affect all creatures and all objects, also allow colliding with other shots
THit_TrapsAll, // Affect all traps, not just the ones that are destructable
THit_Heart, // Affect only dungeon hearts
THit_HeartNotOwn, // Affect only not own dungeon hearts
THit_CreaturesAndObjectsCanCollide, // Affect all creatures and all objects, also allow colliding with other shots
THit_TrapsAll, // Affect all traps, not just the ones that are destructible
THit_CreaturesOwn, // Affect own creatures
THit_CreaturesFriendly, // Affect own creatures and allied/neutral creatures.
THit_CreaturesHostile, // Affect hostile creatures.
THit_TypesCount, // Last item in enumeration, allows checking amount of valid types
};

Expand Down
Loading