Skip to content

Commit

Permalink
bug: trolls were not infighting due to tp wildcard failure
Browse files Browse the repository at this point in the history
  • Loading branch information
goblinhack committed Jul 18, 2023
1 parent 1db7de3 commit d535d47
Show file tree
Hide file tree
Showing 22 changed files with 425 additions and 151 deletions.
3 changes: 2 additions & 1 deletion python/things/monsters/troll_fire.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

def on_born(me, x, y):
my.thing_enemy(me, "is_ogre")
my.thing_friend(me, "is_troll")
my.thing_friend(me, "troll_fire")
my.thing_enemy(me, "troll_stone")
my.thing_enemy(me, "is_ettin")


Expand Down
3 changes: 2 additions & 1 deletion python/things/monsters/troll_stone.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

def on_born(me, x, y):
my.thing_enemy(me, "is_ogre")
my.thing_friend(me, "is_troll")
my.thing_friend(me, "troll_stone")
my.thing_enemy(me, "troll_fire")
my.thing_enemy(me, "is_ettin")


Expand Down
1 change: 0 additions & 1 deletion src/dungeon.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
//
// Copyright Neil McGill, goblinhack@gmail.com
// See the LICENSE file for license.
//

#include "my_array_bounds_check.hpp"
Expand Down
1 change: 1 addition & 0 deletions src/game_load.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ std::istream &operator>>(std::istream &in, Bits< ThingAip & > my)
in >> bits(my.t->can_see_currently.can_see);
in >> bits(my.t->can_see_ever.can_see);
in >> bits(my.t->thing_enemies);
in >> bits(my.t->thing_attackers);
in >> bits(my.t->perma_enemies);
in >> bits(my.t->thing_friends);
in >> bits(my.t->perma_friends);
Expand Down
1 change: 1 addition & 0 deletions src/game_save.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ std::ostream &operator<<(std::ostream &out, Bits< ThingAip & > const my)
out << bits(my.t->can_see_currently.can_see);
out << bits(my.t->can_see_ever.can_see);
out << bits(my.t->thing_enemies);
out << bits(my.t->thing_attackers);
out << bits(my.t->perma_enemies);
out << bits(my.t->thing_friends);
out << bits(my.t->perma_friends);
Expand Down
15 changes: 8 additions & 7 deletions src/my_monst.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -358,13 +358,14 @@ typedef struct ThingAi_ {

point wander_dest {0, 0};

std::set< TpId > perma_enemies {}; // List of thing types that wronged us
std::set< TpId > perma_friends {}; // List of friends
std::set< ThingId > thing_friends {}; // List of friends
//
std::map< ThingId, int > thing_enemies {}; // List of things that wronged us
std::map< ThingId, int > avoid {}; // List of things that wronged us and need to be avoided
std::map< ThingId, int > goal_penalty {}; // Helps to avoid goal oscillation
std::set< TpId > perma_enemies {}; // List of thing types that wronged us
std::set< TpId > perma_friends {}; // List of friends
std::set< ThingId > thing_friends {}; // List of friends
//
std::map< ThingId, int > thing_enemies {}; // List of things that we want to attack
std::map< ThingId, int > thing_attackers {}; // List of things that attacked us
std::map< ThingId, int > avoid {}; // List of things that wronged us and need to be avoided
std::map< ThingId, int > goal_penalty {}; // Helps to avoid goal oscillation

std::vector< point > move_path;

Expand Down
3 changes: 3 additions & 0 deletions src/my_thing.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,7 @@ typedef class Thing_
bool inventory_shortcuts_remove(Thingp what, DropOptions);
bool inventory_shortcuts_remove(Thingp what, Thingp target, DropOptions);
bool is_adjacent(const Thingp);
bool is_attacker(Thingp it);
bool is_blocking_terrain(const Thingp it);
bool is_bloodied(void);
bool is_carrying_an_item(void);
Expand Down Expand Up @@ -2634,6 +2635,7 @@ typedef class Thing_
void achieve_goals_in_death(void);
void achieve_goals_in_life(void);
void acid_tick(void);
void add_attacker(Thingp attacker, bool is_recursing = false);
void add_avoid(Thingp attacker);
void add_enemy(Thingp attacker, bool is_recursing = false);
void add_enemy(Tpp attacker);
Expand All @@ -2647,6 +2649,7 @@ typedef class Thing_
void ai_log(const std::string &msg, Thingp it);
void animate_choose_tile(Tilemap *tmap, std::vector< Tilep > *tiles, bool *next_frame_please);
void animate(void);
void attackers_tick(void);
void avoid_tick(void);
void awake(void);
void barrel_tick(void);
Expand Down
5 changes: 3 additions & 2 deletions src/my_thing_template.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3169,12 +3169,13 @@ class Tp
inline int gfx_pixelart_animated(void) const { return _gfx_pixelart_animated; }
};

std::vector< class Tp * > tp_find_wildcard(const std::string &name);
std::vector< class Tp * > tp_find_wildcard(Levelp, point p, const std::string &name);

class Tp *string2tp(const char **s);
class Tp *string2tp(const std::string &s, int *len);
class Tp *string2tp(const std::wstring &s, int *len);
class Tp *tp_find(const std::string &name);
class Tp *tp_find_wildcard(const std::string &name);
class Tp *tp_find_wildcard(Levelp, point p, const std::string &name);
class Tp *tp_find(uint32_t id);
class Tp *tp_load(int id, const std::string &file, const std::string &long_name, const std::string &sh_name);
class Tp *tp_random_ascend_dungeon(void);
Expand Down
43 changes: 17 additions & 26 deletions src/py_thing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "my_monst.hpp"
#include "my_python.hpp"
#include "my_string.hpp"
#include "my_template.hpp"
#include "my_thing.hpp"

static int NO_VALUE = -99999;
Expand Down Expand Up @@ -144,7 +145,8 @@ PyObject *thing_shoot_at(PyObject *obj, PyObject *args, PyObject *keywds)
IF_DEBUG { owner->log("Fire %s at %s", item, target->to_short_string().c_str()); }

auto what = std::string(item);
auto itemp = tp_find_wildcard(what);
auto cands = tp_find_wildcard(what);
auto itemp = pcg_one_of(cands);
if (! itemp) {
ERR("%s: Cannot find item to fire %s", __FUNCTION__, item);
Py_RETURN_FALSE;
Expand Down Expand Up @@ -408,7 +410,8 @@ PyObject *thing_carry(PyObject *obj, PyObject *args, PyObject *keywds)
Py_RETURN_FALSE;
}

auto tp = tp_find_wildcard(what);
auto cands = tp_find_wildcard(what);
auto tp = pcg_one_of(cands);
if (unlikely(! tp)) {
t->err("Could not find to carry %s", what);
Py_RETURN_FALSE;
Expand Down Expand Up @@ -461,18 +464,9 @@ PyObject *thing_enemy(PyObject *obj, PyObject *args, PyObject *keywds)
}

bool got_one = false;
auto tp = tp_find_wildcard(what);

if (tp) {
for (auto tp : tp_find_wildcard(what)) {
t->add_enemy(tp);
got_one = true;
} else {
for (auto &tp : tp_id_map) {
if (tp->matches(what)) {
t->add_enemy(tp);
got_one = true;
}
}
}

if (! got_one) {
Expand Down Expand Up @@ -513,17 +507,9 @@ PyObject *thing_friend(PyObject *obj, PyObject *args, PyObject *keywds)
}

bool got_one = false;
auto tp = tp_find_wildcard(what);
if (tp) {
for (auto tp : tp_find_wildcard(what)) {
t->add_friend(tp);
got_one = true;
} else {
for (auto &tp : tp_id_map) {
if (tp->matches(what)) {
t->add_friend(tp);
got_one = true;
}
}
}

if (! got_one) {
Expand Down Expand Up @@ -598,7 +584,8 @@ PyObject *thing_polymorph(PyObject *obj, PyObject *args, PyObject *keywds)
Py_RETURN_FALSE;
}

auto tp = tp_find_wildcard(into);
auto cands = tp_find_wildcard(into);
auto tp = pcg_one_of(cands);
if (unlikely(! tp)) {
ERR("%s: No polymorph into %s found", __FUNCTION__, into);
Py_RETURN_FALSE;
Expand Down Expand Up @@ -794,7 +781,8 @@ PyObject *thing_buff_add(PyObject *obj, PyObject *args, PyObject *keywds)
Py_RETURN_FALSE;
}

auto tp = tp_find_wildcard(what);
auto cands = tp_find_wildcard(what);
auto tp = pcg_one_of(cands);
if (unlikely(! tp)) {
ERR("%s: No buff tp called %s found", __FUNCTION__, what);
Py_RETURN_FALSE;
Expand Down Expand Up @@ -833,7 +821,8 @@ PyObject *thing_debuff_add(PyObject *obj, PyObject *args, PyObject *keywds)
Py_RETURN_FALSE;
}

auto tp = tp_find_wildcard(what);
auto cands = tp_find_wildcard(what);
auto tp = pcg_one_of(cands);
if (unlikely(! tp)) {
ERR("%s: No debuff tp called %s found", __FUNCTION__, what);
Py_RETURN_FALSE;
Expand Down Expand Up @@ -872,7 +861,8 @@ PyObject *thing_buff_remove(PyObject *obj, PyObject *args, PyObject *keywds)
Py_RETURN_FALSE;
}

auto tp = tp_find_wildcard(what);
auto cands = tp_find_wildcard(what);
auto tp = pcg_one_of(cands);
if (unlikely(! tp)) {
ERR("%s: No buff tp called %s found", __FUNCTION__, what);
Py_RETURN_FALSE;
Expand Down Expand Up @@ -911,7 +901,8 @@ PyObject *thing_debuff_remove(PyObject *obj, PyObject *args, PyObject *keywds)
Py_RETURN_FALSE;
}

auto tp = tp_find_wildcard(what);
auto cands = tp_find_wildcard(what);
auto tp = pcg_one_of(cands);
if (unlikely(! tp)) {
ERR("%s: No debuff tp called %s found", __FUNCTION__, what);
Py_RETURN_FALSE;
Expand Down
56 changes: 39 additions & 17 deletions src/thing_ai.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@
#include "my_thing_attack_options.hpp"

#define GOAL_PRIO_VERY_HIGH 0
#define GOAL_PRIO_HIGH 1
#define GOAL_PRIO_MED 2
#define GOAL_PRIO_LOW 3
#define GOAL_PRIO_VERY_LOW 4
#define GOAL_PRIO_HIGHER 1
#define GOAL_PRIO_HIGH 2
#define GOAL_PRIO_MED 3
#define GOAL_PRIO_LOW 4
#define GOAL_PRIO_VERY_LOW 5

bool operator<(const class Goal &lhs, const class Goal &rhs)
{
Expand Down Expand Up @@ -1124,27 +1125,27 @@ void Thing::ai_choose_can_see_goals(std::multiset< Goal > &goals, int minx, int
is_dangerous(it) ? ", is dangerous" : "", is_to_be_avoided(it) ? ", is to be avoided" : "");
TRACE_AND_INDENT();

if (is_enemy(it) && (dist <= max_dist)) {
AI_LOG("Is enemy and is close");
if (is_attacker(it) && (dist <= max_dist)) {
AI_LOG("Is attacker and is close");
if (! is_fearless() && (is_to_be_avoided(it) || is_dangerous(it)) && (health() < health_max() / 2)) {
//
// Low on health. Best to avoid this enemy.
// Low on health. Best to avoid this attacker.
//
AI_LOG("Low on health, best to avoid enemy");
AI_LOG("Low on health, best to avoid attacker");
if (cannot_avoid(it)) {
AI_LOG("Cannot avoid enemy", it);
GOAL_ADD(GOAL_PRIO_HIGH, (int) (max_dist - dist) * health_diff - goal_penalty,
"attack-enemy-i-cannot-avoid", it);
AI_LOG("Cannot avoid attacker", it);
GOAL_ADD(GOAL_PRIO_VERY_HIGH, (int) (max_dist - dist) * health_diff - goal_penalty,
"attack-attacker-i-cannot-avoid", it);
} else {
int avoid_score = ((max_dist - dist) * health_diff) - goal_penalty;
GOAL_AVOID_ADD(GOAL_PRIO_VERY_HIGH, avoid_score, "avoid-monst", it);
}
} else {
//
// The closer an enemy is (something that attacked us), the higher the score
// The closer an attacker is (something that attacked us), the higher the score
//
GOAL_ADD(GOAL_PRIO_VERY_HIGH, aggression_pct() + (int) (max_dist - dist) * health_diff - goal_penalty,
"attack-enemy", it);
"attack-attacker", it);
}
} else if (! is_fearless() && (dist < distance_avoid_get()) && will_avoid_monst(it)) {
//
Expand All @@ -1153,22 +1154,43 @@ void Thing::ai_choose_can_see_goals(std::multiset< Goal > &goals, int minx, int
AI_LOG("Not fearless and monst is close");
if (cannot_avoid(it)) {
AI_LOG("Cannot avoid monst", it);
GOAL_ADD(GOAL_PRIO_HIGH, (int) (max_dist - dist) * health_diff, "attack-monst-i-cannot-avoid", it);
GOAL_ADD(GOAL_PRIO_HIGHER, (int) (max_dist - dist) * health_diff, "attack-monst-i-cannot-avoid", it);
} else {
//
// Higher score the closer you are.
//
int avoid_score = ((max_dist - dist) * health_diff);
GOAL_AVOID_ADD(GOAL_PRIO_VERY_HIGH, avoid_score, "avoid-monst", it);
GOAL_AVOID_ADD(GOAL_PRIO_HIGHER, avoid_score, "avoid-monst", it);
}
} else if (is_enemy(it) && (dist <= max_dist)) {
AI_LOG("Is enemy and is close");
if (! is_fearless() && (is_to_be_avoided(it) || is_dangerous(it)) && (health() < health_max() / 2)) {
//
// Low on health. Best to avoid this enemy.
//
AI_LOG("Low on health, best to avoid enemy");
if (cannot_avoid(it)) {
AI_LOG("Cannot avoid enemy", it);
GOAL_ADD(GOAL_PRIO_HIGHER, (int) (max_dist - dist) * health_diff - goal_penalty,
"attack-enemy-i-cannot-avoid", it);
} else {
int avoid_score = ((max_dist - dist) * health_diff) - goal_penalty;
GOAL_AVOID_ADD(GOAL_PRIO_HIGHER, avoid_score, "avoid-monst", it);
}
} else {
//
// The closer an enemy is (something that attacked us), the higher the score
//
GOAL_ADD(GOAL_PRIO_HIGHER, aggression_pct() + (int) (max_dist - dist) * health_diff - goal_penalty,
"attack-enemy", it);
}
} else if (it->is_mob() && is_able_to_attack_mobs()) {
//
// Very close, very high priority attack as they can spawn much danger!
//
AI_LOG("Very close and can attack mob");

GOAL_ADD(GOAL_PRIO_VERY_HIGH,
200 + aggression_pct() + (int) (max_dist - dist) * health_diff - goal_penalty,
GOAL_ADD(GOAL_PRIO_HIGH, 200 + aggression_pct() + (int) (max_dist - dist) * health_diff - goal_penalty,
"attack-nearby-mob", it);
} else if ((it->is_alive_monst() || it->is_player()) && possible_to_attack(it)) {
//
Expand Down
20 changes: 13 additions & 7 deletions src/thing_attack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,13 @@ bool Thing::possible_to_attack(const Thingp victim)
return true;
}

if (is_attacker(victim)) {
if (is_debug_type()) {
dbg("Can attack attacker %s", victim->to_short_string().c_str());
}
return true;
}

if (is_weapon()) {
if (victim->is_sticky() || victim->is_spiderweb()) {
if (is_able_to_break_out_of_webs()) {
Expand Down Expand Up @@ -1552,6 +1559,12 @@ bool Thing::attack(Thingp victim, ThingAttackOptionsp attack_options)
bonus_to_string(victim_def_bonus).c_str(), to_hit, i_rolled, hit ? "hit" : "miss");
}

//
// Hit or miss, an attempt at an attack counts
//
victim->wake("missed, but should still wake");
victim->add_attacker(this);

//
// Cannot miss (if engulfing?)
//
Expand Down Expand Up @@ -1592,13 +1605,6 @@ bool Thing::attack(Thingp victim, ThingAttackOptionsp attack_options)
lunge(victim->curr_at);
}

//
// An attempt at an attack counts
//
if (victim->wake("missed, but should still wake")) {
victim->add_enemy(this);
}

//
// See if armor crumbles
//
Expand Down

0 comments on commit d535d47

Please sign in to comment.