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

New config for creature: HostileTowards #3654

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
Open
2 changes: 2 additions & 0 deletions config/creatrs/imp.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ PrisonKind = NULL
; Defines the kind of creature it will become if it dies from torture.
; The same rule applies as above, except it does not consider the 'HUMANOID_SKELETON' property.
TortureKind = NULL
; The creature engages in combat with any defined creatures it encounters, regardless of alliance or ownership. Accepts ANY_CREATURE.
HostileTowards = NULL
; Creature properties:
; BLEEDS - the creature leaves blood when is hit, slapped, dying or being injured in any way.
; UNAFFECTED_BY_WIND - the creature isn't pushed back by Wind spell.
Expand Down
37 changes: 37 additions & 0 deletions src/config_crtrmodel.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ const struct NamedCommand creatmodel_attributes_commands[] = {
{"LAIROBJECT", 34},
{"PRISONKIND", 35},
{"TORTUREKIND", 36},
{"HOSTILETOWARDS", 37},
{NULL, 0},
};

Expand Down Expand Up @@ -285,6 +286,10 @@ TbBool parse_creaturemodel_attributes_blocks(long crtr_model,char *buf,long len,
crstat->can_go_locked_doors = false;
crstat->prison_kind = 0;
crstat->torture_kind = 0;
for (int i = 0; i < CREATURE_TYPES_MAX; i++)
{
crstat->hostile_towards[i] = 0;
}
crconf->namestr_idx = 0;
crconf->model_flags = 0;
}
Expand Down Expand Up @@ -884,6 +889,38 @@ TbBool parse_creaturemodel_attributes_blocks(long crtr_model,char *buf,long len,
COMMAND_TEXT(cmd_num), block_buf, config_textname);
}
break;
case 37: // HOSTILETOWARDS
for (int i = 0; i < CREATURE_TYPES_MAX; i++)
{
if (get_conf_parameter_single(buf, &pos, len, word_buf, sizeof(word_buf)) > 0)
{
k = get_id(creature_desc, word_buf);
if (k >= 0)
{
crstat->hostile_towards[i] = k;
n++;
}
else if (0 == strcmp(word_buf, "ANY_CREATURE"))
{
crstat->hostile_towards[i] = CREATURE_ANY;
n++;
}
else
{
crstat->hostile_towards[i] = 0;
if (strcasecmp(word_buf, "NULL") == 0)
{
n++;
}
}
}
}
if (n < 1)
{
CONFWRNLOG("Incorrect value of \"%s\" parameter in [%s] block of %s file of creature %s.",
COMMAND_TEXT(cmd_num), block_buf, config_textname, creature_code_name(crtr_model));
}
break;
case ccr_comment:
break;
case ccr_endOfFile:
Expand Down
1 change: 1 addition & 0 deletions src/creature_control.h
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,7 @@ struct CreatureStats { // These stats are not compatible with original DK - they
unsigned char swipe_idx;
ThingModel prison_kind;
ThingModel torture_kind;
ThingModel hostile_towards[CREATURE_TYPES_MAX];
struct CreaturePickedUpOffset creature_picked_up_offset;
};

Expand Down
87 changes: 67 additions & 20 deletions src/creature_states.c
Original file line number Diff line number Diff line change
Expand Up @@ -4128,59 +4128,106 @@ TbBool process_creature_hunger(struct Thing *thing)
return false;
}

TbBool creature_is_hostile_towards(const struct Thing *fightng, const struct Thing *enmtng)
{
struct CreatureStats* crstat = creature_stats_get_from_thing(fightng);
for (int i = 0; i < CREATURE_TYPES_MAX; i++)
{
if ((crstat->hostile_towards[i] == enmtng->model) || (crstat->hostile_towards[i] == CREATURE_ANY))
{
return true;
}
}
return false;
}

TbBool creature_can_be_hostile(const struct Thing *fightng, const struct Thing *enmtng)
{
// Creatures cannot be hostile towards allies if influenced by CTA.
if (creature_affected_by_call_to_arms(fightng) || creature_affected_by_call_to_arms(enmtng))
{
return false;
}
// Creatures cannot be hostile towards allies if it's part of a group.
if (creature_is_group_member(fightng) || creature_is_group_member(enmtng))
{
return false;
}
// Creatures cannot be hostile towards allies if they are working.
if ((get_creature_state_type(fightng) == CrStTyp_Work) || (get_creature_state_type(enmtng) == CrStTyp_Work))
{
return false;
}
// Lastly, check if both creatures doesn't have hostility set between each other.
if (!creature_is_hostile_towards(fightng, enmtng) && !creature_is_hostile_towards(enmtng, fightng))
{
return false;
}
return true;
}

/**
* Checks if creatures can attack each other.
* Note that this function does not include full check from players_are_enemies(),
* so both should be used when applicable.
* Note that this function does not include full check from players_are_enemies(), so both should be used when applicable.
* @param tng1
* @param tng2
* @return
* @see players_are_enemies()
*/
TbBool creature_will_attack_creature(const struct Thing *fightng, const struct Thing *enmtng)
{
if (creature_is_leaving_and_cannot_be_stopped(fightng) || creature_is_leaving_and_cannot_be_stopped(enmtng)) {
if (creature_is_leaving_and_cannot_be_stopped(fightng) || creature_is_leaving_and_cannot_be_stopped(enmtng))
{
return false;
}
if (creature_is_being_unconscious(fightng) || creature_is_being_unconscious(enmtng)) {
if (creature_is_being_unconscious(fightng) || creature_is_being_unconscious(enmtng))
{
return false;
}
if (thing_is_picked_up(fightng) || thing_is_picked_up(enmtng)) {
if (thing_is_picked_up(fightng) || thing_is_picked_up(enmtng))
{
return false;
}
struct CreatureControl* fighctrl = creature_control_get_from_thing(fightng);
struct CreatureControl* enmctrl = creature_control_get_from_thing(enmtng);
if (players_creatures_tolerate_each_other(fightng->owner, enmtng->owner))
if ((players_creatures_tolerate_each_other(fightng->owner, enmtng->owner)) && (!creature_can_be_hostile(fightng, enmtng)))
{
if (((fighctrl->spell_flags & CSAfF_MadKilling) == 0)
&& ((enmctrl->spell_flags & CSAfF_MadKilling) == 0)) {
if (fighctrl->combat_flags == 0) {
if (((fighctrl->spell_flags & CSAfF_MadKilling) == 0)
&& ((enmctrl->spell_flags & CSAfF_MadKilling) == 0))
{
if (fighctrl->combat_flags == 0)
{
return false;
}
struct Thing* tmptng = thing_get(fighctrl->combat.battle_enemy_idx);
TRACE_THING(tmptng);
if (tmptng->index != enmtng->index) {
if (tmptng->index != enmtng->index)
{
return false;
}
}
// No self fight
if (enmtng->index == fightng->index) {
return false;
}
}
// No fight when creature in custody
// No self fight.
if (enmtng->index == fightng->index)
{
return false;
}
// No fight when creature in custody.
if (creature_is_kept_in_custody_by_player(fightng, enmtng->owner)
|| creature_is_kept_in_custody_by_player(enmtng, fightng->owner)) {
|| creature_is_kept_in_custody_by_player(enmtng, fightng->owner))
{
return false;
}
// No fight while dropping
if (creature_is_being_dropped(fightng) || creature_is_being_dropped(enmtng)) {
// No fight while dropping.
if (creature_is_being_dropped(fightng) || creature_is_being_dropped(enmtng))
{
return false;
}
// Final check - if creature is in control and can see the enemy - fight
// Final check - if creature is in control and can see the enemy - fight.
if ((creature_control_exists(enmctrl)) && ((enmctrl->flgfield_1 & CCFlg_NoCompControl) == 0))
{
if (!creature_is_invisible(enmtng) || creature_can_see_invisible(fightng)) {
if (!creature_is_invisible(enmtng) || creature_can_see_invisible(fightng))
{
return true;
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/creature_states.h
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,8 @@ TbBool creature_is_kept_in_custody_by_enemy(const struct Thing *thing);
TbBool creature_is_kept_in_custody_by_player(const struct Thing *thing, PlayerNumber plyr_idx);
short player_keeping_creature_in_custody(const struct Thing* thing);
TbBool creature_state_is_unset(const struct Thing *thing);
TbBool creature_is_hostile_towards(const struct Thing *tng1, const struct Thing *tng2);
TbBool creature_can_be_hostile(const struct Thing *tng1, const struct Thing *tng2);
TbBool creature_will_attack_creature(const struct Thing *tng1, const struct Thing *tng2);
TbBool creature_will_attack_creature_incl_til_death(const struct Thing *tng1, const struct Thing *tng2);
// Compound checks for specific cases
Expand Down
30 changes: 30 additions & 0 deletions src/lvl_script_commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -2838,6 +2838,25 @@ static void set_creature_configuration_check(const struct ScriptLine* scline)
value1 = get_id(creature_desc, scline->tp[2]);
}
}
else if (creatvar == 37) // HOSTILETOWARDS
{
if (parameter_is_number(scline->tp[2])) // Support name or number for hostile towards.
{
value1 = atoi(scline->tp[2]);
}
else if (0 == strcmp(scline->tp[2], "ANY_CREATURE")) // Support ANY_CREATURE for hostile towards.
{
value1 = CREATURE_ANY;
}
else if (strcasecmp(scline->tp[2], "NULL") == 0) // Support NULL for hostile towards.
{
value1 = 0;
}
else
{
value1 = get_id(creature_desc, scline->tp[2]);
}
}
else
{
value1 = atoi(scline->tp[2]);
Expand Down Expand Up @@ -3124,6 +3143,17 @@ static void set_creature_configuration_process(struct ScriptContext* context)
case 36: // TORTUREKIND
crstat->torture_kind = value;
break;
case 37: // HOSTILETOWARDS
// Assume the mapmaker wants to reset it.
for (int i = 0; i < CREATURE_TYPES_MAX; i++)
{
crstat->hostile_towards[i] = 0;
}
if (value != 0)
{
crstat->hostile_towards[0] = value; // Then apply the change on the first only.
}
break;
case ccr_comment:
break;
case ccr_endOfFile:
Expand Down