Skip to content

Commit

Permalink
Add validation functions for creature self-buff instances (#3527)
Browse files Browse the repository at this point in the history
- Fix Speed is not cast when attacking an object or door.
- Fix Ranged Rebound/Armour being cast when not in combat.
Fixes #3445
  • Loading branch information
Linvail authored Oct 12, 2024
1 parent 1d5ea20 commit 97902cd
Show file tree
Hide file tree
Showing 9 changed files with 554 additions and 252 deletions.
70 changes: 58 additions & 12 deletions config/fxdata/creature.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,30 @@ PrimaryTarget = 0
Properties =
; Function used as the instance action, and its parameters
Function = none 0 0
; Functions used validate the source and the target of the spell.
ValidateFunc = validate_source_generic validate_target_generic
; Functions used search targets of the spell.
SearchTargetsFunc = search_target_generic
; Function to validate the source of the spell. Could have two parameters.
; It checks whether the caster (source creature) is able and legitimate to cast the spell. It
; mainly checks the state of the caster. For example, checking whether it's unconscious/picked up.
; An unconscious/picked creature is unable to cast spells. Checking whether it's in prison.
; validate_source_generic() forbids casting in prison but validate_source_even_in_prison() doesn't.
; This must be set for RANGED_BUFF.
ValidateSourceFunc = validate_source_generic 0 0
; Function to validate the target of the spell. Could have two parameters.
; It checks whether the target creature is able and legitimate to receive the spell. It mainly
; checks if the target can benefit from the spell. For example, a creature having 100% HP doesn't
; need healing. A creature having Speed effect already doesn't need the Speed spell. The Speed
; spell should be cast on another creature who doesn't have the Speed effect.
; It also checks the target's state. For example, an unconscious creature is not a legitimate
; target of Speed or Armour spell.
; This must be set for RANGED_BUFF.
ValidateTargetFunc = validate_target_generic 0 0
; Function to search targets of the ranged spell. Could have two parameters.
; It works with ValidateTargetFunc together to collect one or more targets and run dedicated
; logic to process them. For example, search_target_ranged_heal() will search nearby area
; to collect validated creatures (by validate_target_benefits_from_healing()) and select the creature
; who has lowest percentage of HP as the final receiver of the Heal spell.
; This must be set for RANGED_BUFF.
; When this is set, ValidateTargetFunc must be set, too.
SearchTargetsFunc = search_target_generic 0 0

[instance1]
Name = SWING_WEAPON_SWORD
Expand Down Expand Up @@ -233,6 +253,8 @@ Graphics = ATTACK
Properties = SELF_BUFF
PrimaryTarget = 3
Function = creature_cast_spell SPELL_ARMOUR 0
ValidateSourceFunc = validate_source_generic 0 0
ValidateTargetFunc = validate_target_benefits_from_defensive 0 0

[instance9]
Name = LIGHTNING
Expand Down Expand Up @@ -269,6 +291,8 @@ Graphics = ATTACK
Properties = SELF_BUFF
PrimaryTarget = 3
Function = creature_cast_spell SPELL_REBOUND 0
ValidateSourceFunc = validate_source_generic 0 0
ValidateTargetFunc = validate_target_benefits_from_missile_defense 0 0

[instance11]
Name = HEAL
Expand All @@ -286,6 +310,8 @@ Graphics = ATTACK
Properties = SELF_BUFF
PrimaryTarget = 3
Function = creature_cast_spell SPELL_HEAL 0
ValidateSourceFunc = validate_source_even_in_prison 0 0
ValidateTargetFunc = validate_target_benefits_from_healing 0 0

[instance12]
Name = POISON_CLOUD
Expand Down Expand Up @@ -322,6 +348,8 @@ Graphics = ATTACK
PrimaryTarget = 3
Properties = SELF_BUFF
Function = creature_cast_spell SPELL_INVISIBILITY 0
ValidateSourceFunc = validate_source_generic 0 0
ValidateTargetFunc = validate_target_benefits_from_defensive 0 0

[instance14]
Name = TELEPORT
Expand Down Expand Up @@ -356,6 +384,8 @@ Graphics = ATTACK
PrimaryTarget = 3
Properties = SELF_BUFF
Function = creature_cast_spell SPELL_SPEED 0
ValidateSourceFunc = validate_source_generic 0 0
ValidateTargetFunc = validate_target_generic 0 0

[instance16]
Name = SLOW
Expand Down Expand Up @@ -489,6 +519,10 @@ RangeMax = MAX
PrimaryTarget = 3
Properties =
Function = creature_cast_spell SPELL_WIND 0
ValidateSourceFunc = validate_source_generic 0 0
; Wind can disperse gas and push away melee enemies.
; It has more than one merit. It deserve one dedicated function
ValidateTargetFunc = validate_target_benefits_from_wind 0 0

[instance23]
Name = LIGHT
Expand Down Expand Up @@ -523,6 +557,8 @@ Graphics = ATTACK
Properties = SELF_BUFF
PrimaryTarget = 3
Function = creature_cast_spell SPELL_FLIGHT 0
ValidateSourceFunc = validate_source_generic 0 0
ValidateTargetFunc = validate_target_benefits_from_higher_altitude 0 0

[instance25]
Name = SIGHT
Expand All @@ -540,6 +576,8 @@ Graphics = ATTACK
Properties = SELF_BUFF
PrimaryTarget = 3
Function = creature_cast_spell SPELL_SIGHT 0
ValidateSourceFunc = validate_source_even_in_prison 0 0
ValidateTargetFunc = validate_target_even_in_prison 0 0

[instance26]
Name = GRENADE
Expand Down Expand Up @@ -933,6 +971,8 @@ Graphics = SCREAM
Properties = SELF_BUFF
PrimaryTarget = 8
Function = creature_cast_spell SPELL_SUMMON_FAMILIAR 0
ValidateSourceFunc = validate_source_generic 0 0
ValidateTargetFunc = validate_target_generic 0 0

; Creature is summoned only in battle
[instance49]
Expand All @@ -951,6 +991,8 @@ Graphics = SCREAM
Properties = SELF_BUFF
PrimaryTarget = 8
Function = creature_cast_spell SPELL_SUMMON_CREATURE 0
ValidateSourceFunc = validate_source_generic 0 0
ValidateTargetFunc = validate_target_benefits_from_offensive 0 0

[instance50]
Name = RANGED_HEAL
Expand All @@ -970,8 +1012,9 @@ RangeMax = 5120
PrimaryTarget = 6
Properties = RANGED_BUFF SELF_BUFF NEEDS_TARGET
Function = creature_cast_spell SPELL_HEAL 0
ValidateFunc = validate_source_ranged_heal validate_target_ranged_heal
SearchTargetsFunc = search_target_ranged_heal
ValidateSourceFunc = validate_source_even_in_prison 0 0
ValidateTargetFunc = validate_target_benefits_from_healing 0 0
SearchTargetsFunc = search_target_ranged_heal 0 0

[instance51]
Name = RANGED_SPEED
Expand All @@ -991,8 +1034,9 @@ RangeMax = 5120
PrimaryTarget = 6
Properties = RANGED_BUFF SELF_BUFF NEEDS_TARGET
Function = creature_cast_spell SPELL_SPEED 0
ValidateFunc = validate_source_generic validate_target_generic
SearchTargetsFunc = search_target_generic
ValidateSourceFunc = validate_source_generic 0 0
ValidateTargetFunc = validate_target_generic 0 0
SearchTargetsFunc = search_target_generic 0 0

[instance52]
Name = RANGED_ARMOUR
Expand All @@ -1012,8 +1056,9 @@ RangeMax = 5120
PrimaryTarget = 6
Properties = RANGED_BUFF SELF_BUFF NEEDS_TARGET
Function = creature_cast_spell SPELL_ARMOUR 0
ValidateFunc = validate_source_generic validate_target_generic
SearchTargetsFunc = search_target_generic
ValidateSourceFunc = validate_source_generic 0 0
ValidateTargetFunc = validate_target_benefits_from_defensive 0 0
SearchTargetsFunc = search_target_generic 0 0

[instance53]
Name = RANGED_REBOUND
Expand All @@ -1033,8 +1078,9 @@ RangeMax = 5120
PrimaryTarget = 6
Properties = RANGED_BUFF SELF_BUFF NEEDS_TARGET
Function = creature_cast_spell SPELL_REBOUND 0
ValidateFunc = validate_source_generic validate_target_generic
SearchTargetsFunc = search_target_generic
ValidateSourceFunc = validate_source_generic 0 0
ValidateTargetFunc = validate_target_benefits_from_missile_defense 0 0
SearchTargetsFunc = search_target_generic 0 0

[job0]
; Empty job, indicates no job assigned
Expand Down
1 change: 1 addition & 0 deletions src/bflib_basics.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ enum TbErrorCode {
/******************************************************************************/
#pragma pack(1)

// These types should be deprecated because we have stdint.h now.
typedef unsigned long ulong;
typedef unsigned int uint;
typedef unsigned short ushort;
Expand Down
1 change: 1 addition & 0 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,7 @@ TbBool iterate_conf_blocks(const char * buf, long * pos, long buflen, const char

/**
* Recognizes config command and returns its number, or negative status code.
* The string comparison is done by case-insensitive.
* @param buf
* @param pos
* @param buflen
Expand Down
96 changes: 69 additions & 27 deletions src/config_creature.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,25 +77,26 @@ const struct NamedCommand creaturetype_experience_commands[] = {
};

const struct NamedCommand creaturetype_instance_commands[] = {
{"NAME", 1},
{"TIME", 2},
{"ACTIONTIME", 3},
{"RESETTIME", 4},
{"FPTIME", 5},
{"FPACTIONTIME", 6},
{"FPRESETTIME", 7},
{"FORCEVISIBILITY", 8},
{"TOOLTIPTEXTID", 9},
{"SYMBOLSPRITES", 10},
{"GRAPHICS", 11},
{"FUNCTION", 12},
{"RANGEMIN", 13},
{"RANGEMAX", 14},
{"PROPERTIES", 15},
{"FPINSTANTCAST", 16},
{"PRIMARYTARGET", 17},
{"VALIDATEFUNC", 18},
{"SEARCHTARGETSFUNC", 19},
{"Name", 1},
{"Time", 2},
{"ActionTime", 3},
{"ResetTime", 4},
{"FPTime", 5},
{"FPActiontime", 6},
{"FPResettime", 7},
{"ForceVisibility", 8},
{"TooltipTextID", 9},
{"SymbolSprites", 10},
{"Graphics", 11},
{"Function", 12},
{"RangeMin", 13},
{"RangeMax", 14},
{"Properties", 15},
{"FpinstantCast", 16},
{"PrimaryTarget", 17},
{"ValidateSourceFunc", 18},
{"ValidateTargetFunc", 19},
{"SearchTargetsFunc", 20},
{NULL, 0},
};

Expand Down Expand Up @@ -830,9 +831,12 @@ TbBool parse_creaturetype_instance_blocks(char *buf, long len, const char *confi
inst_inf->tooltip_stridx = 0;
inst_inf->range_min = -1;
inst_inf->range_max = -1;
inst_inf->validate_func_idx[0] = 1;
inst_inf->validate_func_idx[1] = 2;
inst_inf->search_func_idx = 1;
inst_inf->validate_source_func = 0;
inst_inf->validate_source_func_params[0] = 0;
inst_inf->validate_source_func_params[1] = 0;
inst_inf->validate_target_func = 0;
inst_inf->validate_target_func_params[0] = 0;
inst_inf->validate_target_func_params[1] = 0;
}
}
instance_desc[INSTANCE_TYPES_MAX - 1].name = NULL; // must be null for get_id
Expand Down Expand Up @@ -1144,26 +1148,64 @@ TbBool parse_creaturetype_instance_blocks(char *buf, long len, const char *confi
COMMAND_TEXT(cmd_num), blocknamelen, blockname, config_textname);
}
break;
case 18: // VALIDATE_FUNC
case 18: // ValidateSourceFunc
k = recognize_conf_parameter(buf, &pos, len, creature_instances_validate_func_type);
if (k > 0)
{
inst_inf->validate_func_idx[0] = k;
inst_inf->validate_source_func = k;
n++;
}
if (get_conf_parameter_single(buf, &pos, len, word_buf, sizeof(word_buf)) > 0)
{
k = atoi(word_buf);
inst_inf->validate_source_func_params[0] = k;
n++;
if (get_conf_parameter_single(buf, &pos, len, word_buf, sizeof(word_buf)) > 0)
{
k = atoi(word_buf);
inst_inf->validate_source_func_params[1] = k;
n++;
}
}
break;
case 19: // ValidateTargetFunc
k = recognize_conf_parameter(buf, &pos, len, creature_instances_validate_func_type);
if (k > 0)
{
inst_inf->validate_func_idx[1] = k;
inst_inf->validate_target_func = k;
n++;
}
if (get_conf_parameter_single(buf, &pos, len, word_buf, sizeof(word_buf)) > 0)
{
k = atoi(word_buf);
inst_inf->validate_target_func_params[0] = k;
n++;
if (get_conf_parameter_single(buf, &pos, len, word_buf, sizeof(word_buf)) > 0)
{
k = atoi(word_buf);
inst_inf->validate_target_func_params[1] = k;
n++;
}
}
break;
case 19: // SEARCH_TARGETS_FUNC
case 20: // SearchTargetsFunc
k = recognize_conf_parameter(buf, &pos, len, creature_instances_search_targets_func_type);
if (k > 0)
{
inst_inf->search_func_idx = k;
inst_inf->search_func = k;
n++;
}
if (get_conf_parameter_single(buf, &pos, len, word_buf, sizeof(word_buf)) > 0)
{
k = atoi(word_buf);
inst_inf->search_func_params[0] = k;
n++;
if (get_conf_parameter_single(buf, &pos, len, word_buf, sizeof(word_buf)) > 0)
{
k = atoi(word_buf);
inst_inf->search_func_params[1] = k;
n++;
}
}
break;
case ccr_comment:
Expand Down
4 changes: 2 additions & 2 deletions src/creature_control.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,8 @@ struct CreatureControl {
unsigned char party_objective;
unsigned long wait_to_turn;
short distance_to_destination;
short opponents_melee[COMBAT_MELEE_OPPONENTS_LIMIT];
short opponents_ranged[COMBAT_RANGED_OPPONENTS_LIMIT];
ThingIndex opponents_melee[COMBAT_MELEE_OPPONENTS_LIMIT];
ThingIndex opponents_ranged[COMBAT_RANGED_OPPONENTS_LIMIT];
unsigned char opponents_melee_count;
unsigned char opponents_ranged_count;
unsigned short players_prev_creature_idx;
Expand Down
Loading

0 comments on commit 97902cd

Please sign in to comment.