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