Crossfire Server, Trunk  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  */
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;
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;
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.
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 }
ATM_BLUD
#define ATM_BLUD
Definition: attack.h:39
Settings::casting_time
uint8_t casting_time
It takes awhile to cast a spell.
Definition: global.h:271
object_was_destroyed
#define object_was_destroyed(op, old_tag)
Checks if an object still exists.
Definition: object.h:70
object_value_set
bool object_value_set(const object *op, const char *const key)
Determine if an extra value is set.
Definition: object.cpp:4361
did_make_save_item
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
get_attack_message_type
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
living::exp
int64_t exp
Experience.
Definition: living.h:47
UP_OBJ_FACE
#define UP_OBJ_FACE
Only thing that changed was the face.
Definition: object.h:533
PLAYER
@ PLAYER
Definition: object.h:112
object_get_owner
object * object_get_owner(object *op)
Returns the object which this object marks as being the owner.
Definition: object.cpp:789
ATNR_PARALYZE
#define ATNR_PARALYZE
Definition: attack.h:61
EVENT_ATTACKS
#define EVENT_ATTACKS
Weapon or arrow hitting something.
Definition: events.h:30
global.h
deathstrike_living
static void deathstrike_living(object *op, object *hitter, int *dam)
Attempts to kill 'op'.
Definition: attack.cpp:2453
cancellation
static void cancellation(object *op)
Cancels object *op.
Definition: attack.cpp:51
ATNR_CANCELLATION
#define ATNR_CANCELLATION
Definition: attack.h:64
settings
struct Settings settings
Global settings.
Definition: init.cpp:139
Settings::simple_exp
uint8_t simple_exp
If true, use the simple experience system.
Definition: global.h:264
INS_NO_WALK_ON
#define INS_NO_WALK_ON
Don't call check_walk_on against the originator.
Definition: object.h:582
FOR_MAP_FINISH
#define FOR_MAP_FINISH()
Finishes FOR_MAP_PREPARE().
Definition: define.h:724
remove_friendly_object
void remove_friendly_object(object *op)
Removes the specified object from the linked list of friendly objects.
Definition: friend.cpp:52
living::maxhp
int16_t maxhp
Max hit points.
Definition: living.h:41
stick_arrow
static int stick_arrow(object *op, object *tmp)
Try to put an arrow in inventory.
Definition: attack.cpp:952
AT_POISON
#define AT_POISON
Definition: attack.h:86
ATNR_INTERNAL
#define ATNR_INTERNAL
Definition: attack.h:72
object::weapontype
uint32_t weapontype
Type of weapon.
Definition: object.h:381
AT_MAGIC
#define AT_MAGIC
Definition: attack.h:77
FLAG_CONFUSED
#define FLAG_CONFUSED
Will also be unable to cast spells.
Definition: define.h:311
find_applied_skill_by_name
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
abort_attack
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
FORCE_CONFUSION
#define FORCE_CONFUSION
Definition: spells.h:144
llevError
@ llevError
Error, serious thing.
Definition: logger.h:11
FABS
#define FABS(x)
Decstations have trouble with fabs()...
Definition: define.h:22
EVENT_CONNECTOR
@ EVENT_CONNECTOR
Lauwenmark: an invisible object holding a plugin event hook.
Definition: object.h:232
ATM_KARATE
#define ATM_KARATE
Definition: attack.h:29
SYMPTOM
@ SYMPTOM
Definition: object.h:250
WAND
@ WAND
Definition: object.h:225
MSG_TYPE_ADMIN_PLAYER
#define MSG_TYPE_ADMIN_PLAYER
Player coming/going/death.
Definition: newclient.h:500
LOG
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:58
FLAG_UNDEAD
#define FLAG_UNDEAD
Monster is undead.
Definition: define.h:270
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:224
archetype::more
archetype * more
Next part of a linked object.
Definition: object.h:486
FLAG_GENERATOR
#define FLAG_GENERATOR
Will generate type ob->stats.food.
Definition: define.h:248
monster_stand_in_light
int monster_stand_in_light(object *op)
Cache monster_stand_in_light_internal().
Definition: monster.cpp:2856
object::inv
object * inv
Pointer to the first object in the inventory.
Definition: object.h:298
EVENT_DEATH
#define EVENT_DEATH
Player or monster dead.
Definition: events.h:33
GIRDLE
@ GIRDLE
Definition: object.h:228
ATNR_ACID
#define ATNR_ACID
Definition: attack.h:55
player::golem_count
uint32_t golem_count
To track the golem.
Definition: player.h:119
hit_player
int hit_player(object *op, int dam, object *hitter, uint32_t type, int full_hit)
Object is attacked by something.
Definition: attack.cpp:1907
AT_ELECTRICITY
#define AT_ELECTRICITY
Definition: attack.h:79
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
SK_CLAWING
@ SK_CLAWING
Clawing.
Definition: skills.h:50
map_find_by_archetype
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
object_merge
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
make_visible
void make_visible(object *op)
Makes an object visible again.
Definition: player.cpp:3974
op_on_battleground
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:4259
FALSE
#define FALSE
Definition: compat.h:14
AT_PHYSICAL
#define AT_PHYSICAL
Definition: attack.h:76
object::arch
struct archetype * arch
Pointer to archetype.
Definition: object.h:424
MSG_TYPE_ATTACK_DID_HIT
#define MSG_TYPE_ATTACK_DID_HIT
Player hit something else.
Definition: newclient.h:616
object::speed
float speed
Frequency of object 'moves' relative to server tick rate.
Definition: object.h:337
if
if(!(yy_init))
Definition: loader.cpp:36435
object_set_enemy
void object_set_enemy(object *op, object *enemy)
Sets the enemy of an object.
Definition: object.cpp:900
object::invisible
int16_t invisible
How much longer the object will be invis.
Definition: object.h:370
living::Dex
int8_t Dex
Definition: living.h:36
TRAP
@ TRAP
Definition: object.h:246
object::x
int16_t x
Definition: object.h:335
player::peaceful
uint32_t peaceful
If set, won't attack friendly creatures.
Definition: player.h:146
spring_trap
void spring_trap(object *trap, object *victim)
This function generalizes attacks by runes/traps.
Definition: rune.cpp:214
get_attack_message
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
M_IRON
#define M_IRON
Iron.
Definition: material.h:15
ATM_PIERCE
#define ATM_PIERCE
Definition: attack.h:33
object::speed_left
float speed_left
How much speed is left to spend this round.
Definition: object.h:338
PREFER_LOW
#define PREFER_LOW
Definition: define.h:558
object::map
struct mapstruct * map
Pointer to the map in which this object is present.
Definition: object.h:305
object::anim_suffix
sstring anim_suffix
Used to determine combined animations.
Definition: object.h:324
arch_present_in_ob
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
object_set_owner
void object_set_owner(object *op, object *owner)
Sets the owner and sets the skill and exp pointers to owner's current skill and experience objects.
Definition: object.cpp:825
object_handle_death_animation
void object_handle_death_animation(object *op)
Definition: object.cpp:5395
MSG_TYPE_ATTRIBUTE
#define MSG_TYPE_ATTRIBUTE
Changes to attributes (stats, resistances, etc)
Definition: newclient.h:409
SP_CONE
#define SP_CONE
Definition: spells.h:81
ATM_FIRE
#define ATM_FIRE
Definition: attack.h:27
ATNR_SLOW
#define ATNR_SLOW
Definition: attack.h:60
SET_ANIMATION
#define SET_ANIMATION(ob, newanim)
Definition: global.h:164
time
non standard information is not specified or uptime this means how long since the executable has been started A particular host may have been running a server for quite a long time
Definition: arch-handbook.txt:206
AMULET
@ AMULET
Definition: object.h:144
draw_ext_info_format
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...) PRINTF_ARGS(6
MIN
#define MIN(x, y)
Definition: compat.h:21
SKILL
@ SKILL
Also see SKILL_TOOL (74) below.
Definition: object.h:148
play_sound_map
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
object::count
tag_t count
Unique object number for this object.
Definition: object.h:307
RUNE
@ RUNE
Definition: object.h:245
set_materialname
void set_materialname(object *op)
Set the material name and type for an item, if not set.
Definition: utils.cpp:297
ATM_BASIC
#define ATM_BASIC
Definition: attack.h:28
FLAG_SCARED
#define FLAG_SCARED
Monster is scared (mb player in future)
Definition: define.h:271
fix_object
void fix_object(object *op)
Updates all abilities given by applied objects in the inventory of the given object.
Definition: living.cpp:1132
Settings::pk_luck_penalty
int16_t pk_luck_penalty
Amount by which player luck is reduced if they PK.
Definition: global.h:258
SK_KARATE
@ SK_KARATE
Karate.
Definition: skills.h:38
FLAG_ONE_HIT
#define FLAG_ONE_HIT
Monster can only hit once before going away (replaces ghosthit)
Definition: define.h:343
NDI_RED
#define NDI_RED
Definition: newclient.h:249
blank_face
const Face * blank_face
Following can just as easily be pointers, but it is easier to keep them like this.
Definition: image.cpp:36
shuffle_attack
void shuffle_attack(object *op)
This routine shuffles the attack of op to one of the ones in the list.
Definition: spell_util.cpp:1033
confuse_living
void confuse_living(object *op, object *hitter, int dam)
Confuse a living thing.
Definition: attack.cpp:2315
TRANSPORT
@ TRANSPORT
see doc/Developers/objects
Definition: object.h:113
ATNR_PHYSICAL
#define ATNR_PHYSICAL
Definition: attack.h:49
object::enemy
object * enemy
Monster/player to follow even if not closest.
Definition: object.h:391
WEAP_WHIP
#define WEAP_WHIP
whips n chains
Definition: define.h:83
NROFATTACKS
#define NROFATTACKS
Definition: attack.h:17
hit_map
int hit_map(object *op, int dir, uint32_t type, int full_hit)
Attack a spot on the map.
Definition: attack.cpp:355
friendly_fire
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
rndm
int rndm(int min, int max)
Returns a number between min and max.
Definition: utils.cpp:162
ATM_ARROW
#define ATM_ARROW
Definition: attack.h:23
FLAG_BLOCKSVIEW
#define FLAG_BLOCKSVIEW
Object blocks view.
Definition: define.h:269
skills.h
ATNR_TURN_UNDEAD
#define ATNR_TURN_UNDEAD
Definition: attack.h:62
object::hide
uint8_t hide
The object is hidden, not invisible.
Definition: object.h:397
range_golem
@ range_golem
Control golem.
Definition: player.h:34
object::title
sstring title
Of foo, etc.
Definition: object.h:325
partylist
One party.
Definition: party.h:10
materials
std::vector< materialtype_t * > materials
Definition: init.cpp:128
MAXATTACKMESS
#define MAXATTACKMESS
Definition: attack.h:19
FLAG_APPLIED
#define FLAG_APPLIED
Object is ready for use by living.
Definition: define.h:235
object::level
int16_t level
Level of creature or object.
Definition: object.h:361
events_execute_object_event
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
AT_LIFE_STEALING
#define AT_LIFE_STEALING
Definition: attack.h:100
buf
StringBuffer * buf
Definition: readable.cpp:1565
name_to_material
materialtype_t * name_to_material(const char *name)
Convert materialname to materialtype_t.
Definition: utils.cpp:248
object_insert_in_ob
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
MSG_TYPE_VICTIM
#define MSG_TYPE_VICTIM
Something bad is happening to the player.
Definition: newclient.h:419
POISONING
@ POISONING
Definition: object.h:223
MAX
#define MAX(x, y)
Definition: compat.h:24
SOUND_TYPE_HIT
#define SOUND_TYPE_HIT
Definition: newclient.h:341
AT_DEATH
#define AT_DEATH
Definition: attack.h:93
ATM_SLICE
#define ATM_SLICE
Definition: attack.h:35
object::resist
int16_t resist[NROFATTACKS]
Resistance adjustments for attacks.
Definition: object.h:351
FLAG_NO_PICK
#define FLAG_NO_PICK
Object can't be picked up.
Definition: define.h:239
ATNR_CONFUSION
#define ATNR_CONFUSION
Definition: attack.h:54
find_god
const object * find_god(const char *name)
Returns a god's object from its name.
Definition: holy.cpp:317
ATNR_HOLYWORD
#define ATNR_HOLYWORD
Definition: attack.h:70
name
Plugin animator file specs[Config] name
Definition: animfiles.txt:4
attack_ob
int attack_ob(object *op, object *hitter)
Simple wrapper for attack_ob_simple(), will use hitter's values.
Definition: attack.cpp:937
hit_with_one_attacktype
static int hit_with_one_attacktype(object *op, object *hitter, int dam, uint32_t attacknum)
Handles one attacktype's damage.
Definition: attack.cpp:1272
draw_ext_info
vs only yadda is in because all tags get reset on the next draw_ext_info In the second since it is all in one draw_ext_info
Definition: media-tags.txt:61
FLAG_ALIVE
#define FLAG_ALIVE
Object can fight (or be fought)
Definition: define.h:230
Settings::pk_max_experience
int64_t pk_max_experience
Maximum experience one can get for PKing.
Definition: global.h:314
blind_living
void blind_living(object *op, object *hitter, int dam)
Blind a living thing.
Definition: attack.cpp:2358
MSG_TYPE_ATTACK_DID_KILL
#define MSG_TYPE_ATTACK_DID_KILL
Player killed something.
Definition: newclient.h:619
ATM_STAB
#define ATM_STAB
Definition: attack.h:36
ATNR_BLIND
#define ATNR_BLIND
Definition: attack.h:71
object::y
int16_t y
Position in the map for this object.
Definition: object.h:335
m
static event_registration m
Definition: citylife.cpp:424
AT_CHAOS
#define AT_CHAOS
Definition: attack.h:94
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Frees everything allocated by an object, removes it from the list of used objects,...
Definition: object.cpp:1545
save_throw_object
void save_throw_object(object *op, uint32_t type, object *originator)
Object is attacked with some attacktype (fire, ice, ...).
Definition: attack.cpp:202
object_update
void object_update(object *op, int action)
object_update() updates the array which represents the map.
Definition: object.cpp:1419
object::contr
struct player * contr
Pointer to the player which control this object.
Definition: object.h:284
PREFER_HIGH
#define PREFER_HIGH
Definition: define.h:557
FLAG_TEAR_DOWN
#define FLAG_TEAR_DOWN
at->faces[hp*animations/maxhp] at hit
Definition: define.h:279
object::chosen_skill
object * chosen_skill
The skill chosen to use.
Definition: object.h:396
SP_BULLET
#define SP_BULLET
Definition: spells.h:79
POISON
@ POISON
Definition: object.h:118
USING_SKILL
#define USING_SKILL(op, skill)
True if op is using skill, false else.
Definition: skills.h:85
player::killer
char killer[BIG_NAME]
Who killed this player.
Definition: player.h:190
object_find_by_type2
object * object_find_by_type2(const object *who, int type1, int type2)
Find object in inventory.
Definition: object.cpp:4022
object::subtype
uint8_t subtype
Subtype of object.
Definition: object.h:349
FLAG_WAS_WIZ
#define FLAG_WAS_WIZ
Player was once a wiz.
Definition: define.h:234
WEAP_CLEAVE
#define WEAP_CLEAVE
axe
Definition: define.h:80
is_criminal
bool is_criminal(object *op)
Definition: player.cpp:312
Settings::pk_max_experience_percent
int pk_max_experience_percent
Percentage of experience of victim the killer gets.
Definition: global.h:315
add_refcount
sstring add_refcount(sstring str)
This will increase the refcount of the string str.
Definition: shstr.cpp:210
free_no_drop
int free_no_drop(object *op)
Check whether the given object is FLAG_NO_DROP.
Definition: time.cpp:565
adj_attackroll
static int adj_attackroll(object *hitter, object *target)
Adjustments to attack rolls by various conditions.
Definition: attack.cpp:2566
determine_god
const char * determine_god(object *op)
Determines if op worships a god.
Definition: gods.cpp:55
freearr_y
short freearr_y[SIZEOFFREE]
Y offset when searching around a spot.
Definition: object.cpp:305
MSG_TYPE_ATTRIBUTE_BAD_EFFECT_START
#define MSG_TYPE_ATTRIBUTE_BAD_EFFECT_START
Start of a bad effect to the player.
Definition: newclient.h:569
ATM_SUFFER
#define ATM_SUFFER
Definition: attack.h:41
object_present_in_ob_by_name
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
MSG_TYPE_APPLY_SUCCESS
#define MSG_TYPE_APPLY_SUCCESS
Was able to apply object.
Definition: newclient.h:607
query_name
void query_name(const object *op, char *buf, size_t size)
Describes an item.
Definition: item.cpp:594
AT_COLD
#define AT_COLD
Definition: attack.h:80
POTION
@ POTION
Definition: object.h:116
FLAG_RUN_AWAY
#define FLAG_RUN_AWAY
Object runs away from nearest player \ but can still attack at a distance.
Definition: define.h:280
Settings::set_friendly_fire
uint16_t set_friendly_fire
Percent of damage done by peaceful player vs player damage.
Definition: global.h:276
FLAG_KNOWN_CURSED
#define FLAG_KNOWN_CURSED
The object is known to be cursed.
Definition: define.h:320
player::ranges
object * ranges[range_size]
Object for each range.
Definition: player.h:116
check_physically_infect
void check_physically_infect(object *victim, object *hitter)
Possibly infect due to direct physical contact i.e., AT_PHYSICAL.
Definition: disease.cpp:663
calc_skill_exp
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:667
archetype::clone
object clone
An object from which to do object_copy()
Definition: object.h:487
object::run_away
uint8_t run_away
Monster runs away if it's hp goes below this percentage.
Definition: object.h:394
add_string
sstring add_string(const char *str)
This will add 'str' to the hash table.
Definition: shstr.cpp:124
apply_anim_suffix
void apply_anim_suffix(object *who, const char *suffix)
Applies a compound animation to an object.
Definition: anim.cpp:150
EVENT_GKILL
#define EVENT_GKILL
Triggered when anything got killed by anyone.
Definition: events.h:55
FOR_OB_AND_BELOW_FINISH
#define FOR_OB_AND_BELOW_FINISH()
Finishes FOR_OB_AND_BELOW_PREPARE().
Definition: define.h:748
HEAD
#define HEAD(op)
Returns the head part of an object.
Definition: object.h:607
commit_crime
void commit_crime(object *op, const char *description)
Definition: player.cpp:307
MSG_TYPE_ATTACK_PET_DIED
#define MSG_TYPE_ATTACK_PET_DIED
Pet was killed.
Definition: newclient.h:620
ROD
@ ROD
Definition: object.h:114
CONTAINER
@ CONTAINER
Definition: object.h:236
object::casting_time
int16_t casting_time
Time left before spell goes off.
Definition: object.h:414
object::move_type
MoveType move_type
Type of movement this object uses.
Definition: object.h:436
WEAP_HIT
#define WEAP_HIT
the basic
Definition: define.h:77
FLAG_FREED
#define FLAG_FREED
Object is in the list of free objects.
Definition: define.h:233
hit_with_arrow
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
FLAG_BLIND
#define FLAG_BLIND
If set, object cannot see (visually)
Definition: define.h:336
object::face
const Face * face
Face with colors.
Definition: object.h:341
socket_struct::host
char * host
Which host it is connected from (ip address).
Definition: newserver.h:104
SCRIPT_FIX_ALL
#define SCRIPT_FIX_ALL
Definition: global.h:380
MSG_TYPE_ATTACK
#define MSG_TYPE_ATTACK
Attack related messages.
Definition: newclient.h:413
material.h
MOVE_FLYING
#define MOVE_FLYING
Combo of fly_low and fly_high.
Definition: define.h:395
object_update_speed
void object_update_speed(object *op)
Updates the speed of an object.
Definition: object.cpp:1334
FLAG_NO_DAMAGE
#define FLAG_NO_DAMAGE
monster can't be damaged
Definition: define.h:356
slow_living_by
int slow_living_by(object *op, const int speed_penalty)
Definition: attack.cpp:2231
object::type
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:348
INS_NO_MERGE
#define INS_NO_MERGE
Don't try to merge with other items.
Definition: object.h:580
FLAG_DAMNED
#define FLAG_DAMNED
The object is very cursed.
Definition: define.h:317
living::dam
int16_t dam
How much damage this object does when hitting.
Definition: living.h:46
t
in that case they will be relative to whatever the PWD of the crossfire server process is You probably shouldn t
Definition: server-directories.txt:28
object::magic
int8_t magic
Any magical bonuses to this item.
Definition: object.h:358
ATNR_DRAIN
#define ATNR_DRAIN
Definition: attack.h:56
FLAG_PARALYZED
#define FLAG_PARALYZED
Monster or player is paralyzed.
Definition: define.h:371
counterspell
void counterspell(object *op, int dir)
Nullifies spell effects.
Definition: spell_effect.cpp:2911
object::materialname
sstring materialname
Specific material name.
Definition: object.h:356
UPD_FLAGS
#define UPD_FLAGS
Definition: newclient.h:319
FOR_INV_FINISH
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:671
fix_stopped_item
void fix_stopped_item(object *op, mapstruct *map, object *originator)
Put stopped item where stop_item() had found it.
Definition: time.cpp:495
living::food
int32_t food
How much food in stomach.
Definition: living.h:48
GOLEM
@ GOLEM
Definition: object.h:150
change_exp
void change_exp(object *op, int64_t exp, const char *skill_name, int flag)
Changes experience to a player/monster.
Definition: living.cpp:2179
fix_stopped_arrow
object * fix_stopped_arrow(object *op)
An ARROW stops moving.
Definition: time.cpp:512
FLAG_UNAGGRESSIVE
#define FLAG_UNAGGRESSIVE
Monster doesn't attack players.
Definition: define.h:272
ATNR_COUNTERSPELL
#define ATNR_COUNTERSPELL
Definition: attack.h:68
ATM_PUNCH
#define ATM_PUNCH
Definition: attack.h:31
tag_t
uint32_t tag_t
Object tag, unique during the whole game.
Definition: object.h:14
archetype
The archetype structure is a set of rules on how to generate and manipulate objects which point to ar...
Definition: object.h:483
ATNR_POISON
#define ATNR_POISON
Definition: attack.h:59
sproto.h
ARROW
@ ARROW
Definition: object.h:122
ATNR_DEATH
#define ATNR_DEATH
Definition: attack.h:66
MSG_TYPE_VICTIM_WAS_HIT
#define MSG_TYPE_VICTIM_WAS_HIT
Player was hit by something.
Definition: newclient.h:655
FOR_OB_AND_BELOW_PREPARE
#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:744
GET_ANIM_ID
#define GET_ANIM_ID(ob)
Definition: global.h:167
living::Int
int8_t Int
Definition: living.h:36
random_roll
int random_roll(int min, int max, const object *op, int goodbad)
Roll a random number between min and max.
Definition: utils.cpp:42
object::race
sstring race
Human, goblin, dragon, etc.
Definition: object.h:326
RING
@ RING
Definition: object.h:190
materialtype_t::save
int8_t save[NROFATTACKS]
Save chances for the attacks.
Definition: material.h:36
BLINDNESS
@ BLINDNESS
Definition: object.h:152
NDI_BLACK
#define NDI_BLACK
Definition: newclient.h:246
weight
TIPS on SURVIVING Crossfire is populated with a wealth of different monsters These monsters can have varying immunities and attack types In some of them can be quite a bit smarter than others It will be important for new players to learn the abilities of different monsters and learn just how much it will take to kill them This section discusses how monsters can interact with players Most monsters in the game are out to mindlessly kill and destroy the players These monsters will help boost a player s after he kills them When fighting a large amount of monsters in a single attempt to find a narrower hallway so that you are not being attacked from all sides Charging into a room full of Beholders for instance would not be open the door and fight them one at a time For there are several maps designed for them Find these areas and clear them out All throughout these a player can find signs and books which they can read by stepping onto them and hitting A to apply the book sign These messages will help the player to learn the system One more always keep an eye on your food If your food drops to your character will soon so BE CAREFUL ! NPCs Non Player Character are special monsters which have intelligence Players may be able to interact with these monsters to help solve puzzles and find items of interest To speak with a monster you suspect to be a simply move to an adjacent square to them and push the double ie Enter your and press< Return > You can also use say if you feel like typing a little extra Other NPCs may not speak to but display intelligence with their movement Some monsters can be and may attack the nearest of your enemies Others can be in that they follow you around and help you in your quest to kill enemies and find treasure SPECIAL ITEMS There are many special items which can be found in of these the most important may be the signs all a player must do is apply the handle In the case of the player must move items over the button to hold it down Some of the larger buttons may need very large items to be moved onto before they can be activated Gates and locked but be for you could fall down into a pit full of ghosts or dragons and not be able to get back out Break away sometimes it may be worth a player s time to test the walls of a map for secret doors Fire such as missile weapons and spells you will notice them going up in smoke ! So be careful not to destroy valuable items Spellbooks sometimes a player can learn the other times they cannot There are many different types of books and scrolls out there Improve item have lower weight
Definition: survival-guide.txt:100
FLAG_SPLITTING
#define FLAG_SPLITTING
Object splits into stats.food other objs.
Definition: define.h:266
object_insert_in_map_at
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
ATTACKS
Chaos_Attacks ATTACKS[22]
Some local definitions for shuffle_attack().
Definition: init.cpp:81
object::other_arch
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
FLAG_MONSTER
#define FLAG_MONSTER
Will attack players.
Definition: define.h:245
undead_name
const char * undead_name
Definition: init.cpp:125
FLAG_HITBACK
#define FLAG_HITBACK
Object will hit back when hit.
Definition: define.h:267
get_attack_mode
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
P_OUT_OF_MAP
#define P_OUT_OF_MAP
This space is outside the map.
Definition: map.h:249
env
static std::shared_ptr< inja::Environment > env
Rendering environment.
Definition: mapper.cpp:2222
MAX_BUF
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
blame
object * blame(object *op)
Definition: attack.cpp:176
is_wraith_pl
int is_wraith_pl(object *op)
Tests if a player is a wraith.
Definition: player.cpp:173
object::head
object * head
Points to the main object of a large body.
Definition: object.h:304
create_archetype
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
object_present_in_ob
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
object::current_weapon
object * current_weapon
Pointer to the weapon currently used.
Definition: object.h:380
object::weight
int32_t weight
Attributes of the object.
Definition: object.h:375
free_string
void free_string(sstring str)
This will reduce the refcount, and if it has reached 0, str will be freed.
Definition: shstr.cpp:280
object::move_slow
MoveType move_slow
Movement types this slows down.
Definition: object.h:441
living::wc
int8_t wc
Weapon Class, lower WC increases probability of hitting.
Definition: living.h:37
object::move_slow_penalty
float move_slow_penalty
How much this slows down the object.
Definition: object.h:442
RANDOM
#define RANDOM()
Definition: define.h:638
ATNR_FIRE
#define ATNR_FIRE
Definition: attack.h:51
FOR_MAP_PREPARE
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Constructs a loop iterating over all objects of a map tile.
Definition: define.h:717
FLAG_KNOWN_MAGICAL
#define FLAG_KNOWN_MAGICAL
The object is known to be magical.
Definition: define.h:319
change_abil
int change_abil(object *op, object *tmp)
Permanently alters an object's stats/flags based on another object.
Definition: living.cpp:394
OUT_OF_REAL_MAP
#define OUT_OF_REAL_MAP(M, X, Y)
Checks if a square is out of the map.
Definition: map.h:217
attack_mess
attackmess_t attack_mess[NROFATTACKMESS][MAXATTACKMESS]
Definition: init.cpp:78
living::Wis
int8_t Wis
Definition: living.h:36
ATM_WRAITH_FEED
#define ATM_WRAITH_FEED
Definition: attack.h:42
attack_message
static void attack_message(int dam, int type, object *op, object *hitter)
Send an attack message to someone.
Definition: attack.cpp:608
sounds.h
FLAG_REMOVED
#define FLAG_REMOVED
Object is not in any map or invenory.
Definition: define.h:232
object_decrease_nrof
object * object_decrease_nrof(object *op, uint32_t i)
Decreases a specified number from the amount of an object.
Definition: object.cpp:2661
monster_can_see_enemy
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:2878
FLAG_WIZ
#define FLAG_WIZ
Object has special privilegies.
Definition: define.h:231
llevInfo
@ llevInfo
Information.
Definition: logger.h:12
NDI_UNIQUE
#define NDI_UNIQUE
Print immediately, don't buffer.
Definition: newclient.h:266
object::slaying
sstring slaying
Which race to do double damage to.
Definition: object.h:327
MSG_TYPE_ATTACK_PET_HIT
#define MSG_TYPE_ATTACK_PET_HIT
Players pet hit something else.
Definition: newclient.h:617
AT_BLIND
#define AT_BLIND
Definition: attack.h:98
WEAP_BLUD
#define WEAP_BLUD
bludgeoning, club, stick
Definition: define.h:85
FLAG_FRIENDLY
#define FLAG_FRIENDLY
Will help players.
Definition: define.h:246
ATNR_CHAOS
#define ATNR_CHAOS
Definition: attack.h:67
object::name
sstring name
The name of the object, obviously...
Definition: object.h:319
WEAP_STAB
#define WEAP_STAB
knife, dagger
Definition: define.h:82
ATM_CLEAVE
#define ATM_CLEAVE
Definition: attack.h:34
AT_SLOW
#define AT_SLOW
Definition: attack.h:87
SK_PUNCHING
@ SK_PUNCHING
Punching.
Definition: skills.h:36
WEAP_SLASH
#define WEAP_SLASH
slash
Definition: define.h:78
AT_TURN_UNDEAD
#define AT_TURN_UNDEAD
Definition: attack.h:89
tear_down_wall
static void tear_down_wall(object *op)
Handles wall tearing animation.
Definition: attack.cpp:1114
WEAP_PIERCE
#define WEAP_PIERCE
arrows, stiletto
Definition: define.h:79
SK_WRAITH_FEED
@ SK_WRAITH_FEED
Wraith feed.
Definition: skills.h:57
MSG_TYPE_VICTIM_WAS_PUSHED
#define MSG_TYPE_VICTIM_WAS_PUSHED
Player was pushed or attempted pushed.
Definition: newclient.h:661
ATNR_DEPLETE
#define ATNR_DEPLETE
Definition: attack.h:65
get_map_flags
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
DISEASE
@ DISEASE
Definition: object.h:249
attacks
const char *const attacks[NROFATTACKS]
Attack type names.
Definition: living.cpp:129
mapstruct
This is a game-map.
Definition: map.h:315
object::env
object * env
Pointer to the object which is the environment.
Definition: object.h:301
drain_stat
void drain_stat(object *op)
Drains a random stat from op.
Definition: living.cpp:716
NDI_ALL
#define NDI_ALL
Inform all players of this message.
Definition: newclient.h:267
ATM_WHIP
#define ATM_WHIP
Definition: attack.h:37
monster_npc_call_help
void monster_npc_call_help(object *op)
A monster calls for help against its enemy.
Definition: monster.cpp:2025
WEAP_CRUSH
#define WEAP_CRUSH
big hammers, flails
Definition: define.h:84
AT_DEPLETE
#define AT_DEPLETE
Definition: attack.h:92
object::skill
sstring skill
Name of the skill this object uses/grants.
Definition: object.h:329
find_archetype
archetype * find_archetype(const char *name)
Definition: assets.cpp:266
ATM_ELEC
#define ATM_ELEC
Definition: attack.h:25
ATM_CRUSH
#define ATM_CRUSH
Definition: attack.h:38
object_get_materialtype
static void object_get_materialtype(object *op, materialtype_t **mt)
Definition: attack.cpp:75
mapstruct::name
char * name
Name of map as given by its creator.
Definition: map.h:318
get_turn_bonus
int get_turn_bonus(int stat)
Definition: living.cpp:2385
change_luck
void change_luck(object *op, int value)
Alter the object's luck.
Definition: living.cpp:796
esrv_update_item
void esrv_update_item(int flags, object *pl, object *op)
Updates object *op for player *pl.
Definition: main.cpp:359
did_make_save
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
SPELL_EFFECT
@ SPELL_EFFECT
Definition: object.h:220
attack_ob_simple
static int attack_ob_simple(object *op, object *hitter, int base_dam, int wc)
Handles simple attack cases.
Definition: attack.cpp:767
ATNR_MAGIC
#define ATNR_MAGIC
Definition: attack.h:50
MSG_TYPE_ATTACK_FUMBLE
#define MSG_TYPE_ATTACK_FUMBLE
Player fumbled attack.
Definition: newclient.h:618
on_same_map
int on_same_map(const object *op1, const object *op2)
Checks whether 2 objects are on the same map or not.
Definition: map.cpp:2629
CLEAR_FLAG
#define CLEAR_FLAG(xyz, p)
Definition: define.h:225
ob_apply
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
hit_with_drain
static int hit_with_drain(object *op, object *hitter, int dam)
Definition: attack.cpp:1174
living::ac
int8_t ac
Armor Class, lower AC increases probability of not getting hit.
Definition: living.h:38
paralyze_living
void paralyze_living(object *op, int dam)
Paralyze a living thing.
Definition: attack.cpp:2402
NUM_ANIMATIONS
#define NUM_ANIMATIONS(ob)
Definition: global.h:173
player_arrest
int player_arrest(object *who)
Put a player into jail, taking into account cursed exits and player's region.
Definition: c_wiz.cpp:789
share_exp
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
object::duration
int16_t duration
Number of moves (see 'speed') spell lasts.
Definition: object.h:415
arch_to_object
object * arch_to_object(archetype *at)
Creates and returns a new object which is a copy of the given archetype.
Definition: arch.cpp:227
level
int level
Definition: readable.cpp:1563
player::party
partylist * party
Party this player is part of.
Definition: player.h:203
change_object
void change_object(object *op)
Replaces op with its other_arch if it has reached its end of life.
Definition: time.cpp:592
ATM_SLASH
#define ATM_SLASH
Definition: attack.h:32
IS_LIVE
#define IS_LIVE(op)
Definition: define.h:173
WEAP_SLICE
#define WEAP_SLICE
katana
Definition: define.h:81
attackmess_t::level
int level
Definition: attack.h:119
UPD_NAME
#define UPD_NAME
Definition: newclient.h:322
AT_COUNTERSPELL
#define AT_COUNTERSPELL
Definition: attack.h:95
check_exp_loss
int64_t check_exp_loss(const object *op, int64_t exp)
This function checks to make sure that object 'op' can lose 'exp' experience.
Definition: living.cpp:2077
AT_ACID
#define AT_ACID
Definition: attack.h:82
stop_item
object * stop_item(object *op)
An item (ARROW or such) stops moving.
Definition: time.cpp:455
AT_FEAR
#define AT_FEAR
Definition: attack.h:90
scare_creature
static void scare_creature(object *target, object *hitter)
Creature is scared, update its values.
Definition: attack.cpp:1163
skill
skill
Definition: arch-handbook.txt:585
process_object
void process_object(object *op)
Main object move function.
Definition: time.cpp:796
object_remove
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
DOOR
@ DOOR
Definition: object.h:131
player_can_view
int player_can_view(object *pl, object *op)
Check the player los field for viewability of the object op.
Definition: player.cpp:4160
FLAG_UNPAID
#define FLAG_UNPAID
Object hasn't been paid for yet.
Definition: define.h:236
EVENT_ATTACKED
#define EVENT_ATTACKED
Object attacked, with weapon or spell.
Definition: events.h:29
AT_CONFUSION
#define AT_CONFUSION
Definition: attack.h:81
SK_EXP_TOTAL
#define SK_EXP_TOTAL
Give player exp to total, no skill.
Definition: skills.h:79
VERY_BIG_BUF
#define VERY_BIG_BUF
Definition: define.h:36
update_all_los
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
object_copy_owner
void object_copy_owner(object *op, object *clone)
Set the owner to clone's current owner and set the skill and experience objects to clone's objects (t...
Definition: object.cpp:878
ATNR_COLD
#define ATNR_COLD
Definition: attack.h:53
archetype::name
sstring name
More definite name, like "generate_kobold".
Definition: object.h:484
AT_CANCELLATION
#define AT_CANCELLATION
Definition: attack.h:91
SK_EXP_ADD_SKILL
#define SK_EXP_ADD_SKILL
Give the player the skill.
Definition: skills.h:78
object::nrof
uint32_t nrof
Number of objects.
Definition: object.h:342
player::socket
socket_struct * socket
Socket information for this player.
Definition: player.h:107
materialtype_t
One material type.
Definition: material.h:32
object::stats
living stats
Str, Con, Dex, etc.
Definition: object.h:378
player::title
char title[BIG_NAME]
Default title, like fighter, wizard, etc.
Definition: player.h:184
put_in_icecube
static void put_in_icecube(object *op, object *originator)
Definition: attack.cpp:151
BIG_NAME
#define BIG_NAME
Definition: define.h:42
get_attack_message_for_attack_type
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
freearr_x
short freearr_x[SIZEOFFREE]
X offset when searching around a spot.
Definition: object.cpp:299
FLAG_IS_LIGHTABLE
#define FLAG_IS_LIGHTABLE
object can be lit
Definition: define.h:278
AT_PARALYZE
#define AT_PARALYZE
Definition: attack.h:88
TRUE
#define TRUE
Definition: compat.h:11
ATM_COLD
#define ATM_COLD
Definition: attack.h:26
AT_HOLYWORD
#define AT_HOLYWORD
Definition: attack.h:97
SPELL
@ SPELL
Definition: object.h:219
AT_GHOSTHIT
#define AT_GHOSTHIT
Definition: attack.h:85
mapstruct::darkness
uint8_t darkness
Indicates level of darkness of map.
Definition: map.h:336
FLAG_READY_WEAPON
#define FLAG_READY_WEAPON
(Monster or Player) has a weapon readied
Definition: define.h:334
MSG_TYPE_APPLY
#define MSG_TYPE_APPLY
Applying objects.
Definition: newclient.h:412
ATM_CLAW
#define ATM_CLAW
Definition: attack.h:30
object::attacktype
uint32_t attacktype
Bitmask of attacks this object does.
Definition: object.h:352
FLAG_CURSED
#define FLAG_CURSED
The object is cursed.
Definition: define.h:316
kill_object
static int kill_object(object *op, int dam, object *hitter)
An object was killed, handle various things (logging, messages, ...).
Definition: attack.cpp:1586
thrown_item_effect
static void thrown_item_effect(object *, object *)
Handles any special effects of thrown items (like attacking living creatures–a potion thrown at a mon...
Definition: attack.cpp:2526
ATNR_LIFE_STEALING
#define ATNR_LIFE_STEALING
Definition: attack.h:73
living.h
SP_EXPLOSION
#define SP_EXPLOSION
Definition: spells.h:80
kill_player
void kill_player(object *op, const object *killer)
Handle a player's death.
Definition: player.cpp:3506
THROWN_OBJ
@ THROWN_OBJ
Definition: object.h:151
FLAG_SLEEP
#define FLAG_SLEEP
NPC is sleeping.
Definition: define.h:307
MSG_TYPE_ADMIN
#define MSG_TYPE_ADMIN
Definition: newclient.h:406
object::material
uint16_t material
What materials this object consist of.
Definition: object.h:357
IS_ARROW
#define IS_ARROW(op)
Definition: define.h:178
ATM_DOOR
#define ATM_DOOR
Definition: attack.h:40
object::move_block
MoveType move_block
What movement types this blocks.
Definition: object.h:437
is_aimed_missile
static int is_aimed_missile(object *op)
Determine if the object is an 'aimed' missile.
Definition: attack.cpp:2633
FOR_INV_PREPARE
#define FOR_INV_PREPARE(op_, it_)
Constructs a loop iterating over the inventory of an object.
Definition: define.h:664
MAX_FOOD
static const int32_t MAX_FOOD
Definition: define.h:455
living::hp
int16_t hp
Hit Points.
Definition: living.h:40
FORCE
@ FORCE
Definition: object.h:229
AT_DRAIN
#define AT_DRAIN
Definition: attack.h:83
poison_living
static void poison_living(object *op, object *hitter, int dam)
Poison a living thing.
Definition: attack.cpp:2158
events_execute_global_event
void events_execute_global_event(int eventcode,...)
Execute a global event.
Definition: events.cpp:30
object_replace_insert_in_map
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
llevDebug
@ llevDebug
Only for debugging purposes.
Definition: logger.h:13
is_valid_types_gen.type
list type
Definition: is_valid_types_gen.py:25
FORCE_NAME
#define FORCE_NAME
Definition: spells.h:169
ATM_DRAIN
#define ATM_DRAIN
Definition: attack.h:24
living::Con
int8_t Con
Definition: living.h:36
living::Str
int8_t Str
Definition: living.h:36
ATNR_FEAR
#define ATNR_FEAR
Definition: attack.h:63
slow_living
static void slow_living(object *op, object *hitter, int dam)
Slow a living thing.
Definition: attack.cpp:2270
AT_FIRE
#define AT_FIRE
Definition: attack.h:78
MSG_TYPE_APPLY_UNAPPLY
#define MSG_TYPE_APPLY_UNAPPLY
Unapply an object.
Definition: newclient.h:606