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) {
199 object *creature = NULL;
233 object *attacker, *
tmp = NULL;
235 attacker =
npc->attacked_by;
236 npc->attacked_by = NULL;
273 if (attacker->
count ==
npc->attacked_by_count) {
295 snprintf(
buf,
sizeof(
buf),
"Halt, %s, you are under arrest!",
npc->enemy->name);
346 &&
op->map->darkness > 0
351 int dark = radius/(
op->map->darkness);
383 if (talked && strlen(talked) > 0) {
400 for (i = 0; i < 15; i++) {
408 #define MAX_EXPLORE 5000
442 uint16_t dx =
FABS(ax - bx), dy =
FABS(ay - by);
443 uint16_t diag =
MIN(dx, dy);
444 return (
MAX(dx, dy) - diag) * 2 + diag * 3;
470 if (target->
map != source->
map)
475 const uint16_t map_height = cur_map->
height;
479 const int size = cur_map->
width * map_height;
521 for (i = 1; i <= 8; ++i)
551 distance =
static_cast<path_data *
>(malloc(size *
sizeof(*distance)));
552 if (distance == NULL) {
559 memset(distance, 255,
sizeof(*distance) * size);
562 current = &distance[map_height * target->
x + target->
y];
580 for (i = 1; i < 8; ++i) {
586 for (i = 0; i < 8; ++i) {
587 uint16_t new_distance;
592 dir =
absdir(default_dir+4+dirs[i]);
596 if (
x == source->
x &&
y == source->
y) {
608 const path_data *newloc = &distance[map_height * newx + newy];
631 assert(map_height *
x +
y >= 0);
632 assert(map_height *
x +
y < size);
635 explore = &distance[map_height *
x +
y];
639 int16_t move_penalty = 0;
641 if (terrain_value > 0) {
649 move_penalty += (int16_t)
tmp->move_slow_penalty;
663 const int base_move_cost = ((dir & 1) == 0 ? 3 : 2);
669 + (move_penalty != 0 && terrain_value != 0 ? base_move_cost + base_move_cost * move_penalty * terrain_value / 2 : base_move_cost);
672 if (explore->
distance <= new_distance)
724 if (
op->stats.Con > 0 &&
op->stats.hp <
op->stats.maxhp) {
734 op->last_heal += (
int)((
float)(8*
op->stats.Con)/
FABS(
op->speed));
735 op->stats.hp =
MIN((int32_t)
op->stats.hp+
op->last_heal/32,
op->stats.maxhp);
740 &&
op->stats.hp >= (int16_t)((int32_t)
op->run_away *
op->stats.maxhp / 100))
751 if (
op->stats.Pow > 0 &&
op->stats.sp <
op->stats.maxsp) {
761 op->last_sp += (
int)((
float)(8*
op->stats.Pow)/
FABS(
op->speed));
762 op->stats.sp =
MIN(
op->stats.sp+
op->last_sp/128,
op->stats.maxsp);
795 if (
op->attack_movement&
HI4) {
796 switch (
op->attack_movement&
HI4) {
856 object *owner, *enemy, *part;
925 if (
op->race != NULL && strcmp(
op->race,
"doppleganger") == 0) {
941 op->facing =
op->direction;
1008 LOG(
llevMonster,
"monster %s (%d, %d on %s) can't reach enemy %s (%d, %d on %s)\n",
1009 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)");
1016 switch (
op->attack_movement&
LO4) {
1062 for (diff = 1; diff <= maxdiff; diff++) {
1095 if (nearest_player && nearest_player != enemy && !
monster_can_hit(part, enemy, &rv)) {
1097 enemy = nearest_player;
1154 for (more =
ob2->more; more != NULL; more = more->
more) {
1186 assert(spell_ob != NULL);
1210 #define MAX_KNOWN_SPELLS 20
1246 return altern[
RANDOM()%i];
1282 if (owner != NULL) {
1299 if (spell_item == NULL) {
1305 if (!spell_item->
inv) {
1306 LOG(
llevError,
"spellbook %s does not contain a spell?\n", spell_item->
name);
1309 spell_item = spell_item->
inv;
1335 return cast_spell(part, part, dir, spell_item, NULL);
1369 if (owner != NULL) {
1446 if (owner != NULL) {
1471 LOG(
llevDebug,
"Error: Monster %s (%d) has FLAG_READY_SKILL without skill.\n", head->
name, head->
count);
1495 int at_least_one = 0;
1503 if (owner != NULL) {
1514 if (wand->type ==
WAND) {
1517 if (wand->stats.food <= 0)
1527 if (wand->type ==
ROD && wand->inv) {
1530 if (wand->stats.hp <
MAX(wand->inv->stats.sp, wand->inv->stats.grace))
1548 LOG(
llevError,
"Error: Monster %s (%d) HAS_READY_RANG() without wand/horn/rod.\n", head->
name, head->
count);
1594 while (
x !=
pl->x ||
y !=
pl->y ||
map !=
pl->map) {
1599 LOG(
llevError,
"monster_use_bow: no map but still path exists??\n");
1604 if (owner && owner->
x ==
x && owner->
y ==
y && owner->
map ==
map)
1615 return fire_bow(head, NULL, dir, 0, part->
x, part->
y);
1630 val =
item->stats.dam;
1631 val +=
item->magic*3;
1657 if (other_weap == NULL)
1681 val =
item->stats.ac;
1683 val +=
item->magic*3;
1700 object *other_armour;
1704 if (other_armour == NULL)
1716 if (
item->resist[i] > other_armour->
resist[i])
1718 else if (
item->resist[i] < other_armour->
resist[i])
1792 }
else if (
item->type ==
BOW) {
1854 for (part = monster; part != NULL; part = part->
more)
1865 if (
tmp->weight > 0) {
1866 int32_t weight_limit;
1874 nrof =
MAX(1,
tmp->nrof);
1915 else switch (
item->type) {
1965 if (((!(monster->
pick_up&32)) && flag) || ((monster->
pick_up&32) && (!flag)))
1978 switch (
tmp->type) {
2000 if (!monster->
head) {
2014 int help_radius = 3;
2018 int override_help_radius;
2020 override_help_radius = strtol(
value, NULL, 10);
2021 if (override_help_radius >= 0 && override_help_radius < 30)
2022 help_radius = override_help_radius;
2024 LOG(
llevDebug,
"monster_npc_call_help: invalid help_radius %d\n", override_help_radius);
2027 for (
int x = -help_radius;
x <= help_radius;
x++)
2028 for (
int y = -help_radius;
y <= help_radius;
y++) {
2030 int16_t sx =
op->x+
x;
2031 int16_t sy =
op->y+
y;
2077 }
else if (
ob->move_status > 20)
2078 ob->move_status = 0;
2089 if (
ob->move_status++ < 25)
2091 else if (
ob->move_status < 50)
2093 ob->move_status = 0;
2109 if (
ob->move_status || inrange)
2112 if (
ob->move_status == 0)
2114 else if (
ob->move_status < 10)
2116 else if (
ob->move_status < 15)
2118 ob->move_status = 0;
2139 if (
ob->stats.maxhp && (
ob->stats.hp*100)/
ob->stats.maxhp <
ob->run_away)
2161 static const int circle [12] = { 3, 3, 4, 5, 5, 6, 7, 7, 8, 1, 1, 2 };
2163 if (++
ob->move_status > 11)
2164 ob->move_status = 0;
2174 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 };
2176 if (++
ob->move_status > 19)
2177 ob->move_status = 0;
2187 if (
ob->move_status++ > 6)
2188 ob->move_status = 0;
2189 if (
ob->move_status < 4)
2200 if (
ob->move_status++ > 6)
2201 ob->move_status = 0;
2202 if (
ob->move_status < 4)
2213 if (
ob->move_status++ > 16)
2214 ob->move_status = 0;
2215 if (
ob->move_status < 6)
2217 else if (
ob->move_status < 8)
2219 else if (
ob->move_status < 13)
2228 if (
ob->move_status++ > 16)
2229 ob->move_status = 0;
2230 if (
ob->move_status < 6)
2232 else if (
ob->move_status < 8)
2234 else if (
ob->move_status < 13)
2245 if (
ob->move_status < 1
2246 ||
ob->move_status > 8
2248 for (i = 0; i < 5; i++) {
2404 if (orig_map !=
op->map) {
2405 LOG(
llevDebug,
"Warning: Forced to swap out very recent map\n");
2417 snprintf(own,
sizeof(own),
"You say: %s", txt);
2418 snprintf(others,
sizeof(others),
"%s says: %s",
op->name, txt);
2476 value[0] =
'3' + rand() % 6;
2585 if (!
op || !enemy || !
op->map || !enemy->
map)
2613 hide_discovery =
op->stats.Int/5;
2620 int bonus = (
op->level/2)+(
op->stats.Int/5);
2624 if (sk_hide != NULL)
2625 bonus -= sk_hide->
level;
2627 LOG(
llevError,
"monster_can_detect_enemy() got hidden player w/o hiding skill!\n");
2632 bonus -= enemy->
level;
2635 hide_discovery += bonus*5;
2641 radius = radius/2, hide_discovery = hide_discovery/3;
2649 radius +=
op->map->darkness/2;
2651 radius -=
op->map->darkness/2;
2656 if (radius < MIN_MON_RADIUS && op->
map->darkness < 5 && rv->
distance <= 1)
2678 if (enemy->
hide && rv->
distance <= 1 &&
RANDOM()%100 <= (
unsigned int)hide_discovery) {
2683 "You are discovered by %s!",
2694 if (
RANDOM()%50 <= (
unsigned int)hide_discovery) {
2700 "You see %s noticing your position.",
2724 if (
op->glow_radius > 0)
2760 if (
op->light_cached_time ==
pticks)
2761 return op->light_cached;
2764 op->light_cached = val;
2779 object *looker =
HEAD(
op);
2801 "Your light reveals your hiding spot!");
2804 }
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_stand_in_light_internal(object *op)
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)