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

Add THST and doctest #3534

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
7 changes: 4 additions & 3 deletions config/fxdata/creature.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,13 @@ PrimaryTarget = 0
; DANGEROUS will be avoided when attacking Doors and Hearts
; DESTRUCTIVE is required when attacking Doors and Hearts
; SELF_BUFF can be applied to caster.
; RANGED_BUFF can be applied to another friendly creature.
; RANGED_BUFF can be applied to another own creature.
; REPEAT_TRIGGER allows player to hold down the mouse button to cast
; QUICK ranged attacks will be used by units going postal
; DISARMING allows instance to be used against traps
; DISPLAY_SWIPE Shows the swipe in possession loaded from the creatures PossessSwipeIndex
; NEEDS_TARGET Cannot be used in possession without a target to cast it on
; APPLY_TO_ALLIES Allows RANGED_BUFF to be applied to mutual allied player's creature.
Properties =
; Function used as the instance action, and its parameters
Function = none 0 0
Expand Down Expand Up @@ -967,8 +968,8 @@ SymbolSprites = 786
Graphics = ATTACK
RangeMin = MIN
RangeMax = 5120
PrimaryTarget = 6
Properties = RANGED_BUFF SELF_BUFF NEEDS_TARGET
PrimaryTarget = 2
Properties = RANGED_BUFF SELF_BUFF NEEDS_TARGET APPLY_TO_ALLIES
Function = creature_cast_spell SPELL_HEAL 0
ValidateFunc = validate_source_ranged_heal validate_target_ranged_heal
SearchTargetsFunc = search_target_ranged_heal
Expand Down
1 change: 1 addition & 0 deletions src/config_creature.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ const struct NamedCommand creaturetype_instance_properties[] = {
{"DISPLAY_SWIPE", InstPF_UsesSwipe},
{"RANGED_BUFF", InstPF_RangedBuff},
{"NEEDS_TARGET", InstPF_NeedsTarget},
{"APPLY_TO_ALLIES", InstPF_ApplyToAllies},
{NULL, 0},
};

Expand Down
1 change: 1 addition & 0 deletions src/config_creature.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ enum InstancePropertiesFlags {
InstPF_UsesSwipe = 0x0200,
InstPF_RangedBuff = 0x0400,
InstPF_NeedsTarget = 0x0800,
InstPF_ApplyToAllies = 0x1000,
};

enum CreatureDeathKind {
Expand Down
60 changes: 60 additions & 0 deletions src/creature_control.c
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,66 @@ TbBool creature_can_gain_experience(const struct Thing *thing)
return true;
}

/**
* @brief Insert one creature with its distance to the creatures_nearby array of the
* specified creature(center).
* @param center The creature in the center.
* @param creature_idx The index of the nearby creature.
* @param distance The distance of the above creature.
* @return TbBool True if successfully inserted.
*/
TbBool insert_nearby_creature(struct Thing *center, ThingIndex creature_idx, long distance)
{
if (thing_is_invalid(center))
{
ERRORLOG("Invalid thing!");
return false;
}
struct CreatureControl* cctrl = creature_control_get_from_thing(center);
if (creature_control_invalid(cctrl))
{
ERRORLOG("Invalid creature control!");
return false;
}

TbBool ok = true;
for(int i = 0; i < COUNT_OF(cctrl->creatures_nearby); i++)
{
if (cctrl->creatures_nearby[i].creature_idx == 0)
{
// Insert in an empty slot.
cctrl->creatures_nearby[i].creature_idx = creature_idx;
cctrl->creatures_nearby[i].distance = distance;
break;
}
else if(cctrl->creatures_nearby[i].distance > distance)
{
// Conduct insertion sort.
for (int k = COUNT_OF(cctrl->creatures_nearby) - 1; k >= i; k--)
{
if(cctrl->creatures_nearby[k].creature_idx != 0)
{
if(k == COUNT_OF(cctrl->creatures_nearby) - 1)
{
// This array is full. Cannot add anymore.
ok = false;
break;
}
else
{
cctrl->creatures_nearby[k + 1].creature_idx = cctrl->creatures_nearby[k].creature_idx;
cctrl->creatures_nearby[k + 1].distance = cctrl->creatures_nearby[k].distance;
}
}
}
cctrl->creatures_nearby[i].creature_idx = creature_idx;
cctrl->creatures_nearby[i].distance = distance;
break;
}
}
return ok;
}

/******************************************************************************/
#ifdef __cplusplus
}
Expand Down
12 changes: 12 additions & 0 deletions src/creature_control.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ extern "C" {

#define CREATURE_TYPES_MAX 128
#define CREATURE_STATES_MAX 256
#define CREATURE_TRACKING_MAX (CREATURES_COUNT / 4)
// 7680 is roughly 10 slabs.
#define CREATURE_SCAN_RANGE_MAX 7680

#define MAX_SIZEXY 768
/** Max amount of spells casted at the creature at once. */
Expand Down Expand Up @@ -138,6 +141,11 @@ struct CastedSpellData {
short duration;
};

struct CreatureWithDistance {
unsigned int distance;
ThingIndex creature_idx;
};

struct CreatureControl {
unsigned short index;
unsigned char flgfield_1;
Expand Down Expand Up @@ -414,6 +422,8 @@ unsigned char sound_flag;
ThingIndex summoner_idx;
long summon_spl_idx;
ThingIndex familiar_idx[FAMILIAR_MAX];
// Ascending sorted array by the distance.
struct CreatureWithDistance creatures_nearby[CREATURE_TRACKING_MAX];
};

struct CreatureStats { // These stats are not compatible with original DK - they have more fields
Expand Down Expand Up @@ -585,6 +595,8 @@ void play_creature_sound_and_create_sound_thing(struct Thing *thing, long snd_id
struct CreatureSound *get_creature_sound(struct Thing *thing, long snd_idx);
void reset_creature_eye_lens(struct Thing *thing);
TbBool creature_can_gain_experience(const struct Thing *thing);
TbBool insert_nearby_creature(struct Thing *center, ThingIndex creature_idx, long distance);

/******************************************************************************/
#ifdef __cplusplus
}
Expand Down
100 changes: 69 additions & 31 deletions src/creature_instances.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,6 @@
extern "C" {
#endif

#define MAX_CREATURES_SEARCHED 100

/******************************************************************************/
long instf_attack_room_slab(struct Thing *creatng, long *param);
long instf_creature_cast_spell(struct Thing *creatng, long *param);
Expand Down Expand Up @@ -1225,12 +1223,26 @@ TbBool validate_target_basic(struct Thing *source, struct Thing *target, CrInsta
}

struct InstanceInfo* inst_inf = creature_instance_info_get(inst_idx);
if ((inst_inf->instance_property_flags & InstPF_SelfBuff) == 0 && source->index == target->index)
if (!flag_is_set(inst_inf->instance_property_flags, InstPF_SelfBuff) && source->index == target->index)
{
// If this spell doesn't have SELF_BUFF flag, exclude itself.
return false;
}

if (source->owner != target->owner)
{
TbBool allyOk = flag_is_set(inst_inf->instance_property_flags, InstPF_ApplyToAllies);
TbBool players_allied = players_are_mutual_allies(source->owner, target->owner);
SYNCDBG(11, "Can %s be cast on %s(%d)? Having APPLY_TO_ALLIES? %d Is allied creature? %d",
creature_instance_code_name(inst_idx), thing_model_name(target), target->index,
allyOk, players_allied);
if (!allyOk || !players_allied)
{
// Don't cast on hostile creatures.
return false;
}
}

if (// Creature who is leaving doesn't deserve buff from allies.
target->continue_state == CrSt_CreatureLeaves ||
target->active_state == CrSt_CreatureLeavingDungeon ||
Expand Down Expand Up @@ -1322,9 +1334,15 @@ TbBool validate_source_ranged_heal(struct Thing *source, struct Thing *target, C
*/
TbBool validate_target_ranged_heal(struct Thing *source, struct Thing *target, CrInstance inst_idx)
{
if (!validate_target_basic(source, target, CrInst_RANGED_HEAL) || creature_is_being_unconscious(target) ||
!creature_would_benefit_from_healing(target))
if (!validate_target_basic(source, target, inst_idx) || creature_is_being_unconscious(target))
{
return false;
}

if (!creature_would_benefit_from_healing(target))
{
SYNCDBG(11, "%s(%d)'s HP is high enough, it doesn't require healing.",
thing_model_name(target), target->index);
return false;
}

Expand Down Expand Up @@ -1362,30 +1380,58 @@ TbBool search_target_generic(struct Thing *source, CrInstance inst_idx, ThingInd
ERRORLOG("Invalid parameters!");
return false;
}
struct CreatureControl* source_cctrl = creature_control_get_from_thing(source);
if (creature_control_invalid(source_cctrl))
{
ERRORLOG("Invalid creature control");
return false;
}

TbBool ok = true;
// To improve performance, use a smaller number than CREATURES_COUNT.
ThingIndex* results = (ThingIndex*)malloc(MAX_CREATURES_SEARCHED * sizeof(ThingIndex));
memset(results, 0, MAX_CREATURES_SEARCHED * sizeof(ThingIndex));
TbBool add_self = false;
// Firstly, check the source itself.
const struct InstanceInfo* inst_inf = creature_instance_info_get(inst_idx);
if (inst_inf->validate_func_idx[1] > 0)
{
add_self = creature_instances_validate_func_list[inst_inf->validate_func_idx[1]](source, source, inst_idx);
}
int max_count = 0;
for(; max_count < COUNT_OF(source_cctrl->creatures_nearby); max_count++)
{
if (source_cctrl->creatures_nearby[max_count].creature_idx == 0)
{
break;
}
}
SYNCDBG(9, "There are %d nearby creatures around %s(%d).", max_count, thing_model_name(source), source->index);

ThingIndex* results = (ThingIndex*)malloc((add_self ? max_count + 1 : max_count) * sizeof(ThingIndex));
memset(results, 0, (add_self ? max_count + 1 : max_count) * sizeof(ThingIndex));
*found_count = 0;
// Note that we only support buff right now, so we only search source's owner's creature.
// For offensive debuff, we need another loop to iterate all enemies.
struct Dungeon* dungeon = get_players_num_dungeon(source->owner);
int creature_idx = dungeon->creatr_list_start;
int k = 0;
while (creature_idx != 0 && (*found_count) < MAX_CREATURES_SEARCHED)
{
struct Thing* candidate = thing_get(creature_idx);

if (add_self)
{
results[(*found_count)] = source->index;
(*found_count)++;
}

TbBool ok = true;
for(int i = 0; i < max_count; i++)
{
struct Thing* candidate = thing_get(source_cctrl->creatures_nearby[i].creature_idx);
if (thing_is_invalid(candidate))
{
ERRORLOG("Invalid thing on index %d", i);
ok = false;
break;
}
struct CreatureControl* cctrl = creature_control_get_from_thing(candidate);
if (creature_control_invalid(cctrl))
{
ERRORLOG("Invalid creature control");
ERRORLOG("Invalid creature control on index %i", i);
ok = false;
break;
}

creature_idx = cctrl->players_next_creature_idx;
const struct InstanceInfo* inst_inf = creature_instance_info_get(inst_idx);
if (inst_inf->validate_func_idx[1] > 0)
{
if(!creature_instances_validate_func_list[inst_inf->validate_func_idx[1]](source, candidate, inst_idx))
Expand All @@ -1399,24 +1445,16 @@ TbBool search_target_generic(struct Thing *source, CrInstance inst_idx, ThingInd
{
// @todo Consider checking thing_in_field_of_view() in the future, now it is buggy.
// We assume that the source must see the target before it can cast the spell.
int range = get_combat_distance(source, candidate);
if (range < inst_inf->range_min || range > inst_inf->range_max ||
!creature_can_see_combat_path(source, candidate, range))
if (source_cctrl->creatures_nearby[i].distance < inst_inf->range_min ||
source_cctrl->creatures_nearby[i].distance > inst_inf->range_max ||
!creature_can_see_combat_path(source, candidate, source_cctrl->creatures_nearby[i].distance))
{
continue;
}
}

results[(*found_count)] = candidate->index;
(*found_count)++;

k++;
if (k > CREATURES_COUNT)
{
ERRORLOG("Infinite loop detected when sweeping creatures list");
ok = false;
break;
}
}

*targets = results;
Expand Down
2 changes: 1 addition & 1 deletion src/dungeon_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ struct Dungeon {
struct Coord3d mappos;
unsigned char creature_tendencies;
unsigned char computer_enabled;
short creatr_list_start;
ThingIndex creatr_list_start;
short digger_list_start;
ThingIndex summon_list[MAX_SUMMONS];
unsigned short num_summon;
Expand Down
10 changes: 10 additions & 0 deletions src/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,16 @@
#include <algorithm>
using std::min;
using std::max;
#define COUNT_OF(_Array) (sizeof(_Array) / sizeof(_Array[0]))
#else
// C version (from Google's Chromium project)
// It improves on the array[0] or *array version by using 0[array], which is equivalent to array[0] on plain arrays,
// but will fail to compile if array happens to be a C++ type that overloads operator[]()
#define COUNT_OF(_Array) ((sizeof(_Array) / sizeof(0[_Array])) / ((size_t)(!(sizeof(_Array) % sizeof(0[_Array])))))
#endif


#ifdef __cplusplus
extern "C" {
#endif

Expand Down
Loading