ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/attack.C
Revision: 1.69
Committed: Sun Jul 1 05:00:19 2007 UTC (16 years, 11 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.68: +10 -11 lines
Log Message:
- upgrade crossfire trt to the GPL version 3 (hopefully correctly).
- add a single file covered by the GNU Affero General Public License
  (which is not yet released, so I used the current draft, which is
  legally a bit wavy, but its likely better than nothing as it expresses
  direct intent by the authors, and we can upgrade as soon as it has been
  released).
  * this should ensure availability of source code for the server at least
    and hopefully also archetypes and maps even when modified versions
    are not being distributed, in accordance of section 13 of the agplv3.

File Contents

# User Rev Content
1 elmex 1.1 /*
2 root 1.66 * This file is part of Crossfire TRT, the Roguelike Realtime MORPG.
3 pippijn 1.45 *
4 root 1.66 * Copyright (©) 2005,2006,2007 Marc Alexander Lehmann / Robin Redeker / the Crossfire TRT team
5     * Copyright (©) 2002,2007 Mark Wedel & Crossfire Development Team
6     * Copyright (©) 1992,2007 Frank Tore Johansen
7 pippijn 1.45 *
8 root 1.69 * Crossfire TRT is free software: you can redistribute it and/or modify
9     * it under the terms of the GNU General Public License as published by
10     * the Free Software Foundation, either version 3 of the License, or
11     * (at your option) any later version.
12 pippijn 1.45 *
13 root 1.69 * This program is distributed in the hope that it will be useful,
14     * but WITHOUT ANY WARRANTY; without even the implied warranty of
15     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16     * GNU General Public License for more details.
17 root 1.66 *
18 root 1.69 * You should have received a copy of the GNU General Public License
19     * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 pippijn 1.45 *
21     * The authors can be reached via e-mail to <crossfire@schmorp.de>
22     */
23 root 1.66
24 elmex 1.1 #include <assert.h>
25     #include <global.h>
26     #include <living.h>
27     #include <material.h>
28     #include <skills.h>
29     #include <sounds.h>
30 root 1.53 #include <sproto.h>
31 elmex 1.1
32 root 1.9 typedef struct att_msg_str
33     {
34 elmex 1.1 char *msg1;
35     char *msg2;
36     } att_msg;
37    
38     /*#define ATTACK_DEBUG*/
39    
40     /* cancels object *op. Cancellation basically means an object loses
41     * its magical benefits.
42     */
43 root 1.9 void
44     cancellation (object *op)
45 elmex 1.1 {
46 root 1.9 if (op->invisible)
47     return;
48    
49     if (QUERY_FLAG (op, FLAG_ALIVE) || op->type == CONTAINER || op->type == THROWN_OBJ)
50     {
51 root 1.44 /* Recurse through the inventory */
52     for (object *tmp = op->inv; tmp; tmp = tmp->below)
53 root 1.9 if (!did_make_save_item (tmp, AT_CANCELLATION, op))
54     cancellation (tmp);
55     }
56 root 1.44 else if (FABS (op->magic) <= rndm (0, 5))
57 root 1.9 {
58     /* Nullify this object. This code could probably be more complete */
59     /* in what abilities it should cancel */
60     op->magic = 0;
61 root 1.44
62 root 1.9 CLEAR_FLAG (op, FLAG_DAMNED);
63     CLEAR_FLAG (op, FLAG_CURSED);
64     CLEAR_FLAG (op, FLAG_KNOWN_MAGICAL);
65     CLEAR_FLAG (op, FLAG_KNOWN_CURSED);
66 root 1.44
67 root 1.9 if (op->env && op->env->type == PLAYER)
68 root 1.44 esrv_send_item (op->env, op);
69 elmex 1.1 }
70     }
71    
72     /* did_make_save_item just checks to make sure the item actually
73     * made its saving throw based on the tables. It does not take
74     * any further action (like destroying the item).
75     */
76 root 1.9 int
77     did_make_save_item (object *op, int type, object *originator)
78     {
79     int i, roll, saves = 0, attacks = 0, number;
80     materialtype_t *mt;
81    
82     if (op->materialname == NULL)
83     {
84     for (mt = materialt; mt != NULL && mt->next != NULL; mt = mt->next)
85 root 1.49 if (op->materials & mt->material)
86 root 1.26 break;
87 root 1.9 }
88     else
89     mt = name_to_material (op->materialname);
90 root 1.40
91 root 1.9 if (mt == NULL)
92 elmex 1.1 return TRUE;
93 root 1.40
94 root 1.9 roll = rndm (1, 20);
95    
96     /* the attacktypes have no meaning for object saves
97     * If the type is only magic, don't adjust type - basically, if
98     * pure magic is hitting an object, it should save. However, if it
99     * is magic teamed with something else, then strip out the
100     * magic type, and instead let the fire, cold, or whatever component
101     * destroy the item. Otherwise, you get the case of poisoncloud
102     * destroying objects because it has magic attacktype.
103     */
104     if (type != AT_MAGIC)
105     type &= ~(AT_CONFUSION | AT_DRAIN | AT_GHOSTHIT | AT_POISON | AT_SLOW |
106     AT_PARALYZE | AT_TURN_UNDEAD | AT_FEAR | AT_DEPLETE | AT_DEATH |
107     AT_COUNTERSPELL | AT_HOLYWORD | AT_BLIND | AT_LIFE_STEALING | AT_MAGIC);
108    
109     if (type == 0)
110     return TRUE;
111     if (roll == 20)
112     return TRUE;
113     if (roll == 1)
114     return FALSE;
115    
116     for (number = 0; number < NROFATTACKS; number++)
117     {
118     i = 1 << number;
119     if (!(i & type))
120     continue;
121     attacks++;
122     if (op->resist[number] == 100)
123     saves++;
124     else if (roll >= mt->save[number] - op->magic - op->resist[number] / 100)
125     saves++;
126     else if ((20 - mt->save[number]) / 3 > originator->stats.dam)
127     saves++;
128     }
129    
130     if (saves == attacks || attacks == 0)
131     return TRUE;
132 root 1.46
133     if (saves == 0 || (rndm (1, attacks) > saves))
134 root 1.9 return FALSE;
135 root 1.46
136 root 1.9 return TRUE;
137 elmex 1.1 }
138    
139     /* This function calls did_make_save_item. It then performs the
140     * appropriate actions to the item (such as burning the item up,
141     * calling cancellation, etc.)
142     */
143 root 1.9 void
144     save_throw_object (object *op, int type, object *originator)
145 elmex 1.1 {
146 root 1.9 if (!did_make_save_item (op, type, originator))
147 elmex 1.1 {
148 root 1.9 object *env = op->env;
149     int x = op->x, y = op->y;
150 root 1.19 maptile *m = op->map;
151 root 1.9
152     op = stop_item (op);
153     if (op == NULL)
154     return;
155 elmex 1.1
156 root 1.9 /* Hacked the following so that type LIGHTER will work.
157     * Also, objects which are potenital "lights" that are hit by
158     * flame/elect attacks will be set to glow. "lights" are any
159     * object with +/- glow_radius and an "other_arch" to change to.
160     * (and please note that we cant fail our save and reach this
161     * function if the object doesnt contain a material that can burn.
162     * So forget lighting magical swords on fire with this!) -b.t.
163     */
164     if (type & (AT_FIRE | AT_ELECTRICITY) && op->other_arch && QUERY_FLAG (op, FLAG_IS_LIGHTABLE))
165     {
166 root 1.67 const char *arch = op->other_arch->archname;
167 elmex 1.1
168 root 1.9 op = decrease_ob_nr (op, 1);
169 root 1.13
170 root 1.9 if (op)
171     fix_stopped_item (op, m, originator);
172 root 1.13
173 root 1.9 if ((op = get_archetype (arch)) != NULL)
174     {
175     if (env)
176     {
177     op->x = env->x, op->y = env->y;
178     insert_ob_in_ob (op, env);
179     if (env->contr)
180     esrv_send_item (env, op);
181 root 1.5 }
182 root 1.9 else
183     {
184     op->x = x, op->y = y;
185     insert_ob_in_map (op, m, originator, 0);
186     }
187     }
188 root 1.13
189 root 1.9 return;
190     }
191 root 1.13
192 root 1.9 if (type & AT_CANCELLATION)
193     { /* Cancellation. */
194     cancellation (op);
195     fix_stopped_item (op, m, originator);
196     return;
197     }
198 root 1.13
199 root 1.9 if (op->nrof > 1)
200     {
201     op = decrease_ob_nr (op, rndm (0, op->nrof - 1));
202 root 1.13
203 root 1.9 if (op)
204     fix_stopped_item (op, m, originator);
205 elmex 1.1 }
206 root 1.9 else
207     {
208     if (op->env)
209     {
210 root 1.30 object *tmp = op->in_player ();
211 root 1.9
212     if (tmp)
213 root 1.13 esrv_del_item (tmp->contr, op->count);
214 root 1.5 }
215 root 1.13
216 root 1.26 op->destroy ();
217 root 1.9 }
218 root 1.13
219 root 1.9 if (type & (AT_FIRE | AT_ELECTRICITY))
220 root 1.13 if (env)
221     {
222     op = get_archetype ("burnout");
223     op->x = env->x, op->y = env->y;
224     insert_ob_in_ob (op, env);
225     }
226     else
227     replace_insert_ob_in_map ("burnout", originator);
228    
229 root 1.9 return;
230     }
231 root 1.15
232 root 1.9 /* The value of 50 is arbitrary. */
233     if (type & AT_COLD && (op->resist[ATNR_COLD] < 50) && !QUERY_FLAG (op, FLAG_NO_PICK) && (RANDOM () & 2))
234     {
235     object *tmp;
236 root 1.16 archetype *at = archetype::find ("icecube");
237 root 1.9
238     if (at == NULL)
239 root 1.5 return;
240 root 1.15
241 root 1.9 op = stop_item (op);
242     if (op == NULL)
243 elmex 1.1 return;
244 root 1.15
245 root 1.9 if ((tmp = present_arch (at, op->map, op->x, op->y)) == NULL)
246     {
247     tmp = arch_to_object (at);
248     tmp->x = op->x, tmp->y = op->y;
249     /* This was in the old (pre new movement code) -
250     * icecubes have slow_move set to 1 - don't want
251     * that for ones we create.
252     */
253     tmp->move_slow_penalty = 0;
254     tmp->move_slow = 0;
255     insert_ob_in_map (tmp, op->map, originator, 0);
256     }
257 root 1.15
258 root 1.9 if (!QUERY_FLAG (op, FLAG_REMOVED))
259 root 1.25 op->remove ();
260 root 1.15
261     insert_ob_in_ob (op, tmp);
262 root 1.9 return;
263 elmex 1.1 }
264     }
265    
266     /* Object op is hitting the map.
267     * op is going in direction 'dir'
268     * type is the attacktype of the object.
269     * full_hit is set if monster area does not matter.
270     * returns 1 if it hits something, 0 otherwise.
271     */
272 root 1.9 int
273     hit_map (object *op, int dir, int type, int full_hit)
274     {
275 root 1.19 maptile *map;
276 root 1.9 sint16 x, y;
277     int retflag = 0; /* added this flag.. will return 1 if it hits a monster */
278 elmex 1.1
279 root 1.9 if (QUERY_FLAG (op, FLAG_FREED))
280     {
281     LOG (llevError, "BUG: hit_map(): free object\n");
282     return 0;
283 elmex 1.1 }
284    
285 root 1.9 if (QUERY_FLAG (op, FLAG_REMOVED) || op->env != NULL)
286     {
287 root 1.67 LOG (llevError, "BUG: hit_map(): hitter (arch %s, name %s) not on a map\n", &op->arch->archname, &op->name);
288 root 1.9 return 0;
289 elmex 1.1 }
290    
291 root 1.9 if (!op->map)
292     {
293     LOG (llevError, "BUG: hit_map(): %s has no map\n", &op->name);
294     return 0;
295 elmex 1.1 }
296    
297 root 1.9 if (op->head)
298     op = op->head;
299    
300     map = op->map;
301     x = op->x + freearr_x[dir];
302     y = op->y + freearr_y[dir];
303 elmex 1.1
304 root 1.41 if (!xy_normalise (map, x, y))
305     return 0;
306 root 1.9
307     // elmex: a safe map tile can't be hit!
308     // this should prevent most harmful effects on items and players there.
309 root 1.41 mapspace &ms = map->at (x, y);
310    
311     if (ms.flags () & P_SAFE)
312 root 1.9 return 0;
313    
314 root 1.59 /* peterm: a few special cases for special attacktypes --counterspell
315 root 1.9 * must be out here because it strikes things which are not alive
316     */
317 root 1.41 if (type & (AT_COUNTERSPELL | AT_CHAOS))
318 root 1.9 {
319 root 1.41 if (type & AT_COUNTERSPELL)
320     {
321     counterspell (op, dir); /* see spell_effect.c */
322 elmex 1.1
323 root 1.41 /* If the only attacktype is counterspell or magic, don't need
324     * to do any further processing.
325     */
326     if (!(type & ~(AT_COUNTERSPELL | AT_MAGIC)))
327     return 0;
328 root 1.11
329 root 1.41 type &= ~AT_COUNTERSPELL;
330     }
331 elmex 1.1
332 root 1.41 if (type & AT_CHAOS)
333     {
334     shuffle_attack (op, 1); /* flag tells it to change the face */
335     update_object (op, UP_OBJ_FACE);
336     type &= ~AT_CHAOS;
337     }
338 elmex 1.1 }
339    
340 root 1.37 /* There may still be objects that were above 'next', but there is no
341     * simple way to find out short of copying all object references and
342     * tags into a temporary array before we start processing the first
343     * object. That's why we just abort on destroy.
344     *
345     * This happens whenever attack spells (like fire) hit a pile
346     * of objects. This is not a bug - nor an error.
347     */
348 root 1.41 for (object *next = ms.bot; next && !next->destroyed (); )
349 root 1.9 {
350 root 1.37 object *tmp = next;
351 root 1.9 next = tmp->above;
352 root 1.11
353 root 1.9 /* Something could have happened to 'tmp' while 'tmp->below' was processed.
354     * For example, 'tmp' was put in an icecube.
355     * This is one of the few cases where on_same_map should not be used.
356     */
357     if (tmp->map != map || tmp->x != x || tmp->y != y)
358     continue;
359    
360     if (QUERY_FLAG (tmp, FLAG_ALIVE))
361     {
362     hit_player (tmp, op->stats.dam, op, type, full_hit);
363     retflag |= 1;
364 root 1.41
365 root 1.18 if (op->destroyed ())
366 root 1.5 break;
367     }
368 root 1.9 /* Here we are potentially destroying an object. If the object has
369     * NO_PASS set, it is also immune - you can't destroy walls. Note
370     * that weak walls have is_alive set, which prevent objects from
371     * passing over/through them. We don't care what type of movement
372     * the wall blocks - if it blocks any type of movement, can't be
373     * destroyed right now.
374     */
375 root 1.49 else if (tmp->materialname && op->stats.dam > 0 && !tmp->move_block)
376 root 1.9 {
377     save_throw_object (tmp, type, op);
378 root 1.37
379 root 1.18 if (op->destroyed ())
380 root 1.9 break;
381 root 1.5 }
382 elmex 1.1 }
383 root 1.11
384 root 1.9 return 0;
385 elmex 1.1 }
386    
387 root 1.9 void
388     attack_message (int dam, int type, object *op, object *hitter)
389     {
390 elmex 1.1 char buf[MAX_BUF], buf1[MAX_BUF], buf2[MAX_BUF];
391 root 1.9 int i, found = 0;
392 root 1.19 maptile *map;
393 elmex 1.1 object *next, *tmp;
394    
395     /* put in a few special messages for some of the common attacktypes
396     * a player might have. For example, fire, electric, cold, etc
397     * [garbled 20010919]
398     */
399    
400 root 1.9 if (dam == 9998 && op->type == DOOR)
401     {
402     sprintf (buf1, "unlock %s", &op->name);
403     sprintf (buf2, " unlocks");
404     found++;
405     }
406     if (dam < 0)
407     {
408     sprintf (buf1, "hit %s", &op->name);
409     sprintf (buf2, " hits");
410     found++;
411     }
412     else if (dam == 0)
413     {
414     sprintf (buf1, "missed %s", &op->name);
415     sprintf (buf2, " misses");
416     found++;
417     }
418     else if ((hitter->type == DISEASE || hitter->type == SYMPTOM ||
419 root 1.29 hitter->type == POISONING || (type & AT_POISON && op->is_alive ())) && !found)
420 root 1.9 {
421     for (i = 0; i < MAXATTACKMESS && attack_mess[ATM_SUFFER][i].level != -1; i++)
422     if (dam < attack_mess[ATM_SUFFER][i].level || attack_mess[ATM_SUFFER][i + 1].level == -1)
423     {
424     sprintf (buf1, "%s %s%s", attack_mess[ATM_SUFFER][i].buf1, &op->name, attack_mess[ATM_SUFFER][i].buf2);
425     strcpy (buf2, attack_mess[ATM_SUFFER][i].buf3);
426     found++;
427     break;
428     }
429     }
430     else if (op->type == DOOR && !found)
431     {
432     for (i = 0; i < MAXATTACKMESS && attack_mess[ATM_DOOR][i].level != -1; i++)
433     if (dam < attack_mess[ATM_DOOR][i].level || attack_mess[ATM_DOOR][i + 1].level == -1)
434     {
435     sprintf (buf1, "%s %s%s", attack_mess[ATM_DOOR][i].buf1, &op->name, attack_mess[ATM_DOOR][i].buf2);
436     strcpy (buf2, attack_mess[ATM_DOOR][i].buf3);
437     found++;
438     break;
439     }
440     }
441 root 1.29 else if (hitter->type == PLAYER && op->is_alive ())
442 root 1.9 {
443     if (USING_SKILL (hitter, SK_KARATE))
444     {
445     for (i = 0; i < MAXATTACKMESS && attack_mess[ATM_KARATE][i].level != -1; i++)
446     if (dam < attack_mess[ATM_KARATE][i].level || attack_mess[ATM_KARATE][i + 1].level == -1)
447     {
448     sprintf (buf1, "%s %s%s", attack_mess[ATM_KARATE][i].buf1, &op->name, attack_mess[ATM_KARATE][i].buf2);
449     strcpy (buf2, attack_mess[ATM_KARATE][i].buf3);
450 root 1.5 found++;
451     break;
452 root 1.9 }
453     }
454     else if (USING_SKILL (hitter, SK_CLAWING))
455     {
456     for (i = 0; i < MAXATTACKMESS && attack_mess[ATM_CLAW][i].level != -1; i++)
457     if (dam < attack_mess[ATM_CLAW][i].level || attack_mess[ATM_CLAW][i + 1].level == -1)
458     {
459     sprintf (buf1, "%s %s%s", attack_mess[ATM_CLAW][i].buf1, &op->name, attack_mess[ATM_CLAW][i].buf2);
460     strcpy (buf2, attack_mess[ATM_CLAW][i].buf3);
461 root 1.5 found++;
462     break;
463     }
464 root 1.9 }
465     else if (USING_SKILL (hitter, SK_PUNCHING))
466     {
467     for (i = 0; i < MAXATTACKMESS && attack_mess[ATM_PUNCH][i].level != -1; i++)
468     if (dam < attack_mess[ATM_PUNCH][i].level || attack_mess[ATM_PUNCH][i + 1].level == -1)
469     {
470     sprintf (buf1, "%s %s%s", attack_mess[ATM_PUNCH][i].buf1, &op->name, attack_mess[ATM_PUNCH][i].buf2);
471     strcpy (buf2, attack_mess[ATM_PUNCH][i].buf3);
472     found++;
473     break;
474 root 1.5 }
475     }
476 elmex 1.1 }
477 root 1.29
478 root 1.9 if (found)
479     {
480     /* done */
481     }
482 root 1.29 else if (hitter->is_arrow () && (type == AT_PHYSICAL || type == AT_MAGIC))
483 root 1.9 {
484     sprintf (buf1, "hit"); /* just in case */
485     for (i = 0; i < MAXATTACKMESS; i++)
486     if (dam < attack_mess[ATM_ARROW][i].level || attack_mess[ATM_ARROW][i + 1].level == -1)
487     {
488     strcpy (buf2, attack_mess[ATM_ARROW][i].buf3);
489     found++;
490     break;
491     }
492     }
493 root 1.29 else if (type & AT_DRAIN && op->is_alive ())
494 root 1.9 {
495 elmex 1.1 /* drain is first, because some items have multiple attypes */
496 root 1.9 for (i = 0; i < MAXATTACKMESS && attack_mess[ATM_DRAIN][i].level != -1; i++)
497     if (dam < attack_mess[ATM_DRAIN][i].level || attack_mess[ATM_DRAIN][i + 1].level == -1)
498     {
499     sprintf (buf1, "%s %s%s", attack_mess[ATM_DRAIN][i].buf1, &op->name, attack_mess[ATM_DRAIN][i].buf2);
500     strcpy (buf2, attack_mess[ATM_DRAIN][i].buf3);
501     found++;
502     break;
503     }
504     }
505 root 1.29 else if (type & AT_ELECTRICITY && op->is_alive ())
506 root 1.9 {
507     for (i = 0; i < MAXATTACKMESS && attack_mess[ATM_ELEC][i].level != -1; i++)
508     if (dam < attack_mess[ATM_ELEC][i].level || attack_mess[ATM_ELEC][i + 1].level == -1)
509     {
510     sprintf (buf1, "%s %s%s", attack_mess[ATM_ELEC][i].buf1, &op->name, attack_mess[ATM_ELEC][i].buf2);
511     strcpy (buf2, attack_mess[ATM_ELEC][i].buf3);
512     found++;
513     break;
514     }
515     }
516 root 1.29 else if (type & AT_COLD && op->is_alive ())
517 root 1.9 {
518     for (i = 0; i < MAXATTACKMESS && attack_mess[ATM_COLD][i].level != -1; i++)
519     if (dam < attack_mess[ATM_COLD][i].level || attack_mess[ATM_COLD][i + 1].level == -1)
520     {
521     sprintf (buf1, "%s %s%s", attack_mess[ATM_COLD][i].buf1, &op->name, attack_mess[ATM_COLD][i].buf2);
522     strcpy (buf2, attack_mess[ATM_COLD][i].buf3);
523     found++;
524     break;
525     }
526     }
527     else if (type & AT_FIRE)
528     {
529     for (i = 0; i < MAXATTACKMESS && attack_mess[ATM_FIRE][i].level != -1; i++)
530     if (dam < attack_mess[ATM_FIRE][i].level || attack_mess[ATM_FIRE][i + 1].level == -1)
531     {
532     sprintf (buf1, "%s %s%s", attack_mess[ATM_FIRE][i].buf1, &op->name, attack_mess[ATM_FIRE][i].buf2);
533     strcpy (buf2, attack_mess[ATM_FIRE][i].buf3);
534     found++;
535     break;
536     }
537     }
538     else if (hitter->current_weapon != NULL)
539     {
540     int mtype;
541    
542     switch (hitter->current_weapon->weapontype)
543     {
544     case WEAP_HIT:
545     mtype = ATM_BASIC;
546     break;
547     case WEAP_SLASH:
548     mtype = ATM_SLASH;
549     break;
550     case WEAP_PIERCE:
551     mtype = ATM_PIERCE;
552     break;
553     case WEAP_CLEAVE:
554     mtype = ATM_CLEAVE;
555     break;
556     case WEAP_SLICE:
557     mtype = ATM_SLICE;
558     break;
559     case WEAP_STAB:
560     mtype = ATM_STAB;
561     break;
562     case WEAP_WHIP:
563     mtype = ATM_WHIP;
564     break;
565     case WEAP_CRUSH:
566     mtype = ATM_CRUSH;
567     break;
568     case WEAP_BLUD:
569     mtype = ATM_BLUD;
570     break;
571     default:
572     mtype = ATM_BASIC;
573     break;
574     }
575     for (i = 0; i < MAXATTACKMESS && attack_mess[mtype][i].level != -1; i++)
576     if (dam < attack_mess[mtype][i].level || attack_mess[mtype][i + 1].level == -1)
577     {
578     sprintf (buf1, "%s %s%s", attack_mess[mtype][i].buf1, &op->name, attack_mess[mtype][i].buf2);
579     strcpy (buf2, attack_mess[mtype][i].buf3);
580     found++;
581     break;
582     }
583     }
584     else
585     {
586     for (i = 0; i < MAXATTACKMESS && attack_mess[ATM_BASIC][i].level != -1; i++)
587     if (dam < attack_mess[ATM_BASIC][i].level || attack_mess[ATM_BASIC][i + 1].level == -1)
588     {
589     sprintf (buf1, "%s %s%s", attack_mess[ATM_BASIC][i].buf1, &op->name, attack_mess[ATM_BASIC][i].buf2);
590     strcpy (buf2, attack_mess[ATM_BASIC][i].buf3);
591     found++;
592     break;
593     }
594 elmex 1.1 }
595    
596 root 1.9 if (!found)
597     {
598     strcpy (buf1, "hit");
599     strcpy (buf2, " hits");
600 elmex 1.1 }
601    
602 root 1.9 /* bail out if a monster is casting spells */
603 root 1.27 if (!(hitter->type == PLAYER || (hitter->owner != NULL && hitter->owner->type == PLAYER)))
604 root 1.9 return;
605 elmex 1.1
606 root 1.9 /* scale down magic considerably. */
607     if (type & AT_MAGIC && rndm (0, 5))
608     return;
609 elmex 1.1
610 root 1.9 /* Did a player hurt another player? Inform both! */
611 root 1.27 if (op->type == PLAYER && (hitter->owner == NULL ? hitter->type : hitter->owner->type) == PLAYER)
612 root 1.9 {
613 root 1.27 if (hitter->owner != NULL)
614 root 1.9 sprintf (buf, "%s's %s%s you.", &hitter->owner->name, &hitter->name, buf2);
615     else
616     {
617     sprintf (buf, "%s%s you.", &hitter->name, buf2);
618     if (dam != 0)
619     {
620     if (dam < 10)
621     play_sound_player_only (op->contr, SOUND_PLAYER_IS_HIT1, 0, 0);
622     else if (dam < 20)
623     play_sound_player_only (op->contr, SOUND_PLAYER_IS_HIT2, 0, 0);
624     else
625     play_sound_player_only (op->contr, SOUND_PLAYER_IS_HIT3, 0, 0);
626 root 1.5 }
627     }
628 root 1.9 new_draw_info (NDI_BLACK, 0, op, buf);
629     } /* end of player hitting player */
630 elmex 1.1
631 root 1.9 if (hitter->type == PLAYER)
632     {
633     sprintf (buf, "You %s.", buf1);
634     if (dam != 0)
635     {
636     if (dam < 10)
637     play_sound_player_only (hitter->contr, SOUND_PLAYER_HITS1, 0, 0);
638     else if (dam < 20)
639     play_sound_player_only (hitter->contr, SOUND_PLAYER_HITS2, 0, 0);
640     else
641     play_sound_player_only (hitter->contr, SOUND_PLAYER_HITS3, 0, 0);
642 root 1.5 }
643 root 1.9 new_draw_info (NDI_BLACK, 0, hitter, buf);
644     }
645 root 1.27 else if (hitter->owner != NULL && hitter->owner->type == PLAYER)
646 root 1.9 {
647 elmex 1.1 /* look for stacked spells and start reducing the message chances */
648 root 1.9 if (hitter->type == SPELL_EFFECT && (hitter->subtype == SP_EXPLOSION || hitter->subtype == SP_BULLET || hitter->subtype == SP_CONE))
649     {
650     i = 4;
651     map = hitter->map;
652     if (out_of_map (map, hitter->x, hitter->y))
653     return;
654 root 1.53
655 root 1.30 next = GET_MAP_OB (map, hitter->x, hitter->y);
656 root 1.9 if (next)
657     while (next)
658     {
659     if (next->type == SPELL_EFFECT && (next->subtype == SP_EXPLOSION || next->subtype == SP_BULLET || next->subtype == SP_CONE))
660     i *= 3;
661     tmp = next;
662     next = tmp->above;
663     }
664 root 1.53
665 root 1.9 if (i < 0)
666 root 1.5 return;
667 root 1.53
668 root 1.9 if (rndm (0, i) != 0)
669     return;
670     }
671     else if (rndm (0, 5) != 0)
672     return;
673 root 1.53
674 root 1.9 sprintf (buf, "Your %s%s %s.", &hitter->name, buf2, &op->name);
675     play_sound_map (op->map, op->x, op->y, SOUND_PLAYER_HITS4);
676     new_draw_info (NDI_BLACK, 0, hitter->owner, buf);
677 elmex 1.1 }
678     }
679    
680    
681 root 1.9 static int
682     get_attack_mode (object **target, object **hitter, int *simple_attack)
683 elmex 1.1 {
684 root 1.9 if (QUERY_FLAG (*target, FLAG_FREED) || QUERY_FLAG (*hitter, FLAG_FREED))
685     {
686     LOG (llevError, "BUG: get_attack_mode(): freed object\n");
687     return 1;
688 elmex 1.1 }
689 root 1.9 if ((*target)->head)
690     *target = (*target)->head;
691     if ((*hitter)->head)
692     *hitter = (*hitter)->head;
693     if ((*hitter)->env != NULL || (*target)->env != NULL)
694     {
695     *simple_attack = 1;
696     return 0;
697 elmex 1.1 }
698 root 1.9 if (QUERY_FLAG (*target, FLAG_REMOVED)
699     || QUERY_FLAG (*hitter, FLAG_REMOVED) || (*hitter)->map == NULL || !on_same_map ((*hitter), (*target)))
700 elmex 1.1 {
701 root 1.67 LOG (llevError, "BUG: hitter (arch %s, name %s) with no relation to " "target\n", &(*hitter)->arch->archname, &(*hitter)->name);
702 root 1.9 return 1;
703 elmex 1.1 }
704 root 1.9 *simple_attack = 0;
705     return 0;
706 elmex 1.1 }
707    
708 root 1.9 static int
709     abort_attack (object *target, object *hitter, int simple_attack)
710 elmex 1.1 {
711 root 1.9
712 elmex 1.1 /* Check if target and hitter are still in a relation similar to the one
713     * determined by get_attack_mode(). Returns true if the relation has changed.
714     */
715 root 1.9 int new_mode;
716 elmex 1.1
717 root 1.9 if (hitter->env == target || target->env == hitter)
718     new_mode = 1;
719     else if (QUERY_FLAG (hitter, FLAG_REMOVED) || QUERY_FLAG (target, FLAG_REMOVED) || hitter->map == NULL || !on_same_map (hitter, target))
720     return 1;
721     else
722     new_mode = 0;
723     return new_mode != simple_attack;
724 elmex 1.1 }
725    
726     static void thrown_item_effect (object *, object *);
727    
728 root 1.9 static int
729     attack_ob_simple (object *op, object *hitter, int base_dam, int base_wc)
730 elmex 1.1 {
731 root 1.9 int simple_attack, roll, dam = 0;
732     uint32 type;
733     shstr op_name;
734    
735     if (get_attack_mode (&op, &hitter, &simple_attack))
736     goto error;
737    
738     if (hitter->current_weapon)
739     if (INVOKE_OBJECT (WEAPON_ATTACK, hitter->current_weapon, ARG_OBJECT (hitter), ARG_OBJECT (op)))
740     return RESULT_INT (0);
741    
742     if (INVOKE_OBJECT (ATTACK, op, ARG_OBJECT (hitter)))
743     return RESULT_INT (0);
744 elmex 1.1
745 root 1.9 /*
746     * A little check to make it more difficult to dance forward and back
747     * to avoid ever being hit by monsters.
748     */
749 root 1.63 if (!simple_attack && QUERY_FLAG (op, FLAG_MONSTER) && op->speed_left > abs (op->speed) * -0.3f)
750 root 1.9 {
751     /* Decrease speed BEFORE calling process_object. Otherwise, an
752     * infinite loop occurs, with process_object calling move_monster,
753     * which then gets here again. By decreasing the speed before
754     * we call process_object, the 'if' statement above will fail.
755     */
756 root 1.65 --op->speed_left;
757 root 1.9 process_object (op);
758 root 1.26
759 root 1.18 if (op->destroyed () || hitter->destroyed () || abort_attack (op, hitter, simple_attack))
760 elmex 1.1 goto error;
761 root 1.9 }
762 elmex 1.1
763 root 1.9 op_name = op->name;
764 root 1.3
765 root 1.9 roll = random_roll (1, 20, hitter, PREFER_HIGH);
766 elmex 1.1
767 root 1.9 /* Adjust roll for various situations. */
768     if (!simple_attack)
769     roll += adj_attackroll (hitter, op);
770 elmex 1.1
771 root 1.9 /* See if we hit the creature */
772     if (roll == 20 || op->stats.ac >= base_wc - roll)
773     {
774     int hitdam = base_dam;
775    
776     if (!simple_attack)
777 elmex 1.1 {
778 root 1.9 /* If you hit something, the victim should *always* wake up.
779     * Before, invisible hitters could avoid doing this.
780     * -b.t. */
781     if (QUERY_FLAG (op, FLAG_SLEEP))
782     CLEAR_FLAG (op, FLAG_SLEEP);
783    
784     /* If the victim can't see the attacker, it may alert others
785     * for help. */
786 root 1.27 if (op->type != PLAYER && !can_see_enemy (op, hitter) && !op->owner && rndm (0, op->stats.Int))
787 root 1.9 npc_call_help (op);
788    
789     /* if you were hidden and hit by a creature, you are discovered */
790     if (op->hide && QUERY_FLAG (hitter, FLAG_ALIVE))
791     {
792     make_visible (op);
793 root 1.59
794 root 1.9 if (op->type == PLAYER)
795     new_draw_info (NDI_UNIQUE, 0, op, "You were hit by a wild attack. " "You are no longer hidden!");
796     }
797    
798     /* thrown items (hitter) will have various effects
799     * when they hit the victim. For things like thrown daggers,
800     * this sets 'hitter' to the actual dagger, and not the
801     * wrapper object.
802     */
803     thrown_item_effect (hitter, op);
804 root 1.26
805 root 1.18 if (hitter->destroyed () || op->destroyed () || abort_attack (op, hitter, simple_attack))
806 root 1.9 goto leave;
807     }
808    
809     /* Need to do at least 1 damage, otherwise there is no point
810     * to go further and it will cause FPE's below.
811     */
812     if (hitdam <= 0)
813     hitdam = 1;
814 elmex 1.1
815 root 1.9 type = hitter->attacktype;
816 root 1.18
817 root 1.9 if (!type)
818     type = AT_PHYSICAL;
819 root 1.18
820 root 1.9 /* Handle monsters that hit back */
821     if (!simple_attack && QUERY_FLAG (op, FLAG_HITBACK) && QUERY_FLAG (hitter, FLAG_ALIVE))
822     {
823     if (op->attacktype & AT_ACID && hitter->type == PLAYER)
824     new_draw_info (NDI_UNIQUE, 0, hitter, "You are splashed by acid!\n");
825 root 1.18
826 root 1.9 hit_player (hitter, random_roll (0, (op->stats.dam), hitter, PREFER_LOW), op, op->attacktype, 1);
827 root 1.18
828     if (op->destroyed () || hitter->destroyed () || abort_attack (op, hitter, simple_attack))
829 root 1.5 goto leave;
830 root 1.9 }
831 elmex 1.1
832 root 1.9 /* In the new attack code, it should handle multiple attack
833     * types in its area, so remove it from here.
834     */
835     dam = hit_player (op, random_roll (1, hitdam, hitter, PREFER_HIGH), hitter, type, 1);
836 root 1.18
837     if (op->destroyed () || hitter->destroyed () || abort_attack (op, hitter, simple_attack))
838 root 1.9 goto leave;
839     } /* end of if hitter hit op */
840     /* if we missed, dam=0 */
841    
842     /*attack_message(dam, type, op, hitter); */
843 elmex 1.1
844 root 1.9 goto leave;
845 elmex 1.1
846 root 1.9 error:
847     dam = 1;
848 elmex 1.1
849 root 1.9 leave:
850 elmex 1.1
851 root 1.9 return dam;
852 elmex 1.1 }
853    
854 root 1.9 int
855     attack_ob (object *op, object *hitter)
856 elmex 1.1 {
857 root 1.58 hitter = hitter->head_ ();
858 elmex 1.1
859 root 1.9 return attack_ob_simple (op, hitter, hitter->stats.dam, hitter->stats.wc);
860 elmex 1.1 }
861    
862     /* op is the arrow, tmp is what is stopping the arrow.
863     *
864     * Returns 1 if op was inserted into tmp's inventory, 0 otherwise.
865     */
866 root 1.9 static int
867     stick_arrow (object *op, object *tmp)
868 elmex 1.1 {
869 root 1.9 /* If the missile hit a player, we insert it in their inventory.
870     * However, if the missile is heavy, we don't do so (assume it falls
871     * to the ground after a hit). What a good value for this is up to
872     * debate - 5000 is 5 kg, so arrows, knives, and other light weapons
873     * stick around.
874     */
875     if (op->weight <= 5000 && tmp->stats.hp >= 0)
876     {
877 root 1.59 tmp = tmp->head_ ();
878 root 1.10
879 root 1.25 op->remove ();
880 root 1.9 op = insert_ob_in_ob (op, tmp);
881 root 1.10
882 root 1.9 if (tmp->type == PLAYER)
883     esrv_send_item (tmp, op);
884 root 1.10
885 root 1.9 return 1;
886     }
887     else
888     return 0;
889 elmex 1.1 }
890    
891     /* hit_with_arrow() disassembles the missile, attacks the victim and
892     * reassembles the missile.
893     *
894     * It returns a pointer to the reassembled missile, or NULL if the missile
895     * isn't available anymore.
896     */
897 root 1.9 object *
898     hit_with_arrow (object *op, object *victim)
899 elmex 1.1 {
900 root 1.9 object *container, *hitter;
901     int hit_something = 0;
902    
903     /* Disassemble missile */
904     if (op->inv)
905     {
906     container = op;
907     hitter = op->inv;
908 root 1.25 hitter->remove ();
909 root 1.9 insert_ob_in_map (hitter, container->map, hitter, INS_NO_MERGE | INS_NO_WALK_ON);
910     /* Note that we now have an empty THROWN_OBJ on the map. Code that
911     * might be called until this THROWN_OBJ is either reassembled or
912     * removed at the end of this function must be able to deal with empty
913     * THROWN_OBJs. */
914     }
915     else
916     {
917 root 1.21 container = 0;
918 root 1.9 hitter = op;
919     }
920    
921     /* Try to hit victim */
922     hit_something = attack_ob_simple (victim, hitter, op->stats.dam, op->stats.wc);
923    
924     /* Arrow attacks door, rune of summoning is triggered, demon is put on
925     * arrow, move_apply() calls this function, arrow sticks in demon,
926     * attack_ob_simple() returns, and we've got an arrow that still exists
927     * but is no longer on the map. Ugh. (Beware: Such things can happen at
928     * other places as well!)
929     */
930 root 1.18 if (hitter->destroyed () || hitter->env != NULL)
931 root 1.9 {
932     if (container)
933     {
934 root 1.25 container->remove ();
935 root 1.26 container->destroy ();
936 elmex 1.1 }
937 root 1.21
938     return 0;
939 elmex 1.1 }
940    
941 root 1.9 /* Missile hit victim */
942     /* if the speed is > 10, then this is a fast moving arrow, we go straight
943     * through the target
944     */
945     if (hit_something && op->speed <= 10.0)
946     {
947     /* Stop arrow */
948 root 1.21 if (!container)
949 root 1.9 {
950     hitter = fix_stopped_arrow (hitter);
951 root 1.21 if (!hitter)
952     return 0;
953 root 1.9 }
954     else
955 root 1.26 container->destroy ();
956 elmex 1.1
957 root 1.9 /* Try to stick arrow into victim */
958 root 1.18 if (!victim->destroyed () && stick_arrow (hitter, victim))
959 root 1.21 return 0;
960 root 1.9
961     /* Else try to put arrow on victim's map square
962     * remove check for P_WALL here. If the arrow got to this
963     * space, that is good enough - with the new movement code,
964     * there is now the potential for lots of spaces where something
965     * can fly over but not otherwise move over. What is the correct
966     * way to handle those otherwise?
967     */
968 root 1.21 if (victim->x != hitter->x || victim->y != hitter->y)
969 root 1.9 {
970 root 1.25 hitter->remove ();
971 root 1.21 hitter->x = victim->x;
972     hitter->y = victim->y;
973 root 1.9 insert_ob_in_map (hitter, victim->map, hitter, 0);
974 elmex 1.1 }
975 root 1.9 else
976 root 1.21 /* Else leave arrow where it is */
977     merge_ob (hitter, NULL);
978    
979     return 0;
980 elmex 1.1 }
981    
982 root 1.9 if (hit_something && op->speed >= 10.0)
983     op->speed -= 1.0;
984 elmex 1.1
985 root 1.9 /* Missile missed victim - reassemble missile */
986     if (container)
987     {
988 root 1.25 hitter->remove ();
989 root 1.9 insert_ob_in_ob (hitter, container);
990 elmex 1.1 }
991 root 1.21
992 root 1.9 return op;
993 elmex 1.1 }
994    
995 root 1.9 void
996     tear_down_wall (object *op)
997 elmex 1.1 {
998 root 1.9 int perc = 0;
999 elmex 1.1
1000 root 1.9 if (!op->stats.maxhp)
1001     {
1002     LOG (llevError, "TEAR_DOWN wall %s had no maxhp.\n", &op->name);
1003     perc = 1;
1004 elmex 1.1 }
1005 root 1.9 else if (!GET_ANIM_ID (op))
1006     {
1007     /* Object has been called - no animations, so remove it */
1008     if (op->stats.hp < 0)
1009 root 1.26 op->destroy ();
1010    
1011 root 1.9 return; /* no animations, so nothing more to do */
1012     }
1013 root 1.26
1014 root 1.9 perc = NUM_ANIMATIONS (op) - ((int) NUM_ANIMATIONS (op) * op->stats.hp) / op->stats.maxhp;
1015 root 1.26
1016 root 1.9 if (perc >= (int) NUM_ANIMATIONS (op))
1017     perc = NUM_ANIMATIONS (op) - 1;
1018     else if (perc < 1)
1019     perc = 1;
1020 root 1.26
1021 root 1.9 SET_ANIMATION (op, perc);
1022     update_object (op, UP_OBJ_FACE);
1023 root 1.26
1024 root 1.9 if (perc == NUM_ANIMATIONS (op) - 1)
1025     { /* Reached the last animation */
1026     if (op->face == blank_face)
1027 root 1.26 /* If the last face is blank, remove the ob */
1028     op->destroy ();
1029 root 1.9 else
1030     { /* The last face was not blank, leave an image */
1031     CLEAR_FLAG (op, FLAG_BLOCKSVIEW);
1032     update_all_los (op->map, op->x, op->y);
1033     op->move_block = 0;
1034     CLEAR_FLAG (op, FLAG_ALIVE);
1035 root 1.5 }
1036 elmex 1.1 }
1037     }
1038    
1039 root 1.9 void
1040     scare_creature (object *target, object *hitter)
1041 elmex 1.1 {
1042 root 1.27 object *owner = hitter->owner;
1043 elmex 1.1
1044 root 1.9 if (!owner)
1045     owner = hitter;
1046 elmex 1.1
1047 root 1.9 SET_FLAG (target, FLAG_SCARED);
1048     if (!target->enemy)
1049     target->enemy = owner;
1050 elmex 1.1 }
1051    
1052     /* This returns the amount of damage hitter does to op with the
1053     * appropriate attacktype. Only 1 attacktype should be set at a time.
1054     * This doesn't damage the player, but returns how much it should
1055     * take. However, it will do other effects (paralyzation, slow, etc.)
1056     * Note - changed for PR code - we now pass the attack number and not
1057     * the attacktype. Makes it easier for the PR code. */
1058 root 1.9 int
1059     hit_player_attacktype (object *op, object *hitter, int dam, uint32 attacknum, int magic)
1060     {
1061     int doesnt_slay = 1;
1062    
1063     /* Catch anyone that may be trying to send us a bitmask instead of the number */
1064     if (attacknum >= NROFATTACKS)
1065     {
1066     LOG (llevError, "hit_player_attacktype: Invalid attacknumber passed: %u\n", attacknum);
1067     return 0;
1068 elmex 1.1 }
1069 root 1.9
1070     if (dam < 0)
1071     {
1072 root 1.61 LOG (llevError, "hit_player_attacktype called with negative damage %d (hitter %s, target %s)\n",
1073     dam, hitter->debug_desc (), op->debug_desc ());
1074 root 1.9 return 0;
1075 elmex 1.1 }
1076 root 1.9
1077     /* AT_INTERNAL is supposed to do exactly dam. Put a case here so
1078     * people can't mess with that or it otherwise get confused. */
1079     if (attacknum == ATNR_INTERNAL)
1080     return dam;
1081    
1082     if (hitter->slaying)
1083     {
1084 root 1.59 if ((op->race && strstr (hitter->slaying, op->race))
1085 root 1.67 || (op->arch && op->arch->archname && strstr (op->arch->archname, hitter->slaying)))
1086 root 1.9 {
1087     doesnt_slay = 0;
1088     dam *= 3;
1089     }
1090 elmex 1.1 }
1091    
1092 root 1.9 /* Adjust the damage for resistance. Note that neg. values increase damage. */
1093     if (op->resist[attacknum])
1094     {
1095 elmex 1.1 /* basically: dam = dam*(100-op->resist[attacknum])/100;
1096     * in case 0>dam>1, we try to "simulate" a float value-effect */
1097 root 1.9 dam *= (100 - op->resist[attacknum]);
1098     if (dam >= 100)
1099     dam /= 100;
1100 elmex 1.1 else
1101 root 1.9 dam = (dam > (random_roll (0, 99, op, PREFER_LOW))) ? 1 : 0;
1102 elmex 1.1 }
1103    
1104 root 1.9 /* Special hack. By default, if immune to something, you
1105     * shouldn't need to worry. However, acid is an exception, since
1106     * it can still damage your items. Only include attacktypes if
1107     * special processing is needed */
1108    
1109 root 1.59 if (op->resist[attacknum] >= 100
1110     && doesnt_slay
1111     && attacknum != ATNR_ACID)
1112 root 1.9 return 0;
1113    
1114     /* Keep this in order - makes things easier to find */
1115    
1116     switch (attacknum)
1117     {
1118 root 1.40 case ATNR_PHYSICAL:
1119     /* here also check for diseases */
1120     check_physically_infect (op, hitter);
1121     break;
1122    
1123     /* Don't need to do anything for:
1124     magic,
1125     fire,
1126     electricity,
1127     cold */
1128    
1129     case ATNR_CONFUSION:
1130     case ATNR_POISON:
1131     case ATNR_SLOW:
1132     case ATNR_PARALYZE:
1133     case ATNR_FEAR:
1134     case ATNR_CANCELLATION:
1135     case ATNR_DEPLETE:
1136     case ATNR_BLIND:
1137     {
1138     /* chance for inflicting a special attack depends on the
1139     * difference between attacker's and defender's level
1140     */
1141     int level_diff = MIN (110, MAX (0, op->level - hitter->level));
1142    
1143     /* First, only creatures/players with speed can be affected.
1144     * Second, just getting hit doesn't mean it always affects
1145     * you. Third, you still get a saving through against the
1146     * effect.
1147     */
1148     if (op->speed &&
1149     (QUERY_FLAG (op, FLAG_MONSTER) || op->type == PLAYER) &&
1150     !(rndm (0, (attacknum == ATNR_SLOW ? 6 : 3) - 1)) && !did_make_save (op, level_diff, op->resist[attacknum] / 10))
1151     {
1152 root 1.5
1153 root 1.40 /* Player has been hit by something */
1154     if (attacknum == ATNR_CONFUSION)
1155     confuse_player (op, hitter, dam);
1156     else if (attacknum == ATNR_POISON)
1157     poison_player (op, hitter, dam);
1158     else if (attacknum == ATNR_SLOW)
1159     slow_player (op, hitter, dam);
1160     else if (attacknum == ATNR_PARALYZE)
1161     paralyze_player (op, hitter, dam);
1162     else if (attacknum == ATNR_FEAR)
1163     scare_creature (op, hitter);
1164     else if (attacknum == ATNR_CANCELLATION)
1165     cancellation (op);
1166     else if (attacknum == ATNR_DEPLETE)
1167     op->drain_stat ();
1168     else if (attacknum == ATNR_BLIND && !QUERY_FLAG (op, FLAG_UNDEAD) && !QUERY_FLAG (op, FLAG_GENERATOR))
1169     blind_player (op, hitter, dam);
1170     }
1171 root 1.59
1172 root 1.40 dam = 0; /* These are all effects and don't do real damage */
1173     }
1174     break;
1175 root 1.44
1176 root 1.40 case ATNR_ACID:
1177     {
1178     int flag = 0;
1179 root 1.9
1180 root 1.40 /* Items only get corroded if you're not on a battleground and
1181     * if your acid resistance is below 50%. */
1182     if (!op_on_battleground (op, NULL, NULL) && (op->resist[ATNR_ACID] < 50))
1183     {
1184 root 1.44 for (object *tmp = op->inv; tmp; tmp = tmp->below)
1185 root 1.40 {
1186     if (tmp->invisible)
1187     continue;
1188     if (!QUERY_FLAG (tmp, FLAG_APPLIED) || (tmp->resist[ATNR_ACID] >= 10))
1189 root 1.44 /* >= 10% acid res. on items will protect these */
1190 root 1.40 continue;
1191 root 1.49 if (!(tmp->materials & M_IRON))
1192 root 1.40 continue;
1193     if (tmp->magic < -4) /* Let's stop at -5 */
1194     continue;
1195 root 1.44 if (tmp->type == RING
1196     /* removed boots and gloves from exclusion list in PR */
1197     || tmp->type == GIRDLE
1198     || tmp->type == AMULET
1199     || tmp->type == WAND
1200     || tmp->type == ROD
1201     || tmp->type == HORN)
1202 root 1.40 continue; /* To avoid some strange effects */
1203    
1204     /* High damage acid has better chance of corroding
1205     objects */
1206     if (rndm (0, dam + 4) > random_roll (0, 39, op, PREFER_HIGH) + 2 * tmp->magic)
1207     {
1208     if (op->type == PLAYER)
1209     /* Make this more visible */
1210     new_draw_info_format (NDI_UNIQUE | NDI_RED, 0, op,
1211     "The %s's acid corrodes your %s!", query_name (hitter), query_name (tmp));
1212     flag = 1;
1213     tmp->magic--;
1214     if (op->type == PLAYER)
1215     esrv_send_item (op, tmp);
1216     }
1217     }
1218 root 1.44
1219 root 1.40 if (flag)
1220     op->update_stats (); /* Something was corroded */
1221     }
1222     }
1223     break;
1224 root 1.44
1225 root 1.40 case ATNR_DRAIN:
1226     {
1227     /* rate is the proportion of exp drained. High rate means
1228     * not much is drained, low rate means a lot is drained.
1229     */
1230     int rate;
1231 root 1.9
1232 root 1.40 if (op->resist[ATNR_DRAIN] >= 0)
1233     rate = 400 + op->resist[ATNR_DRAIN] * 3;
1234     else
1235     rate = 400 * 100 / (100 - op->resist[ATNR_DRAIN]);
1236 root 1.9
1237 root 1.40 if (op->stats.exp <= rate)
1238     {
1239     if (op->type == GOLEM)
1240     dam = 999; /* Its force is "sucked" away. 8) */
1241     else
1242     /* If we can't drain, lets try to do physical damage */
1243     dam = hit_player_attacktype (op, hitter, dam, ATNR_PHYSICAL, magic);
1244     }
1245     else
1246     {
1247     /* Randomly give the hitter some hp */
1248     if (hitter->stats.hp < hitter->stats.maxhp &&
1249     (op->level > hitter->level) && random_roll (0, (op->level - hitter->level + 2), hitter, PREFER_HIGH) > 3)
1250     hitter->stats.hp++;
1251    
1252     /* Can't do drains on battleground spaces.
1253     * Move the wiz check up here - before, the hitter wouldn't gain exp
1254     * exp, but the wiz would still lose exp! If drainee is a wiz,
1255     * nothing happens.
1256     * Try to credit the owner. We try to display player -> player drain
1257     * attacks, hence all the != PLAYER checks.
1258     */
1259 root 1.64 if (!op_on_battleground (hitter, NULL, NULL) && !QUERY_FLAG (op, FLAG_WIZ))
1260 root 1.40 {
1261     object *owner = hitter->owner;
1262 root 1.9
1263 root 1.40 if (owner && owner != hitter)
1264     {
1265     if (op->type != PLAYER || owner->type != PLAYER)
1266     change_exp (owner, op->stats.exp / (rate * 2),
1267     hitter->chosen_skill ? hitter->chosen_skill->skill : (const char *) 0, SK_EXP_TOTAL);
1268     }
1269     else if (op->type != PLAYER || hitter->type != PLAYER)
1270 root 1.59 change_exp (hitter, op->stats.exp / (rate * 2),
1271     hitter->chosen_skill ? hitter->chosen_skill->skill : (const char *) 0, 0);
1272    
1273 root 1.40 change_exp (op, -op->stats.exp / rate, NULL, 0);
1274     }
1275 root 1.44
1276 root 1.40 dam = 1; /* Drain is an effect. Still return 1 - otherwise, if you have pure
1277     * drain attack, you won't know that you are actually sucking out EXP,
1278     * as the messages will say you missed
1279     */
1280     }
1281     }
1282     break;
1283 root 1.44
1284 root 1.40 case ATNR_TURN_UNDEAD:
1285     {
1286     if (QUERY_FLAG (op, FLAG_UNDEAD))
1287     {
1288     object *owner = hitter->owner ? (object *)hitter->owner : hitter;
1289     object *god = find_god (determine_god (owner));
1290     int div = 1;
1291    
1292     /* if undead are not an enemy of your god, you turn them
1293     * at half strength */
1294     if (!god || !god->slaying || strstr (god->slaying, undead_name) == NULL)
1295     div = 2;
1296 root 1.59
1297 root 1.40 /* Give a bonus if you resist turn undead */
1298     if (op->level * div < (turn_bonus[owner->stats.Wis] + owner->level + (op->resist[ATNR_TURN_UNDEAD] / 100)))
1299     scare_creature (op, owner);
1300     }
1301     else
1302     dam = 0; /* don't damage non undead - should we damage
1303     undead? */
1304     }
1305     break;
1306 root 1.44
1307 root 1.40 case ATNR_DEATH:
1308     deathstrike_player (op, hitter, &dam);
1309     break;
1310 root 1.44
1311 root 1.40 case ATNR_CHAOS:
1312 root 1.61 LOG (llevError, "%s was hit by %s with non-specific chaos.\n", op->debug_desc (), hitter->debug_desc ());
1313 root 1.40 dam = 0;
1314     break;
1315 root 1.44
1316 root 1.40 case ATNR_COUNTERSPELL:
1317 root 1.61 LOG (llevError, "%s was hit by %s with counterspell attack.\n", op->debug_desc (), hitter->debug_desc ());
1318 root 1.40 dam = 0;
1319     /* This should never happen. Counterspell is handled
1320     * seperately and filtered out. If this does happen,
1321     * Counterspell has no effect on anything but spells, so it
1322     * does no damage. */
1323     break;
1324 root 1.44
1325 root 1.40 case ATNR_HOLYWORD:
1326     {
1327     /* This has already been handled by hit_player,
1328     * no need to check twice -- DAMN */
1329     object *owner = hitter->owner ? (object *)hitter->owner : hitter;
1330    
1331     /* As with turn undead above, give a bonus on the saving throw */
1332     if ((op->level + (op->resist[ATNR_HOLYWORD] / 100)) < owner->level + turn_bonus[owner->stats.Wis])
1333     scare_creature (op, owner);
1334     }
1335     break;
1336 root 1.44
1337 root 1.40 case ATNR_LIFE_STEALING:
1338     {
1339     int new_hp;
1340    
1341     /* this is replacement to drain for players, instead of taking
1342     * exp it takes hp. It is geared for players, probably not
1343     * much use giving it to monsters
1344     *
1345     * life stealing doesn't do a lot of damage, but it gives the
1346     * damage it does do to the player. Given that,
1347     * it only does 1/10'th normal damage (hence the divide by
1348     * 1000).
1349     */
1350     /* You can't steal life from something undead */
1351     if ((op->type == GOLEM) || (QUERY_FLAG (op, FLAG_UNDEAD)))
1352     return 0;
1353 root 1.44
1354 root 1.40 /* If drain protection is higher than life stealing, use that */
1355     if (op->resist[ATNR_DRAIN] >= op->resist[ATNR_LIFE_STEALING])
1356     dam = (dam * (100 - op->resist[ATNR_DRAIN])) / 3000;
1357     else
1358     dam = (dam * (100 - op->resist[ATNR_LIFE_STEALING])) / 3000;
1359 root 1.44
1360 root 1.40 /* You die at -1 hp, not zero. */
1361     if (dam > (op->stats.hp + 1))
1362     dam = op->stats.hp + 1;
1363 root 1.44
1364 root 1.40 new_hp = hitter->stats.hp + dam;
1365     if (new_hp > hitter->stats.maxhp)
1366     new_hp = hitter->stats.maxhp;
1367 root 1.44
1368 root 1.40 if (new_hp > hitter->stats.hp)
1369     hitter->stats.hp = new_hp;
1370     }
1371 elmex 1.1 }
1372 root 1.40
1373 root 1.9 return dam;
1374 elmex 1.1 }
1375    
1376     /* GROS: This code comes from hit_player. It has been made external to
1377     * allow script procedures to "kill" objects in a combat-like fashion.
1378     * It was initially used by (kill-object) developed for the Collector's
1379     * Sword. Note that nothing has been changed from the original version
1380     * of the following code.
1381     * op is what is being killed.
1382     * dam is the damage done to it.
1383     * hitter is what is hitting it.
1384     * type is the attacktype.
1385     *
1386     * This function was a bit of a mess with hitter getting changed,
1387     * values being stored away but not used, etc. I've cleaned it up
1388     * a bit - I think it should be functionally equivalant.
1389     * MSW 2002-07-17
1390     */
1391 root 1.9 int
1392     kill_object (object *op, int dam, object *hitter, int type)
1393 elmex 1.1 {
1394 root 1.9 char buf[MAX_BUF];
1395     const char *skill;
1396     int maxdam = 0;
1397     int battleg = 0; /* true if op standing on battleground */
1398     int pk = 0; /* true if op and what controls hitter are both players */
1399 root 1.61 object *owner = 0;
1400     object *skop = 0;
1401 elmex 1.1
1402 root 1.9 if (op->stats.hp >= 0)
1403     return -1;
1404    
1405     if (INVOKE_OBJECT (KILL, op, ARG_OBJECT (hitter)))
1406     return 0;
1407    
1408     /* maxdam needs to be the amount of damage it took to kill
1409     * this creature. The function(s) that call us have already
1410     * adjusted the creatures HP total, so that is negative.
1411     */
1412     maxdam = dam + op->stats.hp + 1;
1413    
1414     if (QUERY_FLAG (op, FLAG_BLOCKSVIEW))
1415     update_all_los (op->map, op->x, op->y); /* makes sure los will be recalculated */
1416    
1417     if (op->type == DOOR)
1418     {
1419 root 1.63 op->set_speed (0.1f);
1420     op->speed_left = -0.05f;
1421 root 1.9 return maxdam;
1422     }
1423 root 1.20
1424 root 1.9 if (QUERY_FLAG (op, FLAG_FRIENDLY) && op->type != PLAYER)
1425     {
1426 root 1.26 op->destroy ();
1427 root 1.9 return maxdam;
1428     }
1429    
1430     /* Now lets start dealing with experience we get for killing something */
1431    
1432 root 1.27 owner = hitter->owner;
1433 root 1.20 if (!owner)
1434 root 1.9 owner = hitter;
1435    
1436     /* is the victim (op) standing on battleground? */
1437     if (op_on_battleground (op, NULL, NULL))
1438     battleg = 1;
1439    
1440     /* is this player killing? */
1441     if (op->type == PLAYER && owner->type == PLAYER)
1442     pk = 1;
1443    
1444     /* Player killed something */
1445     if (owner->type == PLAYER)
1446     {
1447     Log_Kill (owner->name,
1448     query_name (op), op->type, (owner != hitter) ? query_name (hitter) : NULL, (owner != hitter) ? hitter->type : 0);
1449    
1450     /* Log players killing other players - makes it easier to detect
1451     * and filter out malicious player killers - that is why the
1452     * ip address is included.
1453     */
1454     if (op->type == PLAYER && !battleg)
1455     {
1456     time_t t = time (NULL);
1457     struct tm *tmv;
1458     char buf[256];
1459    
1460     tmv = localtime (&t);
1461     strftime (buf, 256, "%a %b %d %H:%M:%S %Y", tmv);
1462    
1463 root 1.31 LOG (llevInfo, "%s PLAYER_KILL_PLAYER: %s (%s) killed %s\n", buf, &owner->name, owner->contr->ns->host, query_name (op));
1464 root 1.9 }
1465    
1466     /* try to filter some things out - basically, if you are
1467     * killing a level 1 creature and your level 20, you
1468     * probably don't want to see that.
1469     */
1470     if (owner->level < op->level * 2 || op->stats.exp > 1000)
1471     {
1472     if (owner != hitter)
1473 root 1.20 new_draw_info_format (NDI_BLACK, 0, owner, "You killed %s with %s.", query_name (op), query_name (hitter));
1474 root 1.9 else
1475 root 1.20 new_draw_info_format (NDI_BLACK, 0, owner, "You killed %s.", query_name (op));
1476    
1477 root 1.9 /* Only play sounds for melee kills */
1478     if (hitter->type == PLAYER)
1479     play_sound_map (owner->map, owner->x, owner->y, SOUND_PLAYER_KILLS);
1480     }
1481    
1482     /* If a player kills another player, not on
1483     * battleground, the "killer" looses 1 luck. Since this is
1484     * not reversible, it's actually quite a pain IMHO. -AV
1485     * Fix bug in that we were changing the luck of the hitter, not
1486     * player that the object belonged to - so if you killed another player
1487     * with spells, pets, whatever, there was no penalty.
1488     * Changed to make luck penalty configurable in settings.
1489     */
1490     if (op->type == PLAYER && owner != op && !battleg)
1491 root 1.32 owner->change_luck (-settings.pk_luck_penalty);
1492 root 1.9
1493     /* This code below deals with finding the appropriate skill
1494 root 1.61 * to credit exp to. This is a bit problematic - we should
1495 root 1.9 * probably never really have to look at current_weapon->skill
1496     */
1497 root 1.20 skill = 0;
1498    
1499 root 1.9 if (hitter->skill && hitter->type != PLAYER)
1500     skill = hitter->skill;
1501     else if (owner->chosen_skill)
1502     {
1503 root 1.61 skop = owner->chosen_skill;
1504     skill = skop->skill;
1505 root 1.9 }
1506     else if (QUERY_FLAG (owner, FLAG_READY_WEAPON))
1507     skill = owner->current_weapon->skill;
1508     else
1509     LOG (llevError, "kill_object - unable to find skill that killed monster\n");
1510 elmex 1.1
1511 root 1.9 /* We have the skill we want to credit to - now find the object this goes
1512 root 1.51 * to. Make sure skop is an actual skill, and not a skill tool!
1513 root 1.9 */
1514     if ((!skop || skop->type != SKILL) && skill)
1515     {
1516     int i;
1517 elmex 1.1
1518 root 1.9 for (i = 0; i < NUM_SKILLS; i++)
1519     if (owner->contr->last_skill_ob[i] && !strcmp (owner->contr->last_skill_ob[i]->skill, skill))
1520     {
1521     skop = owner->contr->last_skill_ob[i];
1522     break;
1523     }
1524 root 1.5 }
1525 root 1.9 } /* Was it a player that hit somethign */
1526     else
1527 root 1.20 skill = 0;
1528 root 1.9
1529     /* Pet (or spell) killed something. */
1530     if (owner != hitter)
1531 root 1.20 sprintf (buf, "%s killed %s with %s%s%s.", &owner->name,
1532     query_name (op), query_name (hitter), battleg ? " (duel)" : "", pk ? " (pk)" : "");
1533 root 1.9 else
1534 root 1.20 sprintf (buf, "%s killed %s%s%s%s.", &hitter->name, &op->name,
1535     (QUERY_FLAG (hitter, FLAG_MONSTER)) || hitter->type == PLAYER ?
1536     " in hand to hand combat" : "", battleg ? " (duel)" : "", pk ? " (pk)" : "");
1537    
1538 root 1.9 /* These may have been set in the player code section above */
1539     if (!skop)
1540     skop = hitter->chosen_skill;
1541 root 1.20
1542 root 1.9 if (!skill && skop)
1543     skill = skop->skill;
1544    
1545     new_draw_info (NDI_ALL, op->type == PLAYER ? 1 : 10, NULL, buf);
1546    
1547     /* If you didn't kill yourself, and your not the wizard */
1548 root 1.64 if (owner != op && !QUERY_FLAG (op, FLAG_WIZ))
1549 root 1.9 {
1550     int exp;
1551    
1552     /* Really don't give much experience for killing other players */
1553 root 1.20 // schmorp: temporarily? reduce the amount of exp gained for pking enourmously
1554 root 1.9 if (op->type == PLAYER)
1555     {
1556     if (battleg)
1557     {
1558     new_draw_info (NDI_UNIQUE, 0, owner, "Your foe has fallen!");
1559     new_draw_info (NDI_UNIQUE, 0, owner, "VICTORY!!!");
1560 root 1.5 }
1561 root 1.9 else
1562     exp = op->stats.exp / 1000;
1563 elmex 1.1 }
1564 root 1.9 else
1565     exp = calc_skill_exp (owner, op, skop);
1566 elmex 1.1
1567 root 1.9 /* if op is standing on "battleground" (arena), no way to gain
1568     * exp by killing him
1569     */
1570     if (battleg)
1571     exp = 0;
1572 elmex 1.1
1573 root 1.9 /* Don't know why this is set this way - doesn't make
1574     * sense to just divide everything by two for no reason.
1575     */
1576 elmex 1.1
1577 root 1.9 if (!settings.simple_exp)
1578     exp = exp / 2;
1579 root 1.5
1580 root 1.9 if (owner->type != PLAYER || owner->contr->party == NULL)
1581 root 1.23 change_exp (owner, exp, skill, 0);
1582 root 1.9 else
1583     {
1584     int shares = 0, count = 0;
1585     partylist *party = owner->contr->party;
1586 root 1.5
1587 root 1.9 add_kill_to_party (party, query_name (owner), query_name (op), exp);
1588 root 1.35
1589 root 1.33 for_all_players (pl)
1590 root 1.20 if (party && pl->ob->contr->party == party && on_same_map (pl->ob, owner))
1591     {
1592     count++;
1593     shares += (pl->ob->level + 4);
1594     }
1595    
1596 root 1.23 if (count == 1 || shares > exp || !shares)
1597 root 1.9 change_exp (owner, exp, skill, SK_EXP_TOTAL);
1598     else
1599     {
1600     int share = exp / shares, given = 0, nexp;
1601    
1602 root 1.33 for_all_players (pl)
1603 root 1.20 if (party && pl->ob->contr->party == party && on_same_map (pl->ob, owner))
1604     {
1605     nexp = (pl->ob->level + 4) * share;
1606     change_exp (pl->ob, nexp, skill, SK_EXP_TOTAL);
1607     given += nexp;
1608     }
1609    
1610 root 1.9 exp -= given;
1611     /* give any remainder to the player */
1612     change_exp (owner, exp, skill, SK_EXP_ADD_SKILL);
1613 root 1.5 }
1614 root 1.9 } /* else part of a party */
1615     } /* end if person didn't kill himself */
1616 elmex 1.1
1617 root 1.9 if (op->type != PLAYER)
1618     {
1619     if (QUERY_FLAG (op, FLAG_FRIENDLY))
1620     {
1621 root 1.27 object *owner1 = op->owner;
1622 elmex 1.1
1623 root 1.20 if (owner1 && owner1->type == PLAYER)
1624 root 1.9 {
1625     play_sound_player_only (owner1->contr, SOUND_PET_IS_KILLED, 0, 0);
1626     /* Maybe we should include the owner that killed this, maybe not */
1627     new_draw_info_format (NDI_UNIQUE, 0, owner1, "Your pet, the %s, is killed by %s.", &op->name, &hitter->name);
1628 root 1.5 }
1629 root 1.12
1630 root 1.9 remove_friendly_object (op);
1631 root 1.5 }
1632 root 1.12
1633 root 1.26 op->destroy ();
1634 elmex 1.1 }
1635 root 1.9 else
1636     {
1637 root 1.20 /* Player has been killed! */
1638 root 1.9 if (owner->type == PLAYER)
1639 root 1.22 snprintf (op->contr->killer, sizeof (op->contr->killer), "%s the %s", &owner->name, owner->contr->title);
1640 root 1.9 else
1641 root 1.12 assign (op->contr->killer, hitter->name);
1642 elmex 1.1 }
1643 root 1.12
1644 root 1.9 /* This was return -1 - that doesn't seem correct - if we return -1, process
1645     * continues in the calling function.
1646     */
1647     return maxdam;
1648 elmex 1.1 }
1649    
1650     /* Find out if this is friendly fire (PVP and attacker is peaceful) or not
1651     * Returns 0 this is not friendly fire
1652     */
1653 root 1.9 int
1654     friendly_fire (object *op, object *hitter)
1655     {
1656     object *owner;
1657     int friendlyfire;
1658    
1659     if (hitter->head)
1660     hitter = hitter->head;
1661    
1662     friendlyfire = 0;
1663    
1664     if (op->type == PLAYER)
1665     {
1666     if (op_on_battleground (hitter, 0, 0))
1667     return 0;
1668    
1669     if (hitter->type == PLAYER && hitter->contr->peaceful == 1)
1670     return 1;
1671    
1672 root 1.27 if ((owner = hitter->owner) != NULL)
1673 root 1.9 {
1674     if (owner->type == PLAYER && owner->contr->peaceful == 1)
1675     friendlyfire = 2;
1676     }
1677    
1678     if (hitter->type == SPELL || hitter->type == POISONING || hitter->type == DISEASE || hitter->type == RUNE)
1679     friendlyfire = 0;
1680 elmex 1.1 }
1681 root 1.62
1682 root 1.9 return friendlyfire;
1683 elmex 1.1 }
1684    
1685     /* This isn't used just for players, but in fact most objects.
1686     * op is the object to be hit, dam is the amount of damage, hitter
1687     * is what is hitting the object, type is the attacktype, and
1688     * full_hit is set if monster area does not matter.
1689     * dam is base damage - protections/vulnerabilities/slaying matches can
1690     * modify it.
1691     */
1692 root 1.40 /* Oct 95 - altered the following slightly for MULTIPLE_GODS hack
1693     * which needs new attacktype AT_HOLYWORD to work . b.t. */
1694 root 1.9 int
1695     hit_player (object *op, int dam, object *hitter, int type, int full_hit)
1696     {
1697     int maxdam = 0, ndam = 0, attacktype = 1, magic = (type & AT_MAGIC);
1698     int maxattacktype, attacknum;
1699     int body_attack = op && op->head; /* Did we hit op's head? */
1700     int simple_attack;
1701     int rtn_kill = 0;
1702     int friendlyfire;
1703 elmex 1.1
1704 root 1.9 if (get_attack_mode (&op, &hitter, &simple_attack))
1705     return 0;
1706 elmex 1.1
1707 root 1.9 /* very simple: if our target has no_damage 1 set or is wiz, we can't hurt him */
1708     if (QUERY_FLAG (op, FLAG_WIZ) || QUERY_FLAG (op, FLAG_NO_DAMAGE))
1709     return 0;
1710 elmex 1.1
1711 root 1.64 // only allow pk for hostile players
1712 root 1.9 if (op->type == PLAYER)
1713     {
1714 root 1.27 object *owner = hitter->owner;
1715 root 1.9
1716     if (!owner)
1717     owner = hitter;
1718 root 1.18
1719 root 1.56 if (owner->type == PLAYER
1720     && (!op_on_battleground (op, 0, 0)
1721     && (op->contr->peaceful || owner->contr->peaceful))
1722     && op != owner)
1723 root 1.18 return 0;
1724 elmex 1.1 }
1725    
1726 root 1.9 if (body_attack)
1727     {
1728     /* slow and paralyze must hit the head. But we don't want to just
1729     * return - we still need to process other attacks the spell still
1730     * might have. So just remove the paralyze and slow attacktypes,
1731     * and keep on processing if we have other attacktypes.
1732     * return if only magic or nothing is left - under normal code
1733     * we don't attack with pure magic if there is another attacktype.
1734     * Only do processing if the initial attacktype includes one of those
1735     * attack so we don't cancel out things like magic bullet.
1736     */
1737     if (type & (AT_PARALYZE | AT_SLOW))
1738     {
1739     type &= ~(AT_PARALYZE | AT_SLOW);
1740 root 1.18
1741 root 1.9 if (!type || type == AT_MAGIC)
1742     return 0;
1743 root 1.5 }
1744 elmex 1.1 }
1745    
1746 root 1.9 if (!simple_attack && op->type == DOOR)
1747     {
1748 root 1.44 for (object *tmp = op->inv; tmp; tmp = tmp->below)
1749 root 1.9 if (tmp->type == RUNE || tmp->type == TRAP)
1750     {
1751     spring_trap (tmp, hitter);
1752 root 1.26
1753 root 1.18 if (hitter->destroyed () || op->destroyed () || abort_attack (op, hitter, simple_attack))
1754 root 1.9 return 0;
1755 root 1.26
1756 root 1.9 break;
1757     }
1758 elmex 1.1 }
1759    
1760 root 1.9 if (!QUERY_FLAG (op, FLAG_ALIVE) || op->stats.hp < 0)
1761     {
1762     /* FIXME: If a player is killed by a rune in a door, the
1763 root 1.18 * destroyed() check above doesn't return, and might get here.
1764 root 1.9 */
1765 elmex 1.54
1766     /* FIXME: This for example happens when a dead door is on a mover and
1767     gets it's speed_left raised on each mover-tick.
1768     Doors are removed in a kinda funny way by giving them speed and speed_left
1769     and waiting for that to run out.
1770     */
1771     LOG (llevDebug, "victim %s (%d) already dead in hit_player()\n", op->debug_desc (), op->stats.hp);
1772 root 1.9 return 0;
1773 elmex 1.1 }
1774    
1775     #ifdef ATTACK_DEBUG
1776 root 1.9 LOG (llevDebug, "hit player: attacktype %d, dam %d\n", type, dam);
1777 elmex 1.1 #endif
1778    
1779 root 1.9 if (magic)
1780     {
1781 elmex 1.1 /* basically: dam = dam*(100-op->resist[attacknum])/100;
1782     * in case 0>dam>1, we try to "simulate" a float value-effect */
1783 root 1.9 dam = dam * (100 - op->resist[ATNR_MAGIC]);
1784 elmex 1.1 if (dam >= 100)
1785 root 1.5 dam /= 100;
1786 elmex 1.1 else
1787 root 1.48 dam = (dam > rndm (0, 99)) ? 1 : 0;
1788 elmex 1.1 }
1789    
1790 root 1.9 /* AT_CHAOS here is a weapon or monster. Spells are handled by hit_map
1791     * If the attacktype still has chaos, shuffle it, then clear the Chaos bit
1792     */
1793     if (type & AT_CHAOS)
1794     {
1795     shuffle_attack (op, 0); /*0 flag tells it to not change the face */
1796     update_object (op, UP_OBJ_FACE);
1797 elmex 1.1 type &= ~AT_CHAOS;
1798     }
1799    
1800 root 1.9 /* Holyword is really an attacktype modifier (like magic is). If
1801     * holyword is part of an attacktype, then make sure the creature is
1802     * a proper match, otherwise no damage.
1803     */
1804     if (type & AT_HOLYWORD)
1805     {
1806     object *god;
1807    
1808     if ((!hitter->slaying ||
1809     (!(op->race && strstr (hitter->slaying, op->race)) &&
1810     !(op->name && strstr (hitter->slaying, op->name)))) &&
1811     (!QUERY_FLAG (op, FLAG_UNDEAD) ||
1812     (hitter->title != NULL
1813     && (god = find_god (determine_god (hitter))) != NULL && god->race != NULL && strstr (god->race, undead_name) != NULL)))
1814     return 0;
1815 elmex 1.1 }
1816    
1817 pippijn 1.36 maxattacktype = type; /* initialise this to something */
1818 root 1.9 for (attacknum = 0; attacknum < NROFATTACKS; attacknum++, attacktype = 1 << attacknum)
1819     {
1820     /* Magic isn't really a true attack type - it gets combined with other
1821     * attack types. As such, skip it over. However, if magic is
1822     * the only attacktype in the group, then still attack with it
1823     */
1824     if ((attacktype == AT_MAGIC) && (type & ~AT_MAGIC))
1825     continue;
1826    
1827     /* Go through and hit the player with each attacktype, one by one.
1828     * hit_player_attacktype only figures out the damage, doesn't inflict
1829     * it. It will do the appropriate action for attacktypes with
1830     * effects (slow, paralization, etc.
1831     */
1832     if (type & attacktype)
1833     {
1834     ndam = hit_player_attacktype (op, hitter, dam, attacknum, magic);
1835     /* the >= causes us to prefer messages from special attacks, if
1836     * the damage is equal.
1837     */
1838     if (ndam >= maxdam)
1839     {
1840 root 1.5 maxdam = ndam;
1841 root 1.9 maxattacktype = 1 << attacknum;
1842 root 1.5 }
1843     }
1844 elmex 1.1 }
1845 root 1.9
1846     /* if this is friendly fire then do a set % of damage only
1847     * Note - put a check in to make sure this attack is actually
1848     * doing damage - otherwise, the +1 in the code below will make
1849     * an attack do damage before when it otherwise didn't
1850     */
1851     friendlyfire = friendly_fire (op, hitter);
1852     if (friendlyfire && maxdam)
1853     {
1854     maxdam = ((dam * settings.set_friendly_fire) / 100);
1855    
1856 elmex 1.1 #ifdef ATTACK_DEBUG
1857 root 1.9 LOG (llevDebug, "Friendly fire (type:%d setting: %d%) did %d damage dropped to %d\n",
1858     friendlyfire, settings.set_friendly_fire, dam, maxdam);
1859 elmex 1.1 #endif
1860     }
1861    
1862 root 1.9 if (!full_hit)
1863     {
1864     int area;
1865     int remainder;
1866    
1867     area = 0;
1868 root 1.68
1869     for (archetype *at = op->arch; at; at = (archetype *)at->more)
1870 root 1.9 area++;
1871 root 1.68
1872 root 1.9 assert (area > 0);
1873    
1874     /* basically: maxdam /= area; we try to "simulate" a float
1875     value-effect */
1876     remainder = 100 * (maxdam % area) / area;
1877     maxdam /= area;
1878 root 1.47 if (rndm (100) < remainder)
1879 root 1.9 maxdam++;
1880 elmex 1.1 }
1881    
1882     #ifdef ATTACK_DEBUG
1883 root 1.9 LOG (llevDebug, "Attacktype %d did %d damage\n", type, maxdam);
1884 elmex 1.1 #endif
1885    
1886 root 1.57 // for now, only do this for active objects, otherwise they
1887     // keep a refcount for a long time and I see no usefulness
1888     // for an non-active objetc to know its enemy.
1889     if (op->active)
1890     if (hitter->owner)
1891     op->enemy = hitter->owner;
1892     else if (QUERY_FLAG (hitter, FLAG_ALIVE))
1893     op->enemy = hitter;
1894 root 1.9
1895     if (QUERY_FLAG (op, FLAG_UNAGGRESSIVE) && op->type != PLAYER)
1896     {
1897     /* The unaggressives look after themselves 8) */
1898     CLEAR_FLAG (op, FLAG_UNAGGRESSIVE);
1899     npc_call_help (op);
1900     }
1901    
1902     if (magic && did_make_save (op, op->level, 0))
1903     maxdam = maxdam / 2;
1904    
1905     attack_message (maxdam, maxattacktype, op, hitter);
1906    
1907     op->stats.hp -= maxdam;
1908    
1909     /* Eneq(@csd.uu.se): Check to see if monster runs away. */
1910     if ((op->stats.hp >= 0) &&
1911     (QUERY_FLAG (op, FLAG_MONSTER) || op->type == PLAYER) &&
1912     op->stats.hp < (signed short) (((float) op->run_away / (float) 100) * (float) op->stats.maxhp))
1913     {
1914 elmex 1.1
1915 root 1.9 if (QUERY_FLAG (op, FLAG_MONSTER))
1916     SET_FLAG (op, FLAG_RUN_AWAY);
1917     else
1918     scare_creature (op, hitter);
1919 elmex 1.1 }
1920    
1921 root 1.9 if (QUERY_FLAG (op, FLAG_TEAR_DOWN))
1922     {
1923     if (maxdam)
1924     tear_down_wall (op);
1925 root 1.26
1926 root 1.9 return maxdam; /* nothing more to do for wall */
1927     }
1928 elmex 1.1
1929 root 1.9 /* See if the creature has been killed */
1930     rtn_kill = kill_object (op, maxdam, hitter, type);
1931     if (rtn_kill != -1)
1932     return rtn_kill;
1933 elmex 1.1
1934    
1935 root 1.9 /* Used to be ghosthit removal - we now use the ONE_HIT flag. Note
1936     * that before if the player was immune to ghosthit, the monster
1937     * remained - that is no longer the case.
1938     */
1939     if (QUERY_FLAG (hitter, FLAG_ONE_HIT))
1940 root 1.56 hitter->destroy ();
1941 root 1.26
1942 root 1.9 /* Lets handle creatures that are splitting now */
1943     else if (type & AT_PHYSICAL && !QUERY_FLAG (op, FLAG_FREED) && QUERY_FLAG (op, FLAG_SPLITTING))
1944     {
1945     int i;
1946     int friendly = QUERY_FLAG (op, FLAG_FRIENDLY);
1947     int unaggressive = QUERY_FLAG (op, FLAG_UNAGGRESSIVE);
1948 root 1.27 object *owner = op->owner;
1949 root 1.5
1950 root 1.9 if (!op->other_arch)
1951     {
1952     LOG (llevError, "SPLITTING without other_arch error.\n");
1953     return maxdam;
1954     }
1955 root 1.26
1956 root 1.25 op->remove ();
1957 root 1.26
1958 root 1.9 for (i = 0; i < NROFNEWOBJS (op); i++)
1959     { /* This doesn't handle op->more yet */
1960     object *tmp = arch_to_object (op->other_arch);
1961     int j;
1962    
1963     tmp->stats.hp = op->stats.hp;
1964 root 1.26
1965 root 1.9 if (friendly)
1966     {
1967     add_friendly_object (tmp);
1968     tmp->attack_movement = PETMOVE;
1969 root 1.39
1970     if (owner)
1971 root 1.27 tmp->set_owner (owner);
1972 root 1.9 }
1973 root 1.26
1974 root 1.9 if (unaggressive)
1975     SET_FLAG (tmp, FLAG_UNAGGRESSIVE);
1976 root 1.26
1977 root 1.9 j = find_first_free_spot (tmp, op->map, op->x, op->y);
1978 root 1.26
1979 root 1.9 if (j == -1) /* No spot to put this monster */
1980 root 1.26 tmp->destroy ();
1981 root 1.9 else
1982     {
1983     tmp->x = op->x + freearr_x[j], tmp->y = op->y + freearr_y[j];
1984     insert_ob_in_map (tmp, op->map, NULL, 0);
1985     }
1986     }
1987 root 1.26
1988     op->destroy ();
1989 root 1.9 }
1990     else if (type & AT_DRAIN && hitter->type == GRIMREAPER && hitter->value++ > 10)
1991 root 1.26 hitter->destroy ();
1992    
1993 root 1.9 return maxdam;
1994     }
1995    
1996     void
1997     poison_player (object *op, object *hitter, int dam)
1998     {
1999 root 1.16 archetype *at = archetype::find ("poisoning");
2000 root 1.9 object *tmp = present_arch_in_ob (at, op);
2001 elmex 1.1
2002 root 1.9 if (tmp == NULL)
2003     {
2004     if ((tmp = arch_to_object (at)) == NULL)
2005     LOG (llevError, "Failed to clone arch poisoning.\n");
2006     else
2007     {
2008     tmp = insert_ob_in_ob (tmp, op);
2009     /* peterm: give poisoning some teeth. It should
2010     * be able to kill things better than it does:
2011     * damage should be dependent something--I choose to
2012     * do this: if it's a monster, the damage from the
2013     * poisoning goes as the level of the monster/2.
2014     * If anything else, goes as damage.
2015     */
2016    
2017     if (QUERY_FLAG (hitter, FLAG_ALIVE))
2018     tmp->stats.dam += hitter->level / 2;
2019     else
2020     tmp->stats.dam = dam;
2021    
2022 root 1.27 tmp->set_owner (hitter); /* so we get credit for poisoning kills */
2023 root 1.9 if (hitter->skill && hitter->skill != tmp->skill)
2024     {
2025     tmp->skill = hitter->skill;
2026     }
2027    
2028     tmp->stats.food += dam; /* more damage, longer poisoning */
2029    
2030     if (op->type == PLAYER)
2031     {
2032     /* player looses stats, maximum is -10 of each */
2033     tmp->stats.Con = MAX (-(dam / 4 + 1), -10);
2034     tmp->stats.Str = MAX (-(dam / 3 + 2), -10);
2035     tmp->stats.Dex = MAX (-(dam / 6 + 1), -10);
2036     tmp->stats.Int = MAX (-dam / 7, -10);
2037     SET_FLAG (tmp, FLAG_APPLIED);
2038 root 1.32 op->update_stats ();
2039 root 1.9 new_draw_info (NDI_UNIQUE, 0, op, "You suddenly feel very ill.");
2040     }
2041 root 1.63
2042 root 1.9 if (hitter->type == PLAYER)
2043     new_draw_info_format (NDI_UNIQUE, 0, hitter, "You poison %s.", &op->name);
2044 root 1.27 else if (hitter->owner != NULL && hitter->owner->type == PLAYER)
2045 root 1.9 new_draw_info_format (NDI_UNIQUE, 0, hitter->owner, "Your %s poisons %s.", &hitter->name, &op->name);
2046 root 1.5 }
2047 root 1.63
2048 root 1.9 tmp->speed_left = 0;
2049     }
2050     else
2051     tmp->stats.food++;
2052     }
2053    
2054     void
2055     slow_player (object *op, object *hitter, int dam)
2056     {
2057 root 1.16 archetype *at = archetype::find ("slowness");
2058 root 1.9 object *tmp;
2059    
2060     if (at == NULL)
2061 root 1.62 LOG (llevError, "Can't find slowness archetype.\n");
2062    
2063 root 1.9 if ((tmp = present_arch_in_ob (at, op)) == NULL)
2064     {
2065     tmp = arch_to_object (at);
2066     tmp = insert_ob_in_ob (tmp, op);
2067     new_draw_info (NDI_UNIQUE, 0, op, "The world suddenly moves very fast!");
2068     }
2069     else
2070     tmp->stats.food++;
2071 root 1.62
2072 root 1.9 SET_FLAG (tmp, FLAG_APPLIED);
2073     tmp->speed_left = 0;
2074 root 1.32 op->update_stats ();
2075 elmex 1.1 }
2076    
2077 root 1.9 void
2078     confuse_player (object *op, object *hitter, int dam)
2079     {
2080     object *tmp;
2081     int maxduration;
2082 elmex 1.1
2083 root 1.9 tmp = present_in_ob_by_name (FORCE, "confusion", op);
2084     if (!tmp)
2085     {
2086     tmp = get_archetype (FORCE_NAME);
2087     tmp = insert_ob_in_ob (tmp, op);
2088     }
2089 root 1.5
2090 root 1.9 /* Duration added per hit and max. duration of confusion both depend
2091     * on the player's resistance
2092     */
2093     tmp->speed = 0.05;
2094     tmp->subtype = FORCE_CONFUSION;
2095     tmp->duration = 8 + MAX (1, 5 * (100 - op->resist[ATNR_CONFUSION]) / 100);
2096     tmp->name = "confusion";
2097     maxduration = MAX (2, 30 * (100 - op->resist[ATNR_CONFUSION]) / 100);
2098 root 1.62
2099 root 1.9 if (tmp->duration > maxduration)
2100     tmp->duration = maxduration;
2101    
2102     if (op->type == PLAYER && !QUERY_FLAG (op, FLAG_CONFUSED))
2103     new_draw_info (NDI_UNIQUE, 0, op, "You suddenly feel very confused!");
2104 root 1.62
2105 root 1.9 SET_FLAG (op, FLAG_CONFUSED);
2106     }
2107 root 1.5
2108 root 1.9 void
2109     blind_player (object *op, object *hitter, int dam)
2110     {
2111     object *tmp, *owner;
2112 root 1.5
2113 root 1.9 /* Save some work if we know it isn't going to affect the player */
2114     if (op->resist[ATNR_BLIND] == 100)
2115     return;
2116 root 1.5
2117 root 1.9 tmp = present_in_ob (BLINDNESS, op);
2118     if (!tmp)
2119     {
2120     tmp = get_archetype ("blindness");
2121     SET_FLAG (tmp, FLAG_BLIND);
2122     SET_FLAG (tmp, FLAG_APPLIED);
2123 elmex 1.1 /* use floats so we don't lose too much precision due to rounding errors.
2124     * speed is a float anyways.
2125     */
2126 root 1.9 tmp->speed = tmp->speed * (100.0 - (float) op->resist[ATNR_BLIND]) / 100;
2127 elmex 1.1
2128 root 1.9 tmp = insert_ob_in_ob (tmp, op);
2129     change_abil (op, tmp); /* Mostly to display any messages */
2130 root 1.32 op->update_stats (); /* This takes care of some other stuff */
2131 elmex 1.1
2132 root 1.9 if (hitter->owner)
2133 root 1.27 owner = hitter->owner;
2134 root 1.9 else
2135     owner = hitter;
2136 elmex 1.1
2137 root 1.9 new_draw_info_format (NDI_UNIQUE, 0, owner, "Your attack blinds %s!", query_name (op));
2138     }
2139     tmp->stats.food += dam;
2140     if (tmp->stats.food > 10)
2141     tmp->stats.food = 10;
2142 elmex 1.1 }
2143    
2144 root 1.9 void
2145     paralyze_player (object *op, object *hitter, int dam)
2146 elmex 1.1 {
2147 root 1.9 float effect, max;
2148    
2149     /* object *tmp; */
2150 elmex 1.1
2151 root 1.9 /* This is strange stuff... someone knows for what this is
2152     * written? Well, i think this can and should be removed
2153     */
2154 elmex 1.1
2155 root 1.9 /*
2156     if((tmp=present(PARAIMAGE,op->map,op->x,op->y))==NULL) {
2157     tmp=clone_arch(PARAIMAGE);
2158     tmp->x=op->x,tmp->y=op->y;
2159     insert_ob_in_map(tmp,op->map,tmp,INS_NO_MERGE | INS_NO_WALK_ON);
2160     }
2161     */
2162 elmex 1.1
2163 root 1.9 /* Do this as a float - otherwise, rounding might very well reduce this to 0 */
2164     effect = (float) dam *3.0 * (100.0 - op->resist[ATNR_PARALYZE]) / 100;
2165 elmex 1.1
2166 root 1.9 if (effect == 0)
2167     return;
2168 elmex 1.1
2169 root 1.9 op->speed_left -= FABS (op->speed) * effect;
2170     /* tmp->stats.food+=(signed short) effect/op->speed; */
2171 elmex 1.1
2172 root 1.9 /* max number of ticks to be affected for. */
2173     max = (100 - op->resist[ATNR_PARALYZE]) / 2;
2174     if (op->speed_left < -(FABS (op->speed) * max))
2175     op->speed_left = (float) -(FABS (op->speed) * max);
2176 elmex 1.1
2177     /* tmp->stats.food = (signed short) (max/FABS(op->speed)); */
2178     }
2179    
2180     /* Attempts to kill 'op'. hitter is the attack object, dam is
2181     * the computed damaged.
2182     */
2183 root 1.9 void
2184     deathstrike_player (object *op, object *hitter, int *dam)
2185 elmex 1.1 {
2186 root 1.9 /* The intention of a death attack is to kill outright things
2187     ** that are a lot weaker than the attacker, have a chance of killing
2188     ** things somewhat weaker than the caster, and no chance of
2189     ** killing something equal or stronger than the attacker.
2190     ** Also, if a deathstrike attack has a slaying, any monster
2191     ** whose name or race matches a comma-delimited list in the slaying
2192     ** field of the deathstriking object */
2193    
2194     int atk_lev, def_lev, kill_lev;
2195    
2196     if (hitter->slaying)
2197     if (!((QUERY_FLAG (op, FLAG_UNDEAD) && strstr (hitter->slaying, undead_name)) || (op->race && strstr (hitter->slaying, op->race))))
2198     return;
2199    
2200     def_lev = op->level;
2201     if (def_lev < 1)
2202     {
2203 root 1.67 LOG (llevError, "BUG: arch %s, name %s with level < 1\n", &op->arch->archname, &op->name);
2204 root 1.9 def_lev = 1;
2205     }
2206 root 1.52
2207 root 1.9 atk_lev = (hitter->chosen_skill ? hitter->chosen_skill->level : hitter->level) / 2;
2208     /* LOG(llevDebug,"Deathstrike - attack level %d, defender level %d\n",
2209     atk_lev, def_lev); */
2210    
2211     if (atk_lev >= def_lev)
2212     {
2213     kill_lev = random_roll (0, atk_lev - 1, hitter, PREFER_HIGH);
2214    
2215     /* Note that the below effectively means the ratio of the atk vs
2216     * defener level is important - if level 52 character has very little
2217     * chance of killing a level 50 monster. This should probably be
2218     * redone.
2219     */
2220     if (kill_lev >= def_lev)
2221     {
2222     *dam = op->stats.hp + 10; /* take all hp. they can still save for 1/2 */
2223     /* I think this doesn't really do much. Because of
2224     * integer rounding, this only makes any difference if the
2225     * attack level is double the defender level.
2226     */
2227     *dam *= kill_lev / def_lev;
2228 root 1.5 }
2229 root 1.9 }
2230     else
2231 root 1.52 *dam = 0; /* no harm done */
2232 elmex 1.1 }
2233    
2234     /* thrown_item_effect() - handles any special effects of thrown
2235     * items (like attacking living creatures--a potion thrown at a
2236     * monster).
2237     */
2238 root 1.9 static void
2239     thrown_item_effect (object *hitter, object *victim)
2240 elmex 1.1 {
2241 root 1.9 if (!QUERY_FLAG (hitter, FLAG_ALIVE))
2242     {
2243     /* May not need a switch for just 2 types, but this makes it
2244     * easier for expansion.
2245     */
2246     switch (hitter->type)
2247     {
2248 root 1.5 case POTION:
2249 root 1.9 /* should player get a save throw instead of checking magic protection? */
2250     if (QUERY_FLAG (victim, FLAG_ALIVE) && !QUERY_FLAG (victim, FLAG_UNDEAD) && (victim->resist[ATNR_MAGIC] < 60))
2251     (void) apply_potion (victim, hitter);
2252     break;
2253    
2254     case POISON: /* poison drinks */
2255     /* As with potions, should monster get a save? */
2256     if (QUERY_FLAG (victim, FLAG_ALIVE) && !QUERY_FLAG (victim, FLAG_UNDEAD) && (victim->resist[ATNR_POISON] < 60))
2257     apply_poison (victim, hitter);
2258     break;
2259    
2260     /* Removed case statements that did nothing.
2261     * food may be poisonous, but monster must be willing to eat it,
2262     * so we don't handle it here.
2263     * Containers should perhaps break open, but that code was disabled.
2264     */
2265 root 1.5 }
2266 elmex 1.1 }
2267     }
2268    
2269     /* adj_attackroll() - adjustments to attacks by various conditions */
2270 root 1.9 int
2271     adj_attackroll (object *hitter, object *target)
2272     {
2273 elmex 1.1 object *attacker = hitter;
2274 root 1.9 int adjust = 0;
2275 elmex 1.1
2276     /* safety */
2277 root 1.9 if (!target || !hitter || !hitter->map || !target->map || !on_same_map (hitter, target))
2278     {
2279     LOG (llevError, "BUG: adj_attackroll(): hitter and target not on same " "map\n");
2280     return 0;
2281     }
2282 elmex 1.1
2283     /* aimed missiles use the owning object's sight */
2284 root 1.9 if (is_aimed_missile (hitter))
2285     {
2286 root 1.27 if ((attacker = hitter->owner) == NULL)
2287 root 1.9 attacker = hitter;
2288     /* A player who saves but hasn't quit still could have objects
2289     * owned by him - need to handle that case to avoid crashes.
2290     */
2291     if (QUERY_FLAG (attacker, FLAG_REMOVED))
2292     attacker = hitter;
2293     }
2294     else if (!QUERY_FLAG (hitter, FLAG_ALIVE))
2295 elmex 1.1 return 0;
2296    
2297 root 1.9 /* determine the condtions under which we make an attack.
2298     * Add more cases, as the need occurs. */
2299 elmex 1.1
2300 root 1.9 if (!can_see_enemy (attacker, target))
2301     {
2302     /* target is unseen */
2303     if (target->invisible || QUERY_FLAG (attacker, FLAG_BLIND))
2304     adjust -= 10;
2305     /* dark map penalty for the hitter (lacks infravision if we got here). */
2306     else if (target->map && target->map->darkness > 0 && !stand_in_light (target))
2307     adjust -= target->map->darkness;
2308     }
2309 elmex 1.1
2310 root 1.9 if (QUERY_FLAG (attacker, FLAG_SCARED))
2311 elmex 1.1 adjust -= 3;
2312    
2313 root 1.9 if (QUERY_FLAG (target, FLAG_UNAGGRESSIVE))
2314 elmex 1.1 adjust += 1;
2315    
2316 root 1.9 if (QUERY_FLAG (target, FLAG_SCARED))
2317 elmex 1.1 adjust += 1;
2318    
2319 root 1.9 if (QUERY_FLAG (attacker, FLAG_CONFUSED))
2320 elmex 1.1 adjust -= 3;
2321    
2322     /* if we attack at a different 'altitude' its harder */
2323 root 1.9 if ((attacker->move_type & target->move_type) == 0)
2324 elmex 1.1 adjust -= 2;
2325    
2326     #if 0
2327     /* slower attacks are less likely to succeed. We should use a
2328     * comparison between attacker/target speeds BUT, players have
2329     * a generally faster speed, so this will wind up being a HUGE
2330     * disadantage for the monsters! Too bad, because missiles which
2331     * fly fast should have a better chance of hitting a slower target.
2332     */
2333 root 1.9 if (hitter->speed < target->speed)
2334     adjust += ((float) hitter->speed - target->speed);
2335 elmex 1.1 #endif
2336    
2337     #if 0
2338 root 1.9 LOG (llevDebug, "adj_attackroll() returns %d (%d)\n", adjust, attacker->count);
2339 elmex 1.1 #endif
2340    
2341     return adjust;
2342 root 1.9 }
2343 elmex 1.1
2344     /* determine if the object is an 'aimed' missile */
2345 root 1.9 int
2346     is_aimed_missile (object *op)
2347     {
2348 elmex 1.1
2349 root 1.9 /* I broke what used to be one big if into a few nested
2350     * ones so that figuring out the logic is at least possible.
2351     */
2352     if (op && (op->move_type & MOVE_FLYING))
2353 root 1.62 if (op->type == ARROW || op->type == THROWN_OBJ)
2354     return 1;
2355     else if (op->type == SPELL_EFFECT && (op->subtype == SP_BULLET || op->subtype == SP_EXPLOSION))
2356     return 1;
2357 root 1.53
2358 root 1.9 return 0;
2359     }