Crossfire Server, Branches 1.12  R18729
attack.c
Go to the documentation of this file.
1 /*
2  * static char *rcsid_attack_c =
3  * "$Id: attack.c 11578 2009-02-23 22:02:27Z lalo $";
4  */
5 /*
6  CrossFire, A Multiplayer game for X-windows
7 
8  Copyright (C) 2002-2006 Mark Wedel & Crossfire Development Team
9  Copyright (C) 1992 Frank Tore Johansen
10 
11  This program is free software; you can redistribute it and/or modify
12  it under the terms of the GNU General Public License as published by
13  the Free Software Foundation; either version 2 of the License, or
14  (at your option) any later version.
15 
16  This program is distributed in the hope that it will be useful,
17  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  GNU General Public License for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with this program; if not, write to the Free Software
23  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 
25  The authors can be reached via e-mail to crossfire-devel@real-time.com
26 */
27 
35 #include <assert.h>
36 #include <global.h>
37 #include <living.h>
38 #include <material.h>
39 #include <skills.h>
40 
41 #ifndef __CEXTRACT__
42 #include <sproto.h>
43 #endif
44 
45 #include <sounds.h>
46 
47 /*#define ATTACK_DEBUG*/
48 
49 static void slow_living(object *op, object *hitter, int dam);
50 static void deathstrike_living(object *op, object *hitter, int *dam);
51 static int adj_attackroll(object *hitter, object *target);
52 static int is_aimed_missile(object *op);
53 static int did_make_save_item(object *op, int type, object *originator);
54 static void poison_living(object *op, object *hitter, int dam);
55 
63 static void cancellation(object *op) {
64  object *tmp;
65 
66  if (op->invisible)
67  return;
68 
69  if (QUERY_FLAG(op, FLAG_ALIVE) || op->type == CONTAINER || op->type == THROWN_OBJ) {
70  /* Recur through the inventory */
71  for (tmp = op->inv; tmp != NULL; tmp = tmp->below)
72  if (!did_make_save_item(tmp, AT_CANCELLATION, op))
73  cancellation(tmp);
74  } else if (FABS(op->magic) <= (rndm(0, 5))) {
75  /* Nullify this object. This code could probably be more complete */
76  /* in what abilities it should cancel */
77  op->magic = 0;
82  if (op->env && op->env->type == PLAYER) {
83  esrv_update_item(UPD_FLAGS, op->env, op);
84  }
85  }
86 }
87 
103 static int did_make_save_item(object *op, int type, object *originator) {
104  int i, roll, saves = 0, attacks = 0, number;
105  materialtype_t *mt;
106 
107  if (op->materialname == NULL) {
108  for (mt = materialt; mt != NULL && mt->next != NULL; mt = mt->next) {
109  if (op->material&mt->material)
110  break;
111  }
112  } else
113  mt = name_to_material(op->materialname);
114  if (mt == NULL)
115  return TRUE;
116  roll = rndm(1, 20);
117 
118  /* the attacktypes have no meaning for object saves
119  * If the type is only magic, don't adjust type - basically, if
120  * pure magic is hitting an object, it should save. However, if it
121  * is magic teamed with something else, then strip out the
122  * magic type, and instead let the fire, cold, or whatever component
123  * destroy the item. Otherwise, you get the case of poisoncloud
124  * destroying objects because it has magic attacktype.
125  */
126  if (type != AT_MAGIC)
130  AT_MAGIC);
131 
132  if (type == 0)
133  return TRUE;
134  if (roll == 20)
135  return TRUE;
136  if (roll == 1)
137  return FALSE;
138 
139  for (number = 0; number < NROFATTACKS; number++) {
140  i = 1<<number;
141  if (!(i&type))
142  continue;
143  attacks++;
144  if (op->resist[number] == 100)
145  saves++;
146  else if (roll >= mt->save[number]-op->magic-op->resist[number]/100)
147  saves++;
148  else if ((20-mt->save[number])/3 > originator->stats.dam)
149  saves++;
150  }
151 
152  if (saves == attacks || attacks == 0)
153  return TRUE;
154  if ((saves == 0) || (rndm(1, attacks) > saves))
155  return FALSE;
156  return TRUE;
157 }
158 
171 void save_throw_object(object *op, uint32 type, object *originator) {
172  if (!did_make_save_item(op, type, originator)) {
173  object *env = op->env;
174  object *inv;
175  int x = op->x, y = op->y;
176  mapstruct *m = op->map;
177 
178  op = stop_item(op);
179  if (op == NULL)
180  return;
181 
182  /* Set off runes in the inventory of the object being destroyed. */
183  inv = op->inv;
184  while (inv != NULL) {
185  if (inv->type == RUNE)
186  spring_trap(inv, originator);
187  inv = inv->below;
188  }
189 
190  /* Hacked the following so that type LIGHTER will work.
191  * Also, objects which are potenital "lights" that are hit by
192  * flame/elect attacks will be set to glow. "lights" are any
193  * object with +/- glow_radius and an "other_arch" to change to.
194  * (and please note that we cant fail our save and reach this
195  * function if the object doesnt contain a material that can burn.
196  * So forget lighting magical swords on fire with this!) -b.t.
197  */
198  if (type&(AT_FIRE|AT_ELECTRICITY)
199  && op->other_arch
200  && QUERY_FLAG(op, FLAG_IS_LIGHTABLE)) {
201  const char *arch = op->other_arch->name;
202 
203  op = decrease_ob_nr(op, 1);
204  if (op)
205  fix_stopped_item(op, m, originator);
206  if ((op = create_archetype(arch)) != NULL) {
207  if (env) {
208  op->x = env->x,
209  op->y = env->y;
210  insert_ob_in_ob(op, env);
211  } else {
212  op->x = x,
213  op->y = y;
214  insert_ob_in_map(op, m, originator, 0);
215  }
216  }
217  return;
218  }
219  if (type&AT_CANCELLATION) { /* Cancellation. */
220  cancellation(op);
221  fix_stopped_item(op, m, originator);
222  return;
223  }
224  if (op->nrof > 1) {
225  op = decrease_ob_nr(op, rndm(0, op->nrof-1));
226  if (op)
227  fix_stopped_item(op, m, originator);
228  } else {
229  if (!QUERY_FLAG(op, FLAG_REMOVED))
230  remove_ob(op);
231  free_object(op);
232  }
233  if (type&(AT_FIRE|AT_ELECTRICITY)) {
234  if (env) {
235  op = create_archetype("burnout");
236  op->x = env->x,
237  op->y = env->y;
238  insert_ob_in_ob(op, env);
239  } else {
240  replace_insert_ob_in_map("burnout", originator);
241  }
242  }
243  return;
244  }
245  /* The value of 50 is arbitrary. */
246  if (type&AT_COLD
247  && (op->resist[ATNR_COLD] < 50)
248  && !QUERY_FLAG(op, FLAG_NO_PICK)
249  && (RANDOM()&2)) {
250  object *tmp;
251  archetype *at = find_archetype("icecube");
252 
253  if (at == NULL)
254  return;
255  op = stop_item(op);
256  if (op == NULL)
257  return;
258  if ((tmp = present_arch(at, op->map, op->x, op->y)) == NULL) {
259  tmp = arch_to_object(at);
260  tmp->x = op->x,
261  tmp->y = op->y;
262  /* This was in the old (pre new movement code) -
263  * icecubes have slow_move set to 1 - don't want
264  * that for ones we create.
265  */
266  tmp->move_slow_penalty = 0;
267  tmp->move_slow = 0;
268  insert_ob_in_map(tmp, op->map, originator, 0);
269  }
270  if (!QUERY_FLAG(op, FLAG_REMOVED))
271  remove_ob(op);
272  (void)insert_ob_in_ob(op, tmp);
273  return;
274  }
275 }
276 
292 int hit_map(object *op, int dir, uint32 type, int full_hit) {
293  object *tmp, *next;
294  mapstruct *map;
295  sint16 x, y;
296  int retflag = 0; /* added this flag.. will return 1 if it hits a monster */
297 
298  tag_t op_tag, next_tag = 0;
299 
300  if (QUERY_FLAG(op, FLAG_FREED)) {
301  LOG(llevError, "BUG: hit_map(): free object\n");
302  return 0;
303  }
304 
305  if (QUERY_FLAG(op, FLAG_REMOVED) || op->env != NULL) {
306  LOG(llevError, "BUG: hit_map(): hitter (arch %s, name %s) not on a map\n", op->arch->name, op->name);
307  return 0;
308  }
309 
310  if (!op->map) {
311  LOG(llevError, "BUG: hit_map(): %s has no map\n", op->name);
312  return 0;
313  }
314 
315  if (op->head)
316  op = op->head;
317 
318  op_tag = op->count;
319 
320  map = op->map;
321  x = op->x+freearr_x[dir];
322  y = op->y+freearr_y[dir];
323  if (get_map_flags(map, &map, x, y, &x, &y)&P_OUT_OF_MAP)
324  return 0;
325 
326  /* peterm: a few special cases for special attacktypes --counterspell
327  * must be out here because it strikes things which are not alive
328  */
329 
330  if (type&AT_COUNTERSPELL) {
331  counterspell(op, dir); /* see spell_effect.c */
332 
333  /* If the only attacktype is counterspell or magic, don't need
334  * to do any further processing.
335  */
336  if (!(type&~(AT_COUNTERSPELL|AT_MAGIC))) {
337  return 0;
338  }
339  type &= ~AT_COUNTERSPELL;
340  }
341 
342  if (type&AT_CHAOS) {
343  shuffle_attack(op, 1); /*1 flag tells it to change the face */
345  type &= ~AT_CHAOS;
346  }
347 
348  next = GET_MAP_OB(map, x, y);
349  if (next)
350  next_tag = next->count;
351 
352  while (next) {
353  if (was_destroyed(next, next_tag)) {
354  /* There may still be objects that were above 'next', but there is no
355  * simple way to find out short of copying all object references and
356  * tags into a temporary array before we start processing the first
357  * object. That's why we just abort.
358  *
359  * This happens whenever attack spells (like fire) hit a pile
360  * of objects. This is not a bug - nor an error. The errormessage
361  * below was spamming the logs for absolutely no reason.
362  */
363  /* LOG (llevDebug, "hit_map(): next object destroyed\n"); */
364  break;
365  }
366  tmp = next;
367  next = tmp->above;
368  if (next)
369  next_tag = next->count;
370 
371  if (QUERY_FLAG(tmp, FLAG_FREED)) {
372  LOG(llevError, "BUG: hit_map(): found freed object\n");
373  break;
374  }
375 
376  /* Something could have happened to 'tmp' while 'tmp->below' was processed.
377  * For example, 'tmp' was put in an icecube.
378  * This is one of the few cases where on_same_map should not be used.
379  */
380  if (tmp->map != map || tmp->x != x || tmp->y != y)
381  continue;
382 
383  if (tmp->head)
384  tmp = tmp->head;
385 
386  /* Need to hit everyone in the transport with this spell */
387  if (tmp->type == TRANSPORT) {
388  object *pl;
389 
390  for (pl = tmp->inv; pl; pl = pl->below) {
391  if (pl->type == PLAYER)
392  hit_player(pl, op->stats.dam, op, type, full_hit);
393  }
394  }
395 
396  if (QUERY_FLAG(tmp, FLAG_ALIVE)) {
397  hit_player(tmp, op->stats.dam, op, type, full_hit);
398  retflag |= 1;
399  if (was_destroyed(op, op_tag))
400  break;
401  }
402  /* Here we are potentially destroying an object. If the object has
403  * NO_PASS set, it is also immune - you can't destroy walls. Note
404  * that weak walls have is_alive set, which prevent objects from
405  * passing over/through them. We don't care what type of movement
406  * the wall blocks - if it blocks any type of movement, can't be
407  * destroyed right now.
408  */
409  else if ((tmp->material || tmp->materialname) && op->stats.dam > 0 && !tmp->move_block) {
410  save_throw_object(tmp, type, op);
411  if (was_destroyed(op, op_tag))
412  break;
413  }
414  }
415  return 0;
416 }
417 
433 static void attack_message(int dam, int type, object *op, object *hitter) {
434  char buf[MAX_BUF], buf1[MAX_BUF], buf2[MAX_BUF];
435  int i, found = 0;
436  mapstruct *map;
437  object *next, *tmp;
438 
439  /* put in a few special messages for some of the common attacktypes
440  * a player might have. For example, fire, electric, cold, etc
441  * [garbled 20010919]
442  */
443 
444  if (dam == 9998 && op->type == DOOR) {
445  sprintf(buf1, "unlock %s", op->name);
446  sprintf(buf2, " unlocks");
447  found++;
448  }
449  if (dam < 0) {
450  sprintf(buf1, "hit %s", op->name);
451  sprintf(buf2, " hits");
452  found++;
453  } else if (dam == 0) {
454  sprintf(buf1, "missed %s", op->name);
455  sprintf(buf2, " misses");
456  found++;
457  } else if ((hitter->type == DISEASE
458  || hitter->type == SYMPTOM
459  || hitter->type == POISONING
460  || (type&AT_POISON && IS_LIVE(op))) && !found) {
461  for (i = 0; i < MAXATTACKMESS && attack_mess[ATM_SUFFER][i].level != -1; i++)
462  if (dam < attack_mess[ATM_SUFFER][i].level
463  || attack_mess[ATM_SUFFER][i+1].level == -1) {
464  sprintf(buf1, "%s %s%s", attack_mess[ATM_SUFFER][i].buf1, op->name, attack_mess[ATM_SUFFER][i].buf2);
465  sprintf(buf2, "%s", attack_mess[ATM_SUFFER][i].buf3);
466  found++;
467  break;
468  }
469  } else if (op->type == DOOR && !found) {
470  for (i = 0; i < MAXATTACKMESS && attack_mess[ATM_DOOR][i].level != -1; i++)
471  if (dam < attack_mess[ATM_DOOR][i].level
472  || attack_mess[ATM_DOOR][i+1].level == -1) {
473  sprintf(buf1, "%s %s%s", attack_mess[ATM_DOOR][i].buf1, op->name, attack_mess[ATM_DOOR][i].buf2);
474  sprintf(buf2, "%s", attack_mess[ATM_DOOR][i].buf3);
475  found++;
476  break;
477  }
478  } else if (hitter->type == PLAYER && IS_LIVE(op)) {
479  if (USING_SKILL(hitter, SK_KARATE)) {
480  for (i = 0; i < MAXATTACKMESS && attack_mess[ATM_KARATE][i].level != -1; i++)
481  if (dam < attack_mess[ATM_KARATE][i].level
482  || attack_mess[ATM_KARATE][i+1].level == -1) {
483  sprintf(buf1, "%s %s%s", attack_mess[ATM_KARATE][i].buf1, op->name, attack_mess[ATM_KARATE][i].buf2);
484  sprintf(buf2, "%s", attack_mess[ATM_KARATE][i].buf3);
485  found++;
486  break;
487  }
488  } else if (USING_SKILL(hitter, SK_CLAWING)) {
489  for (i = 0; i < MAXATTACKMESS && attack_mess[ATM_CLAW][i].level != -1; i++)
490  if (dam < attack_mess[ATM_CLAW][i].level
491  || attack_mess[ATM_CLAW][i+1].level == -1) {
492  sprintf(buf1, "%s %s%s", attack_mess[ATM_CLAW][i].buf1, op->name, attack_mess[ATM_CLAW][i].buf2);
493  sprintf(buf2, "%s", attack_mess[ATM_CLAW][i].buf3);
494  found++;
495  break;
496  }
497  } else if (USING_SKILL(hitter, SK_PUNCHING)) {
498  for (i = 0; i < MAXATTACKMESS && attack_mess[ATM_PUNCH][i].level != -1; i++)
499  if (dam < attack_mess[ATM_PUNCH][i].level
500  || attack_mess[ATM_PUNCH][i+1].level == -1) {
501  sprintf(buf1, "%s %s%s", attack_mess[ATM_PUNCH][i].buf1, op->name, attack_mess[ATM_PUNCH][i].buf2);
502  sprintf(buf2, "%s", attack_mess[ATM_PUNCH][i].buf3);
503  found++;
504  break;
505  }
506  } else if (USING_SKILL(hitter, SK_WRAITH_FEED)) {
507  for (i = 0; i < MAXATTACKMESS && attack_mess[ATM_WRAITH_FEED][i].level != -1; i++)
508  if (dam < attack_mess[ATM_WRAITH_FEED][i].level) {
509  sprintf(buf1, "%s %s%s", attack_mess[ATM_WRAITH_FEED][i].buf1, op->name, attack_mess[ATM_WRAITH_FEED][i].buf2);
510  sprintf(buf2, "%s", attack_mess[ATM_WRAITH_FEED][i].buf3);
511  found++;
512  break;
513  }
514  }
515  }
516  if (found) {
517  /* done */
518  } else if (IS_ARROW(hitter) && (type == AT_PHYSICAL || type == AT_MAGIC)) {
519  sprintf(buf1, "hit"); /* just in case */
520  for (i = 0; i < MAXATTACKMESS; i++)
521  if (dam < attack_mess[ATM_ARROW][i].level
522  || attack_mess[ATM_ARROW][i+1].level == -1) {
523  sprintf(buf2, "%s", attack_mess[ATM_ARROW][i].buf3);
524  found++;
525  break;
526  }
527  } else if (type&AT_DRAIN && IS_LIVE(op)) {
528  /* drain is first, because some items have multiple attypes */
529  for (i = 0; i < MAXATTACKMESS && attack_mess[ATM_DRAIN][i].level != -1; i++)
530  if (dam < attack_mess[ATM_DRAIN][i].level
531  || attack_mess[ATM_DRAIN][i+1].level == -1) {
532  sprintf(buf1, "%s %s%s", attack_mess[ATM_DRAIN][i].buf1, op->name, attack_mess[ATM_DRAIN][i].buf2);
533  sprintf(buf2, "%s", attack_mess[ATM_DRAIN][i].buf3);
534  found++;
535  break;
536  }
537  } else if (type&AT_ELECTRICITY && IS_LIVE(op)) {
538  for (i = 0; i < MAXATTACKMESS && attack_mess[ATM_ELEC][i].level != -1; i++)
539  if (dam < attack_mess[ATM_ELEC][i].level
540  || attack_mess[ATM_ELEC][i+1].level == -1) {
541  sprintf(buf1, "%s %s%s", attack_mess[ATM_ELEC][i].buf1, op->name, attack_mess[ATM_ELEC][i].buf2);
542  sprintf(buf2, "%s", attack_mess[ATM_ELEC][i].buf3);
543  found++;
544  break;
545  }
546  } else if (type&AT_COLD && IS_LIVE(op)) {
547  for (i = 0; i < MAXATTACKMESS && attack_mess[ATM_COLD][i].level != -1; i++)
548  if (dam < attack_mess[ATM_COLD][i].level
549  || attack_mess[ATM_COLD][i+1].level == -1) {
550  sprintf(buf1, "%s %s%s", attack_mess[ATM_COLD][i].buf1, op->name, attack_mess[ATM_COLD][i].buf2);
551  sprintf(buf2, "%s", attack_mess[ATM_COLD][i].buf3);
552  found++;
553  break;
554  }
555  } else if (type&AT_FIRE) {
556  for (i = 0; i < MAXATTACKMESS && attack_mess[ATM_FIRE][i].level != -1; i++)
557  if (dam < attack_mess[ATM_FIRE][i].level
558  || attack_mess[ATM_FIRE][i+1].level == -1) {
559  sprintf(buf1, "%s %s%s", attack_mess[ATM_FIRE][i].buf1, op->name, attack_mess[ATM_FIRE][i].buf2);
560  sprintf(buf2, "%s", attack_mess[ATM_FIRE][i].buf3);
561  found++;
562  break;
563  }
564  } else if (hitter->current_weapon != NULL) {
565  int mtype;
566 
567  switch (hitter->current_weapon->weapontype) {
568  case WEAP_HIT: mtype = ATM_BASIC; break;
569  case WEAP_SLASH: mtype = ATM_SLASH; break;
570  case WEAP_PIERCE: mtype = ATM_PIERCE; break;
571  case WEAP_CLEAVE: mtype = ATM_CLEAVE; break;
572  case WEAP_SLICE: mtype = ATM_SLICE; break;
573  case WEAP_STAB: mtype = ATM_STAB; break;
574  case WEAP_WHIP: mtype = ATM_WHIP; break;
575  case WEAP_CRUSH: mtype = ATM_CRUSH; break;
576  case WEAP_BLUD: mtype = ATM_BLUD; break;
577  default: mtype = ATM_BASIC; break;
578  }
579  for (i = 0; i < MAXATTACKMESS && attack_mess[mtype][i].level != -1; i++)
580  if (dam < attack_mess[mtype][i].level
581  || attack_mess[mtype][i+1].level == -1) {
582  sprintf(buf1, "%s %s%s", attack_mess[mtype][i].buf1, op->name, attack_mess[mtype][i].buf2);
583  sprintf(buf2, "%s", attack_mess[mtype][i].buf3);
584  found++;
585  break;
586  }
587  } else {
588  for (i = 0; i < MAXATTACKMESS && attack_mess[ATM_BASIC][i].level != -1; i++)
589  if (dam < attack_mess[ATM_BASIC][i].level
590  || attack_mess[ATM_BASIC][i+1].level == -1) {
591  sprintf(buf1, "%s %s%s", attack_mess[ATM_BASIC][i].buf1, op->name, attack_mess[ATM_BASIC][i].buf2);
592  sprintf(buf2, "%s", attack_mess[ATM_BASIC][i].buf3);
593  found++;
594  break;
595  }
596  }
597 
598  if (!found) {
599  sprintf(buf1, "hit");
600  sprintf(buf2, "hits");
601  }
602 
603  /* bail out if a monster is casting spells */
604  if (!(hitter->type == PLAYER || (get_owner(hitter) != NULL && hitter->owner->type == PLAYER)))
605  return;
606 
607  /* scale down magic considerably. */
608  if (type&AT_MAGIC && rndm(0, 5))
609  return;
610 
611  /* Did a player hurt another player? Inform both! */
612  /* only show half the player->player combat messages */
613  if (op->type == PLAYER
614  && rndm(0, 1)
615  && (get_owner(hitter) == NULL ? hitter->type : hitter->owner->type) == PLAYER) {
616  if (get_owner(hitter) != NULL)
617  sprintf(buf, "%s's %s %s you.", hitter->owner->name, hitter->name, buf2);
618  else {
619  sprintf(buf, "%s%s you.", hitter->name, buf2);
620  if (dam != 0) {
621  if (hitter->chosen_skill)
623  else if (dam < 10)
624  play_sound_player_only(op->contr, SOUND_TYPE_HIT_BY, op, 0, "low");
625  else if (dam < 20)
626  play_sound_player_only(op->contr, SOUND_TYPE_HIT_BY, op, 0, "medium");
627  else
628  play_sound_player_only(op->contr, SOUND_TYPE_HIT_BY, op, 0, "high");
629  }
630  }
632  } /* end of player hitting player */
633 
634  /* scale down these messages too */
635  if(hitter->type == PLAYER && rndm(0, 2) == 0) {
636  sprintf(buf, "You %s.", buf1);
637  if (dam != 0) {
638  if (hitter->chosen_skill)
639  play_sound_player_only(hitter->contr, SOUND_TYPE_HIT, hitter, 0, hitter->chosen_skill->name);
640  else if (dam < 10)
641  play_sound_player_only(hitter->contr, SOUND_TYPE_HIT, hitter, 0, "low");
642  else if (dam < 20)
643  play_sound_player_only(hitter->contr, SOUND_TYPE_HIT, hitter, 0, "medium");
644  else
645  play_sound_player_only(hitter->contr, SOUND_TYPE_HIT, hitter, 0, "high");
646  }
648  buf, NULL);
649  } else if (get_owner(hitter) != NULL && hitter->owner->type == PLAYER) {
650  /* look for stacked spells and start reducing the message chances */
651  if (hitter->type == SPELL_EFFECT
652  && (hitter->subtype == SP_EXPLOSION || hitter->subtype == SP_BULLET || hitter->subtype == SP_CONE)) {
653  i = 4;
654  map = hitter->map;
655  if (out_of_map(map, hitter->x, hitter->y))
656  return;
657  next = GET_MAP_OB(map, hitter->x, hitter->y);
658  if (next)
659  while (next) {
660  if (next->type == SPELL_EFFECT
661  && (next->subtype == SP_EXPLOSION || next->subtype == SP_BULLET || next->subtype == SP_CONE))
662  i *= 3;
663  tmp = next;
664  next = tmp->above;
665  }
666  if (i < 0)
667  return;
668  if (rndm(0, i) != 0)
669  return;
670  } else if (rndm(0, 5) != 0)
671  return;
672  play_sound_map(SOUND_TYPE_HIT, hitter->owner, 0, "hit");
674  "Your %s%s %s.",
675  "Your %s%s %s.",
676  hitter->name, buf2, op->name);
677  }
678 }
679 
691 static int get_attack_mode(object **target, object **hitter,
692  int *simple_attack) {
693  if (QUERY_FLAG(*target, FLAG_FREED) || QUERY_FLAG(*hitter, FLAG_FREED)) {
694  LOG(llevError, "BUG: get_attack_mode(): freed object\n");
695  return 1;
696  }
697  if ((*target)->head)
698  *target = (*target)->head;
699  if ((*hitter)->head)
700  *hitter = (*hitter)->head;
701  if ((*hitter)->env != NULL || (*target)->env != NULL) {
702  *simple_attack = 1;
703  return 0;
704  }
705  if (QUERY_FLAG(*target, FLAG_REMOVED)
706  || QUERY_FLAG(*hitter, FLAG_REMOVED)
707  || (*hitter)->map == NULL
708  || !on_same_map((*hitter), (*target))) {
709  LOG(llevError, "BUG: hitter (arch %s, name %s) with no relation to target\n", (*hitter)->arch->name, (*hitter)->name);
710  return 1;
711  }
712  *simple_attack = 0;
713  return 0;
714 }
715 
729 static int abort_attack(object *target, object *hitter, int simple_attack) {
730  int new_mode;
731 
732  if (hitter->env == target || target->env == hitter)
733  new_mode = 1;
734  else if (QUERY_FLAG(hitter, FLAG_REMOVED)
735  || QUERY_FLAG(target, FLAG_REMOVED)
736  || hitter->map == NULL || !on_same_map(hitter, target))
737  return 1;
738  else
739  new_mode = 0;
740  return new_mode != simple_attack;
741 }
742 
743 static void thrown_item_effect(object *, object *);
744 
760 static int attack_ob_simple(object *op, object *hitter, int base_dam,
761  int base_wc) {
762  int simple_attack, roll, dam = 0;
763  uint32 type;
764  const char *op_name = NULL;
765  tag_t op_tag, hitter_tag;
766 
767  if (get_attack_mode(&op, &hitter, &simple_attack))
768  goto error;
769 
770  /* Lauwenmark: Handle for plugin attack event */
771  if (execute_event(op, EVENT_ATTACK, hitter, hitter->current_weapon ? hitter->current_weapon : hitter, NULL, SCRIPT_FIX_ALL) != 0)
772  return 0;
773 
774  /* Lauwenmark: This is used to handle script_weapons with weapons.
775  * Only used for players.
776  */
777  if (hitter->type == PLAYER) {
778  if (hitter->current_weapon != NULL) {
779  /* Lauwenmark: Handle for plugin attack event */
781  hitter, op, NULL, SCRIPT_FIX_ALL) != 0)
782  return 0;
783  if (hitter->current_weapon->anim_suffix)
784  apply_anim_suffix(hitter, hitter->current_weapon->anim_suffix);
785  }
786  }
787  op_tag = op->count;
788  hitter_tag = hitter->count;
789  /*
790  * A little check to make it more difficult to dance forward and back
791  * to avoid ever being hit by monsters.
792  */
793  if (!simple_attack && QUERY_FLAG(op, FLAG_MONSTER)
794  && op->speed_left > -(FABS(op->speed))*0.3) {
795  /* Decrease speed BEFORE calling process_object. Otherwise, an
796  * infinite loop occurs, with process_object calling move_monster,
797  * which then gets here again. By decreasing the speed before
798  * we call process_object, the 'if' statement above will fail.
799  */
800  op->speed_left--;
801  process_object(op);
802  if (was_destroyed(op, op_tag)
803  || was_destroyed(hitter, hitter_tag)
804  || abort_attack(op, hitter, simple_attack))
805  goto error;
806  }
807 
808  add_refcount(op_name = op->name);
809 
810  roll = random_roll(1, 20, hitter, PREFER_HIGH);
811 
812  /* Adjust roll for various situations. */
813  if (!simple_attack)
814  roll += adj_attackroll(hitter, op);
815 
816  /* See if we hit the creature */
817  if (roll == 20 || op->stats.ac >= base_wc-roll) {
818  int hitdam = base_dam;
819  if (settings.casting_time == TRUE) {
820  if ((hitter->type == PLAYER)&&(hitter->casting_time > -1)) {
821  hitter->casting_time = -1;
823  "You attacked and lost your spell!", NULL);
824  }
825  if ((op->casting_time > -1)&&(hitdam > 0)) {
826  op->casting_time = -1;
827  if (op->type == PLAYER) {
829  "You were hit and lost your spell!", NULL);
832  "%s was hit by %s and lost a spell.",
833  "%s was hit by %s and lost a spell.",
834  op_name, hitter->name);
835  }
836  }
837  }
838  if (!simple_attack) {
839  /* If you hit something, the victim should *always *wake up.
840  * Before, invisible hitters could avoid doing this.
841  * -b.t. */
842  if (QUERY_FLAG(op, FLAG_SLEEP))
843  CLEAR_FLAG(op, FLAG_SLEEP);
844 
845  /* If the victim can't see the attacker, it may alert others
846  * for help. */
847  if (op->type != PLAYER && !can_see_enemy(op, hitter)
848  && !get_owner(op) && rndm(0, op->stats.Int))
849  npc_call_help(op);
850 
851  /* if you were hidden and hit by a creature, you are discovered*/
852  if (op->hide && QUERY_FLAG(hitter, FLAG_ALIVE)) {
853  make_visible(op);
854  if (op->type == PLAYER)
856  "You were hit by a wild attack. You are no longer hidden!",
857  NULL);
858  }
859 
860  /* thrown items (hitter) will have various effects
861  * when they hit the victim. For things like thrown daggers,
862  * this sets 'hitter' to the actual dagger, and not the
863  * wrapper object.
864  */
865  thrown_item_effect(hitter, op);
866  if (was_destroyed(hitter, hitter_tag)
867  || was_destroyed(op, op_tag)
868  || abort_attack(op, hitter, simple_attack))
869  goto leave;
870  }
871 
872  /* Need to do at least 1 damage, otherwise there is no point
873  * to go further and it will cause FPE's below.
874  */
875  if (hitdam <= 0)
876  hitdam = 1;
877 
878  type = hitter->attacktype;
879  if (!type)
880  type = AT_PHYSICAL;
881  /* Handle monsters that hit back */
882  if (!simple_attack && QUERY_FLAG(op, FLAG_HITBACK)
883  && QUERY_FLAG(hitter, FLAG_ALIVE)) {
884  if (op->attacktype&AT_ACID && hitter->type == PLAYER)
886  "You are splashed by acid!\n", NULL);
887  hit_player(hitter, random_roll(0, (op->stats.dam), hitter, PREFER_LOW), op, op->attacktype, 1);
888  if (was_destroyed(op, op_tag)
889  || was_destroyed(hitter, hitter_tag)
890  || abort_attack(op, hitter, simple_attack))
891  goto leave;
892  }
893 
894  /* In the new attack code, it should handle multiple attack
895  * types in its area, so remove it from here.
896  */
897  dam = hit_player(op, random_roll(1, hitdam, hitter, PREFER_HIGH), hitter, type, 1);
898  if (was_destroyed(op, op_tag)
899  || was_destroyed(hitter, hitter_tag)
900  || abort_attack(op, hitter, simple_attack))
901  goto leave;
902  } /* end of if hitter hit op */
903  /* if we missed, dam=0 */
904 
905  /*attack_message(dam, type, op, hitter);*/
906 
907  goto leave;
908 
909 error:
910  dam = 1;
911  goto leave;
912 
913 leave:
914  if (op_name)
915  free_string(op_name);
916 
917  return dam;
918 }
919 
929 int attack_ob(object *op, object *hitter) {
930 
931  if (hitter->head)
932  hitter = hitter->head;
933  return attack_ob_simple(op, hitter, hitter->stats.dam, hitter->stats.wc);
934 }
935 
946 static int stick_arrow(object *op, object *tmp) {
947  /* If the missile hit a player, we insert it in their inventory.
948  * However, if the missile is heavy, we don't do so (assume it falls
949  * to the ground after a hit). What a good value for this is up to
950  * debate - 5000 is 5 kg, so arrows, knives, and other light weapons
951  * stick around.
952  */
953  if (op->weight <= 5000 && tmp->stats.hp >= 0) {
954  if (tmp->head != NULL)
955  tmp = tmp->head;
956  remove_ob(op);
957  op = insert_ob_in_ob(op, tmp);
958  return 1;
959  } else
960  return 0;
961 }
962 
975 object *hit_with_arrow(object *op, object *victim) {
976  object *container, *hitter;
977  int hit_something = 0;
978  tag_t victim_tag, hitter_tag;
979  sint16 victim_x, victim_y;
980  mapstruct *victim_map;
981  const char *old_skill = NULL;
982 
983  /* Disassemble missile */
984  for (hitter = op->inv; hitter; hitter = hitter->below) {
985  if (hitter->type == EVENT_CONNECTOR)
986  continue;
987  container = op;
988  /* 11-2007, commented seems buggy
989  hitter = op->inv;*/
990  remove_ob(hitter);
991  if (free_no_drop(hitter))
992  return NULL;
993  insert_ob_in_map(hitter, container->map, hitter, INS_NO_MERGE|INS_NO_WALK_ON);
994  break;
995  /* Note that we now have an empty THROWN_OBJ on the map. Code that
996  * might be called until this THROWN_OBJ is either reassembled or
997  * removed at the end of this function must be able to deal with empty
998  * THROWN_OBJs. */
999  }
1000  if (!hitter) {
1001  container = NULL;
1002  hitter = op;
1003  if (free_no_drop(hitter))
1004  return NULL;
1005  }
1006 
1007  /* Try to hit victim */
1008  victim_x = victim->x;
1009  victim_y = victim->y;
1010  victim_map = victim->map;
1011  victim_tag = victim->count;
1012  hitter_tag = hitter->count;
1013  /* Lauwenmark: Handling plugin attack event for thrown items */
1014  /* FIXME provide also to script the skill? hitter is the throwed
1015  items, but there is no information about the fact it was
1016  thrown
1017  */
1018  if (execute_event(op, EVENT_ATTACK, hitter, victim, NULL, SCRIPT_FIX_ALL) == 0) {
1019  /*
1020  * temporary set the hitter's skill to the one associated with the
1021  * throw wrapper. This is needed to that thrower gets it's xp at the
1022  * correct level. This might proves an awfull hack :/ We should really
1023  * provide attack_ob_simple with the skill to use...
1024  */
1025  if (container != NULL) {
1026  old_skill = hitter->skill;
1027  hitter->skill = add_refcount(container->skill);
1028  }
1029  hit_something = attack_ob_simple(victim, hitter, op->stats.dam, op->stats.wc);
1030  }
1031  /* Arrow attacks door, rune of summoning is triggered, demon is put on
1032  * arrow, move_apply() calls this function, arrow sticks in demon,
1033  * attack_ob_simple() returns, and we've got an arrow that still exists
1034  * but is no longer on the map. Ugh. (Beware: Such things can happen at
1035  * other places as well!)
1036  */
1037  if (was_destroyed(hitter, hitter_tag) || hitter->env != NULL) {
1038  if (container) {
1039  remove_ob(container);
1040  free_object(container);
1041  }
1042  return NULL;
1043  }
1044  if (container != NULL) {
1045  free_string(hitter->skill);
1046  hitter->skill = old_skill;
1047  }
1048  /* Missile hit victim */
1049  /* if the speed is > 10, then this is a fast moving arrow, we go straight
1050  * through the target
1051  */
1052  if (hit_something && op->speed <= 10.0) {
1053  /* Stop arrow */
1054  if (container == NULL) {
1055  hitter = fix_stopped_arrow(hitter);
1056  if (hitter == NULL)
1057  return NULL;
1058  } else {
1059  remove_ob(container);
1060  free_object(container);
1061  }
1062 
1063  /* Try to stick arrow into victim */
1064  if (!was_destroyed(victim, victim_tag)
1065  && stick_arrow(hitter, victim))
1066  return NULL;
1067 
1068  /* Else try to put arrow on victim's map square
1069  * remove check for P_WALL here. If the arrow got to this
1070  * space, that is good enough - with the new movement code,
1071  * there is now the potential for lots of spaces where something
1072  * can fly over but not otherwise move over. What is the correct
1073  * way to handle those otherwise?
1074  */
1075  if (victim_x != hitter->x || victim_y != hitter->y) {
1076  remove_ob(hitter);
1077  hitter->x = victim_x;
1078  hitter->y = victim_y;
1079  insert_ob_in_map(hitter, victim_map, hitter, 0);
1080  } else {
1081  /* Else leave arrow where it is */
1082  merge_ob(hitter, NULL);
1083  }
1084  return NULL;
1085  }
1086 
1087  if (hit_something && op->speed >= 10.0)
1088  op->speed -= 1.0;
1089 
1090  /* Missile missed victim - reassemble missile */
1091  if (container) {
1092  remove_ob(hitter);
1093  insert_ob_in_ob(hitter, container);
1094  }
1095  return op;
1096 }
1104 static void tear_down_wall(object *op) {
1105  int perc = 0;
1106 
1107  if (!op->stats.maxhp) {
1108  LOG(llevError, "TEAR_DOWN wall %s had no maxhp.\n", op->name);
1109  perc = 1;
1110  } else if (!GET_ANIM_ID(op)) {
1111  /* Object has been called - no animations, so remove it */
1112  if (op->stats.hp < 0) {
1113  remove_ob(op); /* Should update LOS */
1114  free_object(op);
1115  /* Don't know why this is here - remove_ob should do it for us */
1116  /*update_position(m, x, y);*/
1117  }
1118  return; /* no animations, so nothing more to do */
1119  }
1120  perc = NUM_ANIMATIONS(op)-((int)NUM_ANIMATIONS(op)*op->stats.hp)/op->stats.maxhp;
1121  if (perc >= (int)NUM_ANIMATIONS(op))
1122  perc = NUM_ANIMATIONS(op)-1;
1123  else if (perc < 1)
1124  perc = 1;
1125  SET_ANIMATION(op, perc);
1127  if (perc == NUM_ANIMATIONS(op)-1) { /* Reached the last animation */
1128  if (op->face == blank_face) {
1129  /* If the last face is blank, remove the ob */
1130  remove_ob(op); /* Should update LOS */
1131  free_object(op);
1132 
1133  /* remove_ob should call update_position for us */
1134  /*update_position(m, x, y);*/
1135 
1136  } else { /* The last face was not blank, leave an image */
1138  update_all_los(op->map, op->x, op->y);
1139  op->move_block = 0;
1140  CLEAR_FLAG(op, FLAG_ALIVE);
1141  }
1142  }
1143 }
1144 
1152 static void scare_creature(object *target, object *hitter) {
1153  object *owner = get_owner(hitter);
1154 
1155  if (!owner)
1156  owner = hitter;
1157 
1158  SET_FLAG(target, FLAG_SCARED);
1159  if (!target->enemy)
1160  target->enemy = owner;
1161 }
1162 
1179 static int hit_with_one_attacktype(object *op, object *hitter, int dam, uint32 attacknum) {
1180 
1181  int doesnt_slay = 1;
1182  char name_hitter[MAX_BUF], name_op[MAX_BUF];
1183 
1184  /* Catch anyone that may be trying to send us a bitmask instead of the number */
1185  if (attacknum >= NROFATTACKS) {
1186  LOG(llevError, "hit_with_one_attacktype: Invalid attacknumber passed: %u\n", attacknum);
1187  return 0;
1188  }
1189 
1190  if (dam < 0) {
1191  LOG(llevError, "hit_with_one_attacktype called with negative damage: %d\n", dam);
1192  return 0;
1193  }
1194 
1195  if (hitter->current_weapon && hitter->current_weapon->discrete_damage != NULL)
1196  dam = hitter->current_weapon->discrete_damage[attacknum];
1197  else if (hitter->discrete_damage != NULL)
1198  dam = hitter->discrete_damage[attacknum];
1199 
1200  /* AT_INTERNAL is supposed to do exactly dam. Put a case here so
1201  * people can't mess with that or it otherwise get confused. */
1202  if (attacknum == ATNR_INTERNAL)
1203  return dam;
1204 
1205  if (hitter->slaying) {
1206  if (((op->race != NULL) && strstr(hitter->slaying, op->race))
1207  || (op->arch && (op->arch->name != NULL) && strstr(op->arch->name, hitter->slaying))) {
1208  doesnt_slay = 0;
1209  dam *= 3;
1210  }
1211  }
1212 
1213  /* Adjust the damage for resistance. Note that neg. values increase damage. */
1214  if (op->resist[attacknum]) {
1215  /* basically: dam = dam*(100-op->resist[attacknum])/100;
1216  * in case 0>dam>1, we try to "simulate" a float value-effect */
1217  dam *= (100-op->resist[attacknum]);
1218  if (dam >= 100)
1219  dam /= 100;
1220  else
1221  dam = (dam > (random_roll(0, 99, op, PREFER_LOW))) ? 1 : 0;
1222  }
1223 
1224  /* Special hack. By default, if immune to something, you
1225  * shouldn't need to worry. However, acid is an exception, since
1226  * it can still damage your items. Only include attacktypes if
1227  * special processing is needed */
1228 
1229  if ((op->resist[attacknum] >= 100)
1230  && doesnt_slay
1231  && (attacknum != ATNR_ACID))
1232  return 0;
1233 
1234  /* Keep this in order - makes things easier to find */
1235 
1236  switch (attacknum) {
1237  case ATNR_PHYSICAL:
1238  /* here also check for diseases */
1239  check_physically_infect(op, hitter);
1240  break;
1241 
1242  /* Don't need to do anything for:
1243  magic,
1244  fire,
1245  electricity,
1246  cold */
1247 
1248  case ATNR_CONFUSION:
1249  case ATNR_POISON:
1250  case ATNR_SLOW:
1251  case ATNR_PARALYZE:
1252  case ATNR_FEAR:
1253  case ATNR_CANCELLATION:
1254  case ATNR_DEPLETE:
1255  case ATNR_BLIND: {
1256  /* chance for inflicting a special attack depends on the
1257  * difference between attacker's and defender's level
1258  */
1259  int level_diff = MIN(110, MAX(0, op->level-hitter->level));
1260 
1261  /* First, only creatures/players with speed can be affected.
1262  * Second, just getting hit doesn't mean it always affects
1263  * you. Third, you still get a saving through against the
1264  * effect.
1265  */
1266  if (op->speed
1267  && (QUERY_FLAG(op, FLAG_MONSTER) || op->type == PLAYER)
1268  && !(rndm(0, (attacknum == ATNR_SLOW ? 6 : 3)-1))
1269  && !did_make_save(op, level_diff, op->resist[attacknum]/10)) {
1270  /* Player has been hit by something */
1271  if (attacknum == ATNR_CONFUSION)
1272  confuse_living(op, hitter, dam);
1273  else if (attacknum == ATNR_POISON)
1274  poison_living(op, hitter, dam);
1275  else if (attacknum == ATNR_SLOW)
1276  slow_living(op, hitter, dam);
1277  else if (attacknum == ATNR_PARALYZE)
1278  paralyze_living(op, hitter, dam);
1279  else if (attacknum == ATNR_FEAR)
1280  scare_creature(op, hitter);
1281  else if (attacknum == ATNR_CANCELLATION)
1282  cancellation(op);
1283  else if (attacknum == ATNR_DEPLETE)
1284  drain_stat(op);
1285  else if (attacknum == ATNR_BLIND
1286  && !QUERY_FLAG(op, FLAG_UNDEAD)
1287  && !QUERY_FLAG(op, FLAG_GENERATOR))
1288  blind_living(op, hitter, dam);
1289  }
1290  dam = 0; /* These are all effects and don't do real damage */
1291  }
1292  break;
1293 
1294  case ATNR_ACID: {
1295  int flag = 0;
1296 
1297  /* Items only get corroded if you're not on a battleground and
1298  * if your acid resistance is below 50%. */
1299  if (!op_on_battleground(op, NULL, NULL, NULL)
1300  && (op->resist[ATNR_ACID] < 50)) {
1301  object *tmp;
1302 
1303  for (tmp = op->inv; tmp != NULL; tmp = tmp->below) {
1304  if (tmp->invisible)
1305  continue;
1306  if (!QUERY_FLAG(tmp, FLAG_APPLIED)
1307  || (tmp->resist[ATNR_ACID] >= 10))
1308  /* >= 10% acid res. on itmes will protect these */
1309  continue;
1310  if (!(tmp->material&M_IRON))
1311  continue;
1312  if (tmp->magic < -4) /* Let's stop at -5 */
1313  continue;
1314  if (tmp->type == RING
1315  /* removed boots and gloves from exclusion list in PR */
1316  || tmp->type == GIRDLE
1317  || tmp->type == AMULET
1318  || tmp->type == WAND
1319  || tmp->type == ROD
1320  || tmp->type == HORN)
1321  continue; /* To avoid some strange effects */
1322 
1323  /* High damage acid has better chance of corroding objects */
1324  if (rndm(0, dam+4) > random_roll(0, 39, op, PREFER_HIGH)+2*tmp->magic) {
1325  if (op->type == PLAYER) {
1326  /* Make this more visible */
1327  query_name(hitter, name_hitter, MAX_BUF);
1328  query_name(tmp, name_op, MAX_BUF);
1331  "The %s's acid corrodes your %s!",
1332  "The %s's acid corrodes your %s!",
1333  name_hitter, name_op);
1334  }
1335  flag = 1;
1336  tmp->magic--;
1337  if (op->type == PLAYER)
1338  esrv_update_item(UPD_NAME, op, tmp);
1339  }
1340  }
1341  if (flag)
1342  fix_object(op); /* Something was corroded */
1343  }
1344  }
1345  break;
1346 
1347  case ATNR_DRAIN: {
1348  /* rate is the proportion of exp drained. High rate means
1349  * not much is drained, low rate means a lot is drained.
1350  */
1351  int rate;
1352 
1353  if (op->resist[ATNR_DRAIN] >= 0)
1354  rate = 50+op->resist[ATNR_DRAIN]/2;
1355  else
1356  rate = 5000/(100-op->resist[ATNR_DRAIN]);
1357 
1358  /* full protection has no effect. Nothing else in this
1359  * function needs to get done, so just return. */
1360  if (!rate)
1361  return 0;
1362 
1363  if (op->stats.exp <= rate) {
1364  if (op->type == GOLEM)
1365  dam = 999; /* Its force is "sucked" away. 8) */
1366  else
1367  /* If we can't drain, lets try to do physical damage */
1368  dam = hit_with_one_attacktype(op, hitter, dam, ATNR_PHYSICAL);
1369  } else {
1370  /* Randomly give the hitter some hp */
1371  if (hitter->stats.hp < hitter->stats.maxhp
1372  && (op->level > hitter->level)
1373  && random_roll(0, (op->level-hitter->level+2), hitter, PREFER_HIGH) > 3)
1374  hitter->stats.hp++;
1375 
1376  /* Can't do drains on battleground spaces.
1377  * Move the wiz check up here - before, the hitter wouldn't gain exp
1378  * exp, but the wiz would still lose exp! If drainee is a wiz,
1379  * nothing happens.
1380  * Try to credit the owner. We try to display player -> player drain
1381  * attacks, hence all the != PLAYER checks.
1382  */
1383  if (!op_on_battleground(hitter, NULL, NULL, NULL) && !QUERY_FLAG(op, FLAG_WAS_WIZ)) {
1384  object *owner = get_owner(hitter);
1385 
1386  if (owner && owner != hitter) {
1387  if (op->type != PLAYER || owner->type != PLAYER)
1388  change_exp(owner, op->stats.exp/(rate*2),
1389  hitter->chosen_skill ? hitter->chosen_skill->skill : NULL, SK_EXP_TOTAL);
1390  } else if (op->type != PLAYER || hitter->type != PLAYER) {
1391  change_exp(hitter, op->stats.exp/(rate*2), hitter->chosen_skill ? hitter->chosen_skill->skill : NULL, 0);
1392  }
1393  change_exp(op, -op->stats.exp/rate, NULL, 0);
1394  }
1395  dam = 1; /* Drain is an effect. Still return 1 - otherwise, if you have pure
1396  * drain attack, you won't know that you are actually sucking out EXP,
1397  * as the messages will say you missed
1398  */
1399  }
1400  }
1401  break;
1402 
1403  case ATNR_TURN_UNDEAD: {
1404  if (QUERY_FLAG(op, FLAG_UNDEAD)) {
1405  object *owner = get_owner(hitter) == NULL ? hitter : get_owner(hitter);
1406  const object *god = find_god(determine_god(owner));
1407  int div = 1;
1408 
1409  /* if undead are not an enemy of your god, you turn them
1410  * at half strength */
1411  if (!god
1412  || !god->slaying
1413  || strstr(god->slaying, undead_name) == NULL)
1414  div = 2;
1415  /* Give a bonus if you resist turn undead */
1416  if (op->level*div < (turn_bonus[owner->stats.Wis]+owner->level+(op->resist[ATNR_TURN_UNDEAD]/100)))
1417  scare_creature(op, owner);
1418  } else
1419  dam = 0; /* don't damage non undead - should we damage undead? */
1420  }
1421  break;
1422 
1423  case ATNR_DEATH:
1424  deathstrike_living(op, hitter, &dam);
1425  break;
1426 
1427  case ATNR_CHAOS:
1428  query_name(op, name_op, MAX_BUF);
1429  query_name(hitter, name_hitter, MAX_BUF);
1430  LOG(llevError, "%s was hit by %s with non-specific chaos.\n", name_op, name_hitter);
1431  dam = 0;
1432  break;
1433 
1434  case ATNR_COUNTERSPELL:
1435  query_name(op, name_op, MAX_BUF);
1436  query_name(hitter, name_hitter, MAX_BUF);
1437  LOG(llevError, "%s was hit by %s with counterspell attack.\n", name_op, name_hitter);
1438  dam = 0;
1439  /* This should never happen. Counterspell is handled
1440  * seperately and filtered out. If this does happen,
1441  * Counterspell has no effect on anything but spells, so it
1442  * does no damage. */
1443  break;
1444 
1445  case ATNR_HOLYWORD: {
1446  /* This has already been handled by hit_player,
1447  * no need to check twice -- DAMN */
1448 
1449  object *owner = get_owner(hitter) == NULL ? hitter : get_owner(hitter);
1450 
1451  /* As with turn undead above, give a bonus on the saving throw */
1452  if ((op->level+(op->resist[ATNR_HOLYWORD]/100)) < owner->level+turn_bonus[owner->stats.Wis])
1453  scare_creature(op, owner);
1454  }
1455  break;
1456 
1457  case ATNR_LIFE_STEALING: {
1458  int new_hp;
1459  /* this is replacement to drain for players, instead of taking
1460  * exp it takes hp. It is geared for players, probably not
1461  * much use giving it to monsters
1462  *
1463  * life stealing doesn't do a lot of damage, but it gives the
1464  * damage it does do to the player. Given that,
1465  * it only does 1/30'th normal damage (hence the divide by
1466  * 3000). Wraith get 1/2 of the damage, and therefore divide
1467  * by 200. This number may need tweaking for game balance.
1468  */
1469 
1470  int dam_modifier = is_wraith_pl(hitter) ? 200 : 3000;
1471 
1472  /* You can't steal life from something undead or not alive. */
1473  if (op->type == GOLEM
1474  || (QUERY_FLAG(op, FLAG_UNDEAD))
1475  || !(QUERY_FLAG(op, FLAG_ALIVE))
1476  || (op->type == DOOR))
1477  return 0;
1478  /* If drain protection is higher than life stealing, use that */
1479  if (op->resist[ATNR_DRAIN] >= op->resist[ATNR_LIFE_STEALING])
1480  dam = (dam*(100-op->resist[ATNR_DRAIN]))/dam_modifier;
1481  else
1482  dam = (dam*(100-op->resist[ATNR_LIFE_STEALING]))/dam_modifier;
1483  /* You die at -1 hp, not zero. */
1484  if (dam > (op->stats.hp+1))
1485  dam = op->stats.hp+1;
1486  new_hp = hitter->stats.hp+dam;
1487  if (new_hp > hitter->stats.maxhp)
1488  new_hp = hitter->stats.maxhp;
1489  if (new_hp > hitter->stats.hp)
1490  hitter->stats.hp = new_hp;
1491 
1492  /* Wraith also get food through life stealing */
1493  if (is_wraith_pl(hitter)) {
1494  if (hitter->stats.food+dam >= 999)
1495  hitter->stats.food = 999;
1496  else
1497  hitter->stats.food += dam;
1498  fix_object(hitter);
1499  }
1500  }
1501  }
1502  return dam;
1503 }
1504 
1534 static int kill_object(object *op, int dam, object *hitter, int type) {
1535  char buf[MAX_BUF];
1536  const char *skill;
1537  int maxdam = 0;
1538  int battleg = 0; /* true if op standing on battleground */
1539  int pk = 0; /* true if op and what controls hitter are both players*/
1540  object *owner = NULL;
1541  object *skop = NULL;
1542  sstring death_animation;
1543 
1544  if (op->stats.hp >= 0)
1545  return -1;
1546 
1547  /* Lauwenmark: Handle for plugin death event */
1548  if (execute_event(op, EVENT_DEATH, hitter, NULL, NULL, SCRIPT_FIX_ALL) != 0)
1549  return 0;
1550  /* Lauwenmark: Handle for the global kill event */
1551  execute_global_event(EVENT_GKILL, op, hitter);
1552 
1553  if ((op->map) && (death_animation = get_ob_key_value(op, "death_animation")) != NULL) {
1554  object *death = create_archetype(death_animation);
1555 
1556  if (death) {
1557  death->map = op->map;
1558  death->x = op->x;
1559  death->y = op->y;
1560  insert_ob_in_map(death, op->map, op, 0);
1561  }
1562  }
1563 
1564  /* maxdam needs to be the amount of damage it took to kill
1565  * this creature. The function(s) that call us have already
1566  * adjusted the creatures HP total, so that is negative.
1567  */
1568  maxdam = dam+op->stats.hp+1;
1569 
1570  if (QUERY_FLAG(op, FLAG_BLOCKSVIEW))
1571  update_all_los(op->map, op->x, op->y); /* makes sure los will be recalculated */
1572 
1573  if (op->type == DOOR) {
1574  op->speed = 0.1;
1575  update_ob_speed(op);
1576  op->speed_left = -0.05;
1577  return maxdam;
1578  }
1579  if (QUERY_FLAG(op, FLAG_FRIENDLY) && op->type != PLAYER) {
1581  if (get_owner(op) != NULL
1582  && op->owner->type == PLAYER
1583  && op->owner->contr->ranges[range_golem] == op) {
1584  op->owner->contr->ranges[range_golem] = NULL;
1585  op->owner->contr->golem_count = 0;
1586  } else
1587  LOG(llevError, "BUG: hit_player(): Encountered golem without owner.\n");
1588 
1589  remove_ob(op);
1590  free_object(op);
1591  return maxdam;
1592  }
1593 
1594  /* Now lets start dealing with experience we get for killing something */
1595 
1596  owner = get_owner(hitter);
1597  if (owner == NULL)
1598  owner = hitter;
1599 
1600  /* is the victim (op) standing on battleground? */
1601  if (op_on_battleground(op, NULL, NULL, NULL))
1602  battleg = 1;
1603 
1604  /* is this player killing?*/
1605  if (op->type == PLAYER && owner->type == PLAYER)
1606  pk = 1;
1607 
1608  /* Player killed something */
1609  if (owner->type == PLAYER) {
1610  char name_op[MAX_BUF], name_hitter[MAX_BUF];
1611 
1612  query_name(op, name_op, MAX_BUF);
1613  if (hitter)
1614  query_name(hitter, name_hitter, MAX_BUF);
1615  else
1616  name_hitter[0] = '\0';
1617 
1618  /* Log players killing other players - makes it easier to detect
1619  * and filter out malicious player killers - that is why the
1620  * ip address is included.
1621  */
1622  if (op->type == PLAYER && !battleg) {
1623  time_t t = time(NULL);
1624  struct tm *tmv;
1625  char buf[256];
1626  char name[MAX_BUF];
1627 
1628  tmv = localtime(&t);
1629  strftime(buf, 256, "%a %b %d %H:%M:%S %Y", tmv);
1630  query_name(op, name, MAX_BUF);
1631 
1632  LOG(llevInfo, "%s PLAYER_KILL_PLAYER: %s (%s) killed %s\n", buf, owner->name, owner->contr->socket.host, name);
1633  }
1634 
1635  /* try to filter some things out - basically, if you are
1636  * killing a level 1 creature and your level 20, you
1637  * probably don't want to see that.
1638  */
1639  if (owner->level < op->level*2|| op->stats.exp > 1000) {
1640  if (owner != hitter) {
1641  char killed[MAX_BUF], with[MAX_BUF];
1642 
1643  query_name(op, killed, MAX_BUF);
1644  query_name(hitter, with, MAX_BUF);
1646  "You killed %s with %s.",
1647  "You killed %s with %s.",
1648  killed, with);
1649  } else {
1650  char killed[MAX_BUF];
1651 
1652  query_name(op, killed, MAX_BUF);
1654  "You killed %s.",
1655  "You killed %s.",
1656  killed);
1657  }
1658  /* Only play sounds for melee kills */
1659  if (hitter->type == PLAYER)
1660  play_sound_map(SOUND_TYPE_HIT, owner, 0, "kill");
1661  }
1662 
1663  /* If a player kills another player, not on
1664  * battleground, the "killer" looses 1 luck. Since this is
1665  * not reversible, it's actually quite a pain IMHO. -AV
1666  * Fix bug in that we were changing the luck of the hitter, not
1667  * player that the object belonged to - so if you killed another player
1668  * with spells, pets, whatever, there was no penalty.
1669  * Changed to make luck penalty configurable in settings.
1670  */
1671  if (op->type == PLAYER && owner != op && !battleg)
1673 
1674  /* This code below deals with finding the appropriate skill
1675  * to credit exp to. This is a bit problematic - we should
1676  * probably never really have to look at current_weapon->skill
1677  */
1678  skill = NULL;
1679  if (hitter->skill && hitter->type != PLAYER)
1680  skill = hitter->skill;
1681  else if (owner->chosen_skill) {
1682  skill = owner->chosen_skill->skill;
1683  skop = owner->chosen_skill;
1684  } else if (QUERY_FLAG(owner, FLAG_READY_WEAPON))
1685  skill = owner->current_weapon->skill;
1686  else
1687  LOG(llevError, "kill_object - unable to find skill that killed monster\n");
1688 
1689  /* We have the skill we want to credit to - now find the object this goes
1690  * to. Make sure skop is an actual skill, and not a skill tool!
1691  */
1692  if ((!skop || skop->type != SKILL) && skill) {
1693  int i;
1694 
1695  for (i = 0; i < NUM_SKILLS; i++)
1696  if (owner->contr->last_skill_ob[i]
1697  && !strcmp(owner->contr->last_skill_ob[i]->skill, skill)) {
1698  skop = owner->contr->last_skill_ob[i];
1699  break;
1700  }
1701  }
1702  } /* Was it a player that hit somethign */
1703  else {
1704  skill = NULL;
1705  }
1706 
1707  /* Pet (or spell) killed something. */
1708  if (owner != hitter) {
1709  char name_op[MAX_BUF], name_hitter[MAX_BUF];
1710 
1711  query_name(op, name_op, MAX_BUF);
1712  query_name(hitter, name_hitter, MAX_BUF);
1713  (void)sprintf(buf, "%s killed %s with %s%s.", owner->name, name_op, name_hitter, battleg ? " (duel)" : (pk ? " (pk)" : ""));
1714  } else {
1715  (void)sprintf(buf, "%s killed %s%s%s.", hitter->name, op->name,
1716  (QUERY_FLAG(hitter, FLAG_MONSTER)) || hitter->type == PLAYER ?
1717  " in hand to hand combat" : "", battleg ? " (duel)" : (pk ? " (pk)" : ""));
1718  }
1719  /* These may have been set in the player code section above */
1720  if (!skop)
1721  skop = hitter->chosen_skill;
1722  if (!skill && skop)
1723  skill = skop->skill;
1724 
1726  buf, NULL);
1727 
1728 
1729  /* If you didn't kill yourself, and your not the wizard */
1730  if (owner != op && !QUERY_FLAG(op, FLAG_WAS_WIZ)) {
1731  sint64 exp;
1732 
1733  exp = calc_skill_exp(owner, op, skop);
1734 
1735  /* Really don't give much experience for killing other players */
1736  if (op->type == PLAYER) {
1737  if (battleg) {
1739  "Your foe has fallen!\nVICTORY!!!", NULL);
1740  } else {
1741  exp = settings.pk_max_experience_percent*exp/100;
1742  if (settings.pk_max_experience >= 0)
1743  exp = MIN(settings.pk_max_experience, exp);
1744  /* Never exceed what victim can lose considering permanent exp. */
1745  exp = check_exp_loss(op, exp);
1746  }
1747  }
1748 
1749  /* Don't know why this is set this way - doesn't make
1750  * sense to just divide everything by two for no reason.
1751  */
1752 
1753  if (!settings.simple_exp)
1754  exp = exp/2;
1755 
1756  /* if op is standing on "battleground" (arena), no way to gain
1757  * exp by killing him
1758  */
1759  if (battleg)
1760  exp = 0;
1761 
1762 #ifdef PARTY_KILL_LOG
1763  if (owner->type == PLAYER && owner->contr->party != NULL) {
1764  char name[MAX_BUF];
1765 
1766  query_name(owner, name, MAX_BUF);
1767  add_kill_to_party(party, name, query_name(op), exp);
1768  }
1769 #endif
1770  share_exp(owner, exp, skill, SK_EXP_TOTAL);
1771 
1772  } /* end if person didn't kill himself */
1773 
1774  if (op->type != PLAYER) {
1775  if (QUERY_FLAG(op, FLAG_FRIENDLY)) {
1776  object *owner1 = get_owner(op);
1777 
1778  if (owner1 != NULL && owner1->type == PLAYER) {
1779  /*play_sound_player_only(owner1->contr, SOUND_PET_IS_KILLED, 0, 0);*/
1780  /* Maybe we should include the owner that killed this, maybe not */
1782  "Your pet, the %s, is killed by %s.",
1783  "Your pet, the %s, is killed by %s.",
1784  op->name, hitter->name);
1785  }
1787  }
1788  remove_ob(op);
1789  free_object(op);
1790  /* Player has been killed! */
1791  } else {
1792  if (owner->type == PLAYER) {
1793  snprintf(op->contr->killer, BIG_NAME, "%s the %s", owner->name, owner->contr->title);
1794  } else {
1795  strncpy(op->contr->killer, hitter->name, BIG_NAME);
1796  op->contr->killer[BIG_NAME-1] = '\0';
1797  }
1798  /* Need to run kill_player (just in case, make sure is not wiz) */
1799  if (!QUERY_FLAG(op, FLAG_WIZ))
1800  kill_player(op);
1801  }
1802  /* This was return -1 - that doesn't seem correct - if we return -1, process
1803  * continues in the calling function.
1804  */
1805  return maxdam;
1806 }
1807 
1818 int friendly_fire(object *op, object *hitter) {
1819  object *owner;
1820  int friendlyfire;
1821 
1822  if (hitter->head)
1823  hitter = hitter->head;
1824 
1825  friendlyfire = 0;
1826 
1827  if (op->type == PLAYER) {
1828  if (hitter->type == PLAYER && hitter->contr->peaceful == 1)
1829  return 1;
1830 
1831  if ((owner = get_owner(hitter)) != NULL) {
1832  if (owner->type == PLAYER && owner->contr->peaceful == 1)
1833  friendlyfire = 2;
1834  }
1835 
1836  if (hitter->type == SPELL
1837  || hitter->type == POISONING
1838  || hitter->type == DISEASE
1839  || hitter->type == RUNE)
1840  friendlyfire = 0;
1841  }
1842  return friendlyfire;
1843 }
1844 
1868 int hit_player(object *op, int dam, object *hitter, uint32 type, int full_hit) {
1869  int maxdam = 0, ndam = 0, attacktype = 1, magic = (type&AT_MAGIC);
1870  int maxattacktype, attacknum;
1871  int body_attack = op && op->head; /* Did we hit op's head? */
1872  int simple_attack;
1873  tag_t op_tag, hitter_tag;
1874  int rtn_kill = 0;
1875  int friendlyfire;
1876 
1877  if (get_attack_mode(&op, &hitter, &simple_attack))
1878  return 0;
1879 
1880  /* very simple: if our target has no_damage 1 set or is wiz, we can't hurt him */
1881  if (QUERY_FLAG(op, FLAG_WIZ) || QUERY_FLAG(op, FLAG_NO_DAMAGE))
1882  return 0;
1883 
1884  op_tag = op->count;
1885  hitter_tag = hitter->count;
1886 
1887  if (body_attack) {
1888  /* slow and paralyze must hit the head. But we don't want to just
1889  * return - we still need to process other attacks the spell still
1890  * might have. So just remove the paralyze and slow attacktypes,
1891  * and keep on processing if we have other attacktypes.
1892  * return if only magic or nothing is left - under normal code
1893  * we don't attack with pure magic if there is another attacktype.
1894  * Only do processing if the initial attacktype includes one of those
1895  * attack so we don't cancel out things like magic bullet.
1896  */
1897  if (type&(AT_PARALYZE|AT_SLOW)) {
1898  type &= ~(AT_PARALYZE|AT_SLOW);
1899  if (!type || type == AT_MAGIC)
1900  return 0;
1901  }
1902  }
1903 
1904  if (!simple_attack && op->type == DOOR) {
1905  object *tmp;
1906 
1907  for (tmp = op->inv; tmp != NULL; tmp = tmp->below)
1908  if (tmp->type == RUNE || tmp->type == TRAP) {
1909  spring_trap(tmp, hitter);
1910  if (was_destroyed(hitter, hitter_tag)
1911  || was_destroyed(op, op_tag)
1912  || abort_attack(op, hitter, simple_attack))
1913  return 0;
1914  break;
1915  }
1916  }
1917 
1918  if (!QUERY_FLAG(op, FLAG_ALIVE) || op->stats.hp < 0) {
1919  /* FIXME: If a player is killed by a rune in a door, the
1920  * was_destroyed() check above doesn't return, and might get here.
1921  */
1922  LOG(llevDebug, "victim (arch %s, name %s) already dead in hit_player()\n", op->arch->name, op->name);
1923  return 0;
1924  }
1925 
1926 #ifdef ATTACK_DEBUG
1927  LOG(llevDebug, "hit player: attacktype %d, dam %d\n", type, dam);
1928 #endif
1929 
1930  if (magic) {
1931  /* basically: dam = dam*(100-op->resist[attacknum])/100;
1932  * in case 0>dam>1, we try to "simulate" a float value-effect */
1933  dam = dam*(100-op->resist[ATNR_MAGIC]);
1934  if (dam >= 100)
1935  dam /= 100;
1936  else
1937  dam = (dam > (rndm(0, 99))) ? 1 : 0;
1938  }
1939 
1940  /* AT_CHAOS here is a weapon or monster. Spells are handled by hit_map
1941  * We don't use shuffle_attack(), because that changes the it in the
1942  * creature structure, and thus is permanent until fix_object() is
1943  * called again. Chaos should change on each attack.
1944  */
1945  if (type&AT_CHAOS) {
1946  int i;
1947 
1948  i = rndm(0, 21);
1949  type = ATTACKS[i].attacktype|AT_MAGIC;
1950  }
1951 
1952  /* Holyword is really an attacktype modifier (like magic is). If
1953  * holyword is part of an attacktype, then make sure the creature is
1954  * a proper match, otherwise no damage.
1955  */
1956  if (type&AT_HOLYWORD) {
1957  const object *god;
1958 
1959  if ((!hitter->slaying || (!(op->race && strstr(hitter->slaying, op->race))
1960  && !(op->name && strstr(hitter->slaying, op->name))))
1961  && (!QUERY_FLAG(op, FLAG_UNDEAD) || (hitter->title != NULL
1962  && (god = find_god(determine_god(hitter))) != NULL
1963  && god->race != NULL
1964  && strstr(god->race, undead_name) != NULL)))
1965  return 0;
1966  }
1967 
1968  maxattacktype = type; /* initialize this to something */
1969  for (attacknum = 0; attacknum < NROFATTACKS; attacknum++, attacktype = 1<<attacknum) {
1970  /* Magic isn't really a true attack type - it gets combined with other
1971  * attack types. As such, skip it over. However, if magic is
1972  * the only attacktype in the group, then still attack with it
1973  */
1974  if ((attacktype == AT_MAGIC) && (type&~AT_MAGIC))
1975  continue;
1976 
1977  /* Go through and hit the player with each attacktype, one by one.
1978  * hit_with_one_attacktype only figures out the damage, doesn't inflict
1979  * it. It will do the appropriate action for attacktypes with
1980  * effects (slow, paralization, etc.
1981  */
1982  if (type&attacktype) {
1983  ndam = hit_with_one_attacktype(op, hitter, dam, attacknum);
1984  /* the >= causes us to prefer messages from special attacks, if
1985  * the damage is equal.
1986  */
1987  if (ndam >= maxdam) {
1988  maxdam = ndam;
1989  maxattacktype = 1<<attacknum;
1990  }
1991  /* Special case: death attack always deals all damage, as it should kill the monster
1992  * right away. */
1993  if (attacktype == AT_DEATH && ndam > 0)
1994  full_hit = 1;
1995  }
1996  }
1997 
1998  /* if this is friendly fire then do a set % of damage only
1999  * Note - put a check in to make sure this attack is actually
2000  * doing damage - otherwise, the +1 in the coe below will make
2001  * an attack do damage before when it otherwise didn't
2002  */
2003  friendlyfire = friendly_fire(op, hitter);
2004  if (friendlyfire && maxdam) {
2005  maxdam = ((dam*settings.set_friendly_fire)/100)+1;
2006 
2007 #ifdef ATTACK_DEBUG
2008  LOG(llevDebug, "Friendly fire (type:%d setting: %d%) did %d damage dropped to %d\n", friendlyfire, settings.set_friendly_fire, dam, maxdam);
2009 #endif
2010  }
2011 
2012  if (!full_hit) {
2013  archetype *at;
2014  int area;
2015  int remainder;
2016 
2017  area = 0;
2018  for (at = op->arch; at != NULL; at = at->more)
2019  area++;
2020  assert(area > 0);
2021 
2022  /* basically: maxdam /= area; we try to "simulate" a float
2023  value-effect */
2024  remainder = 100*(maxdam%area)/area;
2025  maxdam /= area;
2026  if (RANDOM()%100 < remainder)
2027  maxdam++;
2028  }
2029 
2030 #ifdef ATTACK_DEBUG
2031  LOG(llevDebug, "Attacktype %d did %d damage\n", type, maxdam);
2032 #endif
2033 
2034  if (get_owner(hitter))
2035  op->enemy = hitter->owner;
2036  else if (QUERY_FLAG(hitter, FLAG_ALIVE))
2037  op->enemy = hitter;
2038 
2039  if (QUERY_FLAG(op, FLAG_UNAGGRESSIVE) && op->type != PLAYER) {
2040  /* The unaggressives look after themselves 8) */
2042  npc_call_help(op);
2043  }
2044 
2045  if (magic && did_make_save(op, op->level, 0))
2046  maxdam = maxdam/2;
2047 
2048  attack_message(maxdam, maxattacktype, op, hitter);
2049 
2050  op->stats.hp -= maxdam;
2051 
2052  /* Eneq(@csd.uu.se): Check to see if monster runs away. */
2053  if ((op->stats.hp >= 0)
2054  && (QUERY_FLAG(op, FLAG_MONSTER) || op->type == PLAYER)
2055  && op->stats.hp < (signed short)(((float)op->run_away/(float)100)*(float)op->stats.maxhp)) {
2056  if (QUERY_FLAG(op, FLAG_MONSTER))
2057  SET_FLAG(op, FLAG_RUN_AWAY);
2058  else
2059  scare_creature(op, hitter);
2060  }
2061 
2062  if (QUERY_FLAG(op, FLAG_TEAR_DOWN)) {
2063  if (maxdam)
2064  tear_down_wall(op);
2065  return maxdam; /* nothing more to do for wall */
2066  }
2067 
2068  /* See if the creature has been killed */
2069  rtn_kill = kill_object(op, maxdam, hitter, type);
2070  if (rtn_kill != -1)
2071  return rtn_kill;
2072 
2073  /* Used to be ghosthit removal - we now use the ONE_HIT flag. Note
2074  * that before if the player was immune to ghosthit, the monster
2075  * remained - that is no longer the case.
2076  */
2077  if (QUERY_FLAG(hitter, FLAG_ONE_HIT)) {
2078  if (QUERY_FLAG(hitter, FLAG_FRIENDLY))
2079  remove_friendly_object(hitter);
2080  remove_ob(hitter);
2081  free_object(hitter);
2082  /* Lets handle creatures that are splitting now */
2083  } else if (type&AT_PHYSICAL && !QUERY_FLAG(op, FLAG_FREED) && QUERY_FLAG(op, FLAG_SPLITTING)) {
2084  int i;
2085  int friendly = QUERY_FLAG(op, FLAG_FRIENDLY);
2086  int unaggressive = QUERY_FLAG(op, FLAG_UNAGGRESSIVE);
2087  object *owner = get_owner(op);
2088 
2089  if (!op->other_arch) {
2090  LOG(llevError, "SPLITTING without other_arch error.\n");
2091  return maxdam;
2092  }
2093  remove_ob(op);
2094  for (i = 0; i < NROFNEWOBJS(op); i++) { /* This doesn't handle op->more yet */
2095  object *tmp = arch_to_object(op->other_arch);
2096  int j;
2097 
2098  tmp->stats.hp = op->stats.hp;
2099  if (friendly) {
2100  SET_FLAG(tmp, FLAG_FRIENDLY);
2101  add_friendly_object(tmp);
2102  tmp->attack_movement = PETMOVE;
2103  if (owner != NULL)
2104  set_owner(tmp, owner);
2105  }
2106  if (unaggressive)
2108  j = find_first_free_spot(tmp, op->map, op->x, op->y);
2109  if (j == -1) /* No spot to put this monster */
2110  free_object(tmp);
2111  else {
2112  tmp->x = op->x+freearr_x[j],
2113  tmp->y = op->y+freearr_y[j];
2114  insert_ob_in_map(tmp, op->map, NULL, 0);
2115  }
2116  }
2117  if (friendly)
2119  free_object(op);
2120  } else if (type&AT_DRAIN && hitter->type == GRIMREAPER && hitter->value++ > 10) {
2121  remove_ob(hitter);
2122  free_object(hitter);
2123  }
2124  return maxdam;
2125 }
2126 
2137 static void poison_living(object *op, object *hitter, int dam) {
2138  archetype *at = find_archetype("poisoning");
2139  object *tmp = present_arch_in_ob(at, op);
2140 
2141  if (tmp == NULL) {
2142  if ((tmp = arch_to_object(at)) == NULL)
2143  LOG(llevError, "Failed to clone arch poisoning.\n");
2144  else {
2145  tmp = insert_ob_in_ob(tmp, op);
2146  /* peterm: give poisoning some teeth. It should
2147  * be able to kill things better than it does:
2148  * damage should be dependent something--I choose to
2149  * do this: if it's a monster, the damage from the
2150  * poisoning goes as the level of the monster/2.
2151  * If anything else, goes as damage.
2152  */
2153 
2154  if (QUERY_FLAG(hitter, FLAG_ALIVE))
2155  tmp->stats.dam += hitter->level/2;
2156  else
2157  tmp->stats.dam = dam;
2158 
2159  copy_owner(tmp, hitter); /* so we get credit for poisoning kills */
2160  if (hitter->skill && hitter->skill != tmp->skill) {
2161  if (tmp->skill)
2162  free_string(tmp->skill);
2163  tmp->skill = add_refcount(hitter->skill);
2164  }
2165 
2166  tmp->stats.food += dam; /* more damage, longer poisoning */
2167 
2168  if (op->type == PLAYER) {
2169  /* player looses stats, maximum is -10 of each */
2170  tmp->stats.Con = MAX(-(dam/4+1), -10);
2171  tmp->stats.Str = MAX(-(dam/3+2), -10);
2172  tmp->stats.Dex = MAX(-(dam/6+1), -10);
2173  tmp->stats.Int = MAX(-dam/7, -10);
2174  SET_FLAG(tmp, FLAG_APPLIED);
2175  fix_object(op);
2176  draw_ext_info(NDI_UNIQUE, 0, op,
2178  "You suddenly feel very ill.", NULL);
2179  }
2180  if (hitter->type == PLAYER)
2181  draw_ext_info_format(NDI_UNIQUE, 0, hitter,
2183  "You poison %s.",
2184  "You poison %s.",
2185  op->name);
2186  else if (get_owner(hitter) != NULL && hitter->owner->type == PLAYER)
2189  "Your %s poisons %s.",
2190  "Your %s poisons %s.",
2191  hitter->name, op->name);
2192  }
2193  tmp->speed_left = 0;
2194  } else
2195  tmp->stats.food++;
2196 }
2197 
2208 static void slow_living(object *op, object *hitter, int dam) {
2209  archetype *at = find_archetype("slowness");
2210  object *tmp;
2211 
2212  if (at == NULL) {
2213  LOG(llevError, "Can't find slowness archetype.\n");
2214  }
2215  if ((tmp = present_arch_in_ob(at, op)) == NULL) {
2216  tmp = arch_to_object(at);
2217  tmp = insert_ob_in_ob(tmp, op);
2219  "The world suddenly moves very fast!", NULL);
2220  } else
2221  tmp->stats.food++;
2222  SET_FLAG(tmp, FLAG_APPLIED);
2223  tmp->speed_left = 0;
2224  fix_object(op);
2225 }
2226 
2237 void confuse_living(object *op, object *hitter, int dam) {
2238  object *tmp;
2239  int maxduration;
2240 
2241  tmp = present_in_ob_by_name(FORCE, "confusion", op);
2242  if (!tmp) {
2244  tmp = insert_ob_in_ob(tmp, op);
2245  }
2246 
2247  /* Duration added per hit and max. duration of confusion both depend
2248  * on the player's resistance
2249  */
2250  tmp->speed = 0.05;
2251  tmp->subtype = FORCE_CONFUSION;
2252  tmp->duration = 8+MAX(1, 5*(100-op->resist[ATNR_CONFUSION])/100);
2253  if (tmp->name)
2254  free_string(tmp->name);
2255  tmp->name = add_string("confusion");
2256  maxduration = MAX(2, 30*(100-op->resist[ATNR_CONFUSION])/100);
2257  if (tmp->duration > maxduration)
2258  tmp->duration = maxduration;
2259 
2260  if (op->type == PLAYER && !QUERY_FLAG(op, FLAG_CONFUSED))
2262  "You suddenly feel very confused!", NULL);
2263  SET_FLAG(op, FLAG_CONFUSED);
2264 }
2265 
2276 void blind_living(object *op, object *hitter, int dam) {
2277  object *tmp, *owner;
2278  char victim[MAX_BUF];
2279 
2280  /* Save some work if we know it isn't going to affect the player */
2281  if (op->resist[ATNR_BLIND] == 100)
2282  return;
2283 
2284  tmp = present_in_ob(BLINDNESS, op);
2285  if (!tmp) {
2286  tmp = create_archetype("blindness");
2287  SET_FLAG(tmp, FLAG_BLIND);
2288  SET_FLAG(tmp, FLAG_APPLIED);
2289  /* use floats so we don't lose too much precision due to rounding errors.
2290  * speed is a float anyways.
2291  */
2292  tmp->speed = tmp->speed*(100.0-(float)op->resist[ATNR_BLIND])/100;
2293 
2294  tmp = insert_ob_in_ob(tmp, op);
2295  change_abil(op, tmp); /* Mostly to display any messages */
2296  fix_object(op); /* This takes care of some other stuff */
2297 
2298  if (hitter->owner)
2299  owner = get_owner(hitter);
2300  else
2301  owner = hitter;
2302 
2303  query_name(op, victim, MAX_BUF);
2305  "Your attack blinds %s!",
2306  "Your attack blinds %s!",
2307  victim);
2308  }
2309  tmp->stats.food += dam;
2310  if (tmp->stats.food > 10)
2311  tmp->stats.food = 10;
2312 }
2313 
2324 void paralyze_living(object *op, object *hitter, int dam) {
2325  float effect, max;
2326  /* object *tmp; */
2327 
2328  /* This is strange stuff... someone knows for what this is
2329  * written? Well, i think this can and should be removed
2330  */
2331 
2332 /*
2333  if ((tmp = present(PARAIMAGE, op->map, op->x, op->y)) == NULL) {
2334  tmp = clone_arch(PARAIMAGE);
2335  tmp->x = op->x,
2336  tmp->y = op->y;
2337  insert_ob_in_map(tmp, op->map, tmp, INS_NO_MERGE|INS_NO_WALK_ON);
2338  }
2339 */
2340 
2341  /* Do this as a float - otherwise, rounding might very well reduce this to 0 */
2342  effect = (float)dam*3.0*(100.0-op->resist[ATNR_PARALYZE])/100;
2343 
2344  if (effect == 0)
2345  return;
2346 
2347  op->speed_left -= FABS(op->speed)*effect;
2348 /* tmp->stats.food += (signed short)
2349  effect/op->speed;*/
2350 
2351  /* max number of ticks to be affected for. */
2352  max = (100-op->resist[ATNR_PARALYZE])/2;
2353  if (op->speed_left < -(FABS(op->speed)*max))
2354  op->speed_left = (float)-(FABS(op->speed)*max);
2355 
2356 /* tmp->stats.food = (signed short)(max/FABS(op->speed)); */
2357 }
2358 
2379 static void deathstrike_living(object *op, object *hitter, int *dam) {
2380  int atk_lev, def_lev, kill_lev;
2381 
2382  if (hitter->slaying) {
2383  if (!((QUERY_FLAG(op, FLAG_UNDEAD) && strstr(hitter->slaying, undead_name))
2384  || (op->race && strstr(hitter->slaying, op->race))))
2385  return;
2386  } else
2387  if (QUERY_FLAG(op, FLAG_UNDEAD))
2388  return;
2389 
2390  def_lev = op->level;
2391  if (def_lev < 1) {
2392  LOG(llevError, "BUG: arch %s, name %s with level < 1\n", op->arch->name, op->name);
2393  def_lev = 1;
2394  }
2395  atk_lev = (hitter->chosen_skill ? hitter->chosen_skill->level : hitter->level)/2;
2396  /* LOG(llevDebug, "Deathstrike - attack level %d, defender level %d\n", atk_lev, def_lev); */
2397 
2398  if (atk_lev >= def_lev) {
2399  kill_lev = random_roll(0, atk_lev-1, hitter, PREFER_HIGH);
2400 
2401  /* Note that the below effectively means the ratio of the atk vs
2402  * defener level is important - if level 52 character has very little
2403  * chance of killing a level 50 monster. This should probably be
2404  * redone.
2405  */
2406  if (kill_lev >= def_lev) {
2407  *dam = op->stats.hp+10; /* take all hp. they can still save for 1/2 */
2408  /* I think this doesn't really do much. Because of
2409  * integer rounding, this only makes any difference if the
2410  * attack level is double the defender level.
2411  */
2412  *dam *= kill_lev/def_lev;
2413  }
2414  } else {
2415  *dam = 0; /* no harm done */
2416  }
2417 }
2418 
2431 static void thrown_item_effect(object *hitter, object *victim) {
2432  if (!QUERY_FLAG(hitter, FLAG_ALIVE)) {
2433  /* May not need a switch for just 2 types, but this makes it
2434  * easier for expansion.
2435  */
2436  switch (hitter->type) {
2437  case POTION:
2438  /* should player get a save throw instead of checking magic protection? */
2439  if (QUERY_FLAG(victim, FLAG_ALIVE)
2440  && !QUERY_FLAG(victim, FLAG_UNDEAD)
2441  && (victim->resist[ATNR_MAGIC] < 60))
2442  (void)ob_apply(hitter, victim, 0);
2443  break;
2444 
2445  case POISON: /* poison drinks */
2446  /* As with potions, should monster get a save? */
2447  if (QUERY_FLAG(victim, FLAG_ALIVE)
2448  && !QUERY_FLAG(victim, FLAG_UNDEAD)
2449  && (victim->resist[ATNR_POISON] < 60))
2450  (void)ob_apply(victim, hitter, 0);
2451  break;
2452 
2453  /* Removed case statements that did nothing.
2454  * food may be poisonous, but monster must be willing to eat it,
2455  * so we don't handle it here.
2456  * Containers should perhaps break open, but that code was disabled.
2457  */
2458  }
2459  }
2460 }
2461 
2471 static int adj_attackroll(object *hitter, object *target) {
2472  object *attacker = hitter;
2473  int adjust = 0;
2474 
2475  /* safety */
2476  if (!target || !hitter || !hitter->map || !target->map || !on_same_map(hitter, target)) {
2477  LOG(llevError, "BUG: adj_attackroll(): hitter and target not on same map\n");
2478  return 0;
2479  }
2480 
2481  /* aimed missiles use the owning object's sight */
2482  if (is_aimed_missile(hitter)) {
2483  if ((attacker = get_owner(hitter)) == NULL)
2484  attacker = hitter;
2485  /* A player who saves but hasn't quit still could have objects
2486  * owned by him - need to handle that case to avoid crashes.
2487  */
2488  if (QUERY_FLAG(attacker, FLAG_REMOVED))
2489  attacker = hitter;
2490  } else if (!QUERY_FLAG(hitter, FLAG_ALIVE))
2491  return 0;
2492 
2493  /* determine the condtions under which we make an attack.
2494  * Add more cases, as the need occurs. */
2495 
2496  if (!can_see_enemy(attacker, target)) {
2497  /* target is unseen */
2498  if (target->invisible || QUERY_FLAG(attacker, FLAG_BLIND))
2499  adjust -= 10;
2500  /* dark map penalty for the hitter (lacks infravision if we got here). */
2501  else if (target->map && target->map->darkness > 0 && !stand_in_light(target))
2502  adjust -= target->map->darkness;
2503  }
2504 
2505  if (QUERY_FLAG(attacker, FLAG_SCARED))
2506  adjust -= 3;
2507 
2508  if (QUERY_FLAG(target, FLAG_UNAGGRESSIVE))
2509  adjust += 1;
2510 
2511  if (QUERY_FLAG(target, FLAG_SCARED))
2512  adjust += 1;
2513 
2514  if (QUERY_FLAG(attacker, FLAG_CONFUSED))
2515  adjust -= 3;
2516 
2517  /* if we attack at a different 'altitude' its harder */
2518  if ((attacker->move_type&target->move_type) == 0)
2519  adjust -= 2;
2520 
2521  return adjust;
2522 }
2523 
2532 static int is_aimed_missile(object *op) {
2533  /* I broke what used to be one big if into a few nested
2534  * ones so that figuring out the logic is at least possible.
2535  */
2536  if (op && (op->move_type&MOVE_FLYING)) {
2537  if (op->type == ARROW || op->type == THROWN_OBJ)
2538  return 1;
2539  else if (op->type == SPELL_EFFECT
2540  && (op->subtype == SP_BULLET || op->subtype == SP_EXPLOSION))
2541  return 1;
2542  }
2543  return 0;
2544 }
static void scare_creature(object *target, object *hitter)
Definition: attack.c:1152
#define UPD_FLAGS
Definition: newclient.h:255
void spring_trap(object *trap, object *victim)
Definition: rune.c:227
#define AT_HOLYWORD
Definition: attack.h:125
#define RING
Definition: define.h:232
static int abort_attack(object *target, object *hitter, int simple_attack)
Definition: attack.c:729
#define SOUND_TYPE_HIT
Definition: sounds.h:39
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, sint16 x, sint16 y, sint16 *nx, sint16 *ny)
Definition: map.c:330
sint8 Int
Definition: living.h:78
Definition: player.h:146
const char * determine_god(object *op)
Definition: gods.c:118
archetype * find_archetype(const char *name)
Definition: arch.c:700
#define FLAG_DAMNED
Definition: define.h:614
sint8 ac
Definition: living.h:79
void share_exp(object *op, sint64 exp, const char *skill, int flag)
Definition: living.c:2150
#define UP_OBJ_FACE
Definition: object.h:356
#define DISEASE
Definition: define.h:331
MoveType move_type
Definition: object.h:277
#define ATM_KARATE
Definition: attack.h:57
void drain_stat(object *op)
Definition: living.c:748
#define FLAG_ONE_HIT
Definition: define.h:640
#define AT_ELECTRICITY
Definition: attack.h:107
#define AT_COUNTERSPELL
Definition: attack.h:123
#define FALSE
Definition: exp.c:42
#define ATM_CRUSH
Definition: attack.h:66
const char * get_ob_key_value(const object *op, const char *const key)
Definition: object.c:3701
#define ATM_PIERCE
Definition: attack.h:61
signed short sint16
Definition: global.h:72
#define AT_DEPLETE
Definition: attack.h:120
#define AT_GHOSTHIT
Definition: attack.h:113
void change_exp(object *op, sint64 exp, const char *skill_name, int flag)
Definition: living.c:2015
void leave(player *pl, int draw_exit)
Definition: server.c:1234
#define ATM_BLUD
Definition: attack.h:67
#define FLAG_SLEEP
Definition: define.h:604
materialtype_t * name_to_material(const char *name)
Definition: utils.c:262
const char * race
Definition: object.h:171
void set_owner(object *op, object *owner)
Definition: object.c:564
#define ATNR_TURN_UNDEAD
Definition: attack.h:90
#define MSG_TYPE_ATTRIBUTE_BAD_EFFECT_START
Definition: newclient.h:480
#define FLAG_HITBACK
Definition: define.h:563
static void attack_message(int dam, int type, object *op, object *hitter)
Definition: attack.c:433
static void thrown_item_effect(object *, object *)
Definition: attack.c:2431
uint16 attack_movement
Definition: object.h:242
#define SET_FLAG(xyz, p)
Definition: define.h:510
object * present_in_ob(uint8 type, const object *op)
Definition: object.c:2806
int level
Definition: attack.h:147
sstring add_refcount(sstring str)
Definition: shstr.c:202
#define SP_CONE
Definition: spells.h:109
#define NDI_ALL
Definition: newclient.h:220
attackmess_t attack_mess[NROFATTACKMESS][MAXATTACKMESS]
Definition: init.c:465
EXTERN materialtype_t * materialt
Definition: material.h:80
void shuffle_attack(object *op, int change_face)
Definition: spell_util.c:1004
char title[BIG_NAME]
Definition: player.h:216
#define FABS(x)
Definition: define.h:61
static int stick_arrow(object *op, object *tmp)
Definition: attack.c:946
#define EVENT_DEATH
Definition: plugin.h:64
#define TRAP
Definition: define.h:326
#define WAND
Definition: define.h:291
uint16 material
Definition: object.h:198
#define WEAP_CLEAVE
Definition: define.h:368
#define UPD_NAME
Definition: newclient.h:258
#define SK_KARATE
Definition: skills.h:66
#define FLAG_FRIENDLY
Definition: define.h:542
#define ATNR_DEPLETE
Definition: attack.h:93
#define DOOR
Definition: define.h:135
#define BIG_NAME
Definition: define.h:88
#define AT_CANCELLATION
Definition: attack.h:119
uint8 casting_time
Definition: global.h:358
void free_string(sstring str)
Definition: shstr.c:272
#define WEAP_SLICE
Definition: define.h:369
void fix_stopped_item(object *op, mapstruct *map, object *originator)
Definition: time.c:466
#define SET_ANIMATION(ob, newanim)
Definition: global.h:247
void esrv_update_item(int flags, object *pl, object *op)
Definition: standalone.c:200
#define ATNR_SLOW
Definition: attack.h:88
sint16 duration
Definition: object.h:254
socket_struct socket
Definition: player.h:148
sint16 invisible
Definition: object.h:211
short freearr_x[SIZEOFFREE]
Definition: object.c:75
#define PREFER_LOW
Definition: define.h:909
#define POTION
Definition: define.h:117
object * merge_ob(object *op, object *top)
Definition: object.c:1724
#define MSG_TYPE_ADMIN_PLAYER
Definition: newclient.h:414
void draw_ext_info(int flags, int pri, const object *pl, uint8 type, uint8 subtype, const char *message, const char *oldmessage)
Definition: standalone.c:171
const char * slaying
Definition: object.h:172
#define NROFNEWOBJS(xyz)
Definition: define.h:688
#define FLAG_CONFUSED
Definition: define.h:608
int free_no_drop(object *op)
Definition: time.c:536
static void tear_down_wall(object *op)
Definition: attack.c:1104
object * ranges[range_size]
Definition: player.h:157
void update_object(object *op, int action)
Definition: object.c:1112
#define MSG_TYPE_VICTIM_WAS_HIT
Definition: newclient.h:567
uint8 subtype
Definition: object.h:190
#define AT_COLD
Definition: attack.h:108
void blind_living(object *op, object *hitter, int dam)
Definition: attack.c:2276
sint64 exp
Definition: living.h:88
#define FLAG_SPLITTING
Definition: define.h:562
#define RUNE
Definition: define.h:325
#define SK_PUNCHING
Definition: skills.h:64
struct obj * above
Definition: object.h:146
int material
Definition: material.h:65
void change_luck(object *op, int value)
Definition: living.c:791
static int is_aimed_missile(object *op)
Definition: attack.c:2532
#define MSG_TYPE_ATTACK_FUMBLE
Definition: newclient.h:529
#define GOLEM
Definition: define.h:168
#define FLAG_IS_LIGHTABLE
Definition: define.h:574
object * stop_item(object *op)
Definition: time.c:426
sint16 x
Definition: object.h:179
#define GIRDLE
Definition: define.h:295
void remove_friendly_object(object *op)
Definition: friend.c:69
method_ret ob_apply(object *op, object *applier, int aflags)
Definition: ob_methods.c:59
static int did_make_save_item(object *op, int type, object *originator)
Definition: attack.c:103
#define FLAG_TEAR_DOWN
Definition: define.h:575
#define AT_BLIND
Definition: attack.h:126
const object * find_god(const char *name)
Definition: gods.c:92
#define NDI_BLACK
Definition: newclient.h:195
#define WEAP_BLUD
Definition: define.h:373
#define PETMOVE
Definition: define.h:826
#define SCRIPT_FIX_ALL
Definition: global.h:450
void draw_ext_info_format(int flags, int pri, const object *pl, uint8 type, uint8 subtype, const char *new_format, const char *old_format,...)
Definition: standalone.c:175
struct obj * enemy
Definition: object.h:232
struct archt * other_arch
Definition: object.h:264
static int kill_object(object *op, int dam, object *hitter, int type)
Definition: attack.c:1534
#define ATM_FIRE
Definition: attack.h:55
#define ATNR_CONFUSION
Definition: attack.h:82
Definition: object.h:321
char * host
Definition: newserver.h:125
#define MSG_TYPE_ATTACK_PET_DIED
Definition: newclient.h:531
#define ATM_WHIP
Definition: attack.h:65
#define PLAYER
Definition: define.h:113
static int adj_attackroll(object *hitter, object *target)
Definition: attack.c:2471
sint8 Con
Definition: living.h:78
#define FLAG_REMOVED
Definition: define.h:528
sint16 hp
Definition: living.h:81
short freearr_y[SIZEOFFREE]
Definition: object.c:81
partylist * party
Definition: player.h:237
#define FLAG_KNOWN_MAGICAL
Definition: define.h:616
#define AT_TURN_UNDEAD
Definition: attack.h:117
#define POISONING
Definition: define.h:287
#define AT_LIFE_STEALING
Definition: attack.h:128
int rndm(int min, int max)
Definition: utils.c:174
#define WEAP_WHIP
Definition: define.h:371
#define AMULET
Definition: define.h:153
#define FLAG_UNDEAD
Definition: define.h:566
#define AT_CHAOS
Definition: attack.h:122
uint32 tag_t
Definition: object.h:40
struct obj * chosen_skill
Definition: object.h:237
int change_abil(object *op, object *tmp)
Definition: living.c:443
const char * title
Definition: object.h:170
sint64 check_exp_loss(const object *op, sint64 exp)
Definition: living.c:1915
void confuse_living(object *op, object *hitter, int dam)
Definition: attack.c:2237
void remove_ob(object *op)
Definition: object.c:1515
#define NDI_RED
Definition: newclient.h:198
sint16 maxhp
Definition: living.h:82
#define POISON
Definition: define.h:119
#define ATM_ARROW
Definition: attack.h:51
#define SP_BULLET
Definition: spells.h:107
#define FLAG_ALIVE
Definition: define.h:526
#define SYMPTOM
Definition: define.h:332
#define ATNR_CANCELLATION
Definition: attack.h:92
#define TRANSPORT
Definition: define.h:114
static int get_attack_mode(object **target, object **hitter, int *simple_attack)
Definition: attack.c:691
uint32 golem_count
Definition: player.h:160
object * create_archetype(const char *name)
Definition: arch.c:625
EXTERN const char * undead_name
Definition: global.h:239
float speed_left
Definition: object.h:182
int is_wraith_pl(object *op)
Definition: player.c:173
#define SK_EXP_TOTAL
Definition: skills.h:104
#define ATNR_PARALYZE
Definition: attack.h:89
#define MSG_TYPE_VICTIM
Definition: newclient.h:336
EXTERN Chaos_Attacks ATTACKS[22]
Definition: attack.h:161
const char * materialname
Definition: object.h:197
sint32 weight
Definition: object.h:216
sint16 pk_luck_penalty
Definition: global.h:345
void update_all_los(const mapstruct *map, int x, int y)
Definition: los.c:544
uint32 peaceful
Definition: player.h:185
sint8 Wis
Definition: living.h:78
#define ATM_PUNCH
Definition: attack.h:59
#define FLAG_UNAGGRESSIVE
Definition: define.h:568
struct mapdef * map
Definition: object.h:155
#define ATM_SLASH
Definition: attack.h:60
#define ATNR_LIFE_STEALING
Definition: attack.h:101
#define ATNR_DEATH
Definition: attack.h:94
void save_throw_object(object *op, uint32 type, object *originator)
Definition: attack.c:171
#define ATM_CLAW
Definition: attack.h:58
#define HORN
Definition: define.h:147
#define SK_CLAWING
Definition: skills.h:78
#define MOVE_FLYING
Definition: define.h:703
int find_first_free_spot(const object *ob, mapstruct *m, int x, int y)
Definition: object.c:3240
#define MAXATTACKMESS
Definition: attack.h:47
#define GRIMREAPER
Definition: define.h:140
sint16 dam
Definition: living.h:87
sint64 calc_skill_exp(object *who, object *op, object *skill)
Definition: skill_util.c:599
#define ATNR_BLIND
Definition: attack.h:99
int stand_in_light(object *op)
Definition: monster.c:2159
void add_friendly_object(object *op)
Definition: friend.c:43
#define FLAG_BLOCKSVIEW
Definition: define.h:565
#define MSG_TYPE_ATTRIBUTE
Definition: newclient.h:327
const char * name
Definition: object.h:167
struct obj * env
Definition: object.h:151
#define SPELL
Definition: define.h:283
#define ATNR_INTERNAL
Definition: attack.h:100
uint16 run_away
Definition: object.h:235
#define ATNR_FEAR
Definition: attack.h:91
object * get_owner(object *op)
Definition: object.c:524
#define WEAP_STAB
Definition: define.h:370
struct obj * below
Definition: object.h:145
struct archt * more
Definition: object.h:325
int execute_global_event(int eventcode,...)
Definition: standalone.c:229
#define WEAP_PIERCE
Definition: define.h:367
#define INS_NO_WALK_ON
Definition: object.h:396
#define ATM_COLD
Definition: attack.h:54
#define TRUE
Definition: exp.c:41
struct obj * current_weapon
Definition: object.h:221
uint32 nrof
Definition: object.h:184
#define ATNR_MAGIC
Definition: attack.h:78
#define ATM_CLEAVE
Definition: attack.h:62
#define BLINDNESS
Definition: define.h:171
object * present_in_ob_by_name(int type, const char *str, const object *op)
Definition: object.c:2840
#define P_OUT_OF_MAP
Definition: map.h:272
sint16 y
Definition: object.h:179
struct pl * contr
Definition: object.h:134
#define AT_FIRE
Definition: attack.h:106
#define ATNR_HOLYWORD
Definition: attack.h:98
void paralyze_living(object *op, object *hitter, int dam)
Definition: attack.c:2324
#define FLAG_SCARED
Definition: define.h:567
#define FORCE_CONFUSION
Definition: spells.h:171
void play_sound_map(sint8 sound_type, object *emitter, int dir, const char *action)
Definition: sounds.c:90
int op_on_battleground(object *op, int *x, int *y, archetype **trophy)
Definition: player.c:4002
#define ATNR_PHYSICAL
Definition: attack.h:77
object * present_arch(const archetype *at, mapstruct *m, int x, int y)
Definition: object.c:2755
#define ATM_WRAITH_FEED
Definition: attack.h:70
static void deathstrike_living(object *op, object *hitter, int *dam)
Definition: attack.c:2379
#define MAX(x, y)
Definition: define.h:70
#define ATNR_POISON
Definition: attack.h:87
#define AT_PHYSICAL
Definition: attack.h:104
float speed
Definition: object.h:181
int process_object(object *op)
Definition: time.c:724
#define IS_LIVE(op)
Definition: define.h:459
int on_same_map(const object *op1, const object *op2)
Definition: map.c:2609
#define QUERY_FLAG(xyz, p)
Definition: define.h:514
#define CLEAR_FLAG(xyz, p)
Definition: define.h:512
#define FLAG_WIZ
Definition: define.h:527
#define WEAP_CRUSH
Definition: define.h:372
object * insert_ob_in_ob(object *op, object *where)
Definition: object.c:2510
sint8 save[NROFATTACKS]
Definition: material.h:66
#define MAX_BUF
Definition: define.h:81
#define MSG_TYPE_ADMIN
Definition: newclient.h:324
#define WEAP_SLASH
Definition: define.h:366
#define ATM_DRAIN
Definition: attack.h:52
#define ATNR_COUNTERSPELL
Definition: attack.h:96
object * insert_ob_in_map(object *op, mapstruct *m, object *originator, int flag)
Definition: object.c:1992
#define ATM_DOOR
Definition: attack.h:68
MoveType move_slow
Definition: object.h:282
#define ATNR_DRAIN
Definition: attack.h:84
const char * skill
Definition: object.h:174
#define MSG_TYPE_ATTACK_DID_KILL
Definition: newclient.h:530
#define FLAG_RUN_AWAY
Definition: define.h:576
#define NUM_SKILLS
Definition: skills.h:95
sint8 wc
Definition: living.h:79
void copy_owner(object *op, object *clone)
Definition: object.c:614
#define M_IRON
Definition: material.h:45
#define FLAG_READY_WEAPON
Definition: define.h:631
#define AT_DRAIN
Definition: attack.h:111
#define EVENT_GKILL
Definition: plugin.h:83
#define MIN(x, y)
Definition: define.h:67
void npc_call_help(object *op)
Definition: monster.c:1632
sint8 Str
Definition: living.h:78
#define THROWN_OBJ
Definition: define.h:170
const int turn_bonus[MAX_STAT+1]
Definition: living.c:165
sint16 resist[NROFATTACKS]
Definition: object.h:192
uint8 darkness
Definition: map.h:369
#define FLAG_KNOWN_CURSED
Definition: define.h:617
const char * sstring
Definition: global.h:84
#define FLAG_CURSED
Definition: define.h:613
int snprintf(char *dest, int max, const char *format,...)
Definition: porting.c:498
char killer[BIG_NAME]
Definition: player.h:222
#define AT_POISON
Definition: attack.h:114
#define FORCE
Definition: define.h:296
#define SK_WRAITH_FEED
Definition: skills.h:85
#define FLAG_NO_DAMAGE
Definition: define.h:660
#define PREFER_HIGH
Definition: define.h:908
uint32 attacktype
Definition: object.h:193
#define FLAG_GENERATOR
Definition: define.h:544
#define INS_NO_MERGE
Definition: object.h:394
#define SOUND_TYPE_HIT_BY
Definition: sounds.h:40
#define FLAG_BLIND
Definition: define.h:633
#define CONTAINER
Definition: define.h:306
struct obj * owner
Definition: object.h:228
static void cancellation(object *op)
Definition: attack.c:63
#define NUM_ANIMATIONS(ob)
Definition: global.h:255
New_Face * blank_face
Definition: image.c:66
tag_t count
Definition: object.h:157
living stats
Definition: object.h:219
sint8 Dex
Definition: living.h:78
struct archt * arch
Definition: object.h:263
object * present_arch_in_ob(const archetype *at, const object *op)
Definition: object.c:2859
object * decrease_ob_nr(object *op, uint32 i)
Definition: object.c:2345
#define AT_FEAR
Definition: attack.h:118
#define AT_SLOW
Definition: attack.h:115
#define SKILL
Definition: define.h:157
struct Settings settings
Definition: init.c:48
int hit_map(object *op, int dir, uint32 type, int full_hit)
Definition: attack.c:292
static int hit_with_one_attacktype(object *op, object *hitter, int dam, uint32 attacknum)
Definition: attack.c:1179
void check_physically_infect(object *victim, object *hitter)
Definition: disease.c:694
uint32 weapontype
Definition: object.h:222
#define SPELL_EFFECT
Definition: define.h:284
#define FLAG_APPLIED
Definition: define.h:531
#define NROFATTACKS
Definition: attack.h:45
int out_of_map(mapstruct *m, int x, int y)
Definition: map.c:2300
int execute_event(object *op, int eventcode, object *activator, object *third, const char *message, int fix)
Definition: standalone.c:225
const char * anim_suffix
Definition: object.h:169
sint16 casting_time
Definition: object.h:253
#define FORCE_NAME
Definition: spells.h:196
void update_ob_speed(object *op)
Definition: object.c:1008
#define AT_MAGIC
Definition: attack.h:105
#define GET_ANIM_ID(ob)
Definition: global.h:249
sstring add_string(const char *str)
Definition: shstr.c:116
#define EVENT_CONNECTOR
Definition: define.h:300
#define MSG_TYPE_ATTACK_DID_HIT
Definition: newclient.h:527
void play_sound_player_only(player *pl, sint8 sound_type, object *emitter, int dir, const char *action)
Definition: sounds.c:40
#define GET_MAP_OB(M, X, Y)
Definition: map.h:193
int can_see_enemy(object *op, object *enemy)
Definition: monster.c:2199
#define ATM_BASIC
Definition: attack.h:56
#define ATM_SUFFER
Definition: attack.h:69
#define FLAG_MONSTER
Definition: define.h:541
void counterspell(object *op, int dir)
static int attack_ob_simple(object *op, object *hitter, int base_dam, int base_wc)
Definition: attack.c:760
struct obj * inv
Definition: object.h:148
#define NDI_UNIQUE
Definition: newclient.h:219
void apply_anim_suffix(object *who, sstring suffix)
Definition: anim.c:289
struct obj * head
Definition: object.h:154
#define ATM_SLICE
Definition: attack.h:63
uint16 set_friendly_fire
Definition: global.h:363
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:63
#define ARROW
Definition: define.h:125
int did_make_save(const object *op, int level, int bonus)
Definition: living.c:2121
void make_visible(object *op)
Definition: player.c:3712
unsigned int uint32
Definition: global.h:58
#define ROD
Definition: define.h:115
#define FLAG_WAS_WIZ
Definition: define.h:530
#define was_destroyed(op, old_tag)
Definition: object.h:94
struct _materialtype * next
Definition: material.h:77
MoveType move_block
Definition: object.h:278
object * last_skill_ob[NUM_SKILLS]
Definition: player.h:191
#define EVENT_ATTACK
Definition: plugin.h:63
void kill_player(object *op)
Definition: player.c:3238
#define ATNR_COLD
Definition: attack.h:81
float move_slow_penalty
Definition: object.h:283
void query_name(const object *op, char *buf, size_t size)
Definition: item.c:628
void free_object(object *ob)
Definition: object.c:1238
static void slow_living(object *op, object *hitter, int dam)
Definition: attack.c:2208
Definition: map.h:346
int hit_player(object *op, int dam, object *hitter, uint32 type, int full_hit)
Definition: attack.c:1868
int random_roll(int min, int max, const object *op, int goodbad)
Definition: utils.c:51
char * buf2
Definition: attack.h:149
sint64 pk_max_experience
Definition: global.h:402
#define USING_SKILL(op, skill)
Definition: skills.h:110
New_Face * face
Definition: object.h:183
#define AT_CONFUSION
Definition: attack.h:109
int friendly_fire(object *op, object *hitter)
Definition: attack.c:1818
#define FLAG_NO_PICK
Definition: define.h:535
#define ATM_STAB
Definition: attack.h:64
int pk_max_experience_percent
Definition: global.h:403
#define IS_ARROW(op)
Definition: define.h:464
void replace_insert_ob_in_map(const char *arch_string, object *op)
Definition: object.c:2271
sint16 level
Definition: object.h:202
#define AT_ACID
Definition: attack.h:110
sint16 * discrete_damage
Definition: object.h:291
void fix_object(object *op)
Definition: living.c:900
#define ATNR_CHAOS
Definition: attack.h:95
#define ATNR_ACID
Definition: attack.h:83
#define SP_EXPLOSION
Definition: spells.h:108
#define AT_DEATH
Definition: attack.h:121
object * arch_to_object(archetype *at)
Definition: arch.c:576
sint32 value
Definition: object.h:201
int attack_ob(object *op, object *hitter)
Definition: attack.c:929
sint8 magic
Definition: object.h:199
const char * name
Definition: object.h:322
#define WEAP_HIT
Definition: define.h:365
#define MSG_TYPE_ATTACK
Definition: newclient.h:331
object * fix_stopped_arrow(object *op)
Definition: time.c:483
static void poison_living(object *op, object *hitter, int dam)
Definition: attack.c:2137
uint8 type
Definition: object.h:189
object * hit_with_arrow(object *op, object *victim)
Definition: attack.c:975
#define AT_PARALYZE
Definition: attack.h:116
uint8 simple_exp
Definition: global.h:351
#define ATM_ELEC
Definition: attack.h:53
const char *const attacks[NROFATTACKS]
Definition: living.c:220
#define MSG_TYPE_ATTACK_PET_HIT
Definition: newclient.h:528
sint32 food
Definition: living.h:89
int attacktype
Definition: attack.h:154
#define FLAG_FREED
Definition: define.h:529
uint32 hide
Definition: object.h:238