Go to the documentation of this file.
56 #define MIN_MON_RADIUS 3
82 else if (
npc->enemy == NULL)
112 ||
npc->enemy == owner))
190 if (nx ==
npc->x && ny ==
npc->y) {
209 LOG(
llevDebug,
"monster_find_nearest_living_creature: map %s (%d,%d) has is_alive set but did not find a monster?\n",
m->path, nx, ny);
235 object *attacker, *
tmp = NULL;
237 attacker =
npc->attacked_by;
238 npc->attacked_by = NULL;
275 if (attacker->
count ==
npc->attacked_by_count) {
297 snprintf(
buf,
sizeof(
buf),
"Halt, %s, you are under arrest!",
npc->enemy->name);
348 &&
op->map->darkness > 0
353 int dark = radius/(
op->map->darkness);
385 if (talked && strlen(talked) > 0) {
402 for (i = 0; i < 15; i++) {
410 #define MAX_EXPLORE 5000
444 uint16_t dx =
FABS(ax - bx), dy =
FABS(ay - by);
445 uint16_t diag =
MIN(dx, dy);
446 return (
MAX(dx, dy) - diag) * 2 + diag * 3;
472 if (target->
map != source->
map)
477 const uint16_t map_height = cur_map->
height;
481 const int size = cur_map->
width * map_height;
523 for (i = 1; i <= 8; ++i)
553 distance =
static_cast<path_data *
>(malloc(size *
sizeof(*distance)));
554 if (distance == NULL) {
561 memset(distance, 255,
sizeof(*distance) * size);
564 current = &distance[map_height * target->
x + target->
y];
582 for (i = 1; i < 8; ++i) {
588 for (i = 0; i < 8; ++i) {
589 uint16_t new_distance;
594 dir =
absdir(default_dir+4+dirs[i]);
598 if (
x == source->
x &&
y == source->
y) {
610 const path_data *newloc = &distance[map_height * newx + newy];
633 assert(map_height *
x +
y >= 0);
634 assert(map_height *
x +
y < size);
637 explore = &distance[map_height *
x +
y];
641 int16_t move_penalty = 0;
643 if (terrain_value > 0) {
651 move_penalty += (int16_t)
tmp->move_slow_penalty;
665 const int base_move_cost = ((dir & 1) == 0 ? 3 : 2);
671 + (move_penalty != 0 && terrain_value != 0 ? base_move_cost + base_move_cost * move_penalty * terrain_value / 2 : base_move_cost);
674 if (explore->
distance <= new_distance)
726 if (
op->stats.Con > 0 &&
op->stats.hp <
op->stats.maxhp) {
736 op->last_heal += (
int)((
float)(8*
op->stats.Con)/
FABS(
op->speed));
737 op->stats.hp =
MIN((int32_t)
op->stats.hp+
op->last_heal/32,
op->stats.maxhp);
742 &&
op->stats.hp >= (int16_t)((int32_t)
op->run_away *
op->stats.maxhp / 100))
753 if (
op->stats.Pow > 0 &&
op->stats.sp <
op->stats.maxsp) {
763 op->last_sp += (
int)((
float)(8*
op->stats.Pow)/
FABS(
op->speed));
764 op->stats.sp =
MIN(
op->stats.sp+
op->last_sp/128,
op->stats.maxsp);
797 if (
op->attack_movement&
HI4) {
798 switch (
op->attack_movement&
HI4) {
858 object *owner, *enemy, *part;
927 if (
op->race != NULL && strcmp(
op->race,
"doppleganger") == 0) {
943 op->facing =
op->direction;
1010 LOG(
llevMonster,
"monster %s (%d, %d on %s) can't reach enemy %s (%d, %d on %s)\n",
1011 op->name,
op->x,
op->y,
op->map ?
op->map->name :
"(unknown map)", enemy->
name, enemy->
x, enemy->
y, enemy->
map ? enemy->
map->
path :
"(unknown map)");
1018 switch (
op->attack_movement&
LO4) {
1064 for (diff = 1; diff <= maxdiff; diff++) {
1097 if (nearest_player && nearest_player != enemy && !
monster_can_hit(part, enemy, &rv)) {
1099 enemy = nearest_player;
1156 for (more =
ob2->more; more != NULL; more = more->
more) {
1188 assert(spell_ob != NULL);
1212 #define MAX_KNOWN_SPELLS 20
1248 return altern[
RANDOM()%i];
1284 if (owner != NULL) {
1301 if (spell_item == NULL) {
1307 if (!spell_item->
inv) {
1308 LOG(
llevError,
"spellbook %s does not contain a spell?\n", spell_item->
name);
1311 spell_item = spell_item->
inv;
1337 return cast_spell(part, part, dir, spell_item, NULL);
1371 if (owner != NULL) {
1448 if (owner != NULL) {
1473 LOG(
llevDebug,
"Error: Monster %s (%d) has FLAG_READY_SKILL without skill.\n", head->
name, head->
count);
1497 int at_least_one = 0;
1505 if (owner != NULL) {
1516 if (wand->type ==
WAND) {
1519 if (wand->stats.food <= 0)
1529 if (wand->type ==
ROD && wand->inv) {
1532 if (wand->stats.hp <
MAX(wand->inv->stats.sp, wand->inv->stats.grace))
1550 LOG(
llevError,
"Error: Monster %s (%d) HAS_READY_RANG() without wand/horn/rod.\n", head->
name, head->
count);
1596 while (
x !=
pl->x ||
y !=
pl->y ||
map !=
pl->map) {
1601 LOG(
llevError,
"monster_use_bow: no map but still path exists??\n");
1606 if (owner && owner->
x ==
x && owner->
y ==
y && owner->
map ==
map)
1617 return fire_bow(head, NULL, dir, 0, part->
x, part->
y);
1632 val =
item->stats.dam;
1633 val +=
item->magic*3;
1659 if (other_weap == NULL)
1683 val =
item->stats.ac;
1685 val +=
item->magic*3;
1702 object *other_armour;
1706 if (other_armour == NULL)
1718 if (
item->resist[i] > other_armour->
resist[i])
1720 else if (
item->resist[i] < other_armour->
resist[i])
1794 }
else if (
item->type ==
BOW) {
1856 for (part = monster; part != NULL; part = part->
more)
1867 if (
tmp->weight > 0) {
1868 int32_t weight_limit;
1876 nrof =
MAX(1,
tmp->nrof);
1917 else switch (
item->type) {
1967 if (((!(monster->
pick_up&32)) && flag) || ((monster->
pick_up&32) && (!flag)))
1980 switch (
tmp->type) {
2002 if (!monster->
head) {
2016 int help_radius = 3;
2020 int override_help_radius;
2022 override_help_radius = strtol(
value, NULL, 10);
2023 if (override_help_radius >= 0 && override_help_radius < 30)
2024 help_radius = override_help_radius;
2026 LOG(
llevDebug,
"monster_npc_call_help: invalid help_radius %d\n", override_help_radius);
2029 for (
int x = -help_radius;
x <= help_radius;
x++)
2030 for (
int y = -help_radius;
y <= help_radius;
y++) {
2032 int16_t sx =
op->x+
x;
2033 int16_t sy =
op->y+
y;
2079 }
else if (
ob->move_status > 20)
2080 ob->move_status = 0;
2091 if (
ob->move_status++ < 25)
2093 else if (
ob->move_status < 50)
2095 ob->move_status = 0;
2111 if (
ob->move_status || inrange)
2114 if (
ob->move_status == 0)
2116 else if (
ob->move_status < 10)
2118 else if (
ob->move_status < 15)
2120 ob->move_status = 0;
2141 if (
ob->stats.maxhp && (
ob->stats.hp*100)/
ob->stats.maxhp <
ob->run_away)
2163 static const int circle [12] = { 3, 3, 4, 5, 5, 6, 7, 7, 8, 1, 1, 2 };
2165 if (++
ob->move_status > 11)
2166 ob->move_status = 0;
2176 static const int circle[20] = { 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 7, 7, 7, 8, 8, 1, 1, 1, 2, 2 };
2178 if (++
ob->move_status > 19)
2179 ob->move_status = 0;
2189 if (
ob->move_status++ > 6)
2190 ob->move_status = 0;
2191 if (
ob->move_status < 4)
2202 if (
ob->move_status++ > 6)
2203 ob->move_status = 0;
2204 if (
ob->move_status < 4)
2215 if (
ob->move_status++ > 16)
2216 ob->move_status = 0;
2217 if (
ob->move_status < 6)
2219 else if (
ob->move_status < 8)
2221 else if (
ob->move_status < 13)
2230 if (
ob->move_status++ > 16)
2231 ob->move_status = 0;
2232 if (
ob->move_status < 6)
2234 else if (
ob->move_status < 8)
2236 else if (
ob->move_status < 13)
2247 if (
ob->move_status < 1
2248 ||
ob->move_status > 8
2250 for (i = 0; i < 5; i++) {
2406 if (orig_map !=
op->map) {
2407 LOG(
llevDebug,
"Warning: Forced to swap out very recent map\n");
2419 snprintf(own,
sizeof(own),
"You say: %s", txt);
2420 snprintf(others,
sizeof(others),
"%s says: %s",
op->name, txt);
2478 value[0] =
'3' + rand() % 6;
2587 if (!
op || !enemy || !
op->map || !enemy->
map)
2615 hide_discovery =
op->stats.Int/5;
2622 int bonus = (
op->level/2)+(
op->stats.Int/5);
2626 if (sk_hide != NULL)
2627 bonus -= sk_hide->
level;
2629 LOG(
llevError,
"monster_can_detect_enemy() got hidden player w/o hiding skill!\n");
2634 bonus -= enemy->
level;
2637 hide_discovery += bonus*5;
2643 radius = radius/2, hide_discovery = hide_discovery/3;
2651 radius +=
op->map->darkness/2;
2653 radius -=
op->map->darkness/2;
2658 if (radius < MIN_MON_RADIUS && op->
map->darkness < 5 && rv->
distance <= 1)
2680 if (enemy->
hide && rv->
distance <= 1 &&
RANDOM()%100 <= (
unsigned int)hide_discovery) {
2685 "You are discovered by %s!",
2696 if (
RANDOM()%50 <= (
unsigned int)hide_discovery) {
2702 "You see %s noticing your position.",
2729 if (
op->glow_radius > 0)
2767 object *looker =
HEAD(
op);
2789 "Your light reveals your hiding spot!");
2792 }
else if (enemy->
hide)
bool object_value_set(const object *op, const char *const key)
#define GET_MAP_OB(M, X, Y)
int do_skill(object *op, object *part, object *skill, int dir, const char *string)
object * object_get_owner(object *op)
int path_to_player(object *mon, object *pl, unsigned mindiff)
static void monster_pace2_movev(object *ob)
static int monster_check_wakeup(object *op, object *enemy, rv_vector *rv)
static uint16_t estimate_distance(int16_t ax, int16_t ay, int16_t bx, int16_t by)
object * object_find_by_type_subtype(const object *who, int type, int subtype)
sstring replies[MAX_REPLIES]
void remove_friendly_object(object *op)
object * object_find_by_type_applied(const object *who, int type)
#define NUM_BODY_LOCATIONS
object * find_skill_by_number(object *who, int skillno)
void LOG(LogLevel logLevel, const char *format,...)
sstring replies_words[MAX_REPLIES]
#define CAN_APPLY_NOT_MASK
void monster_check_apply_all(object *monster)
#define QUERY_FLAG(xyz, p)
static int monster_disthit_att(int dir, object *ob, object *enemy, object *part, rv_vector *rv)
int pets_should_arena_attack(object *pet, object *owner, object *target)
void make_visible(object *op)
void stringbuffer_append_printf(StringBuffer *sb, const char *format,...)
#define WILL_APPLY_HANDLE
int cast_spell(object *op, object *caster, int dir, object *spell_ob, char *stringarg)
StringBuffer * stringbuffer_new(void)
#define FOR_BELOW_PREPARE(op_, it_)
void object_set_enemy(object *op, object *enemy)
static int monster_check_good_weapon(object *who, object *item)
object * monster_check_enemy(object *npc, rv_vector *rv)
static int monster_run_att(int dir, object *ob, object *enemy, object *part, rv_vector *rv)
void monster_check_doors(object *op, mapstruct *m, int x, int y)
#define FLAG_SEE_INVISIBLE
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...) PRINTF_ARGS(6
static void monster_check_pickup(object *monster)
static int monster_check_good_armour(object *who, object *item)
void fix_object(object *op)
#define FLAG_READY_SCROLL
static int monster_can_hit(object *ob1, object *ob2, rv_vector *rv)
object * get_nearest_criminal(object *mon)
int apply_manual(object *op, object *tmp, int aflag)
#define FOR_OB_AND_ABOVE_FINISH()
const char * object_get_value(const object *op, const char *const key)
static object * monster_find_enemy(object *npc, rv_vector *rv)
object * object_insert_in_ob(object *op, object *where)
object * get_nearest_player(object *mon)
int16_t resist[NROFATTACKS]
static void monster_rand_move(object *ob)
#define FOR_BELOW_FINISH()
object * monster_find_nearest_enemy(object *npc, object *owner)
#define FOR_OB_AND_ABOVE_PREPARE(op_)
#define SP_SUMMON_MONSTER
static int monster_wait_att2(int dir, rv_vector *rv)
object * object_find_by_type_and_race(const object *who, int type, const char *race)
static event_registration m
char * stringbuffer_finish(StringBuffer *sb)
void object_free_drop_inventory(object *ob)
object * pets_get_enemy(object *pet, rv_vector *rv)
sstring add_refcount(sstring str)
short freearr_y[SIZEOFFREE]
static int monster_wait_att(int dir, object *ob, object *enemy, object *part, rv_vector *rv)
static int monster_get_armour_quality(const object *item)
void query_name(const object *op, char *buf, size_t size)
int can_see_monsterP(mapstruct *m, int x, int y, int dir)
static int monster_get_weapon_quality(const object *item)
sstring stringbuffer_finish_shared(StringBuffer *sb)
int monster_can_see_enemy(object *op, object *enemy)
sstring add_string(const char *str)
static void monster_apply_below(object *monster)
void void ext_info_map(int color, const mapstruct *map, uint8_t type, uint8_t subtype, const char *str1)
int path_measure_func(const void *ob)
static void monster_circ2_move(object *ob)
int has_carried_lights(const object *op)
static void monster_pace2_moveh(object *ob)
static void monster_pace_moveh(object *ob)
#define GET_MAP_MOVE_BLOCK(M, X, Y)
static int is_enemy(object *who, object *owner)
int apply_can_apply_object(const object *who, const object *op)
#define FLAG_UNAGGRESSIVE
static object * monster_choose_random_spell(object *monster)
#define GET_MAP_LIGHT(M, X, Y)
mapstruct * get_map_from_coord(mapstruct *m, int16_t *x, int16_t *y)
#define FLAG_CAN_USE_SKILL
static int monster_can_pick(object *monster, object *item)
int16_t SP_level_spellpoint_cost(object *caster, object *spell, int flags)
static StringBuffer * monster_format_say(const object *npc, const char *message)
int monster_compute_path(object *source, object *target, int default_dir)
const Animations * animation
object * monster_find_throw_ob(object *op)
int ob_blocked(const object *ob, mapstruct *m, int16_t x, int16_t y)
void fatal(enum fatal_error err)
static int monster_hitrun_att(int dir, object *ob)
void monster_npc_call_help(object *op)
static int monster_use_range(object *head, object *part, object *pl, int dir)
void * minheap_remove(MinHeap *heap)
uint32_t get_weight_limit(int stat)
void free_string(sstring str)
void pets_move(object *ob)
int move_object(object *op, int dir)
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
#define OUT_OF_REAL_MAP(M, X, Y)
void get_search_arr(int *search_arr)
void ext_info_map_except(int color, const mapstruct *map, const object *op, uint8_t type, uint8_t subtype, const char *str1)
static void monster_circ1_move(object *ob)
#define MSG_TYPE_SKILL_FAILURE
static int monster_move_no_enemy(object *op)
int get_dialog_message(object *op, const char *text, struct_dialog_message **message, struct_dialog_reply **reply)
int object_can_pick(const object *who, const object *item)
int monster_can_detect_enemy(object *op, object *enemy, rv_vector *rv)
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, int16_t x, int16_t y, int16_t *nx, int16_t *ny)
void monster_do_say(const mapstruct *map, const char *message)
const typedef char * sstring
void animate_object(object *op, int dir)
object * object_split(object *orig_ob, uint32_t nr, char *err, size_t size)
static int monster_move_randomly(object *op)
int monster_move(object *op)
static int monster_use_skill(object *head, object *part, object *pl, int dir)
static int monster_use_bow(object *head, object *part, object *pl, int dir)
void pets_follow_owner(object *ob, object *owner)
int hit_player(object *op, int dam, object *hitter, uint32_t type, int full_hit)
int get_randomized_dir(int dir)
void do_hidden_move(object *op)
int on_same_map(const object *op1, const object *op2)
#define CLEAR_FLAG(xyz, p)
#define MSG_TYPE_DIALOG_MAGIC_EAR
void minheap_init_static(MinHeap *heap, void **arr, int amt, int(*measure_func)(const void *))
#define MSG_TYPE_DIALOG_NPC
int fire_bow(object *op, object *arrow, int dir, int wc_mod, int16_t sx, int16_t sy)
int get_rangevector(object *op1, const object *op2, rv_vector *retval, int flags)
static void monster_pace_movev(object *ob)
sstring npc_msgs[MAX_NPC]
int8_t body_info[NUM_BODY_LOCATIONS]
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
int monster_stand_in_light(object *op)
void object_remove(object *op)
void monster_do_living(object *op)
int player_can_view(object *pl, object *op)
void monster_npc_say(object *npc, const char *cp)
static int monster_talk_to_npc(object *npc, talk_info *info)
static int monster_use_scroll(object *head, object *part, object *pl, int dir)
int object_set_value(object *op, const char *key, const char *value, int add_key)
#define MSG_TYPE_COMMUNICATION
int8_t get_attr_value(const living *stats, int attr)
void drain_rod_charge(object *rod)
#define WILL_APPLY_TREASURE
int minheap_insert(MinHeap *heap, void *ob)
short freearr_x[SIZEOFFREE]
static int monster_cast_spell(object *head, object *part, object *pl, int dir)
int events_execute_object_say(object *npc, talk_info *talk)
int dirdiff(int dir1, int dir2)
int makes_invisible_to(object *pl, object *mon)
void monster_check_earthwalls(object *op, mapstruct *m, int x, int y)
const char * get_reply_text_own(reply_type rt)
static int monster_dist_att(int dir, object *enemy, object *part, rv_vector *rv)
#define FOR_INV_PREPARE(op_, it_)
#define MSG_TYPE_COMMUNICATION_SAY
void drain_wand_charge(object *wand)
static int monster_should_cast_spell(object *spell_ob)
void monster_communicate(object *op, const char *txt)
static int monster_do_talk_npc(object *npc, talk_info *info)
static void monster_check_apply(object *mon, object *item)
int is_true_undead(object *op)
void skill_attack(object *tmp, object *pl, int dir, const char *string, object *skill)
object * identify(object *op)
static const char * get_reply_text_other(reply_type rt)