Crossfire Server  1.75.0
attack.cpp
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 static int hit_with_one_attacktype(
42  object *op, object *hitter, int dam, uint32_t attacknum);
43 
51 static void cancellation(object *op) {
52  if (op->invisible)
53  return;
54 
55  if (QUERY_FLAG(op, FLAG_ALIVE) || op->type == CONTAINER || op->type == THROWN_OBJ) {
56  /* Recur through the inventory */
57  FOR_INV_PREPARE(op, inv)
58  if (!did_make_save_item(inv, AT_CANCELLATION, op))
59  cancellation(inv);
61  } else if (FABS(op->magic) <= rndm(0, 5)) {
62  /* Nullify this object. This code could probably be more complete */
63  /* in what abilities it should cancel */
64  op->magic = 0;
69  if (op->env && op->env->type == PLAYER) {
71  }
72  }
73 }
74 
75 static void object_get_materialtype(object* op, materialtype_t** mt) {
76  set_materialname(op);
77  if (op->materialname == NULL) {
78  for (auto material : materials) {
79  *mt = material;
80  if (op->material & (*mt)->material) {
81  return;
82  }
83  }
84  *mt = nullptr;
85  } else
86  *mt = name_to_material(op->materialname);
87 }
88 
104 static int did_make_save_item(object *op, int type, object *originator) {
105  int i, roll, saves = 0, attacks = 0, number;
106  materialtype_t* mt;
107  object_get_materialtype(op, &mt);
108  if (mt == NULL)
109  return TRUE;
110  roll = rndm(1, 20);
111 
112  /* the attacktypes have no meaning for object saves
113  * If the type is only magic, don't adjust type - basically, if
114  * pure magic is hitting an object, it should save. However, if it
115  * is magic teamed with something else, then strip out the
116  * magic type, and instead let the fire, cold, or whatever component
117  * destroy the item. Otherwise, you get the case of poisoncloud
118  * destroying objects because it has magic attacktype.
119  */
120  if (type != AT_MAGIC)
124  AT_MAGIC);
125 
126  if (type == 0)
127  return TRUE;
128  if (roll == 20)
129  return TRUE;
130 
131  for (number = 0; number < NROFATTACKS; number++) {
132  i = 1<<number;
133  if (!(i&type))
134  continue;
135  attacks++;
136  if (op->resist[number] == 100)
137  saves++;
138  else if (roll >= mt->save[number]-op->magic-op->resist[number]/100)
139  saves++;
140  else if ((20-mt->save[number])/3 > originator->stats.dam)
141  saves++;
142  }
143 
144  if (saves == attacks || attacks == 0)
145  return TRUE;
146  if (saves == 0 || rndm(1, attacks) > saves)
147  return FALSE;
148  return TRUE;
149 }
150 
151 static void put_in_icecube(object* op, object* originator) {
152  archetype* at = find_archetype("icecube");
153  if (at == NULL)
154  return;
155  op = stop_item(op);
156  if (op == NULL)
157  return;
158 
159  // Put in existing icecube if one exists, otherwise make one
160  object* tmp = map_find_by_archetype(op->map, op->x, op->y, at);
161  if (tmp == NULL) {
162  tmp = arch_to_object(at);
163  /* This was in the old (pre new movement code) -
164  * icecubes have slow_move set to 1 - don't want
165  * that for ones we create.
166  */
167  tmp->move_slow_penalty = 0;
168  tmp->move_slow = 0;
169  object_insert_in_map_at(tmp, op->map, originator, 0, op->x, op->y);
170  }
171  if (!QUERY_FLAG(op, FLAG_REMOVED))
172  object_remove(op);
173  (void)object_insert_in_ob(op, tmp);
174 }
175 
176 object *blame(object *op) {
177  if (op == NULL) {
178  return NULL;
179  }
180  if (op->type == PLAYER) {
181  return op;
182  }
183  object *owner = object_get_owner(op);
184  if (owner != NULL && owner->type == PLAYER) {
185  return owner;
186  }
187  return NULL;
188 }
189 
202 void save_throw_object(object *op, uint32_t type, object *originator) {
203  int dam;
204 
205  if (!did_make_save_item(op, type, originator)) {
206  object *env = op->env;
207  int x = op->x, y = op->y;
208  mapstruct *m = op->map;
209  /* For use with burning off equipped items */
210  int weight = op->weight;
211 
212  op = stop_item(op);
213  if (op == NULL)
214  return;
215 
216  /*
217  * If this object is a transport and has players in it, make them disembark.
218  */
219  if (op->type == TRANSPORT && op->inv) {
220  if (op->map == NULL) {
221  LOG(llevError, "Transport %s not on a map but with an item %s in it?\n", op->name, op->inv->name);
222  } else {
223  char name[MAX_BUF];
224  query_name(op, name, sizeof(name));
225  FOR_INV_PREPARE(op, inv) {
226  if (inv->contr) {
228  "You are expelled from the %s during its destruction.",
229  name);
230  inv->contr->transport = NULL;
231  }
232  }
233  FOR_INV_FINISH();
234  }
235  }
236 
237 
238  /* Set off runes in the inventory of the object being destroyed. */
239  FOR_INV_PREPARE(op, inv)
240  if (inv->type == RUNE)
241  spring_trap(inv, originator);
242  FOR_INV_FINISH();
243 
244  if (QUERY_FLAG(op, FLAG_UNPAID)) {
245  object *badguy = blame(originator);
246  if (badguy != NULL) {
247  // Punish player for destroying unpaid item
248  commit_crime(badguy, "Destruction of unpaid property");
249  }
250  }
251 
252  /* Hacked the following so that type LIGHTER will work.
253  * Also, objects which are potenital "lights" that are hit by
254  * flame/elect attacks will be set to glow. "lights" are any
255  * object with +/- glow_radius and an "other_arch" to change to.
256  * (and please note that we cant fail our save and reach this
257  * function if the object doesnt contain a material that can burn.
258  * So forget lighting magical swords on fire with this!) -b.t.
259  */
260  if (type&(AT_FIRE|AT_ELECTRICITY)
261  && op->other_arch
262  && QUERY_FLAG(op, FLAG_IS_LIGHTABLE)) {
263  const char *arch = op->other_arch->name;
264  int no_pick = QUERY_FLAG(op, FLAG_NO_PICK);
265 
266  op = object_decrease_nrof(op, 1);
267  if (op)
268  fix_stopped_item(op, m, originator);
269  op = create_archetype(arch);
270  if (op != NULL) {
271  if (env) {
272  op->x = env->x,
273  op->y = env->y;
274  object_insert_in_ob(op, env);
275  } else {
276  if (no_pick) {
277  SET_FLAG(op, FLAG_NO_PICK);
278  }
279  object_insert_in_map_at(op, m, originator, 0, x, y);
280  }
281  }
282  return;
283  }
284  if (type&AT_CANCELLATION) { /* Cancellation. */
285  cancellation(op);
286  fix_stopped_item(op, m, originator);
287  return;
288  }
289  if (op->nrof > 1) {
290  op = object_decrease_nrof(op, rndm(0, op->nrof-1));
291  if (op)
292  fix_stopped_item(op, m, originator);
293  } else {
294  if (!QUERY_FLAG(op, FLAG_REMOVED))
295  object_remove(op);
297  }
298  if (type&(AT_FIRE|AT_ELECTRICITY)) {
299  if (env) {
300  /* Check to see if the item being burnt is being worn */
301  if (QUERY_FLAG(op, FLAG_APPLIED)) {
302  /* if the object is applied, it should be safe to assume env is a player or creature. */
303  if (env->resist[ATNR_FIRE] < 100)
304  /* Should the message type be something different? */
306  "OUCH! It burns!");
307  else
309  "Despite the flame, you feel nothing.");
310  /* burning off an item causes 1 point of fire damage for every kilogram of mass the item has */
311  dam = weight / 1000 * (100 - env->resist[ATNR_FIRE]) / 100;
312  /* Double the damage on cursed items */
313  if (QUERY_FLAG(op, FLAG_CURSED))
314  dam *= 2;
315  /* Triple the damage on damned items. A cursed and damned item would thus inflict 6x damage. */
316  if (QUERY_FLAG(op, FLAG_DAMNED))
317  dam *= 3;
318  env->stats.hp -= dam;
319  /* You die at -1, not 0 */
320  if (env->stats.hp < 0)
321  kill_player(env, NULL);
322  }
323  op = create_archetype("burnout");
324  op->x = env->x,
325  op->y = env->y;
326  object_insert_in_ob(op, env);
327  } else {
328  object_replace_insert_in_map("burnout", originator);
329  }
330  }
331  return;
332  }
333  /* The value of 50 is arbitrary. */
334  if (type & AT_COLD && (op->resist[ATNR_COLD] < 50) &&
335  !QUERY_FLAG(op, FLAG_NO_PICK) && (RANDOM() & 2)) {
336  put_in_icecube(op, originator);
337  }
338 }
339 
355 int hit_map(object *op, int dir, uint32_t type, int full_hit) {
356  mapstruct *map;
357  int16_t x, y;
358  int retflag = 0; /* added this flag.. will return 1 if it hits a monster */
359  tag_t op_tag;
360 
361  if (QUERY_FLAG(op, FLAG_FREED)) {
362  LOG(llevError, "BUG: hit_map(): free object\n");
363  return 0;
364  }
365 
366  if (QUERY_FLAG(op, FLAG_REMOVED) || op->env != NULL) {
367  LOG(llevError, "BUG: hit_map(): hitter (arch %s, name %s) not on a map\n", op->arch->name, op->name);
368  return 0;
369  }
370 
371  if (!op->map) {
372  LOG(llevError, "BUG: hit_map(): %s has no map\n", op->name);
373  return 0;
374  }
375 
376  op = HEAD(op);
377  op_tag = op->count;
378 
379  map = op->map;
380  x = op->x+freearr_x[dir];
381  y = op->y+freearr_y[dir];
382  if (get_map_flags(map, &map, x, y, &x, &y)&P_OUT_OF_MAP)
383  return 0;
384 
385  /* peterm: a few special cases for special attacktypes --counterspell
386  * must be out here because it strikes things which are not alive
387  */
388 
389  if (type&AT_COUNTERSPELL) {
390  counterspell(op, dir); /* see spell_effect.c */
391 
392  /* If the only attacktype is counterspell or magic, don't need
393  * to do any further processing.
394  */
395  if (!(type&~(AT_COUNTERSPELL|AT_MAGIC))) {
396  return 0;
397  }
398  type &= ~AT_COUNTERSPELL;
399  }
400 
401  if (type&AT_CHAOS) {
402  shuffle_attack(op);
404  type &= ~AT_CHAOS;
405  }
406 
407  FOR_MAP_PREPARE(map, x, y, tmp) {
408  if (QUERY_FLAG(tmp, FLAG_FREED)) {
409  LOG(llevError, "BUG: hit_map(): found freed object\n");
410  break;
411  }
412 
413  /* Something could have happened to 'tmp' while 'tmp->below' was processed.
414  * For example, 'tmp' was put in an icecube.
415  * This is one of the few cases where on_same_map should not be used.
416  */
417  if (tmp->map != map || tmp->x != x || tmp->y != y)
418  continue;
419 
420  tmp = HEAD(tmp);
421 
422  /* Need to hit everyone in the transport with this spell */
423  if (tmp->type == TRANSPORT) {
424  FOR_INV_PREPARE(tmp, pl)
425  if (pl->type == PLAYER)
426  hit_player(pl, op->stats.dam, op, type, full_hit);
427  FOR_INV_FINISH();
428  }
429 
430  if (QUERY_FLAG(tmp, FLAG_ALIVE)) {
431  hit_player(tmp, op->stats.dam, op, type, full_hit);
432  retflag |= 1;
433  if (object_was_destroyed(op, op_tag))
434  break;
435  }
436  /* Here we are potentially destroying an object. If the object has
437  * NO_PASS set, it is also immune - you can't destroy walls. Note
438  * that weak walls have is_alive set, which prevent objects from
439  * passing over/through them. We don't care what type of movement
440  * the wall blocks - if it blocks any type of movement, can't be
441  * destroyed right now.
442  */
443  else if ((tmp->material || tmp->materialname) && op->stats.dam > 0 && !tmp->move_block) {
444  save_throw_object(tmp, type, op);
445  if (object_was_destroyed(op, op_tag))
446  break;
447  }
448  } FOR_MAP_FINISH();
449  return 0;
450 }
451 
463 static uint8_t get_attack_message_type(int type, const object *op, const object *hitter) {
464  if ((hitter->type == DISEASE
465  || hitter->type == SYMPTOM
466  || hitter->type == POISONING
467  || (type&AT_POISON && IS_LIVE(op)))) {
468  return ATM_SUFFER;
469  }
470 
471  if (op->type == DOOR) {
472  return ATM_DOOR;
473  }
474 
475  if (hitter->type == PLAYER && IS_LIVE(op)) {
476  if (USING_SKILL(hitter, SK_KARATE)) {
477  return ATM_KARATE;
478  }
479  if (USING_SKILL(hitter, SK_CLAWING)) {
480  return ATM_CLAW;
481  }
482  if (USING_SKILL(hitter, SK_PUNCHING)) {
483  return ATM_PUNCH;
484  }
485  if (USING_SKILL(hitter, SK_WRAITH_FEED)) {
486  return ATM_WRAITH_FEED;
487  }
488  }
489 
490  if (IS_ARROW(hitter) && (type == AT_PHYSICAL || type == AT_MAGIC)) {
491  return ATM_ARROW;
492  }
493 
494  if (type&AT_DRAIN && IS_LIVE(op)) {
495  return ATM_DRAIN;
496  }
497  if (type&AT_ELECTRICITY && IS_LIVE(op)) {
498  return ATM_ELEC;
499  }
500  if (type&AT_COLD && IS_LIVE(op)) {
501  return ATM_COLD;
502  }
503  if (type&AT_FIRE) {
504  return ATM_FIRE;
505  }
506 
507  if (hitter->current_weapon != NULL) {
508  switch (hitter->current_weapon->weapontype) {
509  case WEAP_HIT: return ATM_BASIC;
510  case WEAP_SLASH: return ATM_SLASH;
511  case WEAP_PIERCE: return ATM_PIERCE;
512  case WEAP_CLEAVE: return ATM_CLEAVE;
513  case WEAP_SLICE: return ATM_SLICE;
514  case WEAP_STAB: return ATM_STAB;
515  case WEAP_WHIP: return ATM_WHIP;
516  case WEAP_CRUSH: return ATM_CRUSH;
517  case WEAP_BLUD: return ATM_BLUD;
518  default: return ATM_BASIC;
519  }
520  }
521 
522  return ATM_BASIC;
523 }
524 
538 void get_attack_message_for_attack_type(int dam, uint8_t atm_type, const char *victim_name, char *buf1, char *buf2) {
539  snprintf(buf1, MAX_BUF, "hit");
540  snprintf(buf2, MAX_BUF, "hits");
541 
542  for (int i = 0; i < MAXATTACKMESS && attack_mess[atm_type][i].level != -1; i++) {
543  if (dam < attack_mess[atm_type][i].level
544  || attack_mess[atm_type][i+1].level == -1) {
545  snprintf(buf1, MAX_BUF, "%s %s%s", attack_mess[atm_type][i].buf1, victim_name, attack_mess[atm_type][i].buf2);
546  snprintf(buf2, MAX_BUF, "%s", attack_mess[atm_type][i].buf3);
547  return;
548  }
549  }
550 }
551 
569 static void get_attack_message(int dam, int type, const object *op, const object *hitter, char *buf1, char *buf2) {
570  if (dam == 9998 && op->type == DOOR) {
571  snprintf(buf1, MAX_BUF, "unlock %s", op->name);
572  snprintf(buf2, MAX_BUF, " unlocks");
573  return;
574  }
575  if (dam < 0) {
576  snprintf(buf1, MAX_BUF, "hit %s", op->name);
577  snprintf(buf2, MAX_BUF, " hits");
578  return;
579  }
580  if (dam == 0) {
581  snprintf(buf1, MAX_BUF, "missed %s", op->name);
582  snprintf(buf2, MAX_BUF, " misses");
583  return;
584  }
585 
586  snprintf(buf1, MAX_BUF, "hit");
587  snprintf(buf2, MAX_BUF, "hits");
588 
589  uint8_t atm_type = get_attack_message_type(type, op, hitter);
590  get_attack_message_for_attack_type(dam, atm_type, op->name, buf1, buf2);
591 }
592 
608 static void attack_message(int dam, int type, object *op, object *hitter) {
609  char buf[VERY_BIG_BUF], buf1[MAX_BUF], buf2[MAX_BUF];
610  object *owner;
611 
612  if (dam > 0) {
613  if (hitter->chosen_skill)
614  play_sound_map(SOUND_TYPE_HIT, hitter, 0, hitter->chosen_skill->name);
615  }
616 
617  /* bail out if a monster is casting spells */
618  owner = object_get_owner(hitter);
619  if (hitter->type != PLAYER && (owner == NULL || owner->type != PLAYER))
620  return;
621 
622  /* scale down magic considerably. */
623  if (type&AT_MAGIC && rndm(0, 5))
624  return;
625 
626  get_attack_message(dam, type, op, hitter, buf1, buf2);
627 
628  /* Did a player hurt another player? Inform both! */
629  /* only show half the player->player combat messages */
630  if (op->type == PLAYER
631  && rndm(0, 1)
632  && ((owner != NULL ? owner : hitter)->type) == PLAYER) {
633  if (owner != NULL)
634  snprintf(buf, sizeof(buf), "%s's %s%s you.", owner->name, hitter->name, buf2);
635  else {
636  snprintf(buf, sizeof(buf), "%s%s you.", hitter->name, buf2);
637  }
639  } /* end of player hitting player */
640 
641  /* scale down these messages too */
642  /*if(hitter->type == PLAYER && rndm(0, 2) == 0) {*/
643  if (hitter->type == PLAYER) {
644  snprintf(buf, sizeof(buf), "You %s.", buf1);
646  buf);
647  } else if (owner != NULL && owner->type == PLAYER) {
648  /* look for stacked spells and start reducing the message chances */
649  if (hitter->type == SPELL_EFFECT
650  && (hitter->subtype == SP_EXPLOSION || hitter->subtype == SP_BULLET || hitter->subtype == SP_CONE)) {
651  int i = 4;
652  mapstruct *map = hitter->map;
653  if (OUT_OF_REAL_MAP(map, hitter->x, hitter->y))
654  return;
655  FOR_MAP_PREPARE(map, hitter->x, hitter->y, next)
656  if (next->type == SPELL_EFFECT
657  && (next->subtype == SP_EXPLOSION || next->subtype == SP_BULLET || next->subtype == SP_CONE)) {
658  i *= 3;
659  if (i > 10000)
660  /* no need to test more, and avoid overflows */
661  break;
662  }
663  FOR_MAP_FINISH();
664  if (i < 0)
665  return;
666  if (rndm(0, i) != 0)
667  return;
668  } else if (rndm(0, 5) != 0)
669  return;
670  play_sound_map(SOUND_TYPE_HIT, owner, 0, "hit");
672  "Your %s%s %s.",
673  hitter->name, buf2, op->name);
674  }
675 }
676 
688 static int get_attack_mode(object **target, object **hitter,
689  int *simple_attack) {
690  if (QUERY_FLAG(*target, FLAG_FREED) || QUERY_FLAG(*hitter, FLAG_FREED)) {
691  LOG(llevError, "BUG: get_attack_mode(): freed object\n");
692  return 1;
693  }
694  *target = HEAD(*target);
695  *hitter = HEAD(*hitter);
696  if ((*hitter)->env != NULL || (*target)->env != NULL) {
697  *simple_attack = 1;
698  return 0;
699  }
700  if (QUERY_FLAG(*target, FLAG_REMOVED)
701  || QUERY_FLAG(*hitter, FLAG_REMOVED)
702  || (*hitter)->map == NULL
703  || !on_same_map((*hitter), (*target))) {
704  LOG(llevError, "BUG: hitter (arch %s, name %s) with no relation to target\n", (*hitter)->arch->name, (*hitter)->name);
705  return 1;
706  }
707  *simple_attack = 0;
708  return 0;
709 }
710 
724 static int abort_attack(object *target, object *hitter, int simple_attack) {
725  int new_mode;
726 
727  if (hitter->env == target || target->env == hitter)
728  new_mode = 1;
729  else if (QUERY_FLAG(hitter, FLAG_REMOVED)
730  || QUERY_FLAG(target, FLAG_REMOVED)
731  || hitter->map == NULL || !on_same_map(hitter, target))
732  return 1;
733  else
734  new_mode = 0;
735  return new_mode != simple_attack;
736 }
737 
738 static void thrown_item_effect(object *, object *);
739 
767 static int attack_ob_simple(object *op, object *hitter, int base_dam, int wc) {
768  int simple_attack, roll, dam;
769  uint32_t type;
770  tag_t op_tag, hitter_tag;
771  const char *anim_suffix = NULL;
772 
773  if (get_attack_mode(&op, &hitter, &simple_attack))
774  return 1;
775 
776  /* This is used to handle script_weapons with weapons, only for players. */
777  if (hitter->type == PLAYER) {
778  if (hitter->current_weapon != NULL) {
780  hitter, op, NULL, SCRIPT_FIX_ALL) != 0)
781  return 0;
782  }
783  }
784 
785  if (hitter->current_weapon) {
786  anim_suffix = hitter->current_weapon->anim_suffix;
787  } else if (hitter->chosen_skill) {
788  anim_suffix = hitter->chosen_skill->anim_suffix;
789  }
790 
791  if (!anim_suffix) {
792  anim_suffix = "attack";
793  }
794  apply_anim_suffix(hitter, anim_suffix);
795 
796 
797  op_tag = op->count;
798  hitter_tag = hitter->count;
799  /*
800  * A little check to make it more difficult to dance forward and back
801  * to avoid ever being hit by monsters.
802  */
803  if (!simple_attack && QUERY_FLAG(op, FLAG_MONSTER)
804  && op->speed_left > -(FABS(op->speed))*0.3) {
805  /* Decrease speed BEFORE calling process_object. Otherwise, an
806  * infinite loop occurs, with process_object calling monster_move(),
807  * which then gets here again. By decreasing the speed before
808  * we call process_object, the 'if' statement above will fail.
809  */
810  op->speed_left--;
811  process_object(op);
812  if (object_was_destroyed(op, op_tag)
813  || object_was_destroyed(hitter, hitter_tag)
814  || abort_attack(op, hitter, simple_attack))
815  return 1;
816  }
817 
818  roll = random_roll(1, 20, hitter, PREFER_HIGH);
819 
820  /* Adjust roll for various situations. */
821  if (!simple_attack)
822  roll += adj_attackroll(hitter, op);
823 
824  /* See if we hit the creature */
825  if (roll >= 20 || op->stats.ac >= wc-roll) {
826  if (settings.casting_time == TRUE) {
827  if (hitter->type == PLAYER && hitter->casting_time > -1) {
828  hitter->casting_time = -1;
830  "You attacked and lost your spell!");
831  }
832  if (op->casting_time > -1 && base_dam > 0) {
833  op->casting_time = -1;
834  if (op->type == PLAYER) {
836  "You were hit and lost your spell!");
839  "%s was hit by %s and lost a spell.",
840  op->name, hitter->name);
841  }
842  }
843  }
844  if (!simple_attack) {
845  /* If you hit something, the victim should *always *wake up.
846  * Before, invisible hitters could avoid doing this.
847  * -b.t. */
848  if (QUERY_FLAG(op, FLAG_SLEEP))
849  CLEAR_FLAG(op, FLAG_SLEEP);
850 
851  /* If the victim can't see the attacker, it may alert others
852  * for help. */
853  if (op->type != PLAYER && !monster_can_see_enemy(op, hitter)
854  && !object_get_owner(op) && rndm(0, op->stats.Int))
856 
857  /* if you were hidden and hit by a creature, you are discovered*/
858  if (op->hide && QUERY_FLAG(hitter, FLAG_ALIVE)) {
859  make_visible(op);
860  if (op->type == PLAYER)
862  "You were hit by a wild attack. You are no longer hidden!");
863  }
864 
865  /* thrown items (hitter) will have various effects
866  * when they hit the victim. For things like thrown daggers,
867  * this sets 'hitter' to the actual dagger, and not the
868  * wrapper object.
869  */
870  thrown_item_effect(hitter, op);
871  if (object_was_destroyed(hitter, hitter_tag)
872  || object_was_destroyed(op, op_tag)
873  || abort_attack(op, hitter, simple_attack)) {
874  return 0;
875  }
876  }
877 
878  /* Need to do at least 1 damage, otherwise there is no point
879  * to go further and it will cause FPE's below.
880  */
881  if (base_dam <= 0)
882  base_dam = 1;
883 
884  type = hitter->attacktype;
885  if (!type)
886  type = AT_PHYSICAL;
887  /* Handle monsters that hit back */
888  if (!simple_attack && QUERY_FLAG(op, FLAG_HITBACK)
889  && QUERY_FLAG(hitter, FLAG_ALIVE)) {
890  if (op->attacktype&AT_ACID && hitter->type == PLAYER)
892  "You are splashed by acid!\n");
893  hit_player(hitter, random_roll(0, (op->stats.dam), hitter, PREFER_LOW), op, op->attacktype, 1);
894  if (object_was_destroyed(op, op_tag)
895  || object_was_destroyed(hitter, hitter_tag)
896  || abort_attack(op, hitter, simple_attack)) {
897  return 0;
898  }
899  }
900 
901  /* In the new attack code, it should handle multiple attack
902  * types in its area, so remove it from here.
903  */
904  dam = hit_player(op, random_roll(1, base_dam, hitter, PREFER_HIGH), hitter, type, 1);
905  if (object_was_destroyed(op, op_tag)
906  || object_was_destroyed(hitter, hitter_tag)
907  || abort_attack(op, hitter, simple_attack)) {
908  return 0;
909  }
910 
911  if (object_value_set(hitter, "is_guard") && is_criminal(op)) {
912  // Guards may attack non-criminals (e.g. if they are a pet or get
913  // hit), but don't arrest unless target is actually criminal.
915  "The %s arrests you!", hitter->name);
916  player_arrest(op);
917  }
918  } else {/* end of if hitter hit op */
919  play_sound_map(SOUND_TYPE_HIT, hitter, 0, "miss");
920  dam = 0; /* if we missed, dam=0 */
921  }
922 
923  /*attack_message(dam, type, op, hitter);*/
924 
925  return dam;
926 }
927 
937 int attack_ob(object *op, object *hitter) {
938  hitter = HEAD(hitter);
939  return attack_ob_simple(op, hitter, hitter->stats.dam, hitter->stats.wc);
940 }
941 
952 static int stick_arrow(object *op, object *tmp) {
953  /* If the missile hit a player, we insert it in their inventory.
954  * However, if the missile is heavy, we don't do so (assume it falls
955  * to the ground after a hit). What a good value for this is up to
956  * debate - 5000 is 5 kg, so arrows, knives, and other light weapons
957  * stick around.
958  */
959  if (op->weight <= 5000 && tmp->stats.hp >= 0) {
960  object_remove(op);
961  object_insert_in_ob(op, HEAD(tmp));
962  return 1;
963  } else
964  return 0;
965 }
966 
979 object *hit_with_arrow(object *op, object *victim) {
980  object *container, *hitter;
981  int hit_something = 0;
982  tag_t victim_tag, hitter_tag, container_tag;
983  int16_t victim_x, victim_y;
984  mapstruct *victim_map;
985  const char *old_skill = NULL;
986 
987  /* Disassemble missile */
988  hitter = op->inv;
989  FOR_OB_AND_BELOW_PREPARE(hitter) {
990  if (hitter->type != EVENT_CONNECTOR) {
991  break;
992  }
993  }
995  if (!hitter) {
996  container = NULL;
997  hitter = op;
998  if (free_no_drop(hitter))
999  return NULL;
1000  } else {
1001  container = op;
1002  object_remove(hitter);
1003  if (free_no_drop(hitter))
1004  return NULL;
1005 
1006  object_insert_in_map_at(hitter, container->map, hitter, INS_NO_MERGE|INS_NO_WALK_ON, container->x, container->y);
1007  /* Note that we now have an empty THROWN_OBJ on the map. Code that
1008  * might be called until this THROWN_OBJ is either reassembled or
1009  * removed at the end of this function must be able to deal with empty
1010  * THROWN_OBJs. */
1011  container_tag = container->count;
1012  }
1013 
1014  /* Try to hit victim */
1015  victim_x = victim->x;
1016  victim_y = victim->y;
1017  victim_map = victim->map;
1018  victim_tag = victim->count;
1019  hitter_tag = hitter->count;
1020  /* FIXME provide also to script the skill? hitter is the throwed
1021  items, but there is no information about the fact it was
1022  thrown
1023  */
1024  if (events_execute_object_event(op, EVENT_ATTACKS, hitter, victim, NULL, SCRIPT_FIX_ALL) == 0) {
1025  /*
1026  * temporary set the hitter's skill to the one associated with the
1027  * throw wrapper. This is needed to that thrower gets it's xp at the
1028  * correct level. This might proves an awfull hack :/ We should really
1029  * provide attack_ob_simple with the skill to use...
1030  */
1031  if (container != NULL) {
1032  old_skill = hitter->skill;
1033  hitter->skill = add_refcount(container->skill);
1034  }
1035  hit_something = attack_ob_simple(victim, hitter, op->stats.dam, op->stats.wc);
1036  }
1037  /* Arrow attacks door, rune of summoning is triggered, demon is put on
1038  * arrow, move_apply() calls this function, arrow sticks in demon,
1039  * attack_ob_simple() returns, and we've got an arrow that still exists
1040  * but is no longer on the map. Ugh. (Beware: Such things can happen at
1041  * other places as well!)
1042  */
1043  if (object_was_destroyed(hitter, hitter_tag) || hitter->env != NULL) {
1044  if (container) {
1045  object_remove(container);
1046  object_free_drop_inventory(container);
1047  }
1048  return NULL;
1049  }
1050  if (container != NULL) {
1051  free_string(hitter->skill);
1052  hitter->skill = old_skill;
1053  }
1054  /* Missile hit victim */
1055  /* if the speed is > 10, then this is a fast moving arrow, we go straight
1056  * through the target
1057  */
1058  if (hit_something && op->speed <= 10.0) {
1059  /* Stop arrow */
1060  if (container == NULL) {
1061  hitter = fix_stopped_arrow(hitter);
1062  if (hitter == NULL)
1063  return NULL;
1064  } else {
1065  if(!object_was_destroyed(container, container_tag)) {
1066  object_remove(container);
1067  object_free_drop_inventory(container);
1068  }
1069  }
1070 
1071  /* Try to stick arrow into victim */
1072  if (!object_was_destroyed(victim, victim_tag)
1073  && stick_arrow(hitter, victim)) {
1074  object_set_owner(hitter, NULL);
1075  return NULL;
1076  }
1077 
1078  /* Else try to put arrow on victim's map square
1079  * remove check for P_WALL here. If the arrow got to this
1080  * space, that is good enough - with the new movement code,
1081  * there is now the potential for lots of spaces where something
1082  * can fly over but not otherwise move over. What is the correct
1083  * way to handle those otherwise?
1084  */
1085  if (victim_x != hitter->x || victim_y != hitter->y) {
1086  object_remove(hitter);
1087  object_set_owner(hitter, NULL);
1088  object_insert_in_map_at(hitter, victim_map, hitter, 0, victim_x, victim_y);
1089  } else {
1090  /* Else leave arrow where it is */
1091  object_merge(hitter, NULL);
1092  object_set_owner(hitter, NULL);
1093  }
1094  return NULL;
1095  }
1096 
1097  if (hit_something && op->speed >= 10.0)
1098  op->speed -= 1.0;
1099 
1100  /* Missile missed victim - reassemble missile */
1101  if (container) {
1102  object_remove(hitter);
1103  object_insert_in_ob(hitter, container);
1104  }
1105  return op;
1106 }
1114 static void tear_down_wall(object *op) {
1115  int perc = 0;
1116 
1117  if (!op->stats.maxhp) {
1118  LOG(llevError, "TEAR_DOWN wall %s had no maxhp.\n", op->name);
1119  perc = 1;
1120  } else if (!GET_ANIM_ID(op)) {
1121  /* Object has been called - no animations, so remove it */
1122  if (op->stats.hp < 0) {
1123  object_remove(op); /* Should update LOS */
1125  /* Don't know why this is here - object_remove() should do it for us */
1126  /*update_position(m, x, y);*/
1127  }
1128  return; /* no animations, so nothing more to do */
1129  }
1130  assert(op->stats.maxhp > 0);
1131  perc = NUM_ANIMATIONS(op)-((int)NUM_ANIMATIONS(op)*op->stats.hp)/op->stats.maxhp;
1132 
1133  if (perc >= (int)NUM_ANIMATIONS(op))
1134  perc = NUM_ANIMATIONS(op)-1;
1135  else if (perc < 1)
1136  perc = 1;
1137  SET_ANIMATION(op, perc);
1139  if (perc == NUM_ANIMATIONS(op)-1) { /* Reached the last animation */
1140  if (op->face == blank_face) {
1141  /* If the last face is blank, remove the ob */
1142  object_remove(op); /* Should update LOS */
1144 
1145  /* object_remove() should call update_position for us */
1146  /*update_position(m, x, y);*/
1147  } else { /* The last face was not blank, leave an image */
1149  update_all_los(op->map, op->x, op->y);
1150  op->move_block = 0;
1151  CLEAR_FLAG(op, FLAG_ALIVE);
1152  }
1153  }
1154 }
1155 
1163 static void scare_creature(object *target, object *hitter) {
1164  object *owner = object_get_owner(hitter);
1165 
1166  if (!owner)
1167  owner = hitter;
1168 
1169  SET_FLAG(target, FLAG_SCARED);
1170  if (!target->enemy)
1171  object_set_enemy(target, owner);
1172 }
1173 
1174 static int hit_with_drain(object *op, object *hitter, int dam) {
1175  /* rate is the proportion of exp drained. High rate means
1176  * not much is drained, low rate means a lot is drained.
1177  */
1178  int rate;
1179 
1180  // Victim loses 1/rate of their current XP, so this scales from 4%
1181  // of their XP at -100 resist drain, to 2% at no resistance, to 1%
1182  // at 100% resist drain.
1183  // Note that this function is not actually called when a player has
1184  // 100% resistance, as hit_with_one_attacktype() will skip attacks
1185  // when the target has >= 100% resistance for a given attack type.
1186  if (op->resist[ATNR_DRAIN] >= 0)
1187  rate = 50+op->resist[ATNR_DRAIN]/2;
1188  else
1189  rate = 5000/(100-op->resist[ATNR_DRAIN]);
1190 
1191  // This should be impossible, but just in case...
1192  if (!rate)
1193  return 0;
1194 
1195  int exp_to_drain = op->stats.exp/rate;
1196  if (hitter->type != PLAYER) {
1197  // Monsters stop draining once they have gained 5x their original exp
1198  // value. In practice this means they can drain up to 10x their original
1199  // exp from the player, so (e.g.) a grimreaper (exp 800) can drain up to
1200  // 8000 exp from the player and keep 4000 of it.
1201  exp_to_drain = MIN(exp_to_drain,
1202  hitter->arch->clone.stats.exp*6 - hitter->stats.exp);
1203  }
1204 
1205  if (exp_to_drain <= 1) {
1206  // Target is too protected, too low on exp, or attacker is too full.
1207  if (op->type == GOLEM)
1208  return 999; // The force animating it is drained away.
1209  else
1210  // Treat it like a physical attack instead.
1211  return hit_with_one_attacktype(op, hitter, dam, ATNR_PHYSICAL);
1212  }
1213 
1214  // If we get this far we are definitely actually draining some exp from the
1215  // victim.
1216 
1217  // Randomly give the hitter some hp.
1218  if (hitter->stats.hp < hitter->stats.maxhp
1219  && (op->level > hitter->level)
1220  && random_roll(0, (op->level-hitter->level+2), hitter, PREFER_HIGH) > 3)
1221  hitter->stats.hp++;
1222 
1223  // Don't drain exp on battleground spaces or drain the wiz. Still return the
1224  // full damage amount though. Note that checking this as late as we do means
1225  // the life-restore side effect still works, we just don't transfer any exp.
1226  if (op_on_battleground(hitter, NULL, NULL, NULL)
1227  || QUERY_FLAG(op, FLAG_WAS_WIZ))
1228  return dam;
1229 
1230  int64_t orig_exp = op->stats.exp;
1231  change_exp(op, -exp_to_drain, NULL, 0);
1232  exp_to_drain = orig_exp - op->stats.exp; // Now the actual amount drained.
1233 
1234  object *owner = object_get_owner(hitter);
1235  if (owner && owner != hitter) {
1236  // If the attack was made by a pet, credit the pet's owner. If they
1237  // don't know the skill the pet attacked with, just give them generic
1238  // exp.
1239  change_exp(owner, exp_to_drain/2,
1240  hitter->chosen_skill ? hitter->chosen_skill->skill : NULL,
1241  SK_EXP_TOTAL);
1242  } else {
1243  // Otherwise just credit the attacker directly, and give them the skill
1244  // if they don't already have it.
1245  change_exp(hitter, exp_to_drain/2,
1246  hitter->chosen_skill ? hitter->chosen_skill->skill : NULL,
1248  }
1249 
1250  // Nominal 1 point of damage, so that if you have a pure drain attack it is
1251  // still considered successful and you get the messages for a drain attack
1252  // rather than for a miss.
1253  return 1;
1254 }
1255 
1272 static int hit_with_one_attacktype(object *op, object *hitter, int dam, uint32_t attacknum) {
1273  int doesnt_slay = 1;
1274  char name_hitter[MAX_BUF], name_op[MAX_BUF];
1275 
1276  /* Catch anyone that may be trying to send us a bitmask instead of the number */
1277  if (attacknum >= NROFATTACKS) {
1278  LOG(llevError, "hit_with_one_attacktype: Invalid attacknumber passed: %u\n", attacknum);
1279  return 0;
1280  }
1281 
1282  if (dam < 0) {
1283  LOG(llevError, "hit_with_one_attacktype called with negative damage: %d\n", dam);
1284  return 0;
1285  }
1286 
1287  /* AT_INTERNAL is supposed to do exactly dam. Put a case here so
1288  * people can't mess with that or it otherwise get confused. */
1289  if (attacknum == ATNR_INTERNAL)
1290  return dam;
1291 
1292  if (hitter->slaying) {
1293  // Look for the race as one of many that can be listed.
1294  if ((op->race != NULL && strstr(op->race, hitter->slaying))
1295  /*
1296  * Since we can do multiple races, we should be able to avoid the arch check.
1297  * This gives a more flexible race system, so skeletal mages can be a type of skeleton and such
1298  || (op->arch && op->arch->name != NULL && strstr(op->arch->name, hitter->slaying))
1299  */) {
1300  doesnt_slay = 0;
1301  dam *= 3;
1302  }
1303  }
1304 
1305  /* Adjust the damage for resistance. Note that neg. values increase damage. */
1306  /*
1307  * Skip lifestealing here, because it undergoes a more specific resistance scaling
1308  * in its own section that involves the better of drain/life stealing resistance
1309  *
1310  * Neila Hawkins 2018-05-31
1311  */
1312  if (attacknum != ATNR_LIFE_STEALING && op->resist[attacknum]) {
1313  /* basically: dam = dam*(100-op->resist[attacknum])/100;
1314  * in case 0>dam>1, we try to "simulate" a float value-effect */
1315  dam *= (100-op->resist[attacknum]);
1316  if (dam >= 100)
1317  dam /= 100;
1318  else
1319  dam = (dam > (random_roll(0, 99, op, PREFER_LOW))) ? 1 : 0;
1320  }
1321 
1322  /* Special hack. By default, if immune to something, you
1323  * shouldn't need to worry. However, acid is an exception, since
1324  * it can still damage your items. Only include attacktypes if
1325  * special processing is needed */
1326 
1327  if (op->resist[attacknum] >= 100
1328  && doesnt_slay
1329  && attacknum != ATNR_ACID)
1330  return 0;
1331 
1332  /* Keep this in order - makes things easier to find */
1333 
1334  switch (attacknum) {
1335  case ATNR_PHYSICAL:
1336  /* here also check for diseases */
1337  check_physically_infect(op, hitter);
1338  break;
1339 
1340  /* Don't need to do anything for:
1341  magic,
1342  fire,
1343  electricity,
1344  cold */
1345 
1346  case ATNR_CONFUSION:
1347  case ATNR_POISON:
1348  case ATNR_SLOW:
1349  case ATNR_PARALYZE:
1350  case ATNR_FEAR:
1351  case ATNR_CANCELLATION:
1352  case ATNR_DEPLETE:
1353  case ATNR_BLIND: {
1354  /* chance for inflicting a special attack depends on the
1355  * difference between attacker's and defender's level
1356  */
1357  int level_diff = MIN(110, MAX(0, op->level-hitter->level));
1358 
1359  /* First, only creatures/players with speed can be affected.
1360  * Second, just getting hit doesn't mean it always affects
1361  * you. Third, you still get a saving through against the
1362  * effect.
1363  */
1364  if (op->speed
1365  && (QUERY_FLAG(op, FLAG_MONSTER) || op->type == PLAYER)
1366  && !(rndm(0, (attacknum == ATNR_SLOW ? 6 : 3)-1))
1367  && !did_make_save(op, level_diff, op->resist[attacknum]/10)) {
1368  /* Player has been hit by something */
1369  if (attacknum == ATNR_CONFUSION)
1370  confuse_living(op, hitter, dam);
1371  else if (attacknum == ATNR_POISON)
1372  poison_living(op, hitter, dam);
1373  else if (attacknum == ATNR_SLOW)
1374  slow_living(op, hitter, dam);
1375  else if (attacknum == ATNR_PARALYZE)
1376  paralyze_living(op, dam);
1377  else if (attacknum == ATNR_FEAR)
1378  scare_creature(op, hitter);
1379  else if (attacknum == ATNR_CANCELLATION)
1380  cancellation(op);
1381  else if (attacknum == ATNR_DEPLETE)
1382  drain_stat(op);
1383  else if (attacknum == ATNR_BLIND
1384  && !QUERY_FLAG(op, FLAG_UNDEAD)
1385  && !QUERY_FLAG(op, FLAG_GENERATOR))
1386  blind_living(op, hitter, dam);
1387  }
1388  dam = 0; /* These are all effects and don't do real damage */
1389  }
1390  break;
1391 
1392  case ATNR_ACID: {
1393  int flag = 0;
1394 
1395  /* Items only get corroded if you're not on a battleground and
1396  * if your acid resistance is below 50%. */
1397  if (!op_on_battleground(op, NULL, NULL, NULL)
1398  && (op->resist[ATNR_ACID] < 50)) {
1399  FOR_INV_PREPARE(op, tmp) {
1400  if (tmp->invisible)
1401  continue;
1402  if (!QUERY_FLAG(tmp, FLAG_APPLIED)
1403  || (tmp->resist[ATNR_ACID] >= 10))
1404  /* >= 10% acid res. on itmes will protect these */
1405  continue;
1406  if (!(tmp->material&M_IRON))
1407  continue;
1408  if (tmp->magic < -4) /* Let's stop at -5 */
1409  continue;
1410  if (tmp->type == RING
1411  /* removed boots and gloves from exclusion list in PR */
1412  || tmp->type == GIRDLE
1413  || tmp->type == AMULET
1414  || tmp->type == WAND
1415  || tmp->type == ROD)
1416  continue; /* To avoid some strange effects */
1417 
1418  /* High damage acid has better chance of corroding objects */
1419  if (rndm(0, dam+4) > random_roll(0, 39, op, PREFER_HIGH)+2*tmp->magic) {
1420  if (op->type == PLAYER) {
1421  /* Make this more visible */
1422  query_name(hitter, name_hitter, MAX_BUF);
1423  query_name(tmp, name_op, MAX_BUF);
1426  "The %s's acid corrodes your %s!",
1427  name_hitter, name_op);
1428  }
1429  flag = 1;
1430  tmp->magic--;
1431  if (op->type == PLAYER)
1432  esrv_update_item(UPD_NAME, op, tmp);
1433  }
1434  } FOR_INV_FINISH();
1435  if (flag)
1436  fix_object(op); /* Something was corroded */
1437  }
1438  }
1439  break;
1440 
1441  case ATNR_DRAIN:
1442  return hit_with_drain(op, hitter, dam);
1443 
1444  case ATNR_TURN_UNDEAD: {
1445  if (QUERY_FLAG(op, FLAG_UNDEAD)) {
1446  object *owner = object_get_owner(hitter) == NULL ? hitter : object_get_owner(hitter);
1447  const object *god = find_god(determine_god(owner));
1448  int div = 1;
1449 
1450  /* if undead are not an enemy of your god, you turn them
1451  * at half strength */
1452  if (!god
1453  || !god->slaying
1454  || strstr(god->slaying, undead_name) == NULL)
1455  div = 2;
1456 
1457  /* The previous code was highly suspect - resist turn undead/100 would
1458  * at best give a bonus of 1 - increase that to resist turn undead/20 -
1459  * this gives a bit higher bonus. Also the bonus was added to the wrong
1460  * side of the equation, actually making it easier to turn creatures
1461  * if they had that resistance.
1462  */
1463  if ((op->level*div + (op->resist[ATNR_TURN_UNDEAD] / 20)) < (get_turn_bonus(owner->stats.Wis)+owner->level))
1464  scare_creature(op, owner);
1465  } else
1466  dam = 0; /* don't damage non undead - should we damage undead? */
1467  }
1468  break;
1469 
1470  case ATNR_DEATH:
1471  deathstrike_living(op, hitter, &dam);
1472  break;
1473 
1474  case ATNR_CHAOS:
1475  query_name(op, name_op, MAX_BUF);
1476  query_name(hitter, name_hitter, MAX_BUF);
1477  LOG(llevError, "%s was hit by %s with non-specific chaos.\n", name_op, name_hitter);
1478  dam = 0;
1479  break;
1480 
1481  case ATNR_COUNTERSPELL:
1482  dam = 0;
1483  /* While counterspell is handled separately and filtered out when it
1484  * moves, players can still step on a square that has an active
1485  * counterspell. When this happens, do no damage because counterspell
1486  * has no effect on anything but spells. */
1487  break;
1488 
1489  case ATNR_HOLYWORD: {
1490  /* This has already been handled by hit_player,
1491  * no need to check twice -- DAMN */
1492 
1493  object *owner = object_get_owner(hitter) == NULL ? hitter : object_get_owner(hitter);
1494 
1495  /* As with turn undead above, give a bonus on the saving throw */
1496  if (op->level+(op->resist[ATNR_HOLYWORD]/100) < owner->level+get_turn_bonus(owner->stats.Wis))
1497  scare_creature(op, owner);
1498  }
1499  break;
1500 
1501  case ATNR_LIFE_STEALING: {
1502  int new_hp;
1503  /* this is replacement to drain for players, instead of taking
1504  * exp it takes hp. It is geared for players, probably not
1505  * much use giving it to monsters
1506  *
1507  * life stealing doesn't do a lot of damage, but it gives the
1508  * damage it does do to the player. Given that,
1509  * it only does 1/30'th normal damage (hence the divide by
1510  * 3000). Wraith get 1/2 of the damage, and therefore divide
1511  * by 200. This number may need tweaking for game balance.
1512  */
1513 
1514  bool is_wraith = is_wraith_pl(hitter);
1515 
1516  int dam_modifier = is_wraith ? 200 : 3000;
1517 
1518  /* You can't steal life from something undead or not alive. */
1519  if (op->type == GOLEM
1520  || (QUERY_FLAG(op, FLAG_UNDEAD))
1521  || !(QUERY_FLAG(op, FLAG_ALIVE))
1522  || (op->type == DOOR))
1523  return 0;
1524  /* If drain protection is higher than life stealing, use that */
1525  if (op->resist[ATNR_DRAIN] >= op->resist[ATNR_LIFE_STEALING])
1526  dam = (dam*(100-op->resist[ATNR_DRAIN]))/dam_modifier;
1527  else
1528  dam = (dam*(100-op->resist[ATNR_LIFE_STEALING]))/dam_modifier;
1529  /* You die at -1 hp, not zero. */
1530  if (dam > op->stats.hp+1)
1531  dam = op->stats.hp+1;
1532  new_hp = hitter->stats.hp+dam;
1533  if (new_hp > hitter->stats.maxhp)
1534  new_hp = hitter->stats.maxhp;
1535  if (new_hp > hitter->stats.hp)
1536  hitter->stats.hp = new_hp;
1537 
1538  /* Wraith also get food through life stealing */
1539  if (is_wraith) {
1540  if (hitter->stats.food+dam >= MAX_FOOD)
1541  hitter->stats.food = MAX_FOOD;
1542  else
1543  hitter->stats.food += dam;
1544  fix_object(hitter);
1545  }
1546  }
1547  }
1548  return dam;
1549 }
1550 
1551 /*
1552  * This function is defined in party.c, but conditionally, something "make proto"
1553  * doesn't handle. So define it locally.
1554  */
1555 #ifdef PARTY_KILL_LOG
1556 void party_add_kill(partylist *party, const char *killer, const char *dead, long exp);
1557 #endif
1558 
1586 static int kill_object(object *op, int dam, object *hitter) {
1587  char kill_message[VERY_BIG_BUF];
1588  const char *skill;
1589  int maxdam = 0;
1590  int battleg = 0; /* true if op standing on battleground */
1591  int pk = 0; /* true if op and what controls hitter are both players*/
1592  object *owner = NULL;
1593  const object *skop = NULL;
1594 
1595  if (op->stats.hp >= 0)
1596  return -1;
1597 
1598  if (events_execute_object_event(op, EVENT_DEATH, hitter, NULL, NULL, SCRIPT_FIX_ALL) != 0)
1599  return 0;
1601 
1603 
1604  /* maxdam needs to be the amount of damage it took to kill
1605  * this creature. The function(s) that call us have already
1606  * adjusted the creatures HP total, so that is negative.
1607  */
1608  maxdam = dam+op->stats.hp+1;
1609 
1610  if (QUERY_FLAG(op, FLAG_BLOCKSVIEW))
1611  update_all_los(op->map, op->x, op->y); /* makes sure los will be recalculated */
1612 
1613  if (op->type == DOOR) {
1614  op->speed = 0.1;
1615  object_update_speed(op);
1616  op->speed_left = -0.05;
1617  return maxdam;
1618  }
1619  if (QUERY_FLAG(op, FLAG_FRIENDLY) && op->type != PLAYER) {
1620  object *owner;
1621 
1623  owner = object_get_owner(op);
1624  if (owner != NULL
1625  && owner->type == PLAYER) {
1626  if (owner->contr->ranges[range_golem] == op) {
1627  owner->contr->ranges[range_golem] = NULL;
1628  owner->contr->golem_count = 0;
1629  }
1630 
1631  /*play_sound_player_only(owner1->contr, SOUND_PET_IS_KILLED, 0, 0);*/
1632  /* Maybe we should include the owner that killed this, maybe not */
1634  "Your pet, the %s, is killed by %s.",
1635  op->name, hitter->name);
1636  }
1637  /*
1638  * there can be items both friendly and without any owner, for instance
1639  * in various maps, so this isn't an error.
1640  else
1641  LOG(llevError, "BUG: hit_player(): Encountered golem without owner.\n");
1642  */
1643 
1644  object_remove(op);
1646  return maxdam;
1647  }
1648 
1649  /* Now lets start dealing with experience we get for killing something */
1650 
1651  owner = object_get_owner(hitter);
1652  if (owner == NULL)
1653  owner = hitter;
1654 
1655  /* is the victim (op) standing on battleground? */
1656  if (op_on_battleground(op, NULL, NULL, NULL))
1657  battleg = 1;
1658 
1659  /* is this player killing? -- Don't count it if you suicide, though. */
1660  if (op->type == PLAYER && owner->type == PLAYER && owner != op)
1661  pk = 1;
1662 
1663  /* Player killed something */
1664  if (owner->type == PLAYER) {
1665 
1666  /* Log players killing other players - makes it easier to detect
1667  * and filter out malicious player killers - that is why the
1668  * ip address is included.
1669  */
1670  if (op->type == PLAYER && !battleg) {
1671  time_t t = time(NULL);
1672  struct tm *tmv;
1673  char buf[256];
1674  char name[MAX_BUF];
1675 
1676  tmv = localtime(&t);
1677  strftime(buf, sizeof(buf), "%a %b %d %H:%M:%S %Y", tmv);
1678  query_name(op, name, MAX_BUF);
1679 
1680  LOG(llevInfo, "%s PLAYER_KILL_PLAYER: %s (%s) killed %s\n", buf, owner->name, owner->contr->socket->host, name);
1681  }
1682 
1683  /* try to filter some things out - basically, if you are
1684  * killing a level 1 creature and your level 20, you
1685  * probably don't want to see that.
1686  */
1687  if (owner->level < op->level*2 || op->stats.exp > 1000) {
1688  if (owner != hitter) {
1689  char killed[MAX_BUF], with[MAX_BUF];
1690 
1691  query_name(op, killed, MAX_BUF);
1692  query_name(hitter, with, MAX_BUF);
1694  "You killed %s with %s.",
1695  killed, with);
1696  } else {
1697  char killed[MAX_BUF];
1698 
1699  query_name(op, killed, MAX_BUF);
1701  "You killed %s.",
1702  killed);
1703  }
1704  }
1705 
1706  /* If a player kills another player, not on
1707  * battleground, the "killer" looses 1 luck. Since this is
1708  * not reversible, it's actually quite a pain IMHO. -AV
1709  * Fix bug in that we were changing the luck of the hitter, not
1710  * player that the object belonged to - so if you killed another player
1711  * with spells, pets, whatever, there was no penalty.
1712  * Changed to make luck penalty configurable in settings.
1713  *
1714  * Simplified comparison since pk is no longer set to 1 if self-kill
1715  * -- SilverNexus 2017-06-17+
1716  */
1717  if (pk == 1 && !battleg)
1719 
1720  /* This code below deals with finding the appropriate skill
1721  * to credit exp to. This is a bit problematic - we should
1722  * probably never really have to look at current_weapon->skill
1723  */
1724  skill = NULL;
1725  if (hitter->skill && hitter->type != PLAYER)
1726  skill = hitter->skill;
1727  else if (owner->chosen_skill) {
1728  skill = owner->chosen_skill->skill;
1729  skop = owner->chosen_skill;
1730  } else if (QUERY_FLAG(owner, FLAG_READY_WEAPON))
1731  skill = owner->current_weapon->skill;
1732  else
1733  LOG(llevError, "kill_object - unable to find skill that killed monster\n");
1734 
1735  /* We have the skill we want to credit to - now find the object this goes
1736  * to. Make sure skop is an actual skill, and not a skill tool!
1737  */
1738  if ((!skop || skop->type != SKILL) && skill) {
1739  skop = find_applied_skill_by_name(owner, skill);
1740  }
1741  } /* Was it a player that hit somethign */
1742  else {
1743  skill = NULL;
1744  }
1745 
1746  /* Pet (or spell) killed something. */
1747  if (owner != hitter) {
1748  char name_op[MAX_BUF], name_hitter[MAX_BUF];
1749  const char *owner_prefix;
1750  const char *op_prefix;
1751 
1752  owner_prefix = !battleg && pk && owner->contr != NULL && !owner->contr->peaceful ? "hostile " : "";
1753  op_prefix = !battleg && pk && op->contr != NULL && !op->contr->peaceful ? "hostile " : "";
1754 
1755  query_name(op, name_op, MAX_BUF);
1756  query_name(hitter, name_hitter, MAX_BUF);
1757  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)" : ""));
1758  } else {
1759  const char *hitter_prefix;
1760  const char *op_prefix;
1761 
1762  hitter_prefix = !battleg && pk && hitter->contr != NULL && !hitter->contr->peaceful ? "hostile " : "";
1763  op_prefix = !battleg && pk && op->contr != NULL && !op->contr->peaceful ? "hostile " : "";
1764 
1765  snprintf(kill_message, sizeof(kill_message), "%s%s killed %s%s%s%s.", hitter_prefix, hitter->name, op_prefix, op->name,
1766  (QUERY_FLAG(hitter, FLAG_MONSTER)) || hitter->type == PLAYER ?
1767  " in hand to hand combat" : "", battleg ? " (duel)" : (pk ? " (pk)" : ""));
1768  }
1769  /* These may have been set in the player code section above */
1770  if (!skop)
1771  skop = hitter->chosen_skill;
1772  if (!skill && skop)
1773  skill = skop->skill;
1774 
1776  kill_message);
1777  play_sound_map(SOUND_TYPE_HIT, op, 0, "kill");
1778 
1779 
1780  /* If you didn't kill yourself, and your not the wizard */
1781  if (owner != op && !QUERY_FLAG(op, FLAG_WAS_WIZ)) {
1782  int64_t exp;
1783 
1784  exp = calc_skill_exp(owner, op, skop);
1785 
1786  /* Really don't give much experience for killing other players */
1787  if (op->type == PLAYER) {
1788  if (battleg) {
1790  "Your foe has fallen!\nVICTORY!!!");
1791  } else {
1792  exp = settings.pk_max_experience_percent*exp/100;
1793  if (settings.pk_max_experience >= 0)
1794  exp = MIN(settings.pk_max_experience, exp);
1795  /* Never exceed what victim can lose considering permanent exp. */
1796  exp = check_exp_loss(op, exp);
1797  }
1798  }
1799 
1800  /* Don't know why this is set this way - doesn't make
1801  * sense to just divide everything by two for no reason.
1802  */
1803 
1804  if (!settings.simple_exp)
1805  exp = exp/2;
1806 
1807  /* if op is standing on "battleground" (arena), no way to gain
1808  * exp by killing him
1809  */
1810  if (battleg)
1811  exp = 0;
1812 
1813 #ifdef PARTY_KILL_LOG
1814  if (owner->type == PLAYER && owner->contr->party != NULL) {
1815  char name[MAX_BUF];
1816  char op_name[MAX_BUF];
1817 
1818  query_name(owner, name, MAX_BUF);
1819  query_name(op, op_name, sizeof(op_name));
1820  party_add_kill(owner->contr->party, name, op_name, exp);
1821  }
1822 #endif
1823  share_exp(owner, exp, skill, SK_EXP_TOTAL);
1824  } /* end if person didn't kill himself */
1825 
1826  if (op->type != PLAYER) {
1827  object_remove(op);
1829  /* Player has been killed! */
1830  } else {
1831  if (owner->type == PLAYER) {
1832  snprintf(op->contr->killer, BIG_NAME, "%s the %.*s", owner->name,
1833  int(sizeof(op->contr->killer) - strlen(owner->name) - 4), owner->contr->title);
1834  } else {
1835  strncpy(op->contr->killer, hitter->name, BIG_NAME);
1836  op->contr->killer[BIG_NAME-1] = '\0';
1837  }
1838  /* Need to run kill_player (just in case, make sure is not wiz) */
1839  if (!QUERY_FLAG(op, FLAG_WIZ))
1840  kill_player(op, owner->type == PLAYER ? owner : hitter);
1841  }
1842  /* This was return -1 - that doesn't seem correct - if we return -1, process
1843  * continues in the calling function.
1844  */
1845  return maxdam;
1846 }
1847 
1858 int friendly_fire(object *op, object *hitter) {
1859  object *owner;
1860  int friendlyfire;
1861 
1862  hitter = HEAD(hitter);
1863  friendlyfire = 0;
1864 
1865  if (op->type == PLAYER) {
1866  if (hitter->type == PLAYER && hitter->contr->peaceful == 1)
1867  return 1;
1868 
1869  owner = object_get_owner(hitter);
1870  if (owner != NULL) {
1871  if (owner->type == PLAYER && owner->contr->peaceful == 1)
1872  friendlyfire = 2;
1873  }
1874 
1875  if (hitter->type == SPELL
1876  || hitter->type == POISONING
1877  || hitter->type == DISEASE
1878  || hitter->type == RUNE)
1879  friendlyfire = 0;
1880  }
1881  return friendlyfire;
1882 }
1883 
1907 int hit_player(object *op, int dam, object *hitter, uint32_t type, int full_hit) {
1908  int maxdam = 0, ndam = 0, magic = (type&AT_MAGIC);
1909  int maxattacktype, attacknum;
1910  int body_attack = op->head != NULL; /* Did we hit op's head? */
1911  int simple_attack;
1912  tag_t op_tag, hitter_tag;
1913  int rtn_kill = 0;
1914  int friendlyfire;
1915  object *owner;
1916 
1917  if (events_execute_object_event(op, EVENT_ATTACKED, hitter, hitter->current_weapon ? hitter->current_weapon : hitter, NULL, SCRIPT_FIX_ALL) != 0)
1918  return 0;
1919  FOR_INV_PREPARE(op, inv)
1920  if (events_execute_object_event(inv, EVENT_ATTACKED, hitter, hitter->current_weapon ? hitter->current_weapon : hitter, NULL, SCRIPT_FIX_ALL) != 0)
1921  return 0;
1922  FOR_INV_FINISH();
1923 
1924  if (get_attack_mode(&op, &hitter, &simple_attack))
1925  return 0;
1926 
1927  /* very simple: if our target has no_damage 1 set or is wiz, we can't hurt him */
1928  if (QUERY_FLAG(op, FLAG_WIZ) || QUERY_FLAG(op, FLAG_NO_DAMAGE))
1929  return 0;
1930 
1931  op_tag = op->count;
1932  hitter_tag = hitter->count;
1933 
1934  if (body_attack) {
1935  /* slow and paralyze must hit the head. But we don't want to just
1936  * return - we still need to process other attacks the spell still
1937  * might have. So just remove the paralyze and slow attacktypes,
1938  * and keep on processing if we have other attacktypes.
1939  * return if only magic or nothing is left - under normal code
1940  * we don't attack with pure magic if there is another attacktype.
1941  * Only do processing if the initial attacktype includes one of those
1942  * attack so we don't cancel out things like magic bullet.
1943  */
1944  if (type&(AT_PARALYZE|AT_SLOW)) {
1945  type &= ~(AT_PARALYZE|AT_SLOW);
1946  if (!type || type == AT_MAGIC)
1947  return 0;
1948  }
1949  }
1950 
1951  if (!simple_attack && op->type == DOOR) {
1952  object *tmp;
1953 
1954  tmp = object_find_by_type2(op, RUNE, TRAP);
1955  if (tmp != NULL) {
1956  spring_trap(tmp, hitter);
1957  if (object_was_destroyed(hitter, hitter_tag)
1958  || object_was_destroyed(op, op_tag)
1959  || abort_attack(op, hitter, simple_attack))
1960  return 0;
1961  }
1962  }
1963 
1964  if (!QUERY_FLAG(op, FLAG_ALIVE) || op->stats.hp < 0) {
1965  /* FIXME: If a player is killed by a rune in a door, the
1966  * object_was_destroyed() check above doesn't return, and might get here.
1967  */
1968  LOG(llevDebug, "victim (arch %s, name %s) already dead in hit_player()\n", op->arch->name, op->name);
1969  return 0;
1970  }
1971 
1972 #ifdef ATTACK_DEBUG
1973  LOG(llevDebug, "hit player: attacktype %d, dam %d\n", type, dam);
1974 #endif
1975 
1976  if (magic) {
1977  /* basically: dam = dam*(100-op->resist[attacknum])/100;
1978  * in case 0>dam>1, we try to "simulate" a float value-effect */
1979  dam = dam*(100-op->resist[ATNR_MAGIC]);
1980  if (dam >= 100)
1981  dam /= 100;
1982  else
1983  dam = (dam > (rndm(0, 99))) ? 1 : 0;
1984  }
1985 
1986  /* AT_CHAOS here is a weapon or monster. Spells are handled by hit_map
1987  * We don't use shuffle_attack(), because that changes the it in the
1988  * creature structure, and thus is permanent until fix_object() is
1989  * called again. Chaos should change on each attack.
1990  */
1991  if (type&AT_CHAOS) {
1992  type = ATTACKS[RANDOM()%(sizeof(ATTACKS)/sizeof(*ATTACKS))].attacktype|AT_MAGIC;
1993  }
1994 
1995  /* Holyword is really an attacktype modifier (like magic is). If
1996  * holyword is part of an attacktype, then make sure the creature is
1997  * a proper match, otherwise no damage.
1998  */
1999  if (type&AT_HOLYWORD) {
2000  const object *god;
2001 
2002  if ((!hitter->slaying || (!(op->race && strstr(hitter->slaying, op->race))
2003  && !(op->name && strstr(hitter->slaying, op->name))))
2004  && (!QUERY_FLAG(op, FLAG_UNDEAD) || (hitter->title != NULL
2005  && (god = find_god(determine_god(hitter))) != NULL
2006  && god->race != NULL
2007  && strstr(god->race, undead_name) != NULL)))
2008  return 0;
2009  }
2010 
2011  maxattacktype = type; /* initialize this to something */
2012  for (attacknum = 0; attacknum < NROFATTACKS; attacknum++) {
2013  int attacktype;
2014 
2015  attacktype = 1<<attacknum;
2016 
2017  /* Magic isn't really a true attack type - it gets combined with other
2018  * attack types. As such, skip it over. However, if magic is
2019  * the only attacktype in the group, then still attack with it
2020  */
2021  if (attacktype == AT_MAGIC && (type&~AT_MAGIC))
2022  continue;
2023 
2024  /* Go through and hit the player with each attacktype, one by one.
2025  * hit_with_one_attacktype only figures out the damage, doesn't inflict
2026  * it. It will do the appropriate action for attacktypes with
2027  * effects (slow, paralization, etc.
2028  */
2029  if (type&attacktype) {
2030  ndam = hit_with_one_attacktype(op, hitter, dam, attacknum);
2031  /* the >= causes us to prefer messages from special attacks, if
2032  * the damage is equal.
2033  */
2034  if (ndam >= maxdam) {
2035  maxdam = ndam;
2036  maxattacktype = 1<<attacknum;
2037  }
2038  /* Special case: death attack always deals all damage, as it should kill the monster
2039  * right away. */
2040  if (attacktype == AT_DEATH && ndam > 0)
2041  full_hit = 1;
2042  }
2043  }
2044 
2045 
2046  /* if this is friendly fire then do a set % of damage only
2047  * Note - put a check in to make sure this attack is actually
2048  * doing damage - otherwise, the +1 in the coe below will make
2049  * an attack do damage before when it otherwise didn't
2050  * Only reduce damage if not on battlground - if in arena, do
2051  * full damage. Note that it is intentional that the check for
2052  * battleground is inside the friendlyfire if statement - op_on_battleground()
2053  * is a fairly costly function to call, and we don't want to call it for
2054  * every attack - by doing it only for friendlyfire, it shouldn't get called
2055  * that often
2056  */
2057  friendlyfire = friendly_fire(op, hitter);
2058  if (friendlyfire && maxdam) {
2059  if (!op_on_battleground(op, NULL, NULL, NULL)) {
2060  maxdam = ((dam*settings.set_friendly_fire)/100)+1;
2061 #ifdef ATTACK_DEBUG
2062  LOG(llevDebug, "Friendly fire (type:%d setting: %d%) did %d damage dropped to %d\n", friendlyfire, settings.set_friendly_fire, dam, maxdam);
2063 #endif
2064  }
2065  }
2066 
2067  if (!full_hit) {
2068  archetype *at;
2069  unsigned int area = 0;
2070  for (at = op->arch; at != NULL; at = at->more)
2071  area++;
2072 
2073  /* basically: maxdam /= area; we try to "simulate" a float
2074  value-effect */
2075  unsigned int remainder = 100*(maxdam%area)/area;
2076  maxdam /= area;
2077  if (RANDOM()%100 < remainder)
2078  maxdam++;
2079  }
2080 
2081 #ifdef ATTACK_DEBUG
2082  LOG(llevDebug, "Attacktype %d did %d damage\n", type, maxdam);
2083 #endif
2084 
2085  owner = object_get_owner(hitter);
2086  if (owner != NULL) {
2087  if (op->enemy != hitter)
2088  object_set_enemy(op, owner);
2089  } else if (QUERY_FLAG(hitter, FLAG_ALIVE))
2090  if (op->enemy == NULL || rndm(1, 20) == 0)
2091  object_set_enemy(op, hitter);
2092 
2093  if (QUERY_FLAG(op, FLAG_UNAGGRESSIVE) && op->type != PLAYER) {
2094  /* The unaggressives look after themselves 8) */
2097  }
2098 
2099  if (magic && did_make_save(op, op->level, 0))
2100  maxdam = maxdam/2;
2101 
2102  attack_message(maxdam, maxattacktype, op, hitter);
2103 
2104  op->stats.hp -= maxdam;
2105 
2106  /* Eneq(@csd.uu.se): Check to see if monster runs away. */
2107  if (op->stats.hp >= 0
2108  && (QUERY_FLAG(op, FLAG_MONSTER) || op->type == PLAYER)
2109  && op->stats.hp < (int16_t)((int32_t)op->run_away * op->stats.maxhp / 100)) {
2110  if (QUERY_FLAG(op, FLAG_MONSTER))
2111  SET_FLAG(op, FLAG_RUN_AWAY);
2112  else
2113  scare_creature(op, hitter);
2114  }
2115 
2116  if (QUERY_FLAG(op, FLAG_TEAR_DOWN)) {
2117  if (maxdam)
2118  tear_down_wall(op);
2119  return maxdam; /* nothing more to do for wall */
2120  }
2121 
2122  /* See if the creature has been killed */
2123  rtn_kill = kill_object(op, maxdam, hitter);
2124 
2125  // If the attacker has one_hit, it dies after attacking.
2126  // This used to be part of the ghosthit attacktype, but is now a separate
2127  // flag. Note that the attacker is removed whether or not it killed (or
2128  // even damaged) the target.
2129  if (QUERY_FLAG(hitter, FLAG_ONE_HIT) && !QUERY_FLAG(op, FLAG_REMOVED)) {
2130  if (QUERY_FLAG(hitter, FLAG_FRIENDLY))
2131  remove_friendly_object(hitter);
2132  object_remove(hitter);
2134  }
2135 
2136  // Target is dead? Nothing else to do.
2137  if (rtn_kill != -1)
2138  return rtn_kill;
2139 
2140  // If it survived, handle splitting monsters here.
2141  if (type&AT_PHYSICAL && !QUERY_FLAG(op, FLAG_FREED) && QUERY_FLAG(op, FLAG_SPLITTING)) {
2142  change_object(op);
2143  }
2144 
2145  return maxdam;
2146 }
2147 
2158 static void poison_living(object *op, object *hitter, int dam) {
2159  archetype *at = find_archetype("poisoning");
2160  if (at == NULL) {
2161  return;
2162  }
2163  object *tmp = arch_present_in_ob(at, op);
2164  const char *skill;
2165 
2166  if (tmp == NULL) {
2167  tmp = arch_to_object(at);
2168  if (tmp == NULL)
2169  LOG(llevError, "Failed to clone arch poisoning.\n");
2170  else {
2171  tmp = object_insert_in_ob(tmp, op);
2172  /* peterm: give poisoning some teeth. It should
2173  * be able to kill things better than it does:
2174  * damage should be dependent something--I choose to
2175  * do this: if it's a monster, the damage from the
2176  * poisoning goes as the level of the monster/2.
2177  * If anything else, goes as damage.
2178  */
2179 
2180  if (QUERY_FLAG(hitter, FLAG_ALIVE))
2181  tmp->stats.dam += hitter->level/2;
2182  else
2183  tmp->stats.dam = dam;
2184 
2185  object_copy_owner(tmp, hitter); /* so we get credit for poisoning kills */
2186  skill = hitter->skill;
2187  if (!skill && hitter->chosen_skill)
2188  skill = hitter->chosen_skill->name;
2189 
2190  if (skill && skill != tmp->skill) {
2191  if (tmp->skill)
2192  free_string(tmp->skill);
2193  tmp->skill = add_refcount(skill);
2194  }
2195 
2196  tmp->stats.food += dam; /* more damage, longer poisoning */
2197 
2198  if (op->type == PLAYER) {
2199  /* player looses stats, maximum is -10 of each */
2200  tmp->stats.Con = MAX(-(dam/4+1), -10);
2201  tmp->stats.Str = MAX(-(dam/3+2), -10);
2202  tmp->stats.Dex = MAX(-(dam/6+1), -10);
2203  tmp->stats.Int = MAX(-dam/7, -10);
2204  SET_FLAG(tmp, FLAG_APPLIED);
2205  fix_object(op);
2206  draw_ext_info(NDI_UNIQUE, 0, op,
2208  "You suddenly feel very ill.");
2209  }
2210  if (hitter->type == PLAYER)
2211  draw_ext_info_format(NDI_UNIQUE, 0, hitter,
2213  "You poison %s.",
2214  op->name);
2215  else {
2216  object *owner;
2217 
2218  owner = object_get_owner(hitter);
2219  if (owner != NULL && owner->type == PLAYER)
2220  draw_ext_info_format(NDI_UNIQUE, 0, owner,
2222  "Your %s poisons %s.",
2223  hitter->name, op->name);
2224  }
2225  tmp->speed_left = 0;
2226  }
2227  } else
2228  tmp->stats.food++;
2229 }
2230 
2231 int slow_living_by(object *op, const int speed_penalty) {
2232  archetype *at = find_archetype("slowness");
2233  if (at == NULL) {
2234  return 0;
2235  }
2236  object* tmp = arch_present_in_ob(at, op);
2237  int ret;
2238  if (tmp == NULL) {
2239  tmp = arch_to_object(at);
2240  tmp->stats.exp = -speed_penalty;
2241  tmp = object_insert_in_ob(tmp, op);
2242  ret = 1;
2243  }
2244  // If we are hitting for more intense slowness, override the old one.
2245  else if (tmp->stats.exp > -speed_penalty) {
2246  tmp->stats.exp = -speed_penalty;
2247  tmp->stats.food -= 3; // But also reduce the duration to compensate.
2248  ret = 2;
2249  } else {
2250  tmp->stats.food++;
2251  ret = 3;
2252  }
2253  SET_FLAG(tmp, FLAG_APPLIED);
2254  tmp->speed_left = 0;
2255  fix_object(op);
2256  return ret;
2257 }
2258 
2270 static void slow_living(object *op, object *hitter, int dam) {
2271  // Used to calculate the speed penalty of the slow attempt
2272  int speed_penalty;
2273  (void)dam;
2274 
2280  // Higher level slow effects make you slower.
2281  speed_penalty = hitter->level - op->level + random_roll(1, 5, hitter, PREFER_LOW);
2282  // Resistance to slow will also affect how much you are slowed by.
2283  speed_penalty = speed_penalty * (100-op->resist[ATNR_SLOW]) / 100;
2284  // Make sure we actually have a penalty amount. We can assume that op is not immune in this method.
2285  if (speed_penalty < 1)
2286  speed_penalty = 1;
2287  else if (speed_penalty > 30) // Data barrier for stats.exp is 127, but that is huge slowness. Pick something less than that.
2288  speed_penalty = 30;
2289  switch (slow_living_by(op, speed_penalty)) {
2290  case 1:
2293  "The world suddenly moves very fast!");
2294  break;
2295  case 2:
2298  "The world moves even faster!");
2299  break;
2300 
2301  }
2302 }
2303 
2315 void confuse_living(object *op, object *hitter, int dam) {
2316  object *tmp;
2317  int maxduration;
2318  (void)hitter;
2319  (void)dam;
2320 
2321  tmp = object_present_in_ob_by_name(FORCE, "confusion", op);
2322  if (!tmp) {
2324  tmp = object_insert_in_ob(tmp, op);
2325  }
2326  SET_FLAG(tmp, FLAG_APPLIED);
2327  SET_FLAG(tmp, FLAG_CONFUSED);
2328 
2329  /* Duration added per hit and max. duration of confusion both depend
2330  * on the player's resistance
2331  */
2332  tmp->speed = 0.05;
2333  tmp->subtype = FORCE_CONFUSION;
2334  tmp->duration = 8+MAX(1, 5*(100-op->resist[ATNR_CONFUSION])/100);
2335  if (tmp->name)
2336  free_string(tmp->name);
2337  tmp->name = add_string("confusion");
2338  maxduration = MAX(2, 30*(100-op->resist[ATNR_CONFUSION])/100);
2339  if (tmp->duration > maxduration)
2340  tmp->duration = maxduration;
2341 
2342  if (op->type == PLAYER && !QUERY_FLAG(op, FLAG_CONFUSED))
2344  "You suddenly feel very confused!");
2345  SET_FLAG(op, FLAG_CONFUSED);
2346 }
2347 
2358 void blind_living(object *op, object *hitter, int dam) {
2359  object *tmp, *owner;
2360  char victim[MAX_BUF];
2361 
2362  /* Save some work if we know it isn't going to affect the player */
2363  if (op->resist[ATNR_BLIND] == 100)
2364  return;
2365 
2366  tmp = object_present_in_ob(BLINDNESS, op);
2367  if (!tmp) {
2368  tmp = create_archetype("blindness");
2369  SET_FLAG(tmp, FLAG_BLIND);
2370  SET_FLAG(tmp, FLAG_APPLIED);
2371  /* use floats so we don't lose too much precision due to rounding errors.
2372  * speed is a float anyways.
2373  */
2374  tmp->speed = tmp->speed*(100.0-(float)op->resist[ATNR_BLIND])/100;
2375 
2376  tmp = object_insert_in_ob(tmp, op);
2377  change_abil(op, tmp); /* Mostly to display any messages */
2378  fix_object(op); /* This takes care of some other stuff */
2379 
2380  owner = object_get_owner(hitter);
2381  if (owner == NULL)
2382  owner = hitter;
2383 
2384  query_name(op, victim, MAX_BUF);
2386  "Your attack blinds %s!",
2387  victim);
2388  }
2389  tmp->stats.food += dam;
2390  if (tmp->stats.food > 10)
2391  tmp->stats.food = 10;
2392 }
2393 
2402 void paralyze_living(object *op, int dam) {
2403  float effect, max;
2404 
2405  /* Do this as a float - otherwise, rounding might very well reduce this to 0 */
2406  effect = (float)dam*3.0*(100.0-op->resist[ATNR_PARALYZE])/100;
2407 
2408  if (effect == 0)
2409  return;
2410 
2411  op->speed_left -= FABS(op->speed)*effect;
2412 
2413  /* max number of ticks to be affected for. */
2414  max = (100-op->resist[ATNR_PARALYZE])/2;
2415  if (op->speed_left < -(FABS(op->speed)*max))
2416  op->speed_left = (float)-(FABS(op->speed)*max);
2417  // Set a paralyze flag and print a message to a player if the flag isn't set;
2418  // this tells the player that he/she has been hit by a paralysis attack.
2419  if (!QUERY_FLAG(op, FLAG_PARALYZED)) {
2420  SET_FLAG(op, FLAG_PARALYZED);
2421  if (op->type == PLAYER)
2423  "You limbs stop moving!");
2424  }
2425  /* If the flag is already set, then the paralysis is merely extended.
2426  * At this point, we do nothing.
2427  * It may be worthwhile to give players another message on paralysis extensions.
2428  *
2429  * Neila Hawkins 2017-08-22
2430  */
2431 }
2432 
2453 static void deathstrike_living(object *op, object *hitter, int *dam) {
2454  int atk_lev, def_lev, kill_lev, lev_mult = 1;
2455 
2456  if (hitter->slaying) {
2457  if (!((QUERY_FLAG(op, FLAG_UNDEAD) && strstr(hitter->slaying, undead_name))
2458  || (op->race && strstr(op->race, hitter->slaying))))
2459  {
2460  *dam = 0; // Don't do damage if we aren't deathstriking them.
2461  return;
2462  }
2463  // Multiply the attacker level by 3 when doing a slaying effect.
2464  lev_mult = 3;
2465  } else
2466  if (QUERY_FLAG(op, FLAG_UNDEAD))
2467  {
2468  *dam = 0; // Don't do damage if we aren't deathstriking them.
2469  return;
2470  }
2471 
2472  def_lev = op->level;
2473  if (def_lev < 1) {
2474  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);
2475  def_lev = 1;
2476  }
2477  /*
2478  * Redo this calculation -- you could essentially only kill creatures less than half your level,
2479  * making death extremely weak at high levels.
2480  * Refactoring to use a d150 roll with a fairly high DC (still dependent on level)
2481  * Also, toss in a resistance-based hit modifier.
2482  * Higher resistance requires higher levels in order to kill with a death attack.
2483  *
2484  * Neila Hawkins 2018-05-21
2485  */
2486  atk_lev = (hitter->chosen_skill ? hitter->chosen_skill->level : hitter->level);
2487  /* LOG(llevDebug, "Deathstrike - attack level %d, defender level %d\n", atk_lev, def_lev); */
2488 
2489  // If we have a slaying attribute, we triple the level difference.
2490  // Since the calculation is balanced to only work at or above level parity for the attacker,
2491  // the more strong negatives this would also produce become irrelevant.
2492  // After that, apply a resistance multiplier to the result. Death resistance is a linear scale
2493  // for the level difference. Thus death vulnerability does not incur a chance
2494  // at lower levels than otherwise, but does increase the chance once the level is met.
2495  kill_lev = (atk_lev - def_lev) * lev_mult * (100 - op->resist[ATNR_DEATH]) / 100;
2496 
2497  // Use 150 as a kill for same level and no resistance; that's 0.67% + 0.67%/level
2498  kill_lev += random_roll(1, 150, hitter, PREFER_HIGH) - 149;
2499 
2500  // If we hit, then kill them. Otherwise, damage is 0.
2501  if (kill_lev > 0) {
2502  *dam = op->stats.hp+10; /* take all hp. they can still save for 1/2 */
2503  /* I think this doesn't really do much. Because of
2504  * integer rounding, this only makes any difference if the
2505  * attack level is double the defender level.
2506  */
2507  *dam *= kill_lev/def_lev;
2508  }
2509  else {
2510  *dam = 0; /* no harm done */
2511  }
2512 }
2513 
2526 static void thrown_item_effect(object *hitter, object *victim) {
2527  if (!QUERY_FLAG(hitter, FLAG_ALIVE)) {
2528  /* May not need a switch for just 2 types, but this makes it
2529  * easier for expansion.
2530  */
2531  switch (hitter->type) {
2532  case POTION:
2533  /* should player get a save throw instead of checking magic protection? */
2534  if (QUERY_FLAG(victim, FLAG_ALIVE)
2535  && !QUERY_FLAG(victim, FLAG_UNDEAD)
2536  && (victim->resist[ATNR_MAGIC] < 60))
2537  (void)ob_apply(hitter, victim, 0);
2538  break;
2539 
2540  case POISON: /* poison drinks */
2541  /* As with potions, should monster get a save? */
2542  if (QUERY_FLAG(victim, FLAG_ALIVE)
2543  && !QUERY_FLAG(victim, FLAG_UNDEAD)
2544  && (victim->resist[ATNR_POISON] < 60))
2545  (void)ob_apply(victim, hitter, 0);
2546  break;
2547 
2548  /* Removed case statements that did nothing.
2549  * food may be poisonous, but monster must be willing to eat it,
2550  * so we don't handle it here.
2551  * Containers should perhaps break open, but that code was disabled.
2552  */
2553  }
2554  }
2555 }
2556 
2566 static int adj_attackroll(object *hitter, object *target) {
2567  object *attacker = hitter;
2568  int adjust = 0;
2569 
2570  /* safety */
2571  if (!target || !hitter || !hitter->map || !target->map || !on_same_map(hitter, target)) {
2572  LOG(llevError, "BUG: adj_attackroll(): hitter and target not on same map\n");
2573  return 0;
2574  }
2575 
2576  /* aimed missiles use the owning object's sight */
2577  if (is_aimed_missile(hitter)) {
2578  attacker = object_get_owner(hitter);
2579  if (attacker == NULL)
2580  attacker = hitter;
2581  /* A player who saves but hasn't quit still could have objects
2582  * owned by him - need to handle that case to avoid crashes.
2583  */
2584  if (QUERY_FLAG(attacker, FLAG_REMOVED))
2585  attacker = hitter;
2586  } else if (!QUERY_FLAG(hitter, FLAG_ALIVE))
2587  return 0;
2588 
2589  /* determine the condtions under which we make an attack.
2590  * Add more cases, as the need occurs. */
2591 
2592  if (!monster_can_see_enemy(attacker, target)) {
2593  /* target is unseen */
2594  if (target->invisible || QUERY_FLAG(attacker, FLAG_BLIND))
2595  adjust -= 10;
2596  /* dark map penalty for the hitter, though xray can help for a player */
2597  else if (target->map && target->map->darkness > 0 && !monster_stand_in_light(target) && (hitter->type != PLAYER || !player_can_view(hitter, target)))
2598  adjust -= target->map->darkness;
2599  }
2600 
2601  if (QUERY_FLAG(attacker, FLAG_SCARED))
2602  adjust -= 3;
2603 
2604  if (QUERY_FLAG(target, FLAG_UNAGGRESSIVE))
2605  adjust += 1;
2606 
2607  if (QUERY_FLAG(target, FLAG_SCARED))
2608  adjust += 1;
2609 
2610  if (QUERY_FLAG(attacker, FLAG_CONFUSED))
2611  adjust -= 3;
2612 
2613  /* if we attack at a different 'altitude' its harder
2614  * Note - only make this adjustment if the target actually
2615  * has a move type. Doors don't (they don't move), and
2616  * this would evaluate as true. If anything, something without
2617  * a move type should be easier to hit.
2618  */
2619  if (target->move_type && (attacker->move_type&target->move_type) == 0)
2620  adjust -= 2;
2621 
2622  return adjust;
2623 }
2624 
2633 static int is_aimed_missile(object *op) {
2634  /* I broke what used to be one big if into a few nested
2635  * ones so that figuring out the logic is at least possible.
2636  */
2637  if (op && (op->move_type&MOVE_FLYING)) {
2638  if (op->type == ARROW || op->type == THROWN_OBJ)
2639  return 1;
2640  else if (op->type == SPELL_EFFECT
2641  && (op->subtype == SP_BULLET || op->subtype == SP_EXPLOSION))
2642  return 1;
2643  }
2644  return 0;
2645 }
std::vector< materialtype_t * > materials
Definition: init.cpp:128
#define ATM_BASIC
Definition: attack.h:26
#define ATNR_FEAR
Definition: attack.h:61
Error, serious thing.
Definition: logger.h:11
void spring_trap(object *trap, object *victim)
This function generalizes attacks by runes/traps.
Definition: rune.cpp:214
#define AT_HOLYWORD
Damage based on race and caster&#39;s god.
Definition: attack.h:99
int on_same_map(const object *op1, const object *op2)
Checks whether 2 objects are on the same map or not.
Definition: map.cpp:2628
static int get_attack_mode(object **target, object **hitter, int *simple_attack)
Find correct parameters for attack, do some sanity checks.
Definition: attack.cpp:688
static int hit_with_drain(object *op, object *hitter, int dam)
Definition: attack.cpp:1174
#define SOUND_TYPE_HIT
Definition: newclient.h:353
Sound-related defines.
object * ranges[range_size]
Object for each range.
Definition: player.h:118
const char * determine_god(object *op)
Determines if op worships a god.
Definition: gods.cpp:55
#define FLAG_DAMNED
The object is very cursed.
Definition: define.h:305
#define FLAG_UNPAID
Object hasn&#39;t been paid for yet.
Definition: define.h:223
#define UP_OBJ_FACE
Only thing that changed was the face.
Definition: object.h:533
static void put_in_icecube(object *op, object *originator)
Definition: attack.cpp:151
see doc/Developers/objects
Definition: object.h:113
#define FLAG_ONE_HIT
Monster can only hit once before going away (replaces ghosthit)
Definition: define.h:331
#define AT_ELECTRICITY
Can also ignite objects (8)
Definition: attack.h:81
#define AT_COUNTERSPELL
Cancels magic spells (524288) peterm@soda.berkeley.edu.
Definition: attack.h:97
#define ATM_KARATE
Definition: attack.h:27
Information.
Definition: logger.h:12
See Ring.
Definition: object.h:190
int64_t calc_skill_exp(const object *who, const object *op, const object *skill)
Calculates amount of experience can be gained for successful use of a skill.
Definition: skill_util.cpp:691
int did_make_save(const object *op, int level, int bonus)
This function takes an object (monster/player, op), and determines if it makes a basic save throw by ...
Definition: living.cpp:2293
#define AT_DEPLETE
Lose one point from one stat, can be restored (65536) vick@bern.docs.uu.se.
Definition: attack.h:94
#define AT_GHOSTHIT
Attacker dissolves (512)
Definition: attack.h:87
struct archetype * arch
Pointer to archetype.
Definition: object.h:424
#define ATNR_SLOW
Definition: attack.h:58
const object * find_god(const char *name)
Returns a god&#39;s object from its name.
Definition: holy.cpp:317
#define FLAG_SLEEP
NPC is sleeping.
Definition: define.h:295
Material structures and defines.
#define FLAG_HITBACK
Object will hit back when hit.
Definition: define.h:254
object * object_get_owner(object *op)
Returns the object which this object marks as being the owner.
Definition: object.cpp:789
int level
Definition: attack.h:121
void share_exp(object *op, int64_t exp, const char *skill, int flag)
Gives experience to a player/monster, sharing it with party if applicable.
Definition: living.cpp:2323
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:58
#define SP_CONE
Definition: spells.h:81
#define NDI_ALL
Inform all players of this message.
Definition: newclient.h:271
void confuse_living(object *op, object *hitter, int dam)
Confuse a living thing.
Definition: attack.cpp:2315
#define FABS(x)
Decstations have trouble with fabs()...
Definition: define.h:22
int rndm(int min, int max)
Returns a number between min and max.
Definition: utils.cpp:162
int monster_can_see_enemy(object *op, object *enemy)
Assuming no walls/barriers, lets check to see if its possible to see an enemy.
Definition: monster.cpp:2867
int get_turn_bonus(int stat)
Definition: living.cpp:2385
Wraith feed.
Definition: skills.h:57
void change_luck(object *op, int value)
Alter the object&#39;s luck.
Definition: living.cpp:796
void object_handle_death_animation(object *op)
Definition: object.cpp:5395
#define ATNR_FIRE
Definition: attack.h:49
uint32_t weapontype
Type of weapon.
Definition: object.h:381
materialtype_t * name_to_material(const char *name)
Convert materialname to materialtype_t.
Definition: utils.cpp:248
#define WEAP_CLEAVE
axe
Definition: define.h:80
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...) PRINTF_ARGS(6
#define ATNR_ACID
Definition: attack.h:53
int player_arrest(object *who)
Put a player into jail, taking into account cursed exits and player&#39;s region.
Definition: c_wiz.cpp:789
float move_slow_penalty
How much this slows down the object.
Definition: object.h:442
See Projectile.
Definition: object.h:122
#define FLAG_FRIENDLY
Will help players.
Definition: define.h:233
static void get_attack_message(int dam, int type, const object *op, const object *hitter, char *buf1, char *buf2)
Compute attack messages.
Definition: attack.cpp:569
archetype * find_archetype(const char *name)
Definition: assets.cpp:270
uint32_t peaceful
If set, won&#39;t attack friendly creatures.
Definition: player.h:148
static int attack_ob_simple(object *op, object *hitter, int base_dam, int wc)
Handles simple attack cases.
Definition: attack.cpp:767
void fix_object(object *op)
Updates all abilities given by applied objects in the inventory of the given object.
Definition: living.cpp:1132
object * object_find_by_type2(const object *who, int type1, int type2)
Find object in inventory.
Definition: object.cpp:4022
static void deathstrike_living(object *op, object *hitter, int *dam)
Attempts to kill &#39;op&#39;.
Definition: attack.cpp:2453
void object_remove(object *op)
This function removes the object op from the linked list of objects which it is currently tied to...
Definition: object.cpp:1818
static void scare_creature(object *target, object *hitter)
Creature is scared, update its values.
Definition: attack.cpp:1163
#define BIG_NAME
Definition: define.h:42
void set_materialname(object *op)
Set the material name and type for an item, if not set.
Definition: utils.cpp:297
#define AT_CANCELLATION
Removes magic from items (32768) ylitalo@student.docs.uu.se.
Definition: attack.h:93
void paralyze_living(object *op, int dam)
Paralyze a living thing.
Definition: attack.cpp:2402
int level
Definition: readable.cpp:1561
#define ATNR_CONFUSION
Definition: attack.h:52
#define WEAP_SLICE
katana
Definition: define.h:81
void fix_stopped_item(object *op, mapstruct *map, object *originator)
Put stopped item where stop_item() had found it.
Definition: time.cpp:495
#define SET_ANIMATION(ob, newanim)
Definition: global.h:164
object * blame(object *op)
Definition: attack.cpp:176
void esrv_update_item(int flags, object *pl, object *op)
Updates object *op for player *pl.
Definition: main.cpp:359
partylist * party
Party this player is part of.
Definition: player.h:205
sstring slaying
Which race to do double damage to.
Definition: object.h:327
sstring add_string(const char *str)
Share a string.
Definition: shstr.cpp:137
static int hit_with_one_attacktype(object *op, object *hitter, int dam, uint32_t attacknum)
Handles one attacktype&#39;s damage.
Definition: attack.cpp:1272
#define FLAG_BLIND
If set, object cannot see (visually)
Definition: define.h:324
#define PREFER_LOW
Definition: define.h:585
See Rune.
Definition: object.h:245
void remove_friendly_object(object *op)
Removes the specified object from the linked list of friendly objects.
Definition: friend.cpp:52
void change_exp(object *op, int64_t exp, const char *skill_name, int flag)
Changes experience to a player/monster.
Definition: living.cpp:2179
void get_attack_message_for_attack_type(int dam, uint8_t atm_type, const char *victim_name, char *buf1, char *buf2)
Get the attack message for a damage and a type.
Definition: attack.cpp:538
#define FLAG_CONFUSED
Will also be unable to cast spells.
Definition: define.h:299
int free_no_drop(object *op)
Check whether the given object is FLAG_NO_DROP.
Definition: time.cpp:565
void save_throw_object(object *op, uint32_t type, object *originator)
Object is attacked with some attacktype (fire, ice, ...).
Definition: attack.cpp:202
int slow_living_by(object *op, const int speed_penalty)
Definition: attack.cpp:2231
#define ATNR_CHAOS
Definition: attack.h:65
See Rod.
Definition: object.h:114
#define AT_COLD
Can freeze objects into ice cubes (16)
Definition: attack.h:82
int16_t y
Position in the map for this object.
Definition: object.h:335
int8_t magic
Any magical bonuses to this item.
Definition: object.h:358
uint16_t material
What materials this object consist of.
Definition: object.h:357
sstring add_refcount(sstring str)
Like add_string(), but the string is already a shared string.
Definition: shstr.cpp:224
static void object_get_materialtype(object *op, materialtype_t **mt)
Definition: attack.cpp:75
MoveType move_block
What movement types this blocks.
Definition: object.h:437
#define OUT_OF_REAL_MAP(M, X, Y)
Checks if a square is out of the map.
Definition: map.h:220
#define object_was_destroyed(op, old_tag)
Checks if an object still exists.
Definition: object.h:70
#define TRUE
Definition: compat.h:11
See Girdle.
Definition: object.h:228
#define ATM_PIERCE
Definition: attack.h:31
int16_t duration
Number of moves (see &#39;speed&#39;) spell lasts.
Definition: object.h:415
#define FLAG_IS_LIGHTABLE
object can be lit
Definition: define.h:265
object * stop_item(object *op)
An item (ARROW or such) stops moving.
Definition: time.cpp:455
See Amulet.
Definition: object.h:144
#define ATNR_PARALYZE
Definition: attack.h:59
#define FALSE
Definition: compat.h:14
object * chosen_skill
The skill chosen to use.
Definition: object.h:396
#define MAX(x, y)
Definition: compat.h:24
#define ATM_BLUD
Definition: attack.h:37
#define FLAG_TEAR_DOWN
at->faces[hp*animations/maxhp] at hit
Definition: define.h:266
void object_set_owner(object *op, object *owner)
Sets the owner and sets the skill and exp pointers to owner&#39;s current skill and experience objects...
Definition: object.cpp:825
#define AT_BLIND
Blinds victim (4194304) thomas@astro.psu.edu.
Definition: attack.h:100
char title[BIG_NAME]
Default title, like fighter, wizard, etc.
Definition: player.h:186
int16_t x
Definition: object.h:335
void process_object(object *op)
Main object move function.
Definition: time.cpp:796
#define NDI_BLACK
Definition: newclient.h:246
#define WEAP_BLUD
bludgeoning, club, stick
Definition: define.h:85
int player_can_view(object *pl, object *op)
Check the player los field for viewability of the object op.
Definition: player.cpp:4168
Global type definitions and header inclusions.
struct player * contr
Pointer to the player which control this object.
Definition: object.h:284
int8_t Con
Use
Definition: living.h:36
const char * undead_name
Definition: init.cpp:125
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Sends message to player(s).
Definition: main.cpp:308
char * host
Which host it is connected from (ip address).
Definition: newserver.h:104
See Wand & Staff.
Definition: object.h:225
#define MSG_TYPE_APPLY
Applying objects.
Definition: newclient.h:425
uint8_t casting_time
It takes awhile to cast a spell.
Definition: global.h:271
#define FOR_OB_AND_BELOW_FINISH()
Finishes FOR_OB_AND_BELOW_PREPARE().
Definition: define.h:777
#define MIN(x, y)
Definition: compat.h:21
#define FLAG_REMOVED
Object is not in any map or invenory.
Definition: define.h:219
int32_t weight
Attributes of the object.
Definition: object.h:375
void events_execute_global_event(int eventcode,...)
Execute a global event.
Definition: events.cpp:30
#define EVENT_ATTACKED
Object attacked, with weapon or spell.
Definition: events.h:29
object * find_applied_skill_by_name(const object *op, const char *name)
Find a skill by name using the last_skill_ob list.
Definition: living.cpp:1932
int friendly_fire(object *op, object *hitter)
Find out if this is friendly fire (PVP and attacker is peaceful) or not.
Definition: attack.cpp:1858
#define FLAG_KNOWN_MAGICAL
The object is known to be magical.
Definition: define.h:307
#define ATM_COLD
Definition: attack.h:24
static std::shared_ptr< inja::Environment > env
Rendering environment.
Definition: mapper.cpp:2222
Clawing.
Definition: skills.h:50
#define AT_TURN_UNDEAD
Like Fear, but for undead only (8192)
Definition: attack.h:91
#define ATM_WRAITH_FEED
Definition: attack.h:40
#define NROFATTACKS
Definition: attack.h:15
uint8_t run_away
Monster runs away if it&#39;s hp goes below this percentage.
Definition: object.h:394
const Face * blank_face
Following can just as easily be pointers, but it is easier to keep them like this.
Definition: image.cpp:36
#define AT_LIFE_STEALING
16777216 for hp drain
Definition: attack.h:102
#define WEAP_WHIP
whips n chains
Definition: define.h:83
#define FLAG_UNDEAD
Monster is undead.
Definition: define.h:257
#define ATNR_TURN_UNDEAD
Definition: attack.h:60
int change_abil(object *op, object *tmp)
Permanently alters an object&#39;s stats/flags based on another object.
Definition: living.cpp:394
#define AT_CHAOS
None by itself, uses random other types (262144) peterm@soda.berkeley.edu.
Definition: attack.h:96
void free_string(sstring str)
This will reduce the refcount, and if it has reached 0, str will be freed.
Definition: shstr.cpp:294
static int stick_arrow(object *op, object *tmp)
Try to put an arrow in inventory.
Definition: attack.cpp:952
#define MSG_TYPE_ATTACK_PET_DIED
Pet was killed.
Definition: newclient.h:652
See Trap.
Definition: object.h:246
int16_t level
Level of creature or object.
Definition: object.h:361
object * object_decrease_nrof(object *op, uint32_t i)
Decreases a specified number from the amount of an object.
Definition: object.cpp:2661
#define ATNR_DEATH
Definition: attack.h:64
#define NDI_RED
Definition: newclient.h:249
One party.
Definition: party.h:10
static int kill_object(object *op, int dam, object *hitter)
An object was killed, handle various things (logging, messages, ...).
Definition: attack.cpp:1586
int16_t casting_time
Time left before spell goes off.
Definition: object.h:414
uint8_t hide
The object is hidden, not invisible.
Definition: object.h:397
#define SP_BULLET
Definition: spells.h:79
#define FLAG_ALIVE
Object can fight (or be fought)
Definition: define.h:217
int16_t resist[NROFATTACKS]
Resistance adjustments for attacks.
Definition: object.h:351
void kill_player(object *op, const object *killer)
Handle a player&#39;s death.
Definition: player.cpp:3514
int8_t save[NROFATTACKS]
Save chances for the attacks.
Definition: material.h:37
#define MSG_TYPE_VICTIM
Something bad is happening to the player.
Definition: newclient.h:433
#define ATM_SLICE
Definition: attack.h:33
#define ATNR_COLD
Definition: attack.h:51
#define ATM_DRAIN
Definition: attack.h:22
The archetype structure is a set of rules on how to generate and manipulate objects which point to ar...
Definition: object.h:483
#define ATM_DOOR
Definition: attack.h:38
sstring materialname
Specific material name.
Definition: object.h:356
sstring name
More definite name, like "generate_kobold".
Definition: object.h:484
#define SK_EXP_TOTAL
Give player exp to total, no skill.
Definition: skills.h:79
int8_t Dex
Use
Definition: living.h:36
float speed
Frequency of object &#39;moves&#39; relative to server tick rate.
Definition: object.h:337
object * arch_to_object(archetype *at)
Creates and returns a new object which is a copy of the given archetype.
Definition: arch.cpp:227
object * create_archetype(const char *name)
Finds which archetype matches the given name, and returns a new object containing a copy of the arche...
Definition: arch.cpp:276
int64_t pk_max_experience
Maximum experience one can get for PKing.
Definition: global.h:314
object * env
Pointer to the object which is the environment.
Definition: object.h:301
#define SET_FLAG(xyz, p)
Definition: define.h:384
#define FLAG_UNAGGRESSIVE
Monster doesn&#39;t attack players.
Definition: define.h:259
int monster_stand_in_light(object *op)
Cache monster_stand_in_light_internal().
Definition: monster.cpp:2845
#define QUERY_FLAG(xyz, p)
Definition: define.h:386
void monster_npc_call_help(object *op)
A monster calls for help against its enemy.
Definition: monster.cpp:2014
#define MSG_TYPE_ADMIN_PLAYER
Player coming/going/death.
Definition: newclient.h:515
int8_t Wis
Use
Definition: living.h:36
#define MSG_TYPE_ATTACK_DID_KILL
Player killed something.
Definition: newclient.h:651
sstring anim_suffix
Used to determine combined animations.
Definition: object.h:324
#define ATM_FIRE
Definition: attack.h:25
#define MSG_TYPE_ATTRIBUTE
Changes to attributes (stats, resistances, etc)
Definition: newclient.h:421
#define ATNR_INTERNAL
Definition: attack.h:70
void query_name(const object *op, char *buf, size_t size)
Describes an item.
Definition: item.cpp:594
void object_free_drop_inventory(object *ob)
Frees everything allocated by an object, removes it from the list of used objects, and puts it on the list of free objects.
Definition: object.cpp:1545
short freearr_x[SIZEOFFREE]
X offset when searching around a spot.
Definition: object.cpp:299
#define EVENT_GKILL
Triggered when anything got killed by anyone.
Definition: events.h:55
#define MOVE_FLYING
Combo of fly_low and fly_high.
Definition: define.h:401
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:700
Control golem.
Definition: player.h:34
socket_struct * socket
Socket information for this player.
Definition: player.h:109
uint32_t golem_count
To track the golem.
Definition: player.h:121
object * head
Points to the main object of a large body.
Definition: object.h:304
int64_t check_exp_loss(const object *op, int64_t exp)
This function checks to make sure that object &#39;op&#39; can lose &#39;exp&#39; experience.
Definition: living.cpp:2077
sstring race
Human, goblin, dragon, etc.
Definition: object.h:326
This is a game-map.
Definition: map.h:320
Definition: object.h:150
#define FLAG_BLOCKSVIEW
Object blocks view.
Definition: define.h:256
void update_all_los(const mapstruct *map, int x, int y)
This function makes sure that update_los() will be called for all players on the given map within the...
Definition: los.cpp:595
#define ATNR_BLIND
Definition: attack.h:69
#define WEAP_STAB
knife, dagger
Definition: define.h:82
#define WEAP_PIERCE
arrows, stiletto
Definition: define.h:79
#define MSG_TYPE_VICTIM_WAS_HIT
Player was hit by something.
Definition: newclient.h:688
#define INS_NO_WALK_ON
Don&#39;t call check_walk_on against the originator.
Definition: object.h:584
#define FLAG_PARALYZED
Monster or player is paralyzed.
Definition: define.h:367
const Face * face
Face with colors.
Definition: object.h:341
char killer[BIG_NAME]
Who killed this player.
Definition: player.h:192
#define UPD_FLAGS
Definition: newclient.h:331
#define P_OUT_OF_MAP
This space is outside the map.
Definition: map.h:254
int hit_map(object *op, int dir, uint32_t type, int full_hit)
Attack a spot on the map.
Definition: attack.cpp:355
See Potion.
Definition: object.h:116
#define AT_FIRE
Can ignite objects (4)
Definition: attack.h:80
struct Settings settings
Global settings.
Definition: init.cpp:139
#define FLAG_SCARED
Monster is scared (mb player in future)
Definition: define.h:258
static int did_make_save_item(object *op, int type, object *originator)
Checks to make sure the item actually made its saving throw based on the tables.
Definition: attack.cpp:104
#define FORCE_CONFUSION
Definition: spells.h:144
#define ATM_CLAW
Definition: attack.h:28
int op_on_battleground(object *op, int *x, int *y, archetype **trophy)
Check if the given object (usually a player) is standing on a battleground tile.
Definition: player.cpp:4267
object * object_present_in_ob(uint8_t type, const object *op)
Searches for any objects with a matching type variable in the inventory of the given object...
Definition: object.cpp:3153
uint8_t simple_exp
If true, use the simple experience system.
Definition: global.h:264
int random_roll(int min, int max, const object *op, int goodbad)
Roll a random number between min and max.
Definition: utils.cpp:42
uint32_t tag_t
Object tag, unique during the whole game.
Definition: object.h:14
int16_t dam
How much damage this object does when hitting.
Definition: living.h:46
void object_replace_insert_in_map(const char *arch_string, object *op)
This function inserts an object of a specified archetype in the map, but if it finds objects of its o...
Definition: object.cpp:2582
#define AT_PHYSICAL
Basic attack (1)
Definition: attack.h:78
See Spell.
Definition: object.h:219
#define IS_LIVE(op)
Definition: define.h:173
#define HEAD(op)
Returns the head part of an object.
Definition: object.h:609
#define MSG_TYPE_APPLY_UNAPPLY
Unapply an object.
Definition: newclient.h:638
#define FLAG_WIZ
Object has special privilegies.
Definition: define.h:218
const char *const attacks[NROFATTACKS]
Attack type names.
Definition: living.cpp:129
#define MSG_TYPE_ATTACK_FUMBLE
Player fumbled attack.
Definition: newclient.h:650
#define WEAP_CRUSH
big hammers, flails
Definition: define.h:84
living stats
Str, Con, Dex, etc.
Definition: object.h:378
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
#define MSG_TYPE_ATTACK
Attack related messages.
Definition: newclient.h:426
static void attack_message(int dam, int type, object *op, object *hitter)
Send an attack message to someone.
Definition: attack.cpp:608
#define ATNR_POISON
Definition: attack.h:57
See Door.
Definition: object.h:131
#define ATNR_COUNTERSPELL
Definition: attack.h:66
int16_t invisible
How much longer the object will be invis.
Definition: object.h:370
#define ATM_STAB
Definition: attack.h:34
#define MSG_TYPE_ADMIN
Definition: newclient.h:418
#define MSG_TYPE_ATTACK_DID_HIT
Player hit something else.
Definition: newclient.h:648
Punching.
Definition: skills.h:36
#define WEAP_SLASH
slash
Definition: define.h:78
object * map_find_by_archetype(mapstruct *m, int x, int y, const archetype *at)
Searches for any objects with a matching archetype at the given map and coordinates.
Definition: object.cpp:3103
float speed_left
How much speed is left to spend this round.
Definition: object.h:338
object * arch_present_in_ob(const archetype *at, const object *op)
Searches for any objects with a matching archetype in the inventory of the given object.
Definition: object.cpp:3207
Karate.
Definition: skills.h:38
struct mapstruct * map
Pointer to the map in which this object is present.
Definition: object.h:305
#define FLAG_RUN_AWAY
Object runs away from nearest player \ but can still attack at a distance.
Definition: define.h:267
Skill-related defines, including subtypes.
#define EVENT_ATTACKS
Weapon or arrow hitting something.
Definition: events.h:30
#define M_IRON
Iron.
Definition: material.h:15
See Container.
Definition: object.h:236
#define ATM_CRUSH
Definition: attack.h:36
#define FLAG_READY_WEAPON
(Monster or Player) has a weapon readied
Definition: define.h:322
#define AT_DRAIN
Victim loses 2% exp, attacker gains half of that (128)
Definition: attack.h:85
short freearr_y[SIZEOFFREE]
Y offset when searching around a spot.
Definition: object.cpp:305
object * object_present_in_ob_by_name(int type, const char *str, const object *op)
Searches for any objects with a matching type & name variable in the inventory of the given object...
Definition: object.cpp:3188
#define FOR_MAP_FINISH()
Finishes FOR_MAP_PREPARE().
Definition: define.h:753
MoveType move_slow
Movement types this slows down.
Definition: object.h:441
#define FLAG_KNOWN_CURSED
The object is known to be cursed.
Definition: define.h:308
object * object_merge(object *op, object *top)
This function goes through all objects below and including top, and merges op to the first matching o...
Definition: object.cpp:2036
#define FLAG_CURSED
The object is cursed.
Definition: define.h:304
See Player.
Definition: object.h:112
struct archetype * other_arch
Pointer used for various things - mostly used for what this objects turns into or what this object cr...
Definition: object.h:425
See Poison Food.
Definition: object.h:118
#define MAXATTACKMESS
Definition: attack.h:17
#define AT_POISON
Some damage each turn thereafter (1024)
Definition: attack.h:88
static int adj_attackroll(object *hitter, object *target)
Adjustments to attack rolls by various conditions.
Definition: attack.cpp:2566
Chaos_Attacks ATTACKS[22]
Some local definitions for shuffle_attack().
Definition: init.cpp:81
#define FLAG_NO_DAMAGE
monster can&#39;t be damaged
Definition: define.h:351
#define PREFER_HIGH
Definition: define.h:584
static int abort_attack(object *target, object *hitter, int simple_attack)
Check if target and hitter are still in a relation similar to the one determined by get_attack_mode()...
Definition: attack.cpp:724
#define FLAG_GENERATOR
Will generate type ob->stats.food.
Definition: define.h:235
#define INS_NO_MERGE
Don&#39;t try to merge with other items.
Definition: object.h:582
static event_registration m
Definition: citylife.cpp:424
uint16_t set_friendly_fire
Percent of damage done by peaceful player vs player damage.
Definition: global.h:276
#define ATM_ARROW
Definition: attack.h:21
#define VERY_BIG_BUF
Definition: define.h:36
#define RANDOM()
Definition: define.h:667
int attack_ob(object *op, object *hitter)
Simple wrapper for attack_ob_simple(), will use hitter&#39;s values.
Definition: attack.cpp:937
#define NUM_ANIMATIONS(ob)
Definition: global.h:173
Also see SKILL_TOOL (74) below.
Definition: object.h:148
MoveType move_type
Type of movement this object uses.
Definition: object.h:436
#define ATNR_DRAIN
Definition: attack.h:54
sstring name
The name of the object, obviously...
Definition: object.h:319
#define SCRIPT_FIX_ALL
Definition: global.h:380
sstring title
Of foo, etc.
Definition: object.h:325
Only for debugging purposes.
Definition: logger.h:13
uint32_t nrof
Number of objects.
Definition: object.h:342
static void thrown_item_effect(object *, object *)
Handles any special effects of thrown items (like attacking living creatures–a potion thrown at a mo...
Definition: attack.cpp:2526
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, int16_t x, int16_t y, int16_t *nx, int16_t *ny)
This rolls up wall, blocks_magic, blocks_view, etc, all into one function that just returns a P_...
Definition: map.cpp:300
static void tear_down_wall(object *op)
Handles wall tearing animation.
Definition: attack.cpp:1114
uint8_t darkness
Indicates level of darkness of map.
Definition: map.h:341
static void cancellation(object *op)
Cancels object *op.
Definition: attack.cpp:51
#define AT_FEAR
(16384)
Definition: attack.h:92
#define AT_SLOW
Speed is reduced (2048)
Definition: attack.h:89
void object_set_enemy(object *op, object *enemy)
Sets the enemy of an object.
Definition: object.cpp:900
#define SK_EXP_ADD_SKILL
Give the player the skill.
Definition: skills.h:78
#define CLEAR_FLAG(xyz, p)
Definition: define.h:385
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:348
#define ATM_WHIP
Definition: attack.h:35
#define ATNR_CANCELLATION
Definition: attack.h:62
#define FLAG_SPLITTING
Object splits into stats.food other objs.
Definition: define.h:253
void check_physically_infect(object *victim, object *hitter)
Possibly infect due to direct physical contact i.e., AT_PHYSICAL.
Definition: disease.cpp:663
int8_t ac
Armor Class, lower AC increases probability of not getting hit.
Definition: living.h:38
#define ATM_CLEAVE
Definition: attack.h:32
#define FLAG_APPLIED
Object is ready for use by living.
Definition: define.h:222
#define ATNR_MAGIC
Definition: attack.h:48
void object_update_speed(object *op)
Updates the speed of an object.
Definition: object.cpp:1334
#define UPD_NAME
Definition: newclient.h:334
#define ATM_SLASH
Definition: attack.h:30
#define ATM_PUNCH
Definition: attack.h:29
#define MSG_TYPE_APPLY_SUCCESS
Was able to apply object.
Definition: newclient.h:639
object * inv
Pointer to the first object in the inventory.
Definition: object.h:298
#define FOR_OB_AND_BELOW_PREPARE(op_)
Constructs a loop iterating over an object and all objects below it in the same pile.
Definition: define.h:773
#define ATNR_HOLYWORD
Definition: attack.h:68
method_ret ob_apply(object *op, object *applier, int aflags)
Apply an object by running an event hook or an object method.
Definition: ob_methods.cpp:44
#define FORCE_NAME
Definition: spells.h:169
#define AT_MAGIC
All magic spells, but not prayers (2)
Definition: attack.h:79
#define GET_ANIM_ID(ob)
Definition: global.h:167
int hit_player(object *op, int dam, object *hitter, uint32_t type, int full_hit)
Object is attacked by something.
Definition: attack.cpp:1907
Lauwenmark: an invisible object holding a plugin event hook.
Definition: object.h:232
static int is_aimed_missile(object *op)
Determine if the object is an &#39;aimed&#39; missile.
Definition: attack.cpp:2633
void object_copy_owner(object *op, object *clone)
Set the owner to clone&#39;s current owner and set the skill and experience objects to clone&#39;s objects (t...
Definition: object.cpp:878
object * hit_with_arrow(object *op, object *victim)
hit_with_arrow() disassembles the missile, attacks the victim and reassembles the missile...
Definition: attack.cpp:979
void blind_living(object *op, object *hitter, int dam)
Blind a living thing.
Definition: attack.cpp:2358
static const int32_t MAX_FOOD
Definition: define.h:461
int64_t exp
Experience.
Definition: living.h:47
sstring skill
Name of the skill this object uses/grants.
Definition: object.h:329
uint32_t attacktype
Bitmask of attacks this object does.
Definition: object.h:352
#define FLAG_MONSTER
Will attack players.
Definition: define.h:232
void counterspell(object *op, int dir)
Nullifies spell effects.
int events_execute_object_event(object *op, int eventcode, object *activator, object *third, const char *message, int fix)
Execute an event on the specified object.
Definition: events.cpp:309
#define NDI_UNIQUE
Print immediately, don&#39;t buffer.
Definition: newclient.h:270
int is_wraith_pl(object *op)
Tests if a player is a wraith.
Definition: player.cpp:174
static void poison_living(object *op, object *hitter, int dam)
Poison a living thing.
Definition: attack.cpp:2158
static void slow_living(object *op, object *hitter, int dam)
Slow a living thing.
Definition: attack.cpp:2270
bool is_criminal(object *op)
Definition: player.cpp:313
#define MSG_TYPE_VICTIM_WAS_PUSHED
Player was pushed or attempted pushed.
Definition: newclient.h:696
void commit_crime(object *op, const char *description)
Definition: player.cpp:308
archetype * more
Next part of a linked object.
Definition: object.h:486
void make_visible(object *op)
Makes an object visible again.
Definition: player.cpp:3982
#define FLAG_WAS_WIZ
Player was once a wiz.
Definition: define.h:221
One material type.
Definition: material.h:33
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Constructs a loop iterating over all objects of a map tile.
Definition: define.h:746
void play_sound_map(int8_t sound_type, object *emitter, int dir, const char *action)
Plays a sound on a map.
Definition: sounds.cpp:113
int32_t food
How much food in stomach.
Definition: living.h:48
StringBuffer * buf
Definition: readable.cpp:1563
#define ATNR_DEPLETE
Definition: attack.h:63
object * current_weapon
Pointer to the weapon currently used.
Definition: object.h:380
Structure containing object statistics.
#define MSG_TYPE_ATTACK_PET_HIT
Players pet hit something else.
Definition: newclient.h:649
int16_t maxhp
Max hit points.
Definition: living.h:41
uint8_t subtype
Subtype of object.
Definition: object.h:349
#define ATM_SUFFER
Definition: attack.h:39
object * object_insert_in_ob(object *op, object *where)
This function inserts the object op in the linked list inside the object environment.
Definition: object.cpp:2842
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Same as object_insert_in_map() except it handle separate coordinates and do a clean job preparing mul...
Definition: object.cpp:2085
int8_t wc
Weapon Class, lower WC increases probability of hitting.
Definition: living.h:37
int8_t Int
Use
Definition: living.h:36
#define USING_SKILL(op, skill)
True if op is using skill, false else.
Definition: skills.h:85
#define AT_CONFUSION
Movement/attack directions become random (32)
Definition: attack.h:83
void object_update(object *op, int action)
object_update() updates the array which represents the map.
Definition: object.cpp:1419
tag_t count
Unique object number for this object.
Definition: object.h:307
#define FLAG_NO_PICK
Object can&#39;t be picked up.
Definition: define.h:226
int pk_max_experience_percent
Percentage of experience of victim the killer gets.
Definition: global.h:315
#define IS_ARROW(op)
Definition: define.h:178
#define AT_ACID
Random equipped item might corrode when hit (64)
Definition: attack.h:84
void drain_stat(object *op)
Drains a random stat from op.
Definition: living.cpp:716
attackmess_t attack_mess[NROFATTACKMESS][MAXATTACKMESS]
Definition: init.cpp:78
#define SP_EXPLOSION
Definition: spells.h:80
static uint8_t get_attack_message_type(int type, const object *op, const object *hitter)
Figure the Attack types ATM_xxx type for an attack.
Definition: attack.cpp:463
#define AT_DEATH
Chance of instant death, otherwise nothing (131072) peterm@soda.berkeley.edu.
Definition: attack.h:95
See Disease.
Definition: object.h:249
void change_object(object *op)
Replaces op with its other_arch if it has reached its end of life.
Definition: time.cpp:592
object clone
An object from which to do object_copy()
Definition: object.h:487
#define WEAP_HIT
the basic
Definition: define.h:77
bool object_value_set(const object *op, const char *const key)
Determine if an extra value is set.
Definition: object.cpp:4361
#define ATNR_LIFE_STEALING
Definition: attack.h:71
int8_t Str
Use
Definition: living.h:36
object * fix_stopped_arrow(object *op)
An ARROW stops moving.
Definition: time.cpp:512
#define FOR_INV_PREPARE(op_, it_)
Constructs a loop iterating over the inventory of an object.
Definition: define.h:693
int16_t pk_luck_penalty
Amount by which player luck is reduced if they PK.
Definition: global.h:258
void shuffle_attack(object *op)
This routine shuffles the attack of op to one of the ones in the list.
#define ATNR_PHYSICAL
Definition: attack.h:47
void apply_anim_suffix(object *who, const char *suffix)
Applies a compound animation to an object.
Definition: anim.cpp:150
#define AT_PARALYZE
Speed is reduced to zero (4096)
Definition: attack.h:90
#define MSG_TYPE_ATTRIBUTE_BAD_EFFECT_START
Start of a bad effect to the player.
Definition: newclient.h:599
char * name
Name of map as given by its creator.
Definition: map.h:323
int16_t hp
Hit Points.
Definition: living.h:40
#define FLAG_FREED
Object is in the list of free objects.
Definition: define.h:220
object * enemy
Monster/player to follow even if not closest.
Definition: object.h:391
Definition: object.h:229
#define EVENT_DEATH
Player or monster dead.
Definition: events.h:33
#define ATM_ELEC
Definition: attack.h:23