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 = 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) {
607 const path_data *newloc = &distance[map_height * newx + newy];
627 assert(map_height *
x +
y >= 0);
628 assert(map_height *
x +
y < size);
631 explore = &distance[map_height *
x +
y];
635 int16_t move_penalty = 0;
637 if (terrain_value > 0) {
645 move_penalty += (int16_t)
tmp->move_slow_penalty;
659 const int base_move_cost = ((dir & 1) == 0 ? 3 : 2);
665 + (move_penalty != 0 && terrain_value != 0 ? base_move_cost + base_move_cost * move_penalty * terrain_value / 2 : base_move_cost);
668 if (explore->
distance <= new_distance)
720 if (
op->stats.Con > 0 &&
op->stats.hp <
op->stats.maxhp) {
730 op->last_heal += (
int)((
float)(8*
op->stats.Con)/
FABS(
op->speed));
731 op->stats.hp =
MIN((int32_t)
op->stats.hp+
op->last_heal/32,
op->stats.maxhp);
736 &&
op->stats.hp >= (int16_t)((int32_t)
op->run_away *
op->stats.maxhp / 100))
747 if (
op->stats.Pow > 0 &&
op->stats.sp <
op->stats.maxsp) {
757 op->last_sp += (
int)((
float)(8*
op->stats.Pow)/
FABS(
op->speed));
758 op->stats.sp =
MIN(
op->stats.sp+
op->last_sp/128,
op->stats.maxsp);
791 if (
op->attack_movement&
HI4) {
792 switch (
op->attack_movement&
HI4) {
852 object *owner, *enemy, *part;
921 if (
op->race != NULL && strcmp(
op->race,
"doppleganger") == 0) {
937 op->facing =
op->direction;
1004 LOG(
llevMonster,
"monster %s (%d, %d on %s) can't reach enemy %s (%d, %d on %s)\n",
1005 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)");
1012 switch (
op->attack_movement&
LO4) {
1058 for (diff = 1; diff <= maxdiff; diff++) {
1091 if (nearest_player && nearest_player != enemy && !
monster_can_hit(part, enemy, &rv)) {
1093 enemy = nearest_player;
1150 for (more =
ob2->more; more != NULL; more = more->
more) {
1182 assert(spell_ob != NULL);
1203 #define MAX_KNOWN_SPELLS 20
1239 return altern[
RANDOM()%i];
1275 if (owner != NULL) {
1292 if (spell_item == NULL) {
1298 if (!spell_item->
inv) {
1299 LOG(
llevError,
"spellbook %s does not contain a spell?\n", spell_item->
name);
1302 spell_item = spell_item->
inv;
1327 return cast_spell(part, part, dir, spell_item, NULL);
1361 if (owner != NULL) {
1438 if (owner != NULL) {
1463 LOG(
llevDebug,
"Error: Monster %s (%d) has FLAG_READY_SKILL without skill.\n", head->
name, head->
count);
1487 int at_least_one = 0;
1495 if (owner != NULL) {
1506 if (wand->type ==
WAND) {
1509 if (wand->stats.food <= 0)
1519 if (wand->type ==
ROD && wand->inv) {
1522 if (wand->stats.hp <
MAX(wand->inv->stats.sp, wand->inv->stats.grace))
1540 LOG(
llevError,
"Error: Monster %s (%d) HAS_READY_RANG() without wand/horn/rod.\n", head->
name, head->
count);
1586 while (
x !=
pl->x ||
y !=
pl->y ||
map !=
pl->map) {
1591 LOG(
llevError,
"monster_use_bow: no map but still path exists??\n");
1596 if (owner && owner->
x ==
x && owner->
y ==
y && owner->
map ==
map)
1607 return fire_bow(head, NULL, dir, 0, part->
x, part->
y);
1622 val =
item->stats.dam;
1623 val +=
item->magic*3;
1649 if (other_weap == NULL)
1673 val =
item->stats.ac;
1675 val +=
item->magic*3;
1692 object *other_armour;
1696 if (other_armour == NULL)
1708 if (
item->resist[i] > other_armour->
resist[i])
1710 else if (
item->resist[i] < other_armour->
resist[i])
1784 }
else if (
item->type ==
BOW) {
1846 for (part = monster; part != NULL; part = part->
more)
1857 if (
tmp->weight > 0) {
1858 int32_t weight_limit;
1866 nrof =
MAX(1,
tmp->nrof);
1907 else switch (
item->type) {
1957 if (((!(monster->
pick_up&32)) && flag) || ((monster->
pick_up&32) && (!flag)))
1970 switch (
tmp->type) {
1992 if (!monster->
head) {
2006 int help_radius = 3;
2010 int override_help_radius;
2012 override_help_radius = strtol(
value, NULL, 10);
2013 if (override_help_radius >= 0 && override_help_radius < 30)
2014 help_radius = override_help_radius;
2016 LOG(
llevDebug,
"monster_npc_call_help: invalid help_radius %d\n", override_help_radius);
2019 for (
int x = -help_radius;
x <= help_radius;
x++)
2020 for (
int y = -help_radius;
y <= help_radius;
y++) {
2022 int16_t sx =
op->x+
x;
2023 int16_t sy =
op->y+
y;
2069 }
else if (
ob->move_status > 20)
2070 ob->move_status = 0;
2081 if (
ob->move_status++ < 25)
2083 else if (
ob->move_status < 50)
2085 ob->move_status = 0;
2101 if (
ob->move_status || inrange)
2104 if (
ob->move_status == 0)
2106 else if (
ob->move_status < 10)
2108 else if (
ob->move_status < 15)
2110 ob->move_status = 0;
2131 if (
ob->stats.maxhp && (
ob->stats.hp*100)/
ob->stats.maxhp <
ob->run_away)
2153 static const int circle [12] = { 3, 3, 4, 5, 5, 6, 7, 7, 8, 1, 1, 2 };
2155 if (++
ob->move_status > 11)
2156 ob->move_status = 0;
2166 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 };
2168 if (++
ob->move_status > 19)
2169 ob->move_status = 0;
2179 if (
ob->move_status++ > 6)
2180 ob->move_status = 0;
2181 if (
ob->move_status < 4)
2192 if (
ob->move_status++ > 6)
2193 ob->move_status = 0;
2194 if (
ob->move_status < 4)
2205 if (
ob->move_status++ > 16)
2206 ob->move_status = 0;
2207 if (
ob->move_status < 6)
2209 else if (
ob->move_status < 8)
2211 else if (
ob->move_status < 13)
2220 if (
ob->move_status++ > 16)
2221 ob->move_status = 0;
2222 if (
ob->move_status < 6)
2224 else if (
ob->move_status < 8)
2226 else if (
ob->move_status < 13)
2237 if (
ob->move_status < 1
2238 ||
ob->move_status > 8
2240 for (i = 0; i < 5; i++) {
2396 if (orig_map !=
op->map) {
2397 LOG(
llevDebug,
"Warning: Forced to swap out very recent map\n");
2409 snprintf(own,
sizeof(own),
"You say: %s", txt);
2410 snprintf(others,
sizeof(others),
"%s says: %s",
op->name, txt);
2464 value[0] =
'3' + rand() % 6;
2573 if (!
op || !enemy || !
op->map || !enemy->
map)
2601 hide_discovery =
op->stats.Int/5;
2608 int bonus = (
op->level/2)+(
op->stats.Int/5);
2612 if (sk_hide != NULL)
2613 bonus -= sk_hide->
level;
2615 LOG(
llevError,
"monster_can_detect_enemy() got hidden player w/o hiding skill!\n");
2620 bonus -= enemy->
level;
2623 hide_discovery += bonus*5;
2629 radius = radius/2, hide_discovery = hide_discovery/3;
2637 radius +=
op->map->darkness/2;
2639 radius -=
op->map->darkness/2;
2644 if (radius < MIN_MON_RADIUS && op->
map->darkness < 5 && rv->
distance <= 1)
2666 if (enemy->
hide && rv->
distance <= 1 &&
RANDOM()%100 <= (
unsigned int)hide_discovery) {
2671 "You are discovered by %s!",
2682 if (
RANDOM()%50 <= (
unsigned int)hide_discovery) {
2688 "You see %s noticing your position.",
2715 if (
op->glow_radius > 0)
2753 object *looker =
HEAD(
op);
2775 "Your light reveals your hiding spot!");
2778 }
else if (enemy->
hide)
#define GET_MAP_OB(M, X, Y)
int do_skill(object *op, object *part, object *skill, int dir, const char *string)
uint32_t get_weight_limit(int stat)
int path_to_player(object *mon, object *pl, unsigned mindiff)
static int monster_check_wakeup(object *op, object *enemy, rv_vector *rv)
void monster_npc_call_help(object *op)
sstring add_refcount(sstring str)
sstring add_string(const char *str)
sstring replies[MAX_REPLIES]
void object_remove(object *op)
StringBuffer * stringbuffer_new(void)
void remove_friendly_object(object *op)
void object_set_enemy(object *op, object *enemy)
#define NUM_BODY_LOCATIONS
static int monster_check_good_weapon(object *who, object *item)
object * find_skill_by_number(object *who, int skillno)
sstring replies_words[MAX_REPLIES]
#define CAN_APPLY_NOT_MASK
static int monster_use_scroll(object *head, object *part, object *pl, int dir)
#define QUERY_FLAG(xyz, p)
static void monster_apply_below(object *monster)
int pets_should_arena_attack(object *pet, object *owner, object *target)
void make_visible(object *op)
object * monster_check_enemy(object *npc, rv_vector *rv)
#define WILL_APPLY_HANDLE
static void monster_check_apply(object *mon, object *item)
int cast_spell(object *op, object *caster, int dir, object *spell_ob, char *stringarg)
#define FOR_BELOW_PREPARE(op_, it_)
static int monster_run_att(int dir, object *ob, object *enemy, object *part, rv_vector *rv)
static object * monster_choose_random_spell(object *monster)
static int monster_get_armour_quality(const object *item)
#define FLAG_SEE_INVISIBLE
object * object_find_by_type_applied(const object *who, int type)
int ob_blocked(const object *ob, mapstruct *m, int16_t x, int16_t y)
static int monster_use_range(object *head, object *part, object *pl, int dir)
#define FLAG_READY_SCROLL
object * get_nearest_criminal(object *mon)
static int monster_use_bow(object *head, object *part, object *pl, int dir)
static int is_enemy(object *who, object *owner)
int get_rangevector(object *op1, const object *op2, rv_vector *retval, int flags)
void ext_info_map(int color, const mapstruct *map, uint8_t type, uint8_t subtype, const char *str1)
int8_t body_info[NUM_BODY_LOCATIONS]
static int monster_move_randomly(object *op)
int apply_manual(object *op, object *tmp, int aflag)
#define FOR_OB_AND_ABOVE_FINISH()
void monster_check_apply_all(object *monster)
static int monster_get_weapon_quality(const object *item)
static int monster_should_cast_spell(object *spell_ob)
void monster_npc_say(object *npc, const char *cp)
object * get_nearest_player(object *mon)
short freearr_x[SIZEOFFREE]
short freearr_y[SIZEOFFREE]
#define FOR_BELOW_FINISH()
void animate_object(object *op, int dir)
#define FOR_OB_AND_ABOVE_PREPARE(op_)
const char * object_get_value(const object *op, const char *const key)
struct obj * chosen_skill
#define SP_SUMMON_MONSTER
void free_string(sstring str)
static event_registration m
void monster_check_earthwalls(object *op, mapstruct *m, int x, int y)
int has_carried_lights(const object *op)
object * object_find_by_type_subtype(const object *who, int type, int subtype)
int monster_stand_in_light(object *op)
object * pets_get_enemy(object *pet, rv_vector *rv)
void * minheap_remove(MinHeap *heap)
void query_name(const object *op, char *buf, size_t size)
sstring stringbuffer_finish_shared(StringBuffer *sb)
void monster_do_say(const mapstruct *map, const char *message)
int minheap_insert(MinHeap *heap, void *ob)
const char * get_reply_text_own(reply_type rt)
int get_randomized_dir(int dir)
static int monster_talk_to_npc(object *npc, talk_info *info)
static StringBuffer * monster_format_say(const object *npc, const char *message)
static int monster_do_talk_npc(object *npc, talk_info *info)
void minheap_init_static(MinHeap *heap, void **arr, int amt, int(*measure_func)(const void *))
void fatal(enum fatal_error err)
static int monster_hitrun_att(int dir, object *ob)
int object_can_pick(const object *who, const object *item)
int monster_move(object *op)
static void monster_pace2_movev(object *ob)
static void monster_circ2_move(object *ob)
void monster_check_doors(object *op, mapstruct *m, int x, int y)
int monster_compute_path(object *source, object *target, int default_dir)
void fix_object(object *op)
char * stringbuffer_finish(StringBuffer *sb)
#define GET_MAP_MOVE_BLOCK(M, X, Y)
int apply_can_apply_object(const object *who, const object *op)
int object_set_value(object *op, const char *key, const char *value, int add_key)
const typedef char * sstring
#define FLAG_UNAGGRESSIVE
#define GET_MAP_LIGHT(M, X, Y)
#define FLAG_CAN_USE_SKILL
int monster_can_see_enemy(object *op, object *enemy)
void monster_communicate(object *op, const char *txt)
int16_t SP_level_spellpoint_cost(object *caster, object *spell, int flags)
static int monster_can_hit(object *ob1, object *ob2, rv_vector *rv)
const Animations * animation
void monster_do_living(object *op)
void pets_move(object *ob)
int move_object(object *op, int dir)
static int monster_check_good_armour(object *who, object *item)
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
#define OUT_OF_REAL_MAP(M, X, Y)
int dirdiff(int dir1, int dir2)
object * monster_find_nearest_enemy(object *npc, object *owner)
static int monster_use_skill(object *head, object *part, object *pl, int dir)
static int monster_dist_att(int dir, object *enemy, object *part, rv_vector *rv)
static const char * get_reply_text_other(reply_type rt)
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_pace_movev(object *ob)
#define MSG_TYPE_SKILL_FAILURE
void LOG(LogLevel logLevel, const char *format,...)
int path_measure_func(const void *ob)
bool object_value_set(const object *op, const char *const key)
static int monster_can_pick(object *monster, object *item)
void pets_follow_owner(object *ob, object *owner)
int get_dialog_message(object *op, const char *text, struct_dialog_message **message, struct_dialog_reply **reply)
int hit_player(object *op, int dam, object *hitter, uint32_t type, int full_hit)
void do_hidden_move(object *op)
#define CLEAR_FLAG(xyz, p)
void stringbuffer_append_printf(StringBuffer *sb, const char *format,...)
object * object_insert_in_ob(object *op, object *where)
#define MSG_TYPE_DIALOG_MAGIC_EAR
#define MSG_TYPE_DIALOG_NPC
int fire_bow(object *op, object *arrow, int dir, int wc_mod, int16_t sx, int16_t sy)
static object * monster_find_enemy(object *npc, rv_vector *rv)
sstring npc_msgs[MAX_NPC]
static uint16_t estimate_distance(int16_t ax, int16_t ay, int16_t bx, int16_t by)
static void monster_rand_move(object *ob)
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
int8_t get_attr_value(const living *stats, int attr)
void object_free_drop_inventory(object *ob)
static int monster_wait_att(int dir, object *ob, object *enemy, object *part, rv_vector *rv)
int player_can_view(object *pl, object *op)
object * object_find_by_type_and_race(const object *who, int type, const char *race)
static void monster_circ1_move(object *ob)
int monster_can_detect_enemy(object *op, object *enemy, rv_vector *rv)
static void monster_check_pickup(object *monster)
static int monster_move_no_enemy(object *op)
#define MSG_TYPE_COMMUNICATION
void drain_rod_charge(object *rod)
#define WILL_APPLY_TREASURE
static void monster_pace_moveh(object *ob)
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, int16_t x, int16_t y, int16_t *nx, int16_t *ny)
void get_search_arr(int *search_arr)
int events_execute_object_say(object *npc, talk_info *talk)
object * monster_find_throw_ob(object *op)
static void monster_pace2_moveh(object *ob)
static int monster_wait_att2(int dir, rv_vector *rv)
int makes_invisible_to(object *pl, object *mon)
static int monster_cast_spell(object *head, object *part, object *pl, int dir)
int on_same_map(const object *op1, const object *op2)
int16_t resist[NROFATTACKS]
mapstruct * get_map_from_coord(mapstruct *m, int16_t *x, int16_t *y)
object * object_split(object *orig_ob, uint32_t nr, char *err, size_t size)
#define FOR_INV_PREPARE(op_, it_)
#define MSG_TYPE_COMMUNICATION_SAY
void drain_wand_charge(object *wand)
static int monster_disthit_att(int dir, object *ob, object *enemy, object *part, rv_vector *rv)
int can_see_monsterP(mapstruct *m, int x, int y, int dir)
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...)
int is_true_undead(object *op)
void skill_attack(object *tmp, object *pl, int dir, const char *string, object *skill)
object * object_get_owner(object *op)