ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/monster.C
(Generate patch)

Comparing deliantra/server/server/monster.C (file contents):
Revision 1.7 by pippijn, Thu Sep 7 10:01:58 2006 UTC vs.
Revision 1.10 by root, Thu Sep 14 22:34:04 2006 UTC

1/*
2 * static char *rcsid_monster_c =
3 * "$Id: monster.C,v 1.7 2006/09/07 10:01:58 pippijn Exp $";
4 */
5
6/* 1/*
7 CrossFire, A Multiplayer game for X-windows 2 CrossFire, A Multiplayer game for X-windows
8 3
9 Copyright (C) 2002 Mark Wedel & Crossfire Development Team 4 Copyright (C) 2002 Mark Wedel & Crossfire Development Team
10 Copyright (C) 1992 Frank Tore Johansen 5 Copyright (C) 1992 Frank Tore Johansen
21 16
22 You should have received a copy of the GNU General Public License 17 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software 18 along with this program; if not, write to the Free Software
24 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 20
26 The authors can be reached via e-mail at crossfire-devel@real-time.com 21 The authors can be reached via e-mail at <crossfire@schmorp.de>
27*/ 22*/
28 23
29#include <global.h> 24#include <global.h>
30#ifndef __CEXTRACT__ 25#ifndef __CEXTRACT__
31#include <sproto.h> 26# include <sproto.h>
32#include <spells.h> 27# include <spells.h>
33#include <skills.h> 28# include <skills.h>
34#endif 29#endif
35 30
36 31
37#define MIN_MON_RADIUS 3 /* minimum monster detection radius */ 32#define MIN_MON_RADIUS 3 /* minimum monster detection radius */
38 33
39 34
40/* checks npc->enemy and returns that enemy if still valid, 35/* checks npc->enemy and returns that enemy if still valid,
41 * NULL otherwise. 36 * NULL otherwise.
42 * this is map tile aware. 37 * this is map tile aware.
43 * If this returns an enemy, the range vector rv should also be 38 * If this returns an enemy, the range vector rv should also be
44 * set to sane values. 39 * set to sane values.
45 */ 40 */
41object *
46object *check_enemy(object *npc, rv_vector *rv) { 42check_enemy (object *npc, rv_vector * rv)
47 43{
44
48 /* if this is pet, let him attack the same enemy as his owner 45 /* if this is pet, let him attack the same enemy as his owner
49 * TODO: when there is no ower enemy, try to find a target, 46 * TODO: when there is no ower enemy, try to find a target,
50 * which CAN attack the owner. */ 47 * which CAN attack the owner. */
51 if ((npc->attack_movement & HI4) == PETMOVE) 48 if ((npc->attack_movement & HI4) == PETMOVE)
52 { 49 {
53 if (npc->owner == NULL) 50 if (npc->owner == NULL)
54 npc->enemy = NULL; 51 npc->enemy = NULL;
55 else if (npc->enemy == NULL) 52 else if (npc->enemy == NULL)
56 npc->enemy = npc->owner->enemy; 53 npc->enemy = npc->owner->enemy;
57 } 54 }
58 55
59 /* periodically, a monster mayu change its target. Also, if the object 56 /* periodically, a monster mayu change its target. Also, if the object
60 * has been destroyed, etc, clear the enemy. 57 * has been destroyed, etc, clear the enemy.
61 * TODO: this should be changed, because it invokes to attack forced or 58 * TODO: this should be changed, because it invokes to attack forced or
62 * attacked monsters to leave the attacker alone, before it is destroyed 59 * attacked monsters to leave the attacker alone, before it is destroyed
63 */ 60 */
64 /* i had removed the random target leave, this invokes problems with friendly 61 /* i had removed the random target leave, this invokes problems with friendly
65 * objects, getting attacked and defending herself - they don't try to attack 62 * objects, getting attacked and defending herself - they don't try to attack
66 * again then but perhaps get attack on and on 63 * again then but perhaps get attack on and on
67 * If we include a aggravated flag in , we can handle evil vs evil and good vs good 64 * If we include a aggravated flag in , we can handle evil vs evil and good vs good
68 * too. */ 65 * too. */
69 66
70 if(npc->enemy) 67 if (npc->enemy)
71 { 68 {
72 /* I broke these if's apart to better be able to see what 69 /* I broke these if's apart to better be able to see what
73 * the grouping checks are. Code is the same. 70 * the grouping checks are. Code is the same.
74 */ 71 */
75 if ( QUERY_FLAG(npc->enemy,FLAG_REMOVED) || 72 if (QUERY_FLAG (npc->enemy, FLAG_REMOVED) ||
76 QUERY_FLAG(npc->enemy,FLAG_FREED) || 73 QUERY_FLAG (npc->enemy, FLAG_FREED) ||
77 !on_same_map(npc, npc->enemy) || 74 !on_same_map (npc, npc->enemy) || npc == npc->enemy || QUERY_FLAG (npc, FLAG_NEUTRAL) || QUERY_FLAG (npc->enemy, FLAG_NEUTRAL))
78 npc == npc->enemy ||
79 QUERY_FLAG(npc, FLAG_NEUTRAL) ||
80 QUERY_FLAG(npc->enemy, FLAG_NEUTRAL))
81 npc->enemy = NULL; 75 npc->enemy = NULL;
82 76
83 else if (QUERY_FLAG(npc, FLAG_FRIENDLY) && ( 77 else if (QUERY_FLAG (npc, FLAG_FRIENDLY) && ((QUERY_FLAG (npc->enemy, FLAG_FRIENDLY)
84 (QUERY_FLAG(npc->enemy, FLAG_FRIENDLY) && !(should_arena_attack(npc, npc->owner, npc->enemy))) || 78 && !(should_arena_attack (npc, npc->owner, npc->enemy)))
85 ((npc->enemy->type == PLAYER) && !(should_arena_attack(npc, npc->owner, npc->enemy))) 79 || ((npc->enemy->type == PLAYER) && !(should_arena_attack (npc, npc->owner, npc->enemy)))
86 || npc->enemy == npc->owner)) 80 || npc->enemy == npc->owner))
87 npc->enemy = NULL; 81 npc->enemy = NULL;
88 82
89 83
90 else if (!QUERY_FLAG(npc, FLAG_FRIENDLY) && 84 else if (!QUERY_FLAG (npc, FLAG_FRIENDLY) && (!QUERY_FLAG (npc->enemy, FLAG_FRIENDLY) && npc->enemy->type != PLAYER))
91 (!QUERY_FLAG(npc->enemy, FLAG_FRIENDLY) && npc->enemy->type!=PLAYER))
92 npc->enemy=NULL; 85 npc->enemy = NULL;
93 86
94 /* I've noticed that pets could sometimes get an arrow as the 87 /* I've noticed that pets could sometimes get an arrow as the
95 * target enemy - this code below makes sure the enemy is something 88 * target enemy - this code below makes sure the enemy is something
96 * that should be attacked. My guess is that the arrow hits 89 * that should be attacked. My guess is that the arrow hits
97 * the creature/owner, and so the creature then takes that 90 * the creature/owner, and so the creature then takes that
98 * as the enemy to attack. 91 * as the enemy to attack.
99 */ 92 */
100 else if (!QUERY_FLAG(npc->enemy, FLAG_MONSTER) && 93 else if (!QUERY_FLAG (npc->enemy, FLAG_MONSTER) &&
101 !QUERY_FLAG(npc->enemy,FLAG_GENERATOR) &&
102 npc->enemy->type!=PLAYER && npc->enemy->type != GOLEM) 94 !QUERY_FLAG (npc->enemy, FLAG_GENERATOR) && npc->enemy->type != PLAYER && npc->enemy->type != GOLEM)
103 npc->enemy=NULL; 95 npc->enemy = NULL;
104 96
105 } 97 }
106 return can_detect_enemy(npc,npc->enemy,rv)?npc->enemy:NULL; 98 return can_detect_enemy (npc, npc->enemy, rv) ? npc->enemy : NULL;
107} 99}
108 100
109/* Returns the nearest living creature (monster or generator). 101/* Returns the nearest living creature (monster or generator).
110 * Modified to deal with tiled maps properly. 102 * Modified to deal with tiled maps properly.
111 * Also fixed logic so that monsters in the lower directions were more 103 * Also fixed logic so that monsters in the lower directions were more
118 * the first few directions, it could very well choose something 110 * the first few directions, it could very well choose something
119 * 3 spaces away even though something directly north is closer. 111 * 3 spaces away even though something directly north is closer.
120 * 112 *
121 * this function is map tile aware. 113 * this function is map tile aware.
122 */ 114 */
115object *
123object *find_nearest_living_creature(object *npc) { 116find_nearest_living_creature (object *npc)
117{
124 int i,mflags; 118 int i, mflags;
125 sint16 nx,ny; 119 sint16 nx, ny;
126 mapstruct *m; 120 mapstruct *m;
127 object *tmp; 121 object *tmp;
128 int search_arr[SIZEOFFREE]; 122 int search_arr[SIZEOFFREE];
129 123
130 get_search_arr(search_arr); 124 get_search_arr (search_arr);
131 for(i=0;i<SIZEOFFREE;i++) { 125 for (i = 0; i < SIZEOFFREE; i++)
126 {
132 /* modified to implement smart searching using search_arr 127 /* modified to implement smart searching using search_arr
133 * guidance array to determine direction of search order 128 * guidance array to determine direction of search order
134 */ 129 */
135 nx = npc->x + freearr_x[search_arr[i]]; 130 nx = npc->x + freearr_x[search_arr[i]];
136 ny = npc->y + freearr_y[search_arr[i]]; 131 ny = npc->y + freearr_y[search_arr[i]];
137 m = npc->map; 132 m = npc->map;
138 133
139 mflags = get_map_flags(m, &m, nx, ny, &nx, &ny); 134 mflags = get_map_flags (m, &m, nx, ny, &nx, &ny);
140 if (mflags & P_OUT_OF_MAP) continue; 135 if (mflags & P_OUT_OF_MAP)
136 continue;
141 137
142 if (mflags & P_IS_ALIVE) { 138 if (mflags & P_IS_ALIVE)
139 {
143 tmp=get_map_ob(m,nx,ny); 140 tmp = get_map_ob (m, nx, ny);
144 while(tmp!=NULL && !QUERY_FLAG(tmp,FLAG_MONSTER)&& 141 while (tmp != NULL && !QUERY_FLAG (tmp, FLAG_MONSTER) && !QUERY_FLAG (tmp, FLAG_GENERATOR) && tmp->type != PLAYER)
145 !QUERY_FLAG(tmp,FLAG_GENERATOR ) && tmp->type!=PLAYER)
146 tmp=tmp->above; 142 tmp = tmp->above;
147 143
148 if (!tmp) { 144 if (!tmp)
145 {
149 LOG(llevDebug,"find_nearest_living_creature: map %s (%d,%d) has is_alive set but did not find a monster?\n", 146 LOG (llevDebug, "find_nearest_living_creature: map %s (%d,%d) has is_alive set but did not find a monster?\n",
150 m->path, nx, ny); 147 m->path, nx, ny);
151 } 148 }
152 else { 149 else
150 {
153 if(can_see_monsterP(m,nx,ny,i)) 151 if (can_see_monsterP (m, nx, ny, i))
154 return tmp; 152 return tmp;
155 } 153 }
156 } /* is something living on this space */ 154 } /* is something living on this space */
157 } 155 }
158 return NULL; /* nothing found */ 156 return NULL; /* nothing found */
159} 157}
160 158
161 159
162/* Tries to find an enmy for npc. We pass the range vector since 160/* Tries to find an enmy for npc. We pass the range vector since
163 * our caller will find the information useful. 161 * our caller will find the information useful.
165 * Fix function so that we always make calls to get_rangevector 163 * Fix function so that we always make calls to get_rangevector
166 * if we have a valid target - function as not doing so in 164 * if we have a valid target - function as not doing so in
167 * many cases. 165 * many cases.
168 */ 166 */
169 167
168object *
170object *find_enemy(object *npc, rv_vector *rv) 169find_enemy (object *npc, rv_vector * rv)
171{ 170{
172 object *attacker, *tmp=NULL; 171 object *attacker, *tmp = NULL;
173 172
174 attacker = npc->attacked_by; /* save this for later use. This can be a attacker. */ 173 attacker = npc->attacked_by; /* save this for later use. This can be a attacker. */
175 npc->attacked_by = NULL; /* always clear the attacker entry */ 174 npc->attacked_by = 0; /* always clear the attacker entry */
176 175
177 /* if we berserk, we don't care about others - we attack all we can find */ 176 /* if we berserk, we don't care about others - we attack all we can find */
178 if(QUERY_FLAG(npc,FLAG_BERSERK)) { 177 if (QUERY_FLAG (npc, FLAG_BERSERK))
178 {
179 tmp = find_nearest_living_creature(npc); 179 tmp = find_nearest_living_creature (npc);
180
181 if (tmp)
180 if (tmp) get_rangevector(npc, tmp, rv, 0); 182 get_rangevector (npc, tmp, rv, 0);
181 return tmp; 183 return tmp;
182 } 184 }
183 185
184 /* Here is the main enemy selection. 186 /* Here is the main enemy selection.
185 * We want this: if there is an enemy, attack him until its not possible or 187 * We want this: if there is an enemy, attack him until its not possible or
186 * one of both is dead. 188 * one of both is dead.
187 * If we have no enemy and we are... 189 * If we have no enemy and we are...
188 * a monster: try to find a player, a pet or a friendly monster 190 * a monster: try to find a player, a pet or a friendly monster
189 * a friendly: only target a monster which is targeting you first or targeting a player 191 * a friendly: only target a monster which is targeting you first or targeting a player
190 * a neutral: fight a attacker (but there should be none), then do nothing 192 * a neutral: fight a attacker (but there should be none), then do nothing
191 * a pet: attack player enemy or a monster 193 * a pet: attack player enemy or a monster
192 */ 194 */
193 195
194 /* pet move */ 196 /* pet move */
195 if ((npc->attack_movement & HI4) == PETMOVE) { 197 if ((npc->attack_movement & HI4) == PETMOVE)
198 {
196 tmp= get_pet_enemy(npc,rv); 199 tmp = get_pet_enemy (npc, rv);
200
201 if (tmp)
197 if (tmp) get_rangevector(npc, tmp, rv, 0); 202 get_rangevector (npc, tmp, rv, 0);
203
198 return tmp; 204 return tmp;
199 }
200 205 }
206
201 /* we check our old enemy. */ 207 /* we check our old enemy. */
202 if((tmp=check_enemy(npc, rv))==NULL) 208 if (!(tmp = check_enemy (npc, rv)))
203 { 209 {
204 if(attacker) /* if we have an attacker, check him */ 210 if (attacker) /* if we have an attacker, check him */
205 { 211 {
206 /* we want be sure this is the right one! */ 212 /* TODO: thats not finished */
207 if(attacker->count == npc->attacked_by_count) 213 /* we don't want a fight evil vs evil or good against non evil */
214
215 if (QUERY_FLAG (npc, FLAG_NEUTRAL) || QUERY_FLAG (attacker, FLAG_NEUTRAL) || /* neutral */
216 (QUERY_FLAG (npc, FLAG_FRIENDLY) && QUERY_FLAG (attacker, FLAG_FRIENDLY)) ||
217 (!QUERY_FLAG (npc, FLAG_FRIENDLY) && (!QUERY_FLAG (attacker, FLAG_FRIENDLY) && attacker->type != PLAYER)))
218 CLEAR_FLAG (npc, FLAG_SLEEP); /* skip it, but lets wakeup */
219 else if (on_same_map (npc, attacker)) /* thats the only thing we must know... */
208 { 220 {
209 /* TODO: thats not finished */
210 /* we don't want a fight evil vs evil or good against non evil */
211
212 if( QUERY_FLAG(npc, FLAG_NEUTRAL) || QUERY_FLAG(attacker, FLAG_NEUTRAL) || /* neutral */
213 (QUERY_FLAG(npc, FLAG_FRIENDLY) && QUERY_FLAG(attacker, FLAG_FRIENDLY)) ||
214 (!QUERY_FLAG(npc, FLAG_FRIENDLY) &&
215 (!QUERY_FLAG(attacker, FLAG_FRIENDLY) && attacker->type!=PLAYER)) )
216 CLEAR_FLAG(npc,FLAG_SLEEP); /* skip it, but lets wakeup */
217 else if(on_same_map(npc, attacker)) /* thats the only thing we must know... */
218 {
219 CLEAR_FLAG(npc,FLAG_SLEEP); /* well, NOW we really should wake up! */ 221 CLEAR_FLAG (npc, FLAG_SLEEP); /* well, NOW we really should wake up! */
220 npc->enemy = attacker; 222 npc->enemy = attacker;
221 return attacker; /* yes, we face our attacker! */ 223 return attacker; /* yes, we face our attacker! */
222 }
223 } 224 }
224 } 225 }
225 226
226 /* we have no legal enemy or attacker, so we try to target a new one */ 227 /* we have no legal enemy or attacker, so we try to target a new one */
227 if(!QUERY_FLAG(npc, FLAG_UNAGGRESSIVE) && !QUERY_FLAG(npc, FLAG_FRIENDLY) && 228 if (!QUERY_FLAG (npc, FLAG_UNAGGRESSIVE) && !QUERY_FLAG (npc, FLAG_FRIENDLY) && !QUERY_FLAG (npc, FLAG_NEUTRAL))
228 !QUERY_FLAG(npc, FLAG_NEUTRAL))
229 { 229 {
230 npc->enemy = get_nearest_player(npc); 230 npc->enemy = get_nearest_player (npc);
231 if (npc->enemy) 231 if (npc->enemy)
232 tmp = check_enemy(npc,rv); 232 tmp = check_enemy (npc, rv);
233 }
234 233 }
235 }
236 234
235 }
236
237 return tmp; 237 return tmp;
238} 238}
239 239
240/* Sees if this monster should wake up. 240/* Sees if this monster should wake up.
241 * Currently, this is only called from move_monster, and 241 * Currently, this is only called from move_monster, and
242 * if enemy is set, then so should be rv. 242 * if enemy is set, then so should be rv.
243 * returns 1 if the monster should wake up, 0 otherwise. 243 * returns 1 if the monster should wake up, 0 otherwise.
244 */ 244 */
245 245
246int
246int check_wakeup(object *op, object *enemy, rv_vector *rv) { 247check_wakeup (object *op, object *enemy, rv_vector * rv)
248{
247 int radius = op->stats.Wis>MIN_MON_RADIUS?op->stats.Wis:MIN_MON_RADIUS; 249 int radius = op->stats.Wis > MIN_MON_RADIUS ? op->stats.Wis : MIN_MON_RADIUS;
248 250
249 /* Trim work - if no enemy, no need to do anything below */ 251 /* Trim work - if no enemy, no need to do anything below */
250 if (!enemy) return 0; 252 if (!enemy)
253 return 0;
251 254
252 /* blinded monsters can only find nearby objects to attack */ 255 /* blinded monsters can only find nearby objects to attack */
253 if(QUERY_FLAG(op, FLAG_BLIND)) 256 if (QUERY_FLAG (op, FLAG_BLIND))
254 radius = MIN_MON_RADIUS; 257 radius = MIN_MON_RADIUS;
255 258
256 /* This covers the situation where the monster is in the dark 259 /* This covers the situation where the monster is in the dark
257 * and has an enemy. If the enemy has no carried light (or isnt 260 * and has an enemy. If the enemy has no carried light (or isnt
258 * glowing!) then the monster has trouble finding the enemy. 261 * glowing!) then the monster has trouble finding the enemy.
259 * Remember we already checked to see if the monster can see in 262 * Remember we already checked to see if the monster can see in
260 * the dark. */ 263 * the dark. */
261 264
262 else if(op->map && op->map->darkness>0 && enemy && !enemy->invisible && 265 else if (op->map && op->map->darkness > 0 && enemy && !enemy->invisible &&
263 !stand_in_light(enemy) &&
264 (!QUERY_FLAG(op,FLAG_SEE_IN_DARK) || !QUERY_FLAG(op,FLAG_SEE_INVISIBLE))) { 266 !stand_in_light (enemy) && (!QUERY_FLAG (op, FLAG_SEE_IN_DARK) || !QUERY_FLAG (op, FLAG_SEE_INVISIBLE)))
267 {
265 int dark = radius/(op->map->darkness); 268 int dark = radius / (op->map->darkness);
269
266 radius = (dark>MIN_MON_RADIUS)?(dark+1):MIN_MON_RADIUS; 270 radius = (dark > MIN_MON_RADIUS) ? (dark + 1) : MIN_MON_RADIUS;
267 } 271 }
268 else if(!QUERY_FLAG(op,FLAG_SLEEP)) return 1; 272 else if (!QUERY_FLAG (op, FLAG_SLEEP))
273 return 1;
269 274
270 /* enemy should already be on this map, so don't really need to check 275 /* enemy should already be on this map, so don't really need to check
271 * for that. 276 * for that.
272 */ 277 */
273 if (rv->distance < (unsigned int) (QUERY_FLAG(enemy, FLAG_STEALTH) ? (radius / 2) + 1 : radius)) { 278 if (rv->distance < (unsigned int) (QUERY_FLAG (enemy, FLAG_STEALTH) ? (radius / 2) + 1 : radius))
279 {
274 CLEAR_FLAG(op,FLAG_SLEEP); 280 CLEAR_FLAG (op, FLAG_SLEEP);
281 return 1;
282 }
283 return 0;
284}
285
286int
287move_randomly (object *op)
288{
289 int i;
290
291 /* Give up to 15 chances for a monster to move randomly */
292 for (i = 0; i < 15; i++)
293 {
294 if (move_object (op, RANDOM () % 8 + 1))
275 return 1; 295 return 1;
276 } 296 }
277 return 0; 297 return 0;
278}
279
280int move_randomly(object *op) {
281 int i;
282
283 /* Give up to 15 chances for a monster to move randomly */
284 for(i=0;i<15;i++) {
285 if(move_object(op,RANDOM()%8+1))
286 return 1;
287 }
288 return 0;
289} 298}
290 299
291/* 300/*
292 * Move-monster returns 1 if the object has been freed, otherwise 0. 301 * Move-monster returns 1 if the object has been freed, otherwise 0.
293 */ 302 */
294 303
304int
295int move_monster(object *op) { 305move_monster (object *op)
306{
296 int dir, diff, pre_att_dir; /* elmex: pre_att_dir remembers the direction before attack movement */ 307 int dir, diff, pre_att_dir; /* elmex: pre_att_dir remembers the direction before attack movement */
297 object *owner, *enemy, *part, *oph=op; 308 object *owner, *enemy, *part, *oph = op;
298 rv_vector rv; 309 rv_vector rv;
299 310
300 /* Monsters not on maps don't do anything. These monsters are things 311 /* Monsters not on maps don't do anything. These monsters are things
301 * Like royal guards in city dwellers inventories. 312 * Like royal guards in city dwellers inventories.
302 */ 313 */
303 if (!op->map) return 0; 314 if (!op->map)
315 return 0;
304 316
305 /* for target facing, we copy this value here for fast access */ 317 /* for target facing, we copy this value here for fast access */
306 if(oph->head) /* force update the head - one arch one pic */ 318 if (oph->head) /* force update the head - one arch one pic */
307 oph = oph->head; 319 oph = oph->head;
308 320
309 if (QUERY_FLAG(op, FLAG_NO_ATTACK)) /* we never ever attack */ 321 if (QUERY_FLAG (op, FLAG_NO_ATTACK)) /* we never ever attack */
310 enemy = op->enemy = NULL; 322 enemy = op->enemy = NULL;
311 else if((enemy= find_enemy(op, &rv))) 323 else if ((enemy = find_enemy (op, &rv)))
312 {
313 /* we have an enemy, just tell him we want him dead */ 324 /* we have an enemy, just tell him we want him dead */
314 enemy->attacked_by = op; /* our ptr */ 325 enemy->attacked_by = op; /* our ptr */
315 enemy->attacked_by_count = op->count; /* our tag */ 326
316 }
317
318 /* generate hp, if applicable */ 327 /* generate hp, if applicable */
319 if(op->stats.Con > 0 && op->stats.hp < op->stats.maxhp) { 328 if (op->stats.Con > 0 && op->stats.hp < op->stats.maxhp)
329 {
320 330
321 /* last heal is in funny units. Dividing by speed puts 331 /* last heal is in funny units. Dividing by speed puts
322 * the regeneration rate on a basis of time instead of 332 * the regeneration rate on a basis of time instead of
323 * #moves the monster makes. The scaling by 8 is 333 * #moves the monster makes. The scaling by 8 is
324 * to capture 8th's of a hp fraction regens 334 * to capture 8th's of a hp fraction regens
325 * 335 *
326 * Cast to sint32 before comparing to maxhp since otherwise an (sint16) 336 * Cast to sint32 before comparing to maxhp since otherwise an (sint16)
327 * overflow might produce monsters with negative hp. 337 * overflow might produce monsters with negative hp.
328 */ 338 */
329 339
330 op->last_heal+= (int)((float)(8*op->stats.Con)/FABS(op->speed)); 340 op->last_heal += (int) ((float) (8 * op->stats.Con) / FABS (op->speed));
331 op->stats.hp = MIN((sint32)op->stats.hp+op->last_heal/32, op->stats.maxhp); /* causes Con/4 hp/tick */ 341 op->stats.hp = MIN ((sint32) op->stats.hp + op->last_heal / 32, op->stats.maxhp); /* causes Con/4 hp/tick */
332 op->last_heal%=32; 342 op->last_heal %= 32;
333 343
334 /* So if the monster has gained enough HP that they are no longer afraid */ 344 /* So if the monster has gained enough HP that they are no longer afraid */
335 if (QUERY_FLAG(op,FLAG_RUN_AWAY) && 345 if (QUERY_FLAG (op, FLAG_RUN_AWAY) && op->stats.hp >= (signed short) (((float) op->run_away / (float) 100) * (float) op->stats.maxhp))
336 op->stats.hp >= (signed short)(((float)op->run_away/(float)100)*
337 (float)op->stats.maxhp))
338 CLEAR_FLAG(op, FLAG_RUN_AWAY); 346 CLEAR_FLAG (op, FLAG_RUN_AWAY);
339 347
340 if(op->stats.hp>op->stats.maxhp) 348 if (op->stats.hp > op->stats.maxhp)
341 op->stats.hp=op->stats.maxhp; 349 op->stats.hp = op->stats.maxhp;
342 } 350 }
343 351
344 /* generate sp, if applicable */ 352 /* generate sp, if applicable */
345 if(op->stats.Pow > 0 && op->stats.sp < op->stats.maxsp) { 353 if (op->stats.Pow > 0 && op->stats.sp < op->stats.maxsp)
354 {
346 355
347 /* last_sp is in funny units. Dividing by speed puts 356 /* last_sp is in funny units. Dividing by speed puts
348 * the regeneration rate on a basis of time instead of 357 * the regeneration rate on a basis of time instead of
349 * #moves the monster makes. The scaling by 8 is 358 * #moves the monster makes. The scaling by 8 is
350 * to capture 8th's of a sp fraction regens 359 * to capture 8th's of a sp fraction regens
351 * 360 *
352 * Cast to sint32 before comparing to maxhp since otherwise an (sint16) 361 * Cast to sint32 before comparing to maxhp since otherwise an (sint16)
353 * overflow might produce monsters with negative sp. 362 * overflow might produce monsters with negative sp.
354 */ 363 */
355 364
356 op->last_sp+= (int)((float)(8*op->stats.Pow)/FABS(op->speed)); 365 op->last_sp += (int) ((float) (8 * op->stats.Pow) / FABS (op->speed));
357 op->stats.sp = MIN(op->stats.sp+op->last_sp/128, op->stats.maxsp); /* causes Pow/16 sp/tick */ 366 op->stats.sp = MIN (op->stats.sp + op->last_sp / 128, op->stats.maxsp); /* causes Pow/16 sp/tick */
358 op->last_sp%=128; 367 op->last_sp %= 128;
359 } 368 }
360 369
361 /* this should probably get modified by many more values. 370 /* this should probably get modified by many more values.
362 * (eg, creatures resistance to fear, level, etc. ) 371 * (eg, creatures resistance to fear, level, etc. )
363 */ 372 */
364 if(QUERY_FLAG(op, FLAG_SCARED) &&!(RANDOM()%20)) { 373 if (QUERY_FLAG (op, FLAG_SCARED) && !(RANDOM () % 20))
374 {
365 CLEAR_FLAG(op,FLAG_SCARED); /* Time to regain some "guts"... */ 375 CLEAR_FLAG (op, FLAG_SCARED); /* Time to regain some "guts"... */
366 } 376 }
367 377
368 if (INVOKE_OBJECT (MONSTER_MOVE, op, ARG_OBJECT (op->enemy))) 378 if (INVOKE_OBJECT (MONSTER_MOVE, op, ARG_OBJECT (op->enemy)))
369 return QUERY_FLAG (op, FLAG_FREED); 379 return QUERY_FLAG (op, FLAG_FREED);
370 380
371 if ( QUERY_FLAG(op, FLAG_SLEEP) || QUERY_FLAG(op, FLAG_BLIND) || 381 if (QUERY_FLAG (op, FLAG_SLEEP) || QUERY_FLAG (op, FLAG_BLIND) ||
372 ((op->map->darkness>0) && !QUERY_FLAG(op,FLAG_SEE_IN_DARK) && 382 ((op->map->darkness > 0) && !QUERY_FLAG (op, FLAG_SEE_IN_DARK) && !QUERY_FLAG (op, FLAG_SEE_INVISIBLE)))
373 !QUERY_FLAG(op,FLAG_SEE_INVISIBLE))) { 383 {
374 if(!check_wakeup(op,enemy,&rv)) 384 if (!check_wakeup (op, enemy, &rv))
375 return 0; 385 return 0;
376 } 386 }
377 387
378 /* check if monster pops out of hidden spot */ 388 /* check if monster pops out of hidden spot */
389 if (op->hide)
379 if(op->hide) do_hidden_move(op); 390 do_hidden_move (op);
380 391
381 if(op->pick_up) 392 if (op->pick_up)
382 monster_check_pickup(op); 393 monster_check_pickup (op);
383 394
384 if(op->will_apply) 395 if (op->will_apply)
385 monster_apply_below(op); /* Check for items to apply below */ 396 monster_apply_below (op); /* Check for items to apply below */
386 397
387 /* If we don't have an enemy, do special movement or the like */ 398 /* If we don't have an enemy, do special movement or the like */
388 if(!enemy) { 399 if (!enemy)
400 {
389 if(QUERY_FLAG(op, FLAG_ONLY_ATTACK)) { 401 if (QUERY_FLAG (op, FLAG_ONLY_ATTACK))
402 {
390 remove_ob(op); 403 remove_ob (op);
391 free_object(op); 404 free_object (op);
392 return 1; 405 return 1;
393 } 406 }
394 407
395 /* Probably really a bug for a creature to have both 408 /* Probably really a bug for a creature to have both
396 * stand still and a movement type set. 409 * stand still and a movement type set.
397 */ 410 */
398 if(!QUERY_FLAG(op, FLAG_STAND_STILL)) { 411 if (!QUERY_FLAG (op, FLAG_STAND_STILL))
412 {
399 if (op->attack_movement & HI4) 413 if (op->attack_movement & HI4)
400 { 414 {
401 switch (op->attack_movement & HI4) { 415 switch (op->attack_movement & HI4)
416 {
402 case (PETMOVE): 417 case (PETMOVE):
403 pet_move (op); 418 pet_move (op);
404 break; 419 break;
405 420
406 case (CIRCLE1): 421 case (CIRCLE1):
407 circ1_move (op); 422 circ1_move (op);
408 break; 423 break;
409 424
410 case (CIRCLE2): 425 case (CIRCLE2):
411 circ2_move (op); 426 circ2_move (op);
412 break; 427 break;
413 428
414 case (PACEV): 429 case (PACEV):
415 pace_movev(op); 430 pace_movev (op);
416 break; 431 break;
417 432
418 case (PACEH): 433 case (PACEH):
419 pace_moveh(op); 434 pace_moveh (op);
420 break; 435 break;
421 436
422 case (PACEV2): 437 case (PACEV2):
423 pace2_movev (op); 438 pace2_movev (op);
424 break; 439 break;
425 440
426 case (PACEH2): 441 case (PACEH2):
427 pace2_moveh (op); 442 pace2_moveh (op);
428 break; 443 break;
429 444
430 case (RANDO): 445 case (RANDO):
431 rand_move (op); 446 rand_move (op);
432 break; 447 break;
433 448
434 case (RANDO2): 449 case (RANDO2):
435 move_randomly (op); 450 move_randomly (op);
436 break; 451 break;
437 } 452 }
453 return 0;
454 }
455 else if (QUERY_FLAG (op, FLAG_RANDOM_MOVE))
456 (void) move_randomly (op);
457
458 } /* stand still */
459 return 0;
460 } /* no enemy */
461
462 /* We have an enemy. Block immediately below is for pets */
463 if ((op->attack_movement & HI4) == PETMOVE && (owner = get_owner (op)) != NULL && !on_same_map (op, owner))
464 return follow_owner (op, owner);
465
466 /* doppleganger code to change monster facing to that of the nearest
467 * player. Hmm. The code is here, but no monster in the current
468 * arch set uses it.
469 */
470 if ((op->race != NULL) && strcmp (op->race, "doppleganger") == 0)
471 {
472 op->face = enemy->face;
473 op->name = enemy->name;
474 }
475
476 /* Calculate range information for closest body part - this
477 * is used for the 'skill' code, which isn't that smart when
478 * it comes to figuring it out - otherwise, giants throw boulders
479 * into themselves.
480 */
481 get_rangevector (op, enemy, &rv, 0);
482
483 /* Move the check for scared up here - if the monster was scared,
484 * we were not doing any of the logic below, so might as well save
485 * a few cpu cycles.
486 */
487 if (!QUERY_FLAG (op, FLAG_SCARED))
488 {
489 rv_vector rv1;
490
491 /* now we test every part of an object .... this is a real ugly piece of code */
492 for (part = op; part != NULL; part = part->more)
493 {
494 get_rangevector (part, enemy, &rv1, 0x1);
495 dir = rv1.direction;
496
497 /* hm, not sure about this part - in original was a scared flag here too
498 * but that we test above... so can be old code here
499 */
500 if (QUERY_FLAG (op, FLAG_RUN_AWAY))
501 dir = absdir (dir + 4);
502 if (QUERY_FLAG (op, FLAG_CONFUSED))
503 dir = absdir (dir + RANDOM () % 3 + RANDOM () % 3 - 2);
504
505 if (QUERY_FLAG (op, FLAG_CAST_SPELL) && !(RANDOM () % 3))
506 {
507 if (monster_cast_spell (op, part, enemy, dir, &rv1))
438 return 0; 508 return 0;
439 } 509 }
440 else if (QUERY_FLAG(op,FLAG_RANDOM_MOVE))
441 (void) move_randomly(op);
442 510
443 } /* stand still */
444 return 0;
445 } /* no enemy */
446
447 /* We have an enemy. Block immediately below is for pets */
448 if((op->attack_movement&HI4) == PETMOVE && (owner = get_owner(op)) != NULL && !on_same_map(op,owner))
449 return follow_owner(op, owner);
450
451 /* doppleganger code to change monster facing to that of the nearest
452 * player. Hmm. The code is here, but no monster in the current
453 * arch set uses it.
454 */
455 if ( (op->race != NULL)&& strcmp(op->race,"doppleganger") == 0)
456 {
457 op->face = enemy->face;
458 op->name = enemy->name;
459 }
460
461 /* Calculate range information for closest body part - this
462 * is used for the 'skill' code, which isn't that smart when
463 * it comes to figuring it out - otherwise, giants throw boulders
464 * into themselves.
465 */
466 get_rangevector(op, enemy, &rv, 0);
467
468 /* Move the check for scared up here - if the monster was scared,
469 * we were not doing any of the logic below, so might as well save
470 * a few cpu cycles.
471 */
472 if (!QUERY_FLAG(op, FLAG_SCARED))
473 {
474 rv_vector rv1;
475
476 /* now we test every part of an object .... this is a real ugly piece of code */
477 for (part=op; part!=NULL; part=part->more) {
478 get_rangevector(part, enemy, &rv1, 0x1);
479 dir=rv1.direction;
480
481 /* hm, not sure about this part - in original was a scared flag here too
482 * but that we test above... so can be old code here
483 */
484 if(QUERY_FLAG(op,FLAG_RUN_AWAY))
485 dir=absdir(dir+4);
486 if(QUERY_FLAG(op,FLAG_CONFUSED))
487 dir = absdir(dir + RANDOM()%3 + RANDOM()%3 - 2);
488
489 if(QUERY_FLAG(op,FLAG_CAST_SPELL) && !(RANDOM()%3)) {
490 if(monster_cast_spell(op,part,enemy,dir,&rv1))
491 return 0;
492 }
493
494 if(QUERY_FLAG(op,FLAG_READY_SCROLL) && !(RANDOM()%3)) { 511 if (QUERY_FLAG (op, FLAG_READY_SCROLL) && !(RANDOM () % 3))
495 if(monster_use_scroll(op,part,enemy,dir,&rv1))
496 return 0;
497 }
498
499 if(QUERY_FLAG(op,FLAG_READY_RANGE)&&!(RANDOM()%3)) {
500 if(monster_use_range(op,part,enemy,dir))
501 return 0;
502 }
503 if(QUERY_FLAG(op,FLAG_READY_SKILL)&&!(RANDOM()%3)) {
504 if(monster_use_skill(op,rv.part,enemy,rv.direction))
505 return 0;
506 }
507 if(QUERY_FLAG(op,FLAG_READY_BOW)&&!(RANDOM()%2)) {
508 if(monster_use_bow(op,part,enemy,dir))
509 return 0;
510 }
511 } /* for processing of all parts */
512 } /* If not scared */
513
514
515 part = rv.part;
516 dir=rv.direction;
517
518 if(QUERY_FLAG(op, FLAG_SCARED) || QUERY_FLAG(op,FLAG_RUN_AWAY))
519 dir=absdir(dir+4);
520
521 if(QUERY_FLAG(op,FLAG_CONFUSED))
522 dir = absdir(dir + RANDOM()%3 + RANDOM()%3 - 2);
523
524 pre_att_dir = dir; /* remember the original direction */
525
526 if ((op->attack_movement & LO4) && !QUERY_FLAG(op, FLAG_SCARED))
527 {
528 switch (op->attack_movement & LO4) {
529 case DISTATT:
530 dir = dist_att (dir,op,enemy,part,&rv);
531 break;
532
533 case RUNATT:
534 dir = run_att (dir,op,enemy,part,&rv);
535 break;
536
537 case HITRUN:
538 dir = hitrun_att(dir,op,enemy);
539 break;
540
541 case WAITATT:
542 dir = wait_att (dir,op,enemy,part,&rv);
543 break;
544
545 case RUSH: /* default - monster normally moves towards player */
546 case ALLRUN:
547 break;
548
549 case DISTHIT:
550 dir = disthit_att (dir,op,enemy,part,&rv);
551 break;
552
553 case WAIT2:
554 dir = wait_att2 (dir,op,enemy,part,&rv);
555 break;
556
557 default:
558 LOG(llevDebug,"Illegal low mon-move: %d\n",op->attack_movement & LO4);
559 }
560 }
561
562 if (!dir)
563 return 0;
564
565 if (!QUERY_FLAG(op,FLAG_STAND_STILL)) {
566 if(move_object(op,dir)) /* Can the monster move directly toward player? */
567 { 512 {
568 /* elmex: Turn our monster after it moved if it has DISTATT attack */ 513 if (monster_use_scroll (op, part, enemy, dir, &rv1))
569 if ((op->attack_movement & LO4) == DISTATT)
570 op->direction = pre_att_dir;
571
572 return 0;
573 }
574
575 if(QUERY_FLAG(op, FLAG_SCARED) || !can_hit(part,enemy,&rv)
576 || QUERY_FLAG(op,FLAG_RUN_AWAY)) {
577
578 /* Try move around corners if !close */
579 int maxdiff = (QUERY_FLAG(op, FLAG_ONLY_ATTACK) || RANDOM()&1) ? 1 : 2;
580 for(diff = 1; diff <= maxdiff; diff++) {
581 /* try different detours */
582 int m = 1-(RANDOM()&2); /* Try left or right first? */
583 if(move_object(op,absdir(dir + diff*m)) ||
584 move_object(op,absdir(dir - diff*m)))
585 return 0; 514 return 0;
586 } 515 }
516
517 if (QUERY_FLAG (op, FLAG_READY_RANGE) && !(RANDOM () % 3))
518 {
519 if (monster_use_range (op, part, enemy, dir))
520 return 0;
521 }
522 if (QUERY_FLAG (op, FLAG_READY_SKILL) && !(RANDOM () % 3))
523 {
524 if (monster_use_skill (op, rv.part, enemy, rv.direction))
525 return 0;
526 }
527 if (QUERY_FLAG (op, FLAG_READY_BOW) && !(RANDOM () % 2))
528 {
529 if (monster_use_bow (op, part, enemy, dir))
530 return 0;
531 }
532 } /* for processing of all parts */
533 } /* If not scared */
534
535
536 part = rv.part;
537 dir = rv.direction;
538
539 if (QUERY_FLAG (op, FLAG_SCARED) || QUERY_FLAG (op, FLAG_RUN_AWAY))
540 dir = absdir (dir + 4);
541
542 if (QUERY_FLAG (op, FLAG_CONFUSED))
543 dir = absdir (dir + RANDOM () % 3 + RANDOM () % 3 - 2);
544
545 pre_att_dir = dir; /* remember the original direction */
546
547 if ((op->attack_movement & LO4) && !QUERY_FLAG (op, FLAG_SCARED))
548 {
549 switch (op->attack_movement & LO4)
587 } 550 {
551 case DISTATT:
552 dir = dist_att (dir, op, enemy, part, &rv);
553 break;
554
555 case RUNATT:
556 dir = run_att (dir, op, enemy, part, &rv);
557 break;
558
559 case HITRUN:
560 dir = hitrun_att (dir, op, enemy);
561 break;
562
563 case WAITATT:
564 dir = wait_att (dir, op, enemy, part, &rv);
565 break;
566
567 case RUSH: /* default - monster normally moves towards player */
568 case ALLRUN:
569 break;
570
571 case DISTHIT:
572 dir = disthit_att (dir, op, enemy, part, &rv);
573 break;
574
575 case WAIT2:
576 dir = wait_att2 (dir, op, enemy, part, &rv);
577 break;
578
579 default:
580 LOG (llevDebug, "Illegal low mon-move: %d\n", op->attack_movement & LO4);
581 }
582 }
583
584 if (!dir)
585 return 0;
586
587 if (!QUERY_FLAG (op, FLAG_STAND_STILL))
588 {
589 if (move_object (op, dir)) /* Can the monster move directly toward player? */
590 {
591 /* elmex: Turn our monster after it moved if it has DISTATT attack */
592 if ((op->attack_movement & LO4) == DISTATT)
593 op->direction = pre_att_dir;
594
595 return 0;
596 }
597
598 if (QUERY_FLAG (op, FLAG_SCARED) || !can_hit (part, enemy, &rv) || QUERY_FLAG (op, FLAG_RUN_AWAY))
599 {
600
601 /* Try move around corners if !close */
602 int maxdiff = (QUERY_FLAG (op, FLAG_ONLY_ATTACK) || RANDOM () & 1) ? 1 : 2;
603
604 for (diff = 1; diff <= maxdiff; diff++)
605 {
606 /* try different detours */
607 int m = 1 - (RANDOM () & 2); /* Try left or right first? */
608
609 if (move_object (op, absdir (dir + diff * m)) || move_object (op, absdir (dir - diff * m)))
610 return 0;
611 }
612 }
588 } /* if monster is not standing still */ 613 } /* if monster is not standing still */
589 614
590 /* elmex: Turn our monster after it moved if it has DISTATT attack */ 615 /* elmex: Turn our monster after it moved if it has DISTATT attack */
591 if ((op->attack_movement & LO4) == DISTATT) 616 if ((op->attack_movement & LO4) == DISTATT)
592 op->direction = pre_att_dir; 617 op->direction = pre_att_dir;
593 618
594 /* 619 /*
595 * Eneq(@csd.uu.se): Patch to make RUN_AWAY or SCARED monsters move a random 620 * Eneq(@csd.uu.se): Patch to make RUN_AWAY or SCARED monsters move a random
596 * direction if they can't move away. 621 * direction if they can't move away.
597 */ 622 */
598 if (!QUERY_FLAG(op, FLAG_ONLY_ATTACK)&&(QUERY_FLAG(op,FLAG_RUN_AWAY)||QUERY_FLAG(op, FLAG_SCARED))) 623 if (!QUERY_FLAG (op, FLAG_ONLY_ATTACK) && (QUERY_FLAG (op, FLAG_RUN_AWAY) || QUERY_FLAG (op, FLAG_SCARED)))
599 if(move_randomly(op)) 624 if (move_randomly (op))
600 return 0; 625 return 0;
601 626
602 /* 627 /*
603 * Try giving the monster a new enemy - the player that is closest 628 * Try giving the monster a new enemy - the player that is closest
604 * to it. In this way, it won't just keep trying to get to a target 629 * to it. In this way, it won't just keep trying to get to a target
605 * that is inaccessible. 630 * that is inaccessible.
606 * This could be more clever - it should go through a list of several 631 * This could be more clever - it should go through a list of several
607 * enemies, as it is now, you could perhaps get situations where there 632 * enemies, as it is now, you could perhaps get situations where there
608 * are two players flanking the monster at close distance, but which 633 * are two players flanking the monster at close distance, but which
609 * the monster can't get to, and a third one at a far distance that 634 * the monster can't get to, and a third one at a far distance that
610 * the monster could get to - as it is, the monster won't look at that 635 * the monster could get to - as it is, the monster won't look at that
611 * third one. 636 * third one.
612 */ 637 */
613 if (!QUERY_FLAG(op, FLAG_FRIENDLY) && enemy == op->enemy) 638 if (!QUERY_FLAG (op, FLAG_FRIENDLY) && enemy == op->enemy)
614 { 639 {
615 object *nearest_player = get_nearest_player(op); 640 object *nearest_player = get_nearest_player (op);
641
616 if (nearest_player && nearest_player != enemy && !can_hit(part,enemy,&rv)) { 642 if (nearest_player && nearest_player != enemy && !can_hit (part, enemy, &rv))
643 {
617 op->enemy = NULL; 644 op->enemy = NULL;
618 enemy = nearest_player; 645 enemy = nearest_player;
619 } 646 }
620 } 647 }
621 648
622 if(!QUERY_FLAG(op, FLAG_SCARED)&&can_hit(part,enemy,&rv)) 649 if (!QUERY_FLAG (op, FLAG_SCARED) && can_hit (part, enemy, &rv))
623 { 650 {
624 /* The adjustement to wc that was here before looked totally bogus - 651 /* The adjustement to wc that was here before looked totally bogus -
625 * since wc can in fact get negative, that would mean by adding 652 * since wc can in fact get negative, that would mean by adding
626 * the current wc, the creature gets better? Instead, just 653 * the current wc, the creature gets better? Instead, just
627 * add a fixed amount - nasty creatures that are runny away should 654 * add a fixed amount - nasty creatures that are runny away should
628 * still be pretty nasty. 655 * still be pretty nasty.
629 */ 656 */
630 if(QUERY_FLAG(op,FLAG_RUN_AWAY)) 657 if (QUERY_FLAG (op, FLAG_RUN_AWAY))
631 { 658 {
632 part->stats.wc+=10; 659 part->stats.wc += 10;
633 (void)skill_attack(enemy,part,0,NULL, NULL); 660 (void) skill_attack (enemy, part, 0, NULL, NULL);
634 part->stats.wc-=10; 661 part->stats.wc -= 10;
635 } 662 }
636 else 663 else
637 (void)skill_attack(enemy,part,0,NULL, NULL); 664 (void) skill_attack (enemy, part, 0, NULL, NULL);
638 } /* if monster is in attack range */ 665 } /* if monster is in attack range */
639 666
640 if(QUERY_FLAG(part,FLAG_FREED)) /* Might be freed by ghost-attack or hit-back */ 667 if (QUERY_FLAG (part, FLAG_FREED)) /* Might be freed by ghost-attack or hit-back */
641 return 1; 668 return 1;
642 669
643 if(QUERY_FLAG(op, FLAG_ONLY_ATTACK)) 670 if (QUERY_FLAG (op, FLAG_ONLY_ATTACK))
644 { 671 {
645 remove_ob(op); 672 remove_ob (op);
646 free_object(op); 673 free_object (op);
674 return 1;
675 }
676 return 0;
677}
678
679int
680can_hit (object *ob1, object *ob2, rv_vector * rv)
681{
682 object *more;
683 rv_vector rv1;
684
685 if (QUERY_FLAG (ob1, FLAG_CONFUSED) && !(RANDOM () % 3))
686 return 0;
687
688 if (abs (rv->distance_x) < 2 && abs (rv->distance_y) < 2)
689 return 1;
690
691 /* check all the parts of ob2 - just because we can't get to
692 * its head doesn't mean we don't want to pound its feet
693 */
694 for (more = ob2->more; more != NULL; more = more->more)
695 {
696 get_rangevector (ob1, more, &rv1, 0);
697 if (abs (rv1.distance_x) < 2 && abs (rv1.distance_y) < 2)
647 return 1; 698 return 1;
648 } 699 }
649 return 0; 700 return 0;
650}
651
652int can_hit(object *ob1,object *ob2, rv_vector *rv) {
653 object *more;
654 rv_vector rv1;
655
656 if(QUERY_FLAG(ob1,FLAG_CONFUSED)&&!(RANDOM()%3))
657 return 0;
658
659 if (abs(rv->distance_x)<2&&abs(rv->distance_y)<2) return 1;
660
661 /* check all the parts of ob2 - just because we can't get to
662 * its head doesn't mean we don't want to pound its feet
663 */
664 for (more = ob2->more; more!=NULL; more = more->more) {
665 get_rangevector(ob1, more, &rv1, 0);
666 if (abs(rv1.distance_x)<2&&abs(rv1.distance_y)<2) return 1;
667 }
668 return 0;
669 701
670} 702}
671 703
672/* Returns 1 is monster should cast spell sp at an enemy 704/* Returns 1 is monster should cast spell sp at an enemy
673 * Returns 0 if the monster should not cast this spell. 705 * Returns 0 if the monster should not cast this spell.
683 * This could be a lot smarter - if there are few monsters around, 715 * This could be a lot smarter - if there are few monsters around,
684 * then disease might not be as bad. Likewise, if the monster is damaged, 716 * then disease might not be as bad. Likewise, if the monster is damaged,
685 * the right type of healing spell could be useful. 717 * the right type of healing spell could be useful.
686 */ 718 */
687 719
720static int
688static int monster_should_cast_spell(object *monster, object *spell_ob) 721monster_should_cast_spell (object *monster, object *spell_ob)
689{ 722{
690 if (spell_ob->subtype == SP_BOLT || spell_ob->subtype == SP_BULLET || 723 if (spell_ob->subtype == SP_BOLT || spell_ob->subtype == SP_BULLET ||
691 spell_ob->subtype == SP_EXPLOSION || spell_ob->subtype == SP_CONE || 724 spell_ob->subtype == SP_EXPLOSION || spell_ob->subtype == SP_CONE ||
692 spell_ob->subtype == SP_BOMB || spell_ob->subtype == SP_SMITE || 725 spell_ob->subtype == SP_BOMB || spell_ob->subtype == SP_SMITE ||
693 spell_ob->subtype == SP_MAGIC_MISSILE || spell_ob->subtype == SP_SUMMON_GOLEM || 726 spell_ob->subtype == SP_MAGIC_MISSILE || spell_ob->subtype == SP_SUMMON_GOLEM ||
694 spell_ob->subtype == SP_MAGIC_WALL || spell_ob->subtype == SP_SUMMON_MONSTER || 727 spell_ob->subtype == SP_MAGIC_WALL || spell_ob->subtype == SP_SUMMON_MONSTER ||
695 spell_ob->subtype == SP_MOVING_BALL || spell_ob->subtype == SP_SWARM || 728 spell_ob->subtype == SP_MOVING_BALL || spell_ob->subtype == SP_SWARM || spell_ob->subtype == SP_INVISIBLE)
696 spell_ob->subtype == SP_INVISIBLE)
697 729
698 return 1;
699
700 return 0; 730 return 1;
731
732 return 0;
701} 733}
702 734
703 735
704#define MAX_KNOWN_SPELLS 20 736#define MAX_KNOWN_SPELLS 20
705 737
706/* Returns a randomly selected spell. This logic is still 738/* Returns a randomly selected spell. This logic is still
707 * less than ideal. This code also only seems to deal with 739 * less than ideal. This code also only seems to deal with
708 * wizard spells, as the check is against sp, and not grace. 740 * wizard spells, as the check is against sp, and not grace.
709 * can mosnters know cleric spells? 741 * can mosnters know cleric spells?
710 */ 742 */
743object *
711object *monster_choose_random_spell(object *monster) { 744monster_choose_random_spell (object *monster)
745{
712 object *altern[MAX_KNOWN_SPELLS]; 746 object *altern[MAX_KNOWN_SPELLS];
713 object *tmp; 747 object *tmp;
714 int i=0; 748 int i = 0;
715 749
716 for(tmp=monster->inv;tmp!=NULL;tmp=tmp->below) 750 for (tmp = monster->inv; tmp != NULL; tmp = tmp->below)
717 if (tmp->type==SPELLBOOK || tmp->type==SPELL) { 751 if (tmp->type == SPELLBOOK || tmp->type == SPELL)
752 {
718 /* Check and see if it's actually a useful spell. 753 /* Check and see if it's actually a useful spell.
719 * If its a spellbook, the spell is actually the inventory item. 754 * If its a spellbook, the spell is actually the inventory item.
720 * if it is a spell, then it is just the object itself. 755 * if it is a spell, then it is just the object itself.
721 */ 756 */
722 if (monster_should_cast_spell(monster, (tmp->type==SPELLBOOK)?tmp->inv:tmp)) { 757 if (monster_should_cast_spell (monster, (tmp->type == SPELLBOOK) ? tmp->inv : tmp))
758 {
723 altern[i++]=tmp; 759 altern[i++] = tmp;
724 if(i==MAX_KNOWN_SPELLS) 760 if (i == MAX_KNOWN_SPELLS)
725 break; 761 break;
726 } 762 }
727 } 763 }
728 if(!i) 764 if (!i)
729 return NULL; 765 return NULL;
730 return altern[RANDOM()%i]; 766 return altern[RANDOM () % i];
731} 767}
732 768
733/* This checks to see if the monster should cast a spell/ability. 769/* This checks to see if the monster should cast a spell/ability.
734 * it returns true if the monster casts a spell, 0 if he doesn't. 770 * it returns true if the monster casts a spell, 0 if he doesn't.
735 * head is the head of the monster. 771 * head is the head of the monster.
737 * pl is the target. 773 * pl is the target.
738 * dir is the direction to case. 774 * dir is the direction to case.
739 * rv is the vector which describes where the enemy is. 775 * rv is the vector which describes where the enemy is.
740 */ 776 */
741 777
778int
742int monster_cast_spell(object *head, object *part,object *pl,int dir, rv_vector *rv) { 779monster_cast_spell (object *head, object *part, object *pl, int dir, rv_vector * rv)
780{
743 object *spell_item; 781 object *spell_item;
744 object *owner; 782 object *owner;
745 rv_vector rv1; 783 rv_vector rv1;
746 784
747 /* If you want monsters to cast spells over friends, this spell should 785 /* If you want monsters to cast spells over friends, this spell should
748 * be removed. It probably should be in most cases, since monsters still 786 * be removed. It probably should be in most cases, since monsters still
749 * don't care about residual effects (ie, casting a cone which may have a 787 * don't care about residual effects (ie, casting a cone which may have a
750 * clear path to the player, the side aspects of the code will still hit 788 * clear path to the player, the side aspects of the code will still hit
751 * other monsters) 789 * other monsters)
752 */ 790 */
753 if(!(dir=path_to_player(part,pl,0))) 791 if (!(dir = path_to_player (part, pl, 0)))
754 return 0; 792 return 0;
755 793
756 if(QUERY_FLAG(head,FLAG_FRIENDLY) && (owner = get_owner(head)) != NULL) { 794 if (QUERY_FLAG (head, FLAG_FRIENDLY) && (owner = get_owner (head)) != NULL)
795 {
757 get_rangevector(head, owner, &rv1, 0x1); 796 get_rangevector (head, owner, &rv1, 0x1);
758 if(dirdiff(dir,rv1.direction) < 2) { 797 if (dirdiff (dir, rv1.direction) < 2)
759 return 0; /* Might hit owner with spell */
760 } 798 {
799 return 0; /* Might hit owner with spell */
800 }
761 } 801 }
762 802
763 if(QUERY_FLAG(head,FLAG_CONFUSED)) 803 if (QUERY_FLAG (head, FLAG_CONFUSED))
764 dir = absdir(dir + RANDOM()%3 + RANDOM()%3 - 2); 804 dir = absdir (dir + RANDOM () % 3 + RANDOM () % 3 - 2);
765 805
766 /* If the monster hasn't already chosen a spell, choose one 806 /* If the monster hasn't already chosen a spell, choose one
767 * I'm not sure if it really make sense to pre-select spells (events 807 * I'm not sure if it really make sense to pre-select spells (events
768 * could be different by the time the monster goes again). 808 * could be different by the time the monster goes again).
769 */ 809 */
770 if(head->spellitem==NULL) { 810 if (head->spellitem == NULL)
811 {
771 if((spell_item=monster_choose_random_spell(head))==NULL) { 812 if ((spell_item = monster_choose_random_spell (head)) == NULL)
813 {
772 LOG(llevMonster,"Turned off spells in %s\n",&head->name); 814 LOG (llevMonster, "Turned off spells in %s\n", &head->name);
773 CLEAR_FLAG(head, FLAG_CAST_SPELL); /* Will be turned on when picking up book */ 815 CLEAR_FLAG (head, FLAG_CAST_SPELL); /* Will be turned on when picking up book */
774 return 0; 816 return 0;
775 } 817 }
776 if (spell_item->type == SPELLBOOK) { 818 if (spell_item->type == SPELLBOOK)
819 {
777 if (!spell_item->inv) { 820 if (!spell_item->inv)
821 {
778 LOG(llevError,"spellbook %s does not contain a spell?\n", &spell_item->name); 822 LOG (llevError, "spellbook %s does not contain a spell?\n", &spell_item->name);
779 return 0; 823 return 0;
780 } 824 }
781 spell_item=spell_item->inv; 825 spell_item = spell_item->inv;
782 } 826 }
783 } 827 }
784 else 828 else
785 spell_item=head->spellitem; 829 spell_item = head->spellitem;
786 830
787 if (!spell_item) return 0; 831 if (!spell_item)
832 return 0;
788 833
789 /* Best guess this is a defensive/healing spell */ 834 /* Best guess this is a defensive/healing spell */
790 if (spell_item->range<=1 || spell_item->stats.dam < 0) 835 if (spell_item->range <= 1 || spell_item->stats.dam < 0)
791 dir = 0; 836 dir = 0;
792 837
793 /* Monster doesn't have enough spell-points */ 838 /* Monster doesn't have enough spell-points */
794 if(head->stats.sp<SP_level_spellpoint_cost(head,spell_item, SPELL_MANA)) 839 if (head->stats.sp < SP_level_spellpoint_cost (head, spell_item, SPELL_MANA))
795 return 0; 840 return 0;
796 841
797 if(head->stats.grace<SP_level_spellpoint_cost(head,spell_item, SPELL_GRACE)) 842 if (head->stats.grace < SP_level_spellpoint_cost (head, spell_item, SPELL_GRACE))
798 return 0; 843 return 0;
799 844
800 head->stats.sp-=SP_level_spellpoint_cost(head,spell_item, SPELL_MANA); 845 head->stats.sp -= SP_level_spellpoint_cost (head, spell_item, SPELL_MANA);
801 head->stats.grace-=SP_level_spellpoint_cost(head,spell_item, SPELL_GRACE); 846 head->stats.grace -= SP_level_spellpoint_cost (head, spell_item, SPELL_GRACE);
802 847
803 /* set this to null, so next time monster will choose something different */ 848 /* set this to null, so next time monster will choose something different */
804 head->spellitem = NULL; 849 head->spellitem = NULL;
805 850
806 return cast_spell(part,part,dir, spell_item, NULL); 851 return cast_spell (part, part, dir, spell_item, NULL);
807} 852}
808 853
809 854
855int
810int monster_use_scroll(object *head, object *part,object *pl,int dir, rv_vector *rv) { 856monster_use_scroll (object *head, object *part, object *pl, int dir, rv_vector * rv)
857{
811 object *scroll; 858 object *scroll;
812 object *owner; 859 object *owner;
813 rv_vector rv1; 860 rv_vector rv1;
814 861
815 /* If you want monsters to cast spells over friends, this spell should 862 /* If you want monsters to cast spells over friends, this spell should
816 * be removed. It probably should be in most cases, since monsters still 863 * be removed. It probably should be in most cases, since monsters still
817 * don't care about residual effects (ie, casting a cone which may have a 864 * don't care about residual effects (ie, casting a cone which may have a
818 * clear path to the player, the side aspects of the code will still hit 865 * clear path to the player, the side aspects of the code will still hit
819 * other monsters) 866 * other monsters)
820 */ 867 */
821 if(!(dir=path_to_player(part,pl,0))) 868 if (!(dir = path_to_player (part, pl, 0)))
822 return 0; 869 return 0;
823 870
824 if(QUERY_FLAG(head,FLAG_FRIENDLY) && (owner = get_owner(head)) != NULL) { 871 if (QUERY_FLAG (head, FLAG_FRIENDLY) && (owner = get_owner (head)) != NULL)
872 {
825 get_rangevector(head, owner, &rv1, 0x1); 873 get_rangevector (head, owner, &rv1, 0x1);
826 if(dirdiff(dir,rv1.direction) < 2) { 874 if (dirdiff (dir, rv1.direction) < 2)
827 return 0; /* Might hit owner with spell */
828 } 875 {
876 return 0; /* Might hit owner with spell */
877 }
829 } 878 }
830 879
831 if(QUERY_FLAG(head,FLAG_CONFUSED)) 880 if (QUERY_FLAG (head, FLAG_CONFUSED))
832 dir = absdir(dir + RANDOM()%3 + RANDOM()%3 - 2); 881 dir = absdir (dir + RANDOM () % 3 + RANDOM () % 3 - 2);
833 882
834 for (scroll=head->inv; scroll; scroll=scroll->below) 883 for (scroll = head->inv; scroll; scroll = scroll->below)
835 if (scroll->type == SCROLL && monster_should_cast_spell(head, scroll->inv)) break; 884 if (scroll->type == SCROLL && monster_should_cast_spell (head, scroll->inv))
885 break;
836 886
837 /* Used up all his scrolls, so nothing do to */ 887 /* Used up all his scrolls, so nothing do to */
838 if (!scroll) { 888 if (!scroll)
889 {
839 CLEAR_FLAG(head, FLAG_READY_SCROLL); 890 CLEAR_FLAG (head, FLAG_READY_SCROLL);
840 return 0; 891 return 0;
841 } 892 }
842 893
843 /* Spell should be cast on caster (ie, heal, strength) */ 894 /* Spell should be cast on caster (ie, heal, strength) */
844 if (scroll->inv->range==0) 895 if (scroll->inv->range == 0)
845 dir = 0; 896 dir = 0;
846 897
847 apply_scroll(part, scroll, dir); 898 apply_scroll (part, scroll, dir);
848 return 1; 899 return 1;
849} 900}
850 901
851/* monster_use_skill()-implemented 95-04-28 to allow monster skill use. 902/* monster_use_skill()-implemented 95-04-28 to allow monster skill use.
852 * Note that monsters do not need the skills SK_MELEE_WEAPON and 903 * Note that monsters do not need the skills SK_MELEE_WEAPON and
853 * SK_MISSILE_WEAPON to make those respective attacks, if we 904 * SK_MISSILE_WEAPON to make those respective attacks, if we
856 * 907 *
857 * The skills we are treating here are all but those. -b.t. 908 * The skills we are treating here are all but those. -b.t.
858 * 909 *
859 * At the moment this is only useful for throwing, perhaps for 910 * At the moment this is only useful for throwing, perhaps for
860 * stealing. TODO: This should be more integrated in the game. -MT, 25.11.01 911 * stealing. TODO: This should be more integrated in the game. -MT, 25.11.01
861 */ 912 */
862 913
914int
863int monster_use_skill(object *head, object *part, object *pl,int dir) { 915monster_use_skill (object *head, object *part, object *pl, int dir)
916{
864 object *skill, *owner; 917 object *skill, *owner;
865 918
866 if(!(dir=path_to_player(part,pl,0))) 919 if (!(dir = path_to_player (part, pl, 0)))
867 return 0; 920 return 0;
868 921
869 if(QUERY_FLAG(head,FLAG_FRIENDLY) && (owner = get_owner(head)) != NULL) { 922 if (QUERY_FLAG (head, FLAG_FRIENDLY) && (owner = get_owner (head)) != NULL)
923 {
870 int dir2 = find_dir_2(head->x-owner->x, head->y-owner->y); 924 int dir2 = find_dir_2 (head->x - owner->x, head->y - owner->y);
925
871 if(dirdiff(dir,dir2) < 1) 926 if (dirdiff (dir, dir2) < 1)
872 return 0; /* Might hit owner with skill -thrown rocks for example ?*/ 927 return 0; /* Might hit owner with skill -thrown rocks for example ? */
873 } 928 }
874 if(QUERY_FLAG(head,FLAG_CONFUSED)) 929 if (QUERY_FLAG (head, FLAG_CONFUSED))
875 dir = absdir(dir + RANDOM()%3 + RANDOM()%3 - 2); 930 dir = absdir (dir + RANDOM () % 3 + RANDOM () % 3 - 2);
876 931
877 /* skill selection - monster will use the next unused skill. 932 /* skill selection - monster will use the next unused skill.
878 * well...the following scenario will allow the monster to 933 * well...the following scenario will allow the monster to
879 * toggle between 2 skills. One day it would be nice to make 934 * toggle between 2 skills. One day it would be nice to make
880 * more skills available to monsters. 935 * more skills available to monsters.
881 */ 936 */
882 937
883 for(skill=head->inv;skill!=NULL;skill=skill->below) 938 for (skill = head->inv; skill != NULL; skill = skill->below)
884 if(skill->type==SKILL && skill!=head->chosen_skill) { 939 if (skill->type == SKILL && skill != head->chosen_skill)
940 {
885 head->chosen_skill=skill; 941 head->chosen_skill = skill;
886 break; 942 break;
887 } 943 }
888 944
889 if(!skill && !head->chosen_skill) { 945 if (!skill && !head->chosen_skill)
946 {
890 LOG(llevDebug,"Error: Monster %s (%d) has FLAG_READY_SKILL without skill.\n", 947 LOG (llevDebug, "Error: Monster %s (%d) has FLAG_READY_SKILL without skill.\n", &head->name, head->count);
891 &head->name,head->count);
892 CLEAR_FLAG(head, FLAG_READY_SKILL); 948 CLEAR_FLAG (head, FLAG_READY_SKILL);
893 return 0; 949 return 0;
894 } 950 }
895 /* use skill */ 951 /* use skill */
896 return do_skill(head, part, head->chosen_skill,dir,NULL); 952 return do_skill (head, part, head->chosen_skill, dir, NULL);
897} 953}
898 954
899/* Monster will use a ranged spell attack. */ 955/* Monster will use a ranged spell attack. */
900 956
957int
901int monster_use_range(object *head,object *part,object *pl,int dir) 958monster_use_range (object *head, object *part, object *pl, int dir)
902 { 959{
903 object *wand, *owner; 960 object *wand, *owner;
904 int at_least_one = 0; 961 int at_least_one = 0;
905 962
906 if(!(dir=path_to_player(part,pl,0))) 963 if (!(dir = path_to_player (part, pl, 0)))
907 return 0; 964 return 0;
908 965
909 if(QUERY_FLAG(head,FLAG_FRIENDLY) && (owner = get_owner(head)) != NULL) { 966 if (QUERY_FLAG (head, FLAG_FRIENDLY) && (owner = get_owner (head)) != NULL)
967 {
910 int dir2 = find_dir_2(head->x-owner->x, head->y-owner->y); 968 int dir2 = find_dir_2 (head->x - owner->x, head->y - owner->y);
969
911 if(dirdiff(dir,dir2) < 2) 970 if (dirdiff (dir, dir2) < 2)
912 return 0; /* Might hit owner with spell */ 971 return 0; /* Might hit owner with spell */
913 } 972 }
914 if(QUERY_FLAG(head,FLAG_CONFUSED)) 973 if (QUERY_FLAG (head, FLAG_CONFUSED))
915 dir = absdir(dir + RANDOM()%3 + RANDOM()%3 - 2); 974 dir = absdir (dir + RANDOM () % 3 + RANDOM () % 3 - 2);
916 975
917 for(wand=head->inv;wand!=NULL;wand=wand->below) 976 for (wand = head->inv; wand != NULL; wand = wand->below)
918 { 977 {
919 if (wand->type == WAND) 978 if (wand->type == WAND)
979 {
980 /* Found a wand, let's see if it has charges left */
981 at_least_one = 1;
982 if (wand->stats.food <= 0)
983 continue;
984
985 cast_spell (head, wand, dir, wand->inv, NULL);
986
987 if (!(--wand->stats.food))
920 { 988 {
921 /* Found a wand, let's see if it has charges left */ 989 if (wand->arch)
922 at_least_one = 1;
923 if( wand->stats.food<=0 )
924 continue;
925
926 cast_spell( head, wand, dir, wand->inv, NULL );
927
928 if ( !( --wand->stats.food ) )
929 { 990 {
930 if ( wand->arch )
931 {
932 CLEAR_FLAG(wand, FLAG_ANIMATE); 991 CLEAR_FLAG (wand, FLAG_ANIMATE);
933 wand->face = wand->arch->clone.face; 992 wand->face = wand->arch->clone.face;
934 wand->speed = 0; 993 wand->speed = 0;
935 update_ob_speed(wand); 994 update_ob_speed (wand);
936 }
937 } 995 }
938 /* Success */
939 return 1;
940 } 996 }
997 /* Success */
998 return 1;
999 }
941 else if ( wand->type == ROD || wand->type==HORN ) { 1000 else if (wand->type == ROD || wand->type == HORN)
1001 {
942 /* Found rod/horn, let's use it if possible */ 1002 /* Found rod/horn, let's use it if possible */
943 at_least_one = 1; 1003 at_least_one = 1;
944 if( wand->stats.hp < MAX( wand->inv->stats.sp, wand->inv->stats.grace ) ) 1004 if (wand->stats.hp < MAX (wand->inv->stats.sp, wand->inv->stats.grace))
945 continue; 1005 continue;
946 1006
947 /* drain charge before casting spell - can be a case where the 1007 /* drain charge before casting spell - can be a case where the
948 * spell destroys the monster, and rod, so if done after, results 1008 * spell destroys the monster, and rod, so if done after, results
949 * in crash. 1009 * in crash.
950 */ 1010 */
951 drain_rod_charge( wand ); 1011 drain_rod_charge (wand);
952 cast_spell( head, wand, dir, wand->inv, NULL ); 1012 cast_spell (head, wand, dir, wand->inv, NULL);
953 1013
954 /* Success */ 1014 /* Success */
955 return 1; 1015 return 1;
956 } 1016 }
957 } 1017 }
958 1018
959 if ( at_least_one ) 1019 if (at_least_one)
960 return 0; 1020 return 0;
961 1021
962 LOG(llevError,"Error: Monster %s (%d) HAS_READY_RANG() without wand/horn/rod.\n", 1022 LOG (llevError, "Error: Monster %s (%d) HAS_READY_RANG() without wand/horn/rod.\n", &head->name, head->count);
963 &head->name,head->count);
964 CLEAR_FLAG(head, FLAG_READY_RANGE); 1023 CLEAR_FLAG (head, FLAG_READY_RANGE);
965 return 0; 1024 return 0;
966 } 1025}
967 1026
1027int
968int monster_use_bow(object *head, object *part, object *pl, int dir) { 1028monster_use_bow (object *head, object *part, object *pl, int dir)
1029{
969 object *owner; 1030 object *owner;
970 1031
971 if(!(dir=path_to_player(part,pl,0))) 1032 if (!(dir = path_to_player (part, pl, 0)))
972 return 0; 1033 return 0;
973 if(QUERY_FLAG(head,FLAG_CONFUSED)) 1034 if (QUERY_FLAG (head, FLAG_CONFUSED))
974 dir = absdir(dir + RANDOM()%3 + RANDOM()%3 - 2); 1035 dir = absdir (dir + RANDOM () % 3 + RANDOM () % 3 - 2);
975 1036
976 if(QUERY_FLAG(head,FLAG_FRIENDLY) && (owner = get_owner(head)) != NULL) { 1037 if (QUERY_FLAG (head, FLAG_FRIENDLY) && (owner = get_owner (head)) != NULL)
1038 {
977 int dir2 = find_dir_2(head->x-owner->x, head->y-owner->y); 1039 int dir2 = find_dir_2 (head->x - owner->x, head->y - owner->y);
1040
978 if(dirdiff(dir,dir2) < 1) 1041 if (dirdiff (dir, dir2) < 1)
979 return 0; /* Might hit owner with arrow */ 1042 return 0; /* Might hit owner with arrow */
980 } 1043 }
981 1044
982 /* in server/player.c */ 1045 /* in server/player.c */
983 return fire_bow(head, part, NULL, dir, 0, part->x, part->y); 1046 return fire_bow (head, part, NULL, dir, 0, part->x, part->y);
984 1047
985} 1048}
986 1049
987/* Checks if putting on 'item' will make 'who' do more 1050/* Checks if putting on 'item' will make 'who' do more
988 * damage. This is a very simplistic check - also checking things 1051 * damage. This is a very simplistic check - also checking things
989 * like speed and ac are also relevant. 1052 * like speed and ac are also relevant.
990 * 1053 *
991 * return true if item is a better object. 1054 * return true if item is a better object.
992 */ 1055 */
993 1056
1057int
994int check_good_weapon(object *who, object *item) { 1058check_good_weapon (object *who, object *item)
1059{
995 object *other_weap; 1060 object *other_weap;
996 int val=0, i; 1061 int val = 0, i;
997 1062
998 for(other_weap=who->inv;other_weap!=NULL;other_weap=other_weap->below) 1063 for (other_weap = who->inv; other_weap != NULL; other_weap = other_weap->below)
999 if(other_weap->type==item->type&&QUERY_FLAG(other_weap,FLAG_APPLIED)) 1064 if (other_weap->type == item->type && QUERY_FLAG (other_weap, FLAG_APPLIED))
1000 break; 1065 break;
1001 1066
1002 if(other_weap==NULL) /* No other weapons */ 1067 if (other_weap == NULL) /* No other weapons */
1003 return 1; 1068 return 1;
1004 1069
1005 /* Rather than go through and apply the new one, and see if it is 1070 /* Rather than go through and apply the new one, and see if it is
1006 * better, just do some simple checks 1071 * better, just do some simple checks
1007 * Put some multipliers for things that hvae several effects, 1072 * Put some multipliers for things that hvae several effects,
1008 * eg, magic affects both damage and wc, so it has more weight 1073 * eg, magic affects both damage and wc, so it has more weight
1009 */ 1074 */
1010 1075
1011 val = item->stats.dam - other_weap->stats.dam; 1076 val = item->stats.dam - other_weap->stats.dam;
1012 val += (item->magic - other_weap->magic) * 3; 1077 val += (item->magic - other_weap->magic) * 3;
1013 /* Monsters don't really get benefits from things like regen rates 1078 /* Monsters don't really get benefits from things like regen rates
1014 * from items. But the bonus for their stats are very important. 1079 * from items. But the bonus for their stats are very important.
1015 */ 1080 */
1016 for (i=0; i<NUM_STATS; i++) 1081 for (i = 0; i < NUM_STATS; i++)
1017 val += (get_attr_value(&item->stats, i) - get_attr_value(&other_weap->stats, i))*2; 1082 val += (get_attr_value (&item->stats, i) - get_attr_value (&other_weap->stats, i)) * 2;
1018 1083
1019 if (val > 0) return 1; 1084 if (val > 0)
1085 return 1;
1086 else
1020 else return 0; 1087 return 0;
1021 1088
1022} 1089}
1023 1090
1091int
1024int check_good_armour(object *who, object *item) { 1092check_good_armour (object *who, object *item)
1093{
1025 object *other_armour; 1094 object *other_armour;
1026 int val=0,i; 1095 int val = 0, i;
1027 1096
1028 for (other_armour = who->inv; other_armour != NULL; 1097 for (other_armour = who->inv; other_armour != NULL; other_armour = other_armour->below)
1029 other_armour = other_armour->below)
1030 if (other_armour->type == item->type && QUERY_FLAG(other_armour,FLAG_APPLIED)) 1098 if (other_armour->type == item->type && QUERY_FLAG (other_armour, FLAG_APPLIED))
1031 break; 1099 break;
1032 1100
1033 if (other_armour == NULL) /* No other armour, use the new */ 1101 if (other_armour == NULL) /* No other armour, use the new */
1034 return 1; 1102 return 1;
1035 1103
1036 /* Like above function , see which is better */ 1104 /* Like above function , see which is better */
1037 val = item->stats.ac - other_armour->stats.ac; 1105 val = item->stats.ac - other_armour->stats.ac;
1038 val = (item->resist[ATNR_PHYSICAL] - other_armour->resist[ATNR_PHYSICAL])/5; 1106 val = (item->resist[ATNR_PHYSICAL] - other_armour->resist[ATNR_PHYSICAL]) / 5;
1039 val += (item->magic - other_armour->magic) * 3; 1107 val += (item->magic - other_armour->magic) * 3;
1040 1108
1041 /* for the other protections, do weigh them very much in the equation - 1109 /* for the other protections, do weigh them very much in the equation -
1042 * it is the armor protection which is most important, because there is 1110 * it is the armor protection which is most important, because there is
1043 * no good way to know what the player may attack the monster with. 1111 * no good way to know what the player may attack the monster with.
1044 * So if the new item has better protection than the old, give that higher 1112 * So if the new item has better protection than the old, give that higher
1045 * value. If the reverse, then decrease the value of this item some. 1113 * value. If the reverse, then decrease the value of this item some.
1046 */ 1114 */
1047 for (i=1; i <NROFATTACKS; i++) { 1115 for (i = 1; i < NROFATTACKS; i++)
1116 {
1048 if (item->resist[i] > other_armour->resist[i]) val++; 1117 if (item->resist[i] > other_armour->resist[i])
1118 val++;
1049 else if (item->resist[i] < other_armour->resist[i]) val--; 1119 else if (item->resist[i] < other_armour->resist[i])
1120 val--;
1050 } 1121 }
1051 1122
1052 /* Very few armours have stats, so not much need to worry about those. */ 1123 /* Very few armours have stats, so not much need to worry about those. */
1053 1124
1054 if (val > 0) return 1; 1125 if (val > 0)
1126 return 1;
1127 else
1055 else return 0; 1128 return 0;
1056 1129
1057} 1130}
1058 1131
1059/* 1132/*
1060 * monster_check_pickup(): checks for items that monster can pick up. 1133 * monster_check_pickup(): checks for items that monster can pick up.
1070 * became a recursive loop. It may be better to call monster_check_apply 1143 * became a recursive loop. It may be better to call monster_check_apply
1071 * after we pick everything up, since that function may call others which 1144 * after we pick everything up, since that function may call others which
1072 * affect stacking on this space. 1145 * affect stacking on this space.
1073 */ 1146 */
1074 1147
1148void
1075void monster_check_pickup(object *monster) { 1149monster_check_pickup (object *monster)
1150{
1076 object *tmp,*next; 1151 object *tmp, *next;
1077 int next_tag; 1152 int next_tag;
1078 1153
1079 for(tmp=monster->below;tmp!=NULL;tmp=next) { 1154 for (tmp = monster->below; tmp != NULL; tmp = next)
1155 {
1080 next=tmp->below; 1156 next = tmp->below;
1081 next_tag = next ? next->count : 0; 1157 next_tag = next ? next->count : 0;
1082 if (monster_can_pick(monster,tmp)) { 1158 if (monster_can_pick (monster, tmp))
1159 {
1083 remove_ob(tmp); 1160 remove_ob (tmp);
1084 tmp = insert_ob_in_ob(tmp,monster); 1161 tmp = insert_ob_in_ob (tmp, monster);
1085 (void) monster_check_apply(monster,tmp); 1162 (void) monster_check_apply (monster, tmp);
1086 } 1163 }
1087 /* We could try to re-establish the cycling, of the space, but probably 1164 /* We could try to re-establish the cycling, of the space, but probably
1088 * not a big deal to just bail out. 1165 * not a big deal to just bail out.
1089 */ 1166 */
1090 if (next && was_destroyed(next, next_tag)) return; 1167 if (next && was_destroyed (next, next_tag))
1168 return;
1091 } 1169 }
1092} 1170}
1093 1171
1094/* 1172/*
1095 * monster_can_pick(): If the monster is interested in picking up 1173 * monster_can_pick(): If the monster is interested in picking up
1096 * the item, then return 0. Otherwise 0. 1174 * the item, then return 0. Otherwise 0.
1097 * Instead of pick_up, flags for "greed", etc, should be used. 1175 * Instead of pick_up, flags for "greed", etc, should be used.
1098 * I've already utilized flags for bows, wands, rings, etc, etc. -Frank. 1176 * I've already utilized flags for bows, wands, rings, etc, etc. -Frank.
1099 */ 1177 */
1100 1178
1179int
1101int monster_can_pick(object *monster, object *item) { 1180monster_can_pick (object *monster, object *item)
1181{
1102 int flag=0; 1182 int flag = 0;
1103 int i; 1183 int i;
1104 1184
1105 if(!can_pick(monster,item)) 1185 if (!can_pick (monster, item))
1106 return 0; 1186 return 0;
1107 1187
1108 if(QUERY_FLAG(item,FLAG_UNPAID)) 1188 if (QUERY_FLAG (item, FLAG_UNPAID))
1109 return 0; 1189 return 0;
1110 1190
1111 if (monster->pick_up&64) /* All */ 1191 if (monster->pick_up & 64) /* All */
1112 flag=1; 1192 flag = 1;
1113 1193
1194 else
1114 else switch(item->type) { 1195 switch (item->type)
1196 {
1115 case MONEY: 1197 case MONEY:
1116 case GEM: 1198 case GEM:
1117 flag=monster->pick_up&2; 1199 flag = monster->pick_up & 2;
1118 break; 1200 break;
1119 1201
1120 case FOOD: 1202 case FOOD:
1121 flag=monster->pick_up&4; 1203 flag = monster->pick_up & 4;
1122 break; 1204 break;
1123 1205
1124 case WEAPON: 1206 case WEAPON:
1125 flag=(monster->pick_up&8)||QUERY_FLAG(monster,FLAG_USE_WEAPON); 1207 flag = (monster->pick_up & 8) || QUERY_FLAG (monster, FLAG_USE_WEAPON);
1126 break; 1208 break;
1127 1209
1128 case ARMOUR: 1210 case ARMOUR:
1129 case SHIELD: 1211 case SHIELD:
1130 case HELMET: 1212 case HELMET:
1131 case BOOTS: 1213 case BOOTS:
1132 case GLOVES: 1214 case GLOVES:
1133 case GIRDLE: 1215 case GIRDLE:
1134 flag=(monster->pick_up&16)||QUERY_FLAG(monster,FLAG_USE_ARMOUR); 1216 flag = (monster->pick_up & 16) || QUERY_FLAG (monster, FLAG_USE_ARMOUR);
1135 break; 1217 break;
1136 1218
1137 case SKILL: 1219 case SKILL:
1138 flag=QUERY_FLAG(monster,FLAG_CAN_USE_SKILL); 1220 flag = QUERY_FLAG (monster, FLAG_CAN_USE_SKILL);
1139 break; 1221 break;
1140 1222
1141 case RING: 1223 case RING:
1142 flag=QUERY_FLAG(monster,FLAG_USE_RING); 1224 flag = QUERY_FLAG (monster, FLAG_USE_RING);
1143 break; 1225 break;
1144 1226
1145 case WAND: 1227 case WAND:
1146 case HORN: 1228 case HORN:
1147 case ROD: 1229 case ROD:
1148 flag=QUERY_FLAG(monster,FLAG_USE_RANGE); 1230 flag = QUERY_FLAG (monster, FLAG_USE_RANGE);
1149 break; 1231 break;
1150 1232
1151 case SPELLBOOK: 1233 case SPELLBOOK:
1152 flag=(monster->arch!=NULL&&QUERY_FLAG((&monster->arch->clone),FLAG_CAST_SPELL)); 1234 flag = (monster->arch != NULL && QUERY_FLAG ((&monster->arch->clone), FLAG_CAST_SPELL));
1153 break; 1235 break;
1154 1236
1155 case SCROLL: 1237 case SCROLL:
1156 flag = QUERY_FLAG(monster,FLAG_USE_SCROLL); 1238 flag = QUERY_FLAG (monster, FLAG_USE_SCROLL);
1157 break; 1239 break;
1158 1240
1159 case BOW: 1241 case BOW:
1160 case ARROW: 1242 case ARROW:
1161 flag=QUERY_FLAG(monster,FLAG_USE_BOW); 1243 flag = QUERY_FLAG (monster, FLAG_USE_BOW);
1162 break; 1244 break;
1163 } 1245 }
1164 /* Simplistic check - if the monster has a location to equip it, he will 1246 /* Simplistic check - if the monster has a location to equip it, he will
1165 * pick it up. Note that this doesn't handle cases where an item may 1247 * pick it up. Note that this doesn't handle cases where an item may
1166 * use several locations. 1248 * use several locations.
1167 */ 1249 */
1168 for (i=0; i < NUM_BODY_LOCATIONS; i++) { 1250 for (i = 0; i < NUM_BODY_LOCATIONS; i++)
1251 {
1169 if (monster->body_info[i] && item->body_info[i]) { 1252 if (monster->body_info[i] && item->body_info[i])
1253 {
1170 flag=1; 1254 flag = 1;
1171 break; 1255 break;
1172 } 1256 }
1173 } 1257 }
1174 1258
1175 if (((!(monster->pick_up&32))&&flag) || ((monster->pick_up&32)&&(!flag))) 1259 if (((!(monster->pick_up & 32)) && flag) || ((monster->pick_up & 32) && (!flag)))
1176 return 1;
1177 return 0; 1260 return 1;
1261 return 0;
1178} 1262}
1179 1263
1180/* 1264/*
1181 * monster_apply_below(): 1265 * monster_apply_below():
1182 * Vick's (vick@bern.docs.uu.se) @921107 -> If a monster who's 1266 * Vick's (vick@bern.docs.uu.se) @921107 -> If a monster who's
1183 * eager to apply things, encounters something apply-able, 1267 * eager to apply things, encounters something apply-able,
1184 * then make him apply it 1268 * then make him apply it
1185 */ 1269 */
1186 1270
1271void
1187void monster_apply_below(object *monster) { 1272monster_apply_below (object *monster)
1273{
1188 object *tmp, *next; 1274 object *tmp, *next;
1189 1275
1190 for(tmp=monster->below;tmp!=NULL;tmp=next) { 1276 for (tmp = monster->below; tmp != NULL; tmp = next)
1277 {
1191 next=tmp->below; 1278 next = tmp->below;
1192 switch (tmp->type) { 1279 switch (tmp->type)
1280 {
1193 case CF_HANDLE: 1281 case CF_HANDLE:
1194 case TRIGGER: 1282 case TRIGGER:
1195 if (monster->will_apply&1) 1283 if (monster->will_apply & 1)
1196 manual_apply(monster,tmp,0); 1284 manual_apply (monster, tmp, 0);
1197 break; 1285 break;
1198 1286
1199 case TREASURE: 1287 case TREASURE:
1200 if (monster->will_apply&2) 1288 if (monster->will_apply & 2)
1201 manual_apply(monster,tmp,0); 1289 manual_apply (monster, tmp, 0);
1202 break; 1290 break;
1203 1291
1204 } 1292 }
1205 if (QUERY_FLAG (tmp, FLAG_IS_FLOOR)) 1293 if (QUERY_FLAG (tmp, FLAG_IS_FLOOR))
1206 break; 1294 break;
1207 } 1295 }
1208} 1296}
1209 1297
1210/* 1298/*
1211 * monster_check_apply() is meant to be called after an item is 1299 * monster_check_apply() is meant to be called after an item is
1217 * they can pick up all that they can use. 1305 * they can pick up all that they can use.
1218 */ 1306 */
1219 1307
1220/* Sept 96, fixed this so skills will be readied -b.t.*/ 1308/* Sept 96, fixed this so skills will be readied -b.t.*/
1221 1309
1310void
1222void monster_check_apply(object *mon, object *item) { 1311monster_check_apply (object *mon, object *item)
1312{
1223 1313
1224 int flag = 0; 1314 int flag = 0;
1225 1315
1226 if(item->type==SPELLBOOK&&
1227 mon->arch!=NULL&&(QUERY_FLAG((&mon->arch->clone),FLAG_CAST_SPELL))) { 1316 if (item->type == SPELLBOOK && mon->arch != NULL && (QUERY_FLAG ((&mon->arch->clone), FLAG_CAST_SPELL)))
1317 {
1228 SET_FLAG(mon, FLAG_CAST_SPELL); 1318 SET_FLAG (mon, FLAG_CAST_SPELL);
1229 return; 1319 return;
1230 } 1320 }
1231 1321
1232 /* If for some reason, this item is already applied, no more work to do */ 1322 /* If for some reason, this item is already applied, no more work to do */
1233 if(QUERY_FLAG(item,FLAG_APPLIED)) return; 1323 if (QUERY_FLAG (item, FLAG_APPLIED))
1234
1235 /* Might be better not to do this - if the monster can fire a bow,
1236 * it is possible in his wanderings, he will find one to use. In
1237 * which case, it would be nice to have ammo for it.
1238 */
1239 if(QUERY_FLAG(mon,FLAG_USE_BOW) && item->type==ARROW) {
1240 /* Check for the right kind of bow */
1241 object *bow;
1242 for(bow=mon->inv;bow!=NULL;bow=bow->below)
1243 if(bow->type==BOW && bow->race==item->race) {
1244 SET_FLAG(mon, FLAG_READY_BOW);
1245 LOG(llevMonster,"Found correct bow for arrows.\n");
1246 return; /* nothing more to do for arrows */
1247 }
1248 }
1249
1250 if (item->type == TREASURE && mon->will_apply & WILL_APPLY_TREASURE) flag=1;
1251 /* Eating food gets hp back */
1252 else if (item->type == FOOD && mon->will_apply & WILL_APPLY_FOOD) flag=1;
1253 else if (item->type == SCROLL && QUERY_FLAG(mon, FLAG_USE_SCROLL)) {
1254 if (!item->inv)
1255 LOG(llevDebug,"Monster %d having scroll %d with empty inventory!", mon->count, item->count);
1256 else if (monster_should_cast_spell(mon, item->inv))
1257 SET_FLAG(mon, FLAG_READY_SCROLL);
1258 /* Don't use it right now */
1259 return;
1260 }
1261 else if (item->type == WEAPON) flag = check_good_weapon(mon,item);
1262 else if (IS_ARMOR(item)) flag = check_good_armour(mon,item);
1263 /* Should do something more, like make sure this is a better item */
1264 else if (item->type == RING)
1265 flag=1;
1266 else if ( item->type==WAND || item->type == ROD || item->type==HORN )
1267 {
1268 /* We never really 'ready' the wand/rod/horn, because that would mean the
1269 * weapon would get undone.
1270 */
1271 if (!(can_apply_object(mon, item) & CAN_APPLY_NOT_MASK))
1272 {
1273 SET_FLAG(mon, FLAG_READY_RANGE);
1274 SET_FLAG(item, FLAG_APPLIED);
1275 }
1276 return;
1277 }
1278 else if (item->type == BOW) {
1279 /* We never really 'ready' the bow, because that would mean the
1280 * weapon would get undone.
1281 */
1282 if (!(can_apply_object(mon, item) & CAN_APPLY_NOT_MASK))
1283 SET_FLAG(mon, FLAG_READY_BOW);
1284 return;
1285 }
1286 else if ( item->type == SKILL )
1287 {
1288 /*
1289 * skills are specials: monsters must have the 'FLAG_READY_SKILL' flag set,
1290 * else they can't use the skill...
1291 * Skills also don't need to get applied, so return now.
1292 */
1293 SET_FLAG(mon, FLAG_READY_SKILL);
1294 return;
1295 }
1296
1297
1298 /* if we don't match one of the above types, return now.
1299 * can_apply_object will say that we can apply things like flesh,
1300 * bolts, and whatever else, because it only checks against the
1301 * body_info locations.
1302 */
1303 if (!flag) return;
1304
1305 /* Check to see if the monster can use this item. If not, no need
1306 * to do further processing. Note that can_apply_object already checks
1307 * for the CAN_USE flags.
1308 */
1309 if (can_apply_object(mon, item) & CAN_APPLY_NOT_MASK) return;
1310
1311 /* should only be applying this item, not unapplying it.
1312 * also, ignore status of curse so they can take off old armour.
1313 * monsters have some advantages after all.
1314 */
1315 manual_apply(mon, item, AP_APPLY | AP_IGNORE_CURSE);
1316
1317 return; 1324 return;
1318}
1319 1325
1326 /* Might be better not to do this - if the monster can fire a bow,
1327 * it is possible in his wanderings, he will find one to use. In
1328 * which case, it would be nice to have ammo for it.
1329 */
1330 if (QUERY_FLAG (mon, FLAG_USE_BOW) && item->type == ARROW)
1331 {
1332 /* Check for the right kind of bow */
1333 object *bow;
1334
1335 for (bow = mon->inv; bow != NULL; bow = bow->below)
1336 if (bow->type == BOW && bow->race == item->race)
1337 {
1338 SET_FLAG (mon, FLAG_READY_BOW);
1339 LOG (llevMonster, "Found correct bow for arrows.\n");
1340 return; /* nothing more to do for arrows */
1341 }
1342 }
1343
1344 if (item->type == TREASURE && mon->will_apply & WILL_APPLY_TREASURE)
1345 flag = 1;
1346 /* Eating food gets hp back */
1347 else if (item->type == FOOD && mon->will_apply & WILL_APPLY_FOOD)
1348 flag = 1;
1349 else if (item->type == SCROLL && QUERY_FLAG (mon, FLAG_USE_SCROLL))
1350 {
1351 if (!item->inv)
1352 LOG (llevDebug, "Monster %d having scroll %d with empty inventory!", mon->count, item->count);
1353 else if (monster_should_cast_spell (mon, item->inv))
1354 SET_FLAG (mon, FLAG_READY_SCROLL);
1355 /* Don't use it right now */
1356 return;
1357 }
1358 else if (item->type == WEAPON)
1359 flag = check_good_weapon (mon, item);
1360 else if (IS_ARMOR (item))
1361 flag = check_good_armour (mon, item);
1362 /* Should do something more, like make sure this is a better item */
1363 else if (item->type == RING)
1364 flag = 1;
1365 else if (item->type == WAND || item->type == ROD || item->type == HORN)
1366 {
1367 /* We never really 'ready' the wand/rod/horn, because that would mean the
1368 * weapon would get undone.
1369 */
1370 if (!(can_apply_object (mon, item) & CAN_APPLY_NOT_MASK))
1371 {
1372 SET_FLAG (mon, FLAG_READY_RANGE);
1373 SET_FLAG (item, FLAG_APPLIED);
1374 }
1375 return;
1376 }
1377 else if (item->type == BOW)
1378 {
1379 /* We never really 'ready' the bow, because that would mean the
1380 * weapon would get undone.
1381 */
1382 if (!(can_apply_object (mon, item) & CAN_APPLY_NOT_MASK))
1383 SET_FLAG (mon, FLAG_READY_BOW);
1384 return;
1385 }
1386 else if (item->type == SKILL)
1387 {
1388 /*
1389 * skills are specials: monsters must have the 'FLAG_READY_SKILL' flag set,
1390 * else they can't use the skill...
1391 * Skills also don't need to get applied, so return now.
1392 */
1393 SET_FLAG (mon, FLAG_READY_SKILL);
1394 return;
1395 }
1396
1397
1398 /* if we don't match one of the above types, return now.
1399 * can_apply_object will say that we can apply things like flesh,
1400 * bolts, and whatever else, because it only checks against the
1401 * body_info locations.
1402 */
1403 if (!flag)
1404 return;
1405
1406 /* Check to see if the monster can use this item. If not, no need
1407 * to do further processing. Note that can_apply_object already checks
1408 * for the CAN_USE flags.
1409 */
1410 if (can_apply_object (mon, item) & CAN_APPLY_NOT_MASK)
1411 return;
1412
1413 /* should only be applying this item, not unapplying it.
1414 * also, ignore status of curse so they can take off old armour.
1415 * monsters have some advantages after all.
1416 */
1417 manual_apply (mon, item, AP_APPLY | AP_IGNORE_CURSE);
1418
1419 return;
1420}
1421
1422void
1320void npc_call_help(object *op) { 1423npc_call_help (object *op)
1424{
1321 int x,y, mflags; 1425 int x, y, mflags;
1322 object *npc; 1426 object *npc;
1323 sint16 sx, sy; 1427 sint16 sx, sy;
1324 mapstruct *m; 1428 mapstruct *m;
1325 1429
1326 for(x = -3; x < 4; x++) 1430 for (x = -3; x < 4; x++)
1327 for(y = -3; y < 4; y++) { 1431 for (y = -3; y < 4; y++)
1432 {
1328 m = op->map; 1433 m = op->map;
1329 sx = op->x + x; 1434 sx = op->x + x;
1330 sy = op->y + y; 1435 sy = op->y + y;
1331 mflags = get_map_flags(m, &m, sx, sy, &sx, &sy); 1436 mflags = get_map_flags (m, &m, sx, sy, &sx, &sy);
1332 /* If nothing alive on this space, no need to search the space. */ 1437 /* If nothing alive on this space, no need to search the space. */
1333 if ((mflags & P_OUT_OF_MAP) || !(mflags & P_IS_ALIVE)) 1438 if ((mflags & P_OUT_OF_MAP) || !(mflags & P_IS_ALIVE))
1334 continue; 1439 continue;
1335 1440
1336 for(npc = get_map_ob(m,sx,sy);npc!=NULL;npc=npc->above) 1441 for (npc = get_map_ob (m, sx, sy); npc != NULL; npc = npc->above)
1337 if(QUERY_FLAG(npc, FLAG_ALIVE)&&QUERY_FLAG(npc, FLAG_UNAGGRESSIVE)) 1442 if (QUERY_FLAG (npc, FLAG_ALIVE) && QUERY_FLAG (npc, FLAG_UNAGGRESSIVE))
1338 npc->enemy = op->enemy; 1443 npc->enemy = op->enemy;
1339 } 1444 }
1340} 1445}
1341 1446
1342 1447
1448int
1343int dist_att (int dir , object *ob, object *enemy, object *part, rv_vector *rv) { 1449dist_att (int dir, object *ob, object *enemy, object *part, rv_vector * rv)
1450{
1344 1451
1345 if (can_hit(part,enemy,rv)) 1452 if (can_hit (part, enemy, rv))
1346 return dir; 1453 return dir;
1347 if (rv->distance < 10) 1454 if (rv->distance < 10)
1348 return absdir(dir+4); 1455 return absdir (dir + 4);
1349 else if (rv->distance>18) 1456 else if (rv->distance > 18)
1350 return dir; 1457 return dir;
1351 return 0; 1458 return 0;
1352} 1459}
1353 1460
1461int
1354int run_att (int dir, object *ob, object *enemy,object *part, rv_vector *rv) { 1462run_att (int dir, object *ob, object *enemy, object *part, rv_vector * rv)
1463{
1355 1464
1356 if ((can_hit (part,enemy,rv) && ob->move_status <20) || ob->move_status <20) { 1465 if ((can_hit (part, enemy, rv) && ob->move_status < 20) || ob->move_status < 20)
1466 {
1357 ob->move_status++; 1467 ob->move_status++;
1358 return (dir); 1468 return (dir);
1359 } 1469 }
1360 else if (ob->move_status >20) 1470 else if (ob->move_status > 20)
1361 ob->move_status = 0;
1362 return absdir (dir+4);
1363}
1364
1365int hitrun_att (int dir, object *ob,object *enemy) {
1366 if (ob->move_status ++ < 25)
1367 return dir;
1368 else if (ob->move_status <50)
1369 return absdir (dir+4);
1370 else
1371 ob->move_status = 0;
1372 return absdir(dir+4);
1373}
1374
1375int wait_att (int dir, object *ob,object *enemy,object *part,rv_vector *rv) {
1376
1377 int inrange = can_hit (part, enemy,rv);
1378
1379 if (ob->move_status || inrange)
1380 ob->move_status++;
1381
1382 if (ob->move_status == 0)
1383 return 0;
1384 else if (ob->move_status <10)
1385 return dir;
1386 else if (ob->move_status <15)
1387 return absdir(dir+4);
1388 ob->move_status = 0; 1471 ob->move_status = 0;
1472 return absdir (dir + 4);
1473}
1474
1475int
1476hitrun_att (int dir, object *ob, object *enemy)
1477{
1478 if (ob->move_status++ < 25)
1389 return 0; 1479 return dir;
1390} 1480 else if (ob->move_status < 50)
1391
1392int disthit_att (int dir, object *ob, object *enemy, object *part,rv_vector *rv) {
1393
1394 /* The logic below here looked plain wrong before. Basically, what should
1395 * happen is that if the creatures hp percentage falls below run_away,
1396 * the creature should run away (dir+4)
1397 * I think its wrong for a creature to have a zero maxhp value, but
1398 * at least one map has this set, and whatever the map contains, the
1399 * server should try to be resilant enough to avoid the problem
1400 */
1401 if (ob->stats.maxhp && (ob->stats.hp*100)/ob->stats.maxhp < ob->run_away)
1402 return absdir(dir+4);
1403 return dist_att (dir,ob,enemy,part,rv);
1404}
1405
1406int wait_att2 (int dir, object *ob,object *enemy,object *part, rv_vector *rv) {
1407 if (rv->distance < 9)
1408 return absdir (dir+4); 1481 return absdir (dir + 4);
1409 return 0; 1482 else
1410}
1411
1412void circ1_move (object *ob) {
1413 static int circle [12] = {3,3,4,5,5,6,7,7,8,1,1,2};
1414 if(++ob->move_status > 11)
1415 ob->move_status = 0; 1483 ob->move_status = 0;
1416 if (!(move_object(ob,circle[ob->move_status]))) 1484 return absdir (dir + 4);
1417 (void) move_object(ob,RANDOM()%8+1);
1418} 1485}
1419 1486
1487int
1488wait_att (int dir, object *ob, object *enemy, object *part, rv_vector * rv)
1489{
1490
1491 int inrange = can_hit (part, enemy, rv);
1492
1493 if (ob->move_status || inrange)
1494 ob->move_status++;
1495
1496 if (ob->move_status == 0)
1497 return 0;
1498 else if (ob->move_status < 10)
1499 return dir;
1500 else if (ob->move_status < 15)
1501 return absdir (dir + 4);
1502 ob->move_status = 0;
1503 return 0;
1504}
1505
1506int
1507disthit_att (int dir, object *ob, object *enemy, object *part, rv_vector * rv)
1508{
1509
1510 /* The logic below here looked plain wrong before. Basically, what should
1511 * happen is that if the creatures hp percentage falls below run_away,
1512 * the creature should run away (dir+4)
1513 * I think its wrong for a creature to have a zero maxhp value, but
1514 * at least one map has this set, and whatever the map contains, the
1515 * server should try to be resilant enough to avoid the problem
1516 */
1517 if (ob->stats.maxhp && (ob->stats.hp * 100) / ob->stats.maxhp < ob->run_away)
1518 return absdir (dir + 4);
1519 return dist_att (dir, ob, enemy, part, rv);
1520}
1521
1522int
1523wait_att2 (int dir, object *ob, object *enemy, object *part, rv_vector * rv)
1524{
1525 if (rv->distance < 9)
1526 return absdir (dir + 4);
1527 return 0;
1528}
1529
1530void
1420void circ2_move (object *ob) { 1531circ1_move (object *ob)
1532{
1421 static int circle[20] = {3,3,3,4,4,5,5,5,6,6,7,7,7,8,8,1,1,1,2,2}; 1533 static int circle[12] = { 3, 3, 4, 5, 5, 6, 7, 7, 8, 1, 1, 2 };
1422 if(++ob->move_status > 19) 1534 if (++ob->move_status > 11)
1423 ob->move_status = 0; 1535 ob->move_status = 0;
1424 if(!(move_object(ob,circle[ob->move_status]))) 1536 if (!(move_object (ob, circle[ob->move_status])))
1425 (void) move_object(ob,RANDOM()%8+1); 1537 (void) move_object (ob, RANDOM () % 8 + 1);
1426} 1538}
1427 1539
1540void
1541circ2_move (object *ob)
1542{
1543 static int circle[20] = { 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 7, 7, 7, 8, 8, 1, 1, 1, 2, 2 };
1544 if (++ob->move_status > 19)
1545 ob->move_status = 0;
1546 if (!(move_object (ob, circle[ob->move_status])))
1547 (void) move_object (ob, RANDOM () % 8 + 1);
1548}
1549
1550void
1428void pace_movev(object *ob) { 1551pace_movev (object *ob)
1552{
1429 if (ob->move_status++ > 6) 1553 if (ob->move_status++ > 6)
1430 ob->move_status = 0; 1554 ob->move_status = 0;
1431 if (ob->move_status < 4) 1555 if (ob->move_status < 4)
1432 (void) move_object (ob,5); 1556 (void) move_object (ob, 5);
1433 else 1557 else
1434 (void) move_object(ob,1); 1558 (void) move_object (ob, 1);
1435} 1559}
1436 1560
1561void
1437void pace_moveh (object *ob) { 1562pace_moveh (object *ob)
1563{
1438 if (ob->move_status++ > 6) 1564 if (ob->move_status++ > 6)
1439 ob->move_status = 0; 1565 ob->move_status = 0;
1440 if (ob->move_status < 4) 1566 if (ob->move_status < 4)
1441 (void) move_object(ob,3); 1567 (void) move_object (ob, 3);
1442 else 1568 else
1443 (void) move_object(ob,7); 1569 (void) move_object (ob, 7);
1444} 1570}
1445 1571
1572void
1446void pace2_movev (object *ob) { 1573pace2_movev (object *ob)
1574{
1447 if (ob->move_status ++ > 16) 1575 if (ob->move_status++ > 16)
1448 ob->move_status = 0; 1576 ob->move_status = 0;
1449 if (ob->move_status <6) 1577 if (ob->move_status < 6)
1450 (void) move_object (ob,5); 1578 (void) move_object (ob, 5);
1451 else if (ob->move_status < 8) 1579 else if (ob->move_status < 8)
1452 return; 1580 return;
1453 else if (ob->move_status <13) 1581 else if (ob->move_status < 13)
1454 (void) move_object (ob,1); 1582 (void) move_object (ob, 1);
1583 else
1455 else return; 1584 return;
1456} 1585}
1457 1586
1587void
1458void pace2_moveh (object *ob) { 1588pace2_moveh (object *ob)
1589{
1459 if (ob->move_status ++ > 16) 1590 if (ob->move_status++ > 16)
1460 ob->move_status = 0; 1591 ob->move_status = 0;
1461 if (ob->move_status <6) 1592 if (ob->move_status < 6)
1462 (void) move_object (ob,3); 1593 (void) move_object (ob, 3);
1463 else if (ob->move_status < 8) 1594 else if (ob->move_status < 8)
1464 return; 1595 return;
1465 else if (ob->move_status <13) 1596 else if (ob->move_status < 13)
1466 (void) move_object (ob,7); 1597 (void) move_object (ob, 7);
1598 else
1467 else return; 1599 return;
1468} 1600}
1469 1601
1602void
1470void rand_move (object *ob) { 1603rand_move (object *ob)
1604{
1471 int i; 1605 int i;
1472 if (ob->move_status <1 || ob->move_status >8 || 1606
1473 !(move_object(ob,ob->move_status|| ! (RANDOM()% 9)))) 1607 if (ob->move_status < 1 || ob->move_status > 8 || !(move_object (ob, ob->move_status || !(RANDOM () % 9))))
1474 for (i = 0; i < 5; i++) 1608 for (i = 0; i < 5; i++)
1475 if (move_object(ob,ob->move_status = RANDOM()%8+1)) 1609 if (move_object (ob, ob->move_status = RANDOM () % 8 + 1))
1476 return; 1610 return;
1477} 1611}
1478 1612
1613void
1479void check_earthwalls(object *op, mapstruct *m, int x, int y) { 1614check_earthwalls (object *op, mapstruct *m, int x, int y)
1615{
1480 object *tmp; 1616 object *tmp;
1617
1481 for (tmp = get_map_ob(m, x, y); tmp!=NULL; tmp=tmp->above) { 1618 for (tmp = get_map_ob (m, x, y); tmp != NULL; tmp = tmp->above)
1619 {
1482 if (tmp->type == EARTHWALL) { 1620 if (tmp->type == EARTHWALL)
1621 {
1483 hit_player(tmp,op->stats.dam,op,AT_PHYSICAL,1); 1622 hit_player (tmp, op->stats.dam, op, AT_PHYSICAL, 1);
1484 return; 1623 return;
1485 } 1624 }
1486 } 1625 }
1487} 1626}
1488 1627
1628void
1489void check_doors(object *op, mapstruct *m, int x, int y) { 1629check_doors (object *op, mapstruct *m, int x, int y)
1630{
1490 object *tmp; 1631 object *tmp;
1632
1491 for (tmp = get_map_ob(m, x, y); tmp!=NULL; tmp=tmp->above) { 1633 for (tmp = get_map_ob (m, x, y); tmp != NULL; tmp = tmp->above)
1634 {
1492 if (tmp->type == DOOR) { 1635 if (tmp->type == DOOR)
1636 {
1493 hit_player(tmp,1000,op,AT_PHYSICAL,1); 1637 hit_player (tmp, 1000, op, AT_PHYSICAL, 1);
1494 return; 1638 return;
1495 } 1639 }
1496 } 1640 }
1497} 1641}
1498 1642
1499/* find_mon_throw_ob() - modeled on find_throw_ob 1643/* find_mon_throw_ob() - modeled on find_throw_ob
1502 * furniture, even if they are not good throwable objects. 1646 * furniture, even if they are not good throwable objects.
1503 * Probably better to have the monster throw a throwable object 1647 * Probably better to have the monster throw a throwable object
1504 * first, then throw any non equipped weapon. 1648 * first, then throw any non equipped weapon.
1505 */ 1649 */
1506 1650
1651object *
1507object *find_mon_throw_ob( object *op ) { 1652find_mon_throw_ob (object *op)
1653{
1508 object *tmp = NULL; 1654 object *tmp = NULL;
1509
1510 if(op->head) tmp=op->head; else tmp=op;
1511 1655
1656 if (op->head)
1657 tmp = op->head;
1658 else
1659 tmp = op;
1660
1512 /* New throw code: look through the inventory. Grap the first legal is_thrown 1661 /* New throw code: look through the inventory. Grap the first legal is_thrown
1513 * marked item and throw it to the enemy. 1662 * marked item and throw it to the enemy.
1514 */ 1663 */
1515 1664
1516 for(tmp=op->inv;tmp;tmp=tmp->below) { 1665 for (tmp = op->inv; tmp; tmp = tmp->below)
1666 {
1517 1667
1518 /* Can't throw invisible objects or items that are applied */ 1668 /* Can't throw invisible objects or items that are applied */
1519 if(tmp->invisible || QUERY_FLAG(tmp,FLAG_APPLIED)) continue; 1669 if (tmp->invisible || QUERY_FLAG (tmp, FLAG_APPLIED))
1670 continue;
1520 1671
1521 if(QUERY_FLAG(tmp,FLAG_IS_THROWN)) 1672 if (QUERY_FLAG (tmp, FLAG_IS_THROWN))
1522 break; 1673 break;
1523 1674
1524 } 1675 }
1525 1676
1526#ifdef DEBUG_THROW 1677#ifdef DEBUG_THROW
1527 LOG(llevDebug,"%s chooses to throw: %s (%d)\n",op->name, 1678 LOG (llevDebug, "%s chooses to throw: %s (%d)\n", op->name, !(tmp) ? "(nothing)" : query_name (tmp), tmp ? tmp->count : -1);
1528 !(tmp)?"(nothing)":query_name(tmp),tmp?tmp->count:-1);
1529#endif 1679#endif
1530 1680
1531 return tmp; 1681 return tmp;
1532} 1682}
1533 1683
1534/* determine if we can 'detect' the enemy. Check for walls blocking the 1684/* determine if we can 'detect' the enemy. Check for walls blocking the
1535 * los. Also, just because its hidden/invisible, we may be sensitive/smart 1685 * los. Also, just because its hidden/invisible, we may be sensitive/smart
1536 * enough (based on Wis & Int) to figure out where the enemy is. -b.t. 1686 * enough (based on Wis & Int) to figure out where the enemy is. -b.t.
1539 * OR y distance being within some range - that seemed wrong - both should 1689 * OR y distance being within some range - that seemed wrong - both should
1540 * be within the valid range. MSW 2001-08-05 1690 * be within the valid range. MSW 2001-08-05
1541 * Returns 0 if enemy can not be detected, 1 if it is detected 1691 * Returns 0 if enemy can not be detected, 1 if it is detected
1542 */ 1692 */
1543 1693
1694int
1544int can_detect_enemy (object *op, object *enemy, rv_vector *rv) { 1695can_detect_enemy (object *op, object *enemy, rv_vector * rv)
1696{
1545 int radius = MIN_MON_RADIUS, hide_discovery; 1697 int radius = MIN_MON_RADIUS, hide_discovery;
1546 1698
1547 /* null detection for any of these condtions always */ 1699 /* null detection for any of these condtions always */
1548 if(!op || !enemy || !op->map || !enemy->map) 1700 if (!op || !enemy || !op->map || !enemy->map)
1549 return 0; 1701 return 0;
1550 1702
1551 /* If the monster (op) has no way to get to the enemy, do nothing */ 1703 /* If the monster (op) has no way to get to the enemy, do nothing */
1552 if (!on_same_map(op, enemy)) 1704 if (!on_same_map (op, enemy))
1553 return 0; 1705 return 0;
1554 1706
1555 get_rangevector(op, enemy, rv, 0); 1707 get_rangevector (op, enemy, rv, 0);
1556 1708
1557 /* Monsters always ignore the DM */ 1709 /* Monsters always ignore the DM */
1558 if ( ( op->type != PLAYER ) && QUERY_FLAG( enemy, FLAG_WIZ ) ) 1710 if ((op->type != PLAYER) && QUERY_FLAG (enemy, FLAG_WIZ))
1559 return 0; 1711 return 0;
1560 1712
1561 /* simple check. Should probably put some range checks in here. */ 1713 /* simple check. Should probably put some range checks in here. */
1562 if(can_see_enemy(op,enemy)) return 1; 1714 if (can_see_enemy (op, enemy))
1715 return 1;
1563 1716
1564 /* The rest of this is for monsters. Players are on their own for 1717 /* The rest of this is for monsters. Players are on their own for
1565 * finding enemies! 1718 * finding enemies!
1566 */ 1719 */
1567 if(op->type==PLAYER) return 0; 1720 if (op->type == PLAYER)
1721 return 0;
1568 1722
1569 /* Quality invisible? Bah, we wont see them w/o SEE_INVISIBLE 1723 /* Quality invisible? Bah, we wont see them w/o SEE_INVISIBLE
1570 * flag (which was already checked) in can_see_enmy (). Lets get out of here 1724 * flag (which was already checked) in can_see_enmy (). Lets get out of here
1571 */ 1725 */
1572 if(enemy->invisible && (!enemy->contr || (!enemy->contr->tmp_invis && !enemy->contr->hidden))) 1726 if (enemy->invisible && (!enemy->contr || (!enemy->contr->tmp_invis && !enemy->contr->hidden)))
1573 return 0; 1727 return 0;
1574 1728
1575 /* use this for invis also */ 1729 /* use this for invis also */
1576 hide_discovery = op->stats.Int/5; 1730 hide_discovery = op->stats.Int / 5;
1577 1731
1578 /* Determine Detection radii */ 1732 /* Determine Detection radii */
1579 if(!enemy->hide) /* to detect non-hidden (eg dark/invis enemy) */ 1733 if (!enemy->hide) /* to detect non-hidden (eg dark/invis enemy) */
1580 radius = (op->stats.Wis/5)+1>MIN_MON_RADIUS?(op->stats.Wis/5)+1:MIN_MON_RADIUS; 1734 radius = (op->stats.Wis / 5) + 1 > MIN_MON_RADIUS ? (op->stats.Wis / 5) + 1 : MIN_MON_RADIUS;
1735 else
1581 else { /* a level/INT/Dex adjustment for hiding */ 1736 { /* a level/INT/Dex adjustment for hiding */
1582 object *sk_hide; 1737 object *sk_hide;
1583 int bonus = (op->level/2) + (op->stats.Int/5); 1738 int bonus = (op->level / 2) + (op->stats.Int / 5);
1584 1739
1585 if(enemy->type==PLAYER) { 1740 if (enemy->type == PLAYER)
1741 {
1586 if((sk_hide = find_skill_by_number(enemy,SK_HIDING))) 1742 if ((sk_hide = find_skill_by_number (enemy, SK_HIDING)))
1587 bonus -= sk_hide->level; 1743 bonus -= sk_hide->level;
1588 else { 1744 else
1745 {
1589 LOG(llevError,"can_detect_enemy() got hidden player w/o hiding skill!\n"); 1746 LOG (llevError, "can_detect_enemy() got hidden player w/o hiding skill!\n");
1590 make_visible(enemy); 1747 make_visible (enemy);
1591 radius=radius<MIN_MON_RADIUS?MIN_MON_RADIUS:radius; 1748 radius = radius < MIN_MON_RADIUS ? MIN_MON_RADIUS : radius;
1592 } 1749 }
1593 } 1750 }
1594 else /* enemy is not a player */ 1751 else /* enemy is not a player */
1595 bonus -= enemy->level; 1752 bonus -= enemy->level;
1596 1753
1597 radius += bonus/5; 1754 radius += bonus / 5;
1598 hide_discovery += bonus*5; 1755 hide_discovery += bonus * 5;
1599 } /* else creature has modifiers for hiding */ 1756 } /* else creature has modifiers for hiding */
1600 1757
1601 /* Radii stealth adjustment. Only if you are stealthy 1758 /* Radii stealth adjustment. Only if you are stealthy
1602 * will you be able to sneak up closer to creatures */ 1759 * will you be able to sneak up closer to creatures */
1603 if(QUERY_FLAG(enemy,FLAG_STEALTH)) 1760 if (QUERY_FLAG (enemy, FLAG_STEALTH))
1604 radius = radius/2, hide_discovery = hide_discovery/3; 1761 radius = radius / 2, hide_discovery = hide_discovery / 3;
1605 1762
1606 /* Radii adjustment for enemy standing in the dark */ 1763 /* Radii adjustment for enemy standing in the dark */
1607 if(op->map->darkness>0 && !stand_in_light(enemy)) { 1764 if (op->map->darkness > 0 && !stand_in_light (enemy))
1765 {
1608 /* on dark maps body heat can help indicate location with infravision 1766 /* on dark maps body heat can help indicate location with infravision
1609 * undead don't have body heat, so no benefit detecting them. 1767 * undead don't have body heat, so no benefit detecting them.
1610 */ 1768 */
1611 if(QUERY_FLAG(op,FLAG_SEE_IN_DARK) && !is_true_undead(enemy)) 1769 if (QUERY_FLAG (op, FLAG_SEE_IN_DARK) && !is_true_undead (enemy))
1612 radius += op->map->darkness/2; 1770 radius += op->map->darkness / 2;
1613 else 1771 else
1614 radius -= op->map->darkness/2; 1772 radius -= op->map->darkness / 2;
1615 1773
1616 /* op next to a monster (and not in complete darkness) 1774 /* op next to a monster (and not in complete darkness)
1617 * the monster should have a chance to see you. 1775 * the monster should have a chance to see you.
1618 */ 1776 */
1619 if(radius<MIN_MON_RADIUS && op->map->darkness<5 && rv->distance<=1) 1777 if (radius < MIN_MON_RADIUS && op->map->darkness < 5 && rv->distance <= 1)
1620 radius = MIN_MON_RADIUS; 1778 radius = MIN_MON_RADIUS;
1621 } /* if on dark map */ 1779 } /* if on dark map */
1622 1780
1623 /* Lets not worry about monsters that have incredible detection 1781 /* Lets not worry about monsters that have incredible detection
1624 * radii, we only need to worry here about things the player can 1782 * radii, we only need to worry here about things the player can
1625 * (potentially) see. This is 13, as that is the maximum size the player 1783 * (potentially) see. This is 13, as that is the maximum size the player
1626 * may have for their map - in that way, creatures at the edge will 1784 * may have for their map - in that way, creatures at the edge will
1627 * do something. Note that the distance field in the 1785 * do something. Note that the distance field in the
1628 * vector is real distance, so in theory this should be 18 to 1786 * vector is real distance, so in theory this should be 18 to
1629 * find that. 1787 * find that.
1630 */ 1788 */
1631 if(radius>13) radius = 13; 1789 if (radius > 13)
1790 radius = 13;
1632 1791
1633 /* Enemy in range! Now test for detection */ 1792 /* Enemy in range! Now test for detection */
1634 if ((int) rv->distance <= radius) { 1793 if ((int) rv->distance <= radius)
1794 {
1635 /* ah, we are within range, detected? take cases */ 1795 /* ah, we are within range, detected? take cases */
1636 if(!enemy->invisible) /* enemy in dark squares... are seen! */ 1796 if (!enemy->invisible) /* enemy in dark squares... are seen! */
1637 return 1; 1797 return 1;
1638 1798
1639 /* hidden or low-quality invisible */ 1799 /* hidden or low-quality invisible */
1640 if(enemy->hide && (rv->distance <= 1) && (RANDOM()%100<=hide_discovery)) { 1800 if (enemy->hide && (rv->distance <= 1) && (RANDOM () % 100 <= hide_discovery))
1801 {
1641 make_visible(enemy); 1802 make_visible (enemy);
1642 /* inform players of new status */ 1803 /* inform players of new status */
1643 if(enemy->type==PLAYER && player_can_view(enemy,op)) 1804 if (enemy->type == PLAYER && player_can_view (enemy, op))
1644 new_draw_info_format(NDI_UNIQUE,0, enemy, 1805 new_draw_info_format (NDI_UNIQUE, 0, enemy, "You are discovered by %s!", &op->name);
1645 "You are discovered by %s!",&op->name);
1646 return 1; /* detected enemy */ 1806 return 1; /* detected enemy */
1647 } 1807 }
1648 else if (enemy->invisible) { 1808 else if (enemy->invisible)
1809 {
1649 /* Change this around - instead of negating the invisible, just 1810 /* Change this around - instead of negating the invisible, just
1650 * return true so that the mosnter that managed to detect you can 1811 * return true so that the mosnter that managed to detect you can
1651 * do something to you. Decreasing the duration of invisible 1812 * do something to you. Decreasing the duration of invisible
1652 * doesn't make a lot of sense IMO, as a bunch of stupid creatures 1813 * doesn't make a lot of sense IMO, as a bunch of stupid creatures
1653 * can then basically negate the spell. The spell isn't negated - 1814 * can then basically negate the spell. The spell isn't negated -
1654 * they just know where you are! 1815 * they just know where you are!
1655 */ 1816 */
1656 if ((RANDOM() % 50) <= hide_discovery) { 1817 if ((RANDOM () % 50) <= hide_discovery)
1818 {
1657 if (enemy->type == PLAYER) { 1819 if (enemy->type == PLAYER)
1658 new_draw_info_format(NDI_UNIQUE,0, enemy, 1820 {
1659 "You see %s noticing your position.", query_name(op)); 1821 new_draw_info_format (NDI_UNIQUE, 0, enemy, "You see %s noticing your position.", query_name (op));
1660 } 1822 }
1661 return 1; 1823 return 1;
1662 } 1824 }
1663 } 1825 }
1664 } /* within range */ 1826 } /* within range */
1665 1827
1666 /* Wasn't detected above, so still hidden */ 1828 /* Wasn't detected above, so still hidden */
1667 return 0; 1829 return 0;
1668} 1830}
1669 1831
1670/* determine if op stands in a lighted square. This is not a very 1832/* determine if op stands in a lighted square. This is not a very
1671 * intellegent algorithm. For one thing, we ignore los here, SO it 1833 * intellegent algorithm. For one thing, we ignore los here, SO it
1672 * is possible for a bright light to illuminate a player on the 1834 * is possible for a bright light to illuminate a player on the
1673 * other side of a wall (!). 1835 * other side of a wall (!).
1674 */ 1836 */
1675 1837
1838int
1676int stand_in_light( object *op) { 1839stand_in_light (object *op)
1840{
1677 sint16 nx,ny; 1841 sint16 nx, ny;
1678 mapstruct *m; 1842 mapstruct *m;
1679 1843
1680 1844
1845 if (!op)
1681 if(!op) return 0; 1846 return 0;
1682 if(op->glow_radius > 0) return 1; 1847 if (op->glow_radius > 0)
1848 return 1;
1683 1849
1684 if(op->map) { 1850 if (op->map)
1851 {
1685 int x, y, x1, y1; 1852 int x, y, x1, y1;
1686
1687
1688 1853
1854
1855
1689 /* Check the spaces with the max light radius to see if any of them 1856 /* Check the spaces with the max light radius to see if any of them
1690 * have lights, and if any of them light the player enough, then return 1. 1857 * have lights, and if any of them light the player enough, then return 1.
1691 */ 1858 */
1692 for (x = op->x - MAX_LIGHT_RADII; x <= op->x + MAX_LIGHT_RADII; x++) { 1859 for (x = op->x - MAX_LIGHT_RADII; x <= op->x + MAX_LIGHT_RADII; x++)
1860 {
1693 for (y = op->y - MAX_LIGHT_RADII; y <= op->y + MAX_LIGHT_RADII; y++) { 1861 for (y = op->y - MAX_LIGHT_RADII; y <= op->y + MAX_LIGHT_RADII; y++)
1862 {
1694 m = op->map; 1863 m = op->map;
1695 nx = x; 1864 nx = x;
1696 ny = y; 1865 ny = y;
1697 1866
1698 if (get_map_flags(m, &m, nx, ny, &nx, &ny) & P_OUT_OF_MAP) continue; 1867 if (get_map_flags (m, &m, nx, ny, &nx, &ny) & P_OUT_OF_MAP)
1868 continue;
1699 1869
1700 x1 = abs(x - op->x)*abs(x - op->x); 1870 x1 = abs (x - op->x) * abs (x - op->x);
1701 y1 = abs(y - op->y)*abs(y - op->y); 1871 y1 = abs (y - op->y) * abs (y - op->y);
1702 if (isqrt(x1 + y1) < GET_MAP_LIGHT(m, nx, ny)) return 1; 1872 if (isqrt (x1 + y1) < GET_MAP_LIGHT (m, nx, ny))
1873 return 1;
1703 } 1874 }
1704 } 1875 }
1705 } 1876 }
1706 return 0; 1877 return 0;
1707} 1878}
1708 1879
1709 1880
1710/* assuming no walls/barriers, lets check to see if its *possible* 1881/* assuming no walls/barriers, lets check to see if its *possible*
1711 * to see an enemy. Note, "detection" is different from "seeing". 1882 * to see an enemy. Note, "detection" is different from "seeing".
1712 * See can_detect_enemy() for more details. -b.t. 1883 * See can_detect_enemy() for more details. -b.t.
1713 * return 0 if can't be seen, 1 if can be 1884 * return 0 if can't be seen, 1 if can be
1714 */ 1885 */
1715 1886
1887int
1716int can_see_enemy (object *op, object *enemy) { 1888can_see_enemy (object *op, object *enemy)
1889{
1717 object *looker = op->head?op->head:op; 1890 object *looker = op->head ? op->head : op;
1718 1891
1719 /* safety */ 1892 /* safety */
1720 if(!looker||!enemy||!QUERY_FLAG(looker,FLAG_ALIVE)) 1893 if (!looker || !enemy || !QUERY_FLAG (looker, FLAG_ALIVE))
1721 return 0; 1894 return 0;
1722 1895
1723 /* we dont give a full treatment of xrays here (shorter range than normal, 1896 /* we dont give a full treatment of xrays here (shorter range than normal,
1724 * see through walls). Should we change the code elsewhere to make you 1897 * see through walls). Should we change the code elsewhere to make you
1725 * blind even if you can xray? 1898 * blind even if you can xray?
1726 */ 1899 */
1727 if(QUERY_FLAG(looker,FLAG_BLIND) && !QUERY_FLAG(looker,FLAG_XRAYS)) 1900 if (QUERY_FLAG (looker, FLAG_BLIND) && !QUERY_FLAG (looker, FLAG_XRAYS))
1901 return 0;
1902
1903 /* checking for invisible things */
1904 if (enemy->invisible)
1905 {
1906 /* HIDDEN ENEMY. by definition, you can't see hidden stuff!
1907 * However,if you carry any source of light, then the hidden
1908 * creature is seeable (and stupid) */
1909
1910 if (has_carried_lights (enemy))
1911 {
1912 if (enemy->hide)
1913 {
1914 make_visible (enemy);
1915 new_draw_info (NDI_UNIQUE, 0, enemy, "Your light reveals your hiding spot!");
1916 }
1917 return 1;
1918 }
1919 else if (enemy->hide)
1920 return 0;
1921
1922 /* Invisible enemy. Break apart the check for invis undead/invis looker
1923 * into more simple checks - the QUERY_FLAG doesn't return 1/0 values,
1924 * and making it a conditional makes the code pretty ugly.
1925 */
1926 if (!QUERY_FLAG (looker, FLAG_SEE_INVISIBLE))
1927 {
1928 if (makes_invisible_to (enemy, looker))
1728 return 0; 1929 return 0;
1729
1730 /* checking for invisible things */
1731 if(enemy->invisible) {
1732 /* HIDDEN ENEMY. by definition, you can't see hidden stuff!
1733 * However,if you carry any source of light, then the hidden
1734 * creature is seeable (and stupid) */
1735
1736 if(has_carried_lights(enemy)) {
1737 if(enemy->hide) {
1738 make_visible(enemy);
1739 new_draw_info(NDI_UNIQUE,0, enemy,
1740 "Your light reveals your hiding spot!");
1741 } 1930 }
1742 return 1; 1931 }
1743 } else if (enemy->hide) return 0;
1744
1745 /* Invisible enemy. Break apart the check for invis undead/invis looker
1746 * into more simple checks - the QUERY_FLAG doesn't return 1/0 values,
1747 * and making it a conditional makes the code pretty ugly.
1748 */
1749 if (!QUERY_FLAG(looker,FLAG_SEE_INVISIBLE)) {
1750 if (makes_invisible_to(enemy, looker)) return 0;
1751 }
1752 } else if(looker->type==PLAYER) /* for players, a (possible) shortcut */ 1932 else if (looker->type == PLAYER) /* for players, a (possible) shortcut */
1753 if(player_can_view(looker,enemy)) return 1; 1933 if (player_can_view (looker, enemy))
1934 return 1;
1754 1935
1755 /* ENEMY IN DARK MAP. Without infravision, the enemy is not seen 1936 /* ENEMY IN DARK MAP. Without infravision, the enemy is not seen
1756 * unless they carry a light or stand in light. Darkness doesnt 1937 * unless they carry a light or stand in light. Darkness doesnt
1757 * inhibit the undead per se (but we should give their archs 1938 * inhibit the undead per se (but we should give their archs
1758 * CAN_SEE_IN_DARK, this is just a safety 1939 * CAN_SEE_IN_DARK, this is just a safety
1759 * we care about the enemy maps status, not the looker. 1940 * we care about the enemy maps status, not the looker.
1760 * only relevant for tiled maps, but it is possible that the 1941 * only relevant for tiled maps, but it is possible that the
1761 * enemy is on a bright map and the looker on a dark - in that 1942 * enemy is on a bright map and the looker on a dark - in that
1762 * case, the looker can still see the enemy 1943 * case, the looker can still see the enemy
1763 */ 1944 */
1764 if(enemy->map->darkness>0&&!stand_in_light(enemy) 1945 if (enemy->map->darkness > 0 && !stand_in_light (enemy)
1765 &&(!QUERY_FLAG(looker,FLAG_SEE_IN_DARK)|| 1946 && (!QUERY_FLAG (looker, FLAG_SEE_IN_DARK) || !is_true_undead (looker) || !QUERY_FLAG (looker, FLAG_XRAYS)))
1766 !is_true_undead(looker)||!QUERY_FLAG(looker,FLAG_XRAYS)))
1767 return 0; 1947 return 0;
1768 1948
1769 return 1; 1949 return 1;
1770} 1950}
1771

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines