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