Crossfire Server, Trunk  1.75.0
skills.cpp
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2013 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, see the
9  * 'LICENSE' and 'COPYING' files.
10  *
11  * The authors can be reached via e-mail to crossfire-devel@real-time.com
12  *
13  * skills.c -- core skill handling
14  */
15 #ifndef _GNU_SOURCE
16 #define _GNU_SOURCE // strcasestr() is a GNU extension in string.h
17 #endif
18 
19 #include "global.h"
20 
21 #include <stdlib.h>
22 #include <string.h>
23 
24 #include "book.h"
25 #include "living.h"
26 #include "object.h"
27 #include "skills.h"
28 #include "spells.h"
29 #include "sproto.h"
30 
32  SK_KARATE,
33  SK_CLAWING,
37  0
38 };
39 
54 static int adj_stealchance(object *op, object *victim, int roll) {
55  if (!op || !victim || !roll)
56  return -1;
57 
58  /* Only prohibit stealing if the player does not have a free
59  * hand available and in fact does have hands.
60  */
61  if (op->type == PLAYER
62  && op->body_used[BODY_ARMS] <= 0
63  && op->body_info[BODY_ARMS]) {
65  "But you have no free hands to steal with!");
66  return -1;
67  }
68 
69  /* ADJUSTMENTS */
70 
71  /* Its harder to steal from hostile beings! */
72  if (!QUERY_FLAG(victim, FLAG_UNAGGRESSIVE))
73  roll = roll/2;
74 
75  /* Easier to steal from sleeping beings, or if the thief is
76  * unseen */
77  if (QUERY_FLAG(victim, FLAG_SLEEP))
78  roll = roll*3;
79  else if (op->invisible)
80  roll = roll*2;
81 
82  /* check stealing 'encumberance'. Having this equipment applied makes
83  * it quite a bit harder to steal.
84  */
85  FOR_INV_PREPARE(op, equip) {
86  if (equip->type == WEAPON && QUERY_FLAG(equip, FLAG_APPLIED)) {
87  roll -= equip->weight/10000;
88  }
89  if (equip->type == BOW && QUERY_FLAG(equip, FLAG_APPLIED))
90  roll -= equip->weight/5000;
91  if (equip->type == SHIELD && QUERY_FLAG(equip, FLAG_APPLIED)) {
92  roll -= equip->weight/2000;
93  }
94  if (equip->type == ARMOUR && QUERY_FLAG(equip, FLAG_APPLIED))
95  roll -= equip->weight/5000;
96  if (equip->type == GLOVES && QUERY_FLAG(equip, FLAG_APPLIED))
97  roll -= equip->weight/100;
98  } FOR_INV_FINISH();
99  if (roll < 0)
100  roll = 0;
101  return roll;
102 }
103 
122 static int attempt_steal(object *op, object *who, object *skill) {
123  object *success = NULL, *tmp = NULL;
124  int roll = 0, chance = 0, stats_value;
125  rv_vector rv;
126  char name[MAX_BUF];
127 
128  stats_value = ((who->stats.Dex+who->stats.Int)*3)/2;
129 
130  /* if the victim is aware of a thief in the area (FLAG_NO_STEAL set on them)
131  * they will try to prevent stealing if they can. Only unseen theives will
132  * have much chance of success.
133  */
134  if (op->type != PLAYER && QUERY_FLAG(op, FLAG_NO_STEAL)) {
135  if (monster_can_detect_enemy(op, who, &rv)) {
139  "Your attempt is prevented!");
140  return 0;
141  }
142 
143  /* help npc to detect thief next time by raising its wisdom
144  * This probably isn't the right approach - we shouldn't be
145  * changing the stats of the monsters - better approach
146  * might be to use force objects for this - MSW 2009/02/24
147  */
148  op->stats.Wis += (op->stats.Int/5)+1;
149  if (op->stats.Wis > settings.max_stat)
151  }
152  if (op->type == PLAYER && QUERY_FLAG(op, FLAG_WIZ)) {
154  "You can't steal from the dungeon master!");
155  return 0;
156  }
157  if (op->type == PLAYER && who->type == PLAYER && settings.no_player_stealing) {
159  "You can't steal from other players!");
160  return 0;
161  }
162 
163 
164  /* Ok then, go thru their inventory, stealing */
165  FOR_INV_PREPARE(op, inv) {
166  /* you can't steal worn items, starting items, wiz stuff,
167  * innate abilities, or items w/o a type. Generally
168  * speaking, the invisibility flag prevents experience or
169  * abilities from being stolen since these types are currently
170  * always invisible objects. I was implicit here so as to prevent
171  * future possible problems. -b.t.
172  * Flesh items generated w/ fix_flesh_item should have FLAG_NO_STEAL
173  * already -b.t.
174  */
175 
176  if (QUERY_FLAG(inv, FLAG_WAS_WIZ)
177  || QUERY_FLAG(inv, FLAG_APPLIED)
178  || !(inv->type)
179  || inv->type == SPELL
180  || QUERY_FLAG(inv, FLAG_STARTEQUIP)
181  || QUERY_FLAG(inv, FLAG_NO_STEAL)
182  || inv->invisible)
183  continue;
184 
185  /* Okay, try stealing this item. Dependent on dexterity of thief,
186  * skill level, see the adj_stealroll fctn for more detail.
187  */
188 
189  roll = die_roll(2, 100, who, PREFER_LOW)/2; /* weighted 1-100 */
190 
191  chance = adj_stealchance(who, op, stats_value+skill->level*10-op->level*3);
192  if (chance == -1)
193  return 0;
194  if (roll < chance) {
195  tag_t inv_count = inv->count;
196 
197  pick_up(who, inv);
198  /* need to see if the player actually stole this item -
199  * if it is in the players inv, assume it is. This prevents
200  * abuses where the player can not carry the item, so just
201  * keeps stealing it over and over.
202  */
203  if (object_was_destroyed(inv, inv_count) || inv->env != op) {
204  /* for players, play_sound: steals item */
205  success = inv;
207  }
208  tmp = inv;
209  break;
210  }
211  } FOR_INV_FINISH(); /* for loop looking for an item */
212 
213  if (!tmp) {
216  "%s%s has nothing you can steal!",
217  op->type == PLAYER ? "" : "The ", name);
218  return 0;
219  }
220 
221  /* If you arent high enough level, you might get something BUT
222  * the victim will notice your stealing attempt. Ditto if you
223  * attempt to steal something heavy off them, they're bound to notice
224  */
225 
226  if (roll >= skill->level
227  || !chance
228  || (tmp && tmp->weight > 250*random_roll(0, stats_value+skill->level*10-1, who, PREFER_LOW))) {
229  /* victim figures out where the thief is! */
230  if (who->hide)
231  make_visible(who);
232 
233  if (op->type != PLAYER) {
234  /* The unaggressives look after themselves 8) */
235  if (who->type == PLAYER) {
239  "%s notices your attempted pilfering!",
240  name);
241  }
243  /* all remaining npc items are guarded now. Set flag NO_STEAL
244  * on the victim.
245  */
247  } else { /* stealing from another player */
248  char buf[HUGE_BUF];
249 
250  /* Notify the other player */
251  if (success && who->stats.Int > random_roll(0, 19, op, PREFER_LOW)) {
252  query_name(success, name, MAX_BUF);
253  snprintf(buf, sizeof(buf), "Your %s is missing!", name);
254  } else {
255  snprintf(buf, sizeof(buf), "Your pack feels strangely lighter.");
256  }
258  buf);
259  if (!success) {
260  if (who->invisible) {
261  snprintf(buf, sizeof(buf), "you feel itchy fingers getting at your pack.");
262  } else {
263  query_name(who, name, MAX_BUF);
264  snprintf(buf, sizeof(buf), "%s looks very shifty.", name);
265  }
267  buf);
268  }
269  } /* else stealing from another player */
270  /* play_sound("stop! thief!"); kindofthing */
271  } /* if you weren't 100% successful */
272  return success ? 1 : 0;
273 }
274 
275 
288 int steal(object *op, int dir, object *skill) {
289  object *tmp;
290  int16_t x, y;
291  mapstruct *m;
292  int mflags;
293 
294  x = op->x+freearr_x[dir];
295  y = op->y+freearr_y[dir];
296 
297  if (dir == 0) {
298  /* Can't steal from ourself! */
299  return 0;
300  }
301 
302  m = op->map;
303  mflags = get_map_flags(m, &m, x, y, &x, &y);
304  /* Out of map - can't do it. If nothing alive on this space,
305  * don't need to look any further.
306  */
307  if ((mflags&P_OUT_OF_MAP) || !(mflags&P_IS_ALIVE))
308  return 0;
309 
310  /* If player can't move onto the space, can't steal from it. */
312  return 0;
313 
314  /* Find the topmost object at this spot */
315  tmp = GET_MAP_OB(m, x, y);
317  if (tmp->above == NULL)
318  break;
320 
321  /* For all the stacked objects at this point, attempt a steal */
323  /* Minor hack--for multi square beings - make sure we get
324  * the 'head' coz 'tail' objects have no inventory! - b.t.
325  */
326  tmp = HEAD(tmp);
327  if (tmp->type != PLAYER && !QUERY_FLAG(tmp, FLAG_MONSTER))
328  continue;
329 
330  /* do not reveal hidden DMs */
331  if (tmp->type == PLAYER && QUERY_FLAG(tmp, FLAG_WIZ) && tmp->contr->hidden)
332  continue;
333  if (attempt_steal(tmp, op, skill)) {
334  if (tmp->type == PLAYER) /* no xp for stealing from another player */
335  return 0;
336 
337  /* no xp for stealing from pets (of players) */
338  if (QUERY_FLAG(tmp, FLAG_FRIENDLY) && tmp->attack_movement == PETMOVE) {
339  object *owner = object_get_owner(tmp);
340  if (owner != NULL && owner->type == PLAYER)
341  return 0;
342  }
343 
344  return (calc_skill_exp(op, tmp, skill));
345  }
347  return 0;
348 }
349 
364 static int attempt_pick_lock(object *door, object *pl, object *skill) {
365  int difficulty = pl->map->difficulty ? pl->map->difficulty : 0;
366  int success = 0, number; /* did we get anything? */
367 
368  /* Try to pick the lock on this item (doors only for now).
369  * Dependent on dexterity/skill SK_level of the player and
370  * the map level difficulty.
371  */
372  number = (die_roll(2, 40, pl, PREFER_LOW)-2)/2;
373  // Spring traps even if the lock is picked.
374  if (door->inv && (door->inv->type == RUNE || door->inv->type == TRAP)) { /* set off any traps? */
375  spring_trap(door->inv, pl);
376  }
377  if (number < pl->stats.Dex + skill->level*2 - difficulty ) {
378  remove_door(door);
379  success = difficulty;
380  }
381  return success;
382 }
383 
384 
400 int pick_lock(object *pl, int dir, object *skill) {
401  object *tmp;
402  int x = pl->x+freearr_x[dir];
403  int y = pl->y+freearr_y[dir];
404  int difficulty=0;
405 
406  if (!dir)
407  dir = pl->facing;
408 
409  /* For all the stacked objects at this point find a door*/
410  if (OUT_OF_REAL_MAP(pl->map, x, y)) {
412  "There is no lock there.");
413  return 0;
414  }
415 
416  for (tmp = GET_MAP_OB(pl->map, x, y); tmp; tmp = tmp->above)
417  if (tmp->type == DOOR || tmp->type == LOCKED_DOOR)
418  break;
419 
420  if (!tmp) {
422  "There is no lock there.");
423  return 0;
424  }
425 
427  return 0;
428 
429  if (tmp->type == LOCKED_DOOR) {
431  "You can't pick that lock!");
432  return 0;
433  }
434 
435  if (!tmp->move_block) {
437  "The door has no lock!");
438  return 0;
439  }
440 
441  difficulty = attempt_pick_lock(tmp, pl, skill);
442  /* Failure */
443  if (!difficulty) {
445  "You fail to pick the lock.");
446  return 0;
447  }
448 
450  "You pick the lock.");
451  return (calc_skill_exp(pl, NULL, skill) * isqrt(difficulty));
452 }
453 
454 
474 static int attempt_hide(object *op, object *skill) {
475  int number, difficulty = op->map->difficulty;
476  int terrain = hideability(op);
477 
478  if (terrain < -10) /* not enough cover here */
479  return 0;
480 
481  /* Hiding success and duration dependant on skill level,
482  * op->stats.Dex, map difficulty and terrain.
483  */
484 
485  number = (die_roll(2, 25, op, PREFER_LOW)-2)/2;
486  if (!stand_near_hostile(op) && number < op->stats.Dex+skill->level+terrain-difficulty) {
487  op->invisible += 100; /* set the level of 'hiddeness' */
488  if (op->type == PLAYER)
489  op->contr->tmp_invis = 1;
490  op->hide = 1;
491  return 1;
492  }
493  return 0;
494 }
495 
505 int hide(object *op, object *skill) {
506  /* the preliminaries -- Can we really hide now? */
507  /* this keeps monsters from using invisibilty spells and hiding */
508 
509  if (QUERY_FLAG(op, FLAG_MAKE_INVIS)) {
511  "You don't need to hide while invisible!");
512  return 0;
513  }
514 
515  if (!op->hide && op->invisible > 0 && op->type == PLAYER) {
517  "Your attempt to hide breaks the invisibility spell!");
518  make_visible(op);
519  }
520 
521  if (op->invisible > 50*skill->level) {
523  "You are as hidden as you can get.");
524  return 0;
525  }
526 
527  if (attempt_hide(op, skill)) {
529  "You hide in the shadows.");
531  return calc_skill_exp(op, NULL, skill);
532  }
534  "You fail to conceal yourself.");
535  return 0;
536 }
537 
538 
545 static void stop_jump(object *pl) {
546  fix_object(pl);
547  object_insert_in_map_at(pl, pl->map, pl, 0, pl->x, pl->y);
548  // Some monsters can also jump. They do not check for pickup with check_pick().
549  if (pl->contr)
550  check_pick(pl);
551 }
552 
566 static int attempt_jump(object *pl, int dir, int spaces, object *skill) {
571  if (pl->contr && pl->contr->transport){
572  char trans_name[MAX_BUF];
573  query_name(pl->contr->transport, trans_name, MAX_BUF);
575  "Your bounce off the walls of %s.", trans_name);
576  // We failed to jump. Return as a failure.
577  return 0;
578  }
579 
580  int i, dx = freearr_x[dir], dy = freearr_y[dir], mflags;
581  int16_t x, y;
582  mapstruct *m;
583 
584  /* Jump loop. Go through spaces opject wants to jump. Halt the
585  * jump if a wall or creature is in the way. We set FLY_LOW
586  * temporarily to allow player to aviod exits/archs that are not
587  * move_on/off fly_low. This will also prevent pickup of objects
588  * while jumping over them.
589  */
590 
591  object_remove(pl);
592 
593  /*
594  * I don't think this is actually needed - all the movement
595  * code is handled in this function, and I don't see anyplace
596  * that cares about the move_type being flying.
597  */
598  pl->move_type |= MOVE_FLY_LOW;
599 
600  for (i = 0; i <= spaces; i++) {
601  x = pl->x+dx;
602  y = pl->y+dy;
603  m = pl->map;
604 
605  mflags = get_map_flags(m, &m, x, y, &x, &y);
606 
607  if (mflags&P_OUT_OF_MAP) {
608  (void)stop_jump(pl);
609  return 0;
610  }
611  if (OB_TYPE_MOVE_BLOCK(pl, GET_MAP_MOVE_BLOCK(m, x, y))) {
613  "Your jump is blocked.");
614  stop_jump(pl);
615  return 0;
616  }
617 
618  FOR_MAP_PREPARE(m, x, y, tmp) {
619  tmp = HEAD(tmp);
620  /* Jump into creature */
621  if (QUERY_FLAG(tmp, FLAG_MONSTER)
622  || (tmp->type == PLAYER && (!QUERY_FLAG(tmp, FLAG_WIZ) || !tmp->contr->hidden))) {
624  "You jump into %s%s.",
625  tmp->type == PLAYER ? "" : "the ", tmp->name);
626 
627  stop_jump(pl);
628  if (tmp->type != PLAYER
629  || (pl->type == PLAYER && pl->contr->party == NULL)
630  || (pl->type == PLAYER && tmp->type == PLAYER && pl->contr->party != tmp->contr->party))
631  skill_attack(tmp, pl, pl->facing, "kicked", skill); /* pl makes an attack */
632 
633  return 1;
634  }
635  /* If the space has fly on set (no matter what the space is),
636  * we should get the effects - after all, the player is
637  * effectively flying.
638  */
639  if (tmp->move_on&MOVE_FLY_LOW) {
640  pl->x = x;
641  pl->y = y;
642  pl->map = m;
643  if (pl->contr)
644  esrv_map_scroll(pl->contr->socket, dx, dy);
645  stop_jump(pl);
646  return 1;
647  }
648  } FOR_MAP_FINISH();
649  pl->x = x;
650  pl->y = y;
651  pl->map = m;
652  if (pl->contr)
653  esrv_map_scroll(pl->contr->socket, dx, dy);
654  }
655  stop_jump(pl);
656  return 1;
657 }
658 
675 int jump(object *pl, int dir, object *skill) {
676  int spaces = 0, stats;
677  int str = pl->stats.Str;
678  int dex = pl->stats.Dex;
679 
680  dex = dex ? dex : 15;
681  str = str ? str : 10;
682 
683  stats = str*str*str*dex*skill->level;
684 
685  if (pl->carrying != 0) /* don't want div by zero !! */
686  spaces = (int)(stats/pl->carrying);
687  else
688  spaces = 2; /* pl has no objects - gets the far jump */
689 
690  if (spaces > 2)
691  spaces = 2;
692  else if (spaces == 0) {
694  "You are carrying too much weight to jump.");
695  return 0;
696  }
697  return attempt_jump(pl, dir, spaces, skill);
698 }
699 
712 int detect_curse_on_item(object *pl, object *tmp, object *skill) {
714  && (QUERY_FLAG(tmp, FLAG_CURSED) || QUERY_FLAG(tmp, FLAG_DAMNED))
715  && tmp->item_power < skill->level) {
717  esrv_update_item(UPD_FLAGS, pl, tmp);
718  return NROF(tmp) * calc_skill_exp(pl, tmp, skill);
719  }
720  return 0;
721 }
732 static int do_skill_detect_curse(object *pl, object *skill) {
733  int success = 0;
734 
735  FOR_INV_PREPARE(pl, tmp)
736  if (!tmp->invisible) success += detect_curse_on_item(pl, tmp, skill);
737  FOR_INV_FINISH();
738 
739  /* Check ground, too, but only objects the player could pick up. Cauldrons are exceptions,
740  * you definitely want to know if they are cursed */
741  FOR_MAP_PREPARE(pl->map, pl->x, pl->y, tmp)
742  if (object_can_pick(pl, tmp) || QUERY_FLAG(tmp, FLAG_IS_CAULDRON))
743  success += detect_curse_on_item(pl, tmp, skill);
744  FOR_MAP_FINISH();
745 
746  return success;
747 }
761 int detect_magic_on_item(object *pl, object *tmp, object *skill) {
763  && (is_magical(tmp)) && tmp->item_power < skill->level) {
765  esrv_update_item(UPD_FLAGS, pl, tmp);
766  return NROF(tmp) * calc_skill_exp(pl, tmp, skill);
767  }
768  return 0;
769 }
770 
781 static int do_skill_detect_magic(object *pl, object *skill) {
782  int success = 0;
783 
784  FOR_INV_PREPARE(pl, tmp)
785  if (!tmp->invisible)
786  success += detect_magic_on_item(pl, tmp, skill);
787  FOR_INV_FINISH();
788 
789  /* Check ground, too, but like above, only if the object can be picked up*/
790  FOR_MAP_PREPARE(pl->map, pl->x, pl->y, tmp)
791  if (object_can_pick(pl, tmp))
792  success += detect_magic_on_item(pl, tmp, skill);
793  FOR_MAP_FINISH();
794 
795  return success;
796 }
797 
819 int identify_object_with_skill(object *tmp, object *pl, object *skill, int print_on_success) {
820  int success = 0, chance;
821  int skill_value = (skill->level && pl->stats.Int) ? pl->stats.Int : 10;
822 
823  if (!tmp->invisible && !QUERY_FLAG(tmp, FLAG_NO_SKILL_IDENT) && !is_identified(tmp)) {
824  uint32_t identified = 0;
825  for (uint32_t i = 0; i < NROF(tmp); i++) {
826  chance = die_roll(3, 10, pl, PREFER_LOW)-3+rndm(0, (tmp->magic ? tmp->magic*5 : 1)-1);
827  if (skill_value >= chance) {
828  identified++;
829  }
830  }
831 
832  if (identified == 0) {
834  object_merge(tmp, NULL);
835  return 0;
836  }
837 
838  if (identified < NROF(tmp)) {
839  object *left = tmp;
840  tmp = object_split(tmp, identified, NULL, 0);
841  SET_FLAG(left, FLAG_NO_SKILL_IDENT); // Will prevent tmp to be merged right back.
842  // It may happen that tmp is merged while inserting.
843  // It should not be the case because it means somewhere items were not merged correctly.
844  // In this case the player will identify all items but get exp only for "identified" items.
845  if (left->env) {
846  tmp = object_insert_in_ob(tmp, left->env);
847  } else {
848  tmp = object_insert_in_map_at(tmp, left->map, left, INS_BELOW_ORIGINATOR, left->x, left->y);
849  }
850  object_merge(left, NULL);
851  }
852 
853  tmp = identify(tmp);
854  if (pl->type == PLAYER && print_on_success) {
855  char desc[MAX_BUF];
856 
858  "You identify %s.",
859  ob_describe(tmp, pl, 1, desc, sizeof(desc)));
860  if (tmp->msg) {
862  "The item has a story:\n%s",
863  tmp->msg);
864  }
865  }
866  success += identified * calc_skill_exp(pl, tmp, skill);
867  }
868  return success;
869 }
870 
883 static int do_skill_ident(object *pl, int obj_class, object *skill) {
884  int success = 0, area, i;
885 
886  /* check the player */
887  FOR_INV_PREPARE(pl, tmp)
888  if (tmp->type == obj_class)
889  success += identify_object_with_skill(tmp, pl, skill, 1);
890  FOR_INV_FINISH();
891 
892  /* check the ground */
893  /* Altered to allow ident skills to increase in area with
894  * experience. -- Aaron Baugher
895  */
896 
897  if (skill->level > 64) { /* Adjust these levels? */
898  area = 49;
899  } else if (skill->level > 16) {
900  area = 25;
901  } else if (skill->level > 4) {
902  area = 9;
903  } else {
904  area = 1;
905  }
906 
907  for (i = 0; i < area; i++) {
908  int16_t x = pl->x+freearr_x[i];
909  int16_t y = pl->y+freearr_y[i];
910  mapstruct *m = pl->map;
911  int mflags;
912 
913  mflags = get_map_flags(m, &m, x, y, &x, &y);
914  if (mflags&P_OUT_OF_MAP)
915  continue;
916 
917  if (can_see_monsterP(m, pl->x, pl->y, i)) {
918  FOR_MAP_PREPARE(m, x, y, tmp)
919  if (tmp->type == obj_class)
920  success += identify_object_with_skill(tmp, pl, skill, 1);
921  FOR_MAP_FINISH();
922  }
923  }
924  return success;
925 }
926 
936 int skill_ident(object *pl, object *skill) {
937  int success = 0;
938  int i, identifiable_types=0;
939  const typedata *tmptype;
940 
941  if (pl->type != PLAYER)
942  return 0; /* only players will skill-identify */
943 
945  "You look at the objects nearby with your %s skill...", skill->name);
946 
947  switch (skill->subtype) {
948  case SK_DET_CURSE:
949  success = do_skill_detect_curse(pl, skill);
950  if (success)
952  "...and discover cursed items!");
953  break;
954 
955  case SK_DET_MAGIC:
956  success = do_skill_detect_magic(pl, skill);
957  if (success)
959  "...and discover items imbued with mystic forces!");
960  break;
961 
962  default:
963  /* we will try to identify items with this skill instead */
964  for (i=0; i<=OBJECT_TYPE_MAX; i++) {
965  tmptype = get_typedata(i);
966  if (tmptype) {
967  if (skill->subtype == tmptype->identifyskill || skill->subtype == tmptype->identifyskill2) {
968  success += do_skill_ident(pl, i, skill);
969  identifiable_types++;
970  }
971  }
972  }
973  if (identifiable_types == 0) {
974  LOG(llevError, "Error: skill_ident() called with skill %d which can't identify any items\n", skill->subtype);
975  return 0;
976  }
977  break;
978  }
979  if (!success) {
981  "...and learn nothing more.");
982  }
983  return success;
984 }
985 
986 
1005 int use_oratory(object *pl, int dir, object *skill) {
1006  int16_t x = pl->x+freearr_x[dir], y = pl->y+freearr_y[dir];
1007  int mflags, chance;
1008  object *tmp;
1009  mapstruct *m;
1010  char name[MAX_BUF];
1011 
1012  if (pl->type != PLAYER)
1013  return 0; /* only players use this skill */
1014  m = pl->map;
1015  mflags = get_map_flags(m, &m, x, y, &x, &y);
1016  if (mflags&P_OUT_OF_MAP)
1017  return 0;
1018 
1019  /* Save some processing - we have the flag already anyways
1020  */
1021  if (!(mflags&P_IS_ALIVE)) {
1023  "There is nothing to orate to.");
1024  return 0;
1025  }
1026 
1027  tmp = NULL;
1028  FOR_MAP_PREPARE(m, x, y, tmp2) {
1029  tmp2 = HEAD(tmp2);
1030  /* can't persuade players - return because there is nothing else
1031  * on that space to charm.
1032  */
1033  if (tmp2->type == PLAYER)
1034  return 0;
1035 
1036  if (QUERY_FLAG(tmp2, FLAG_MONSTER)) {
1037  if (object_value_set(tmp2, "no_mood_change"))
1038  return 0;
1039 
1040  tmp = tmp2;
1041  break;
1042  }
1043  } FOR_MAP_FINISH();
1044 
1045  if (!tmp) {
1047  "There is nothing to orate to.");
1048  return 0;
1049  }
1050 
1051  query_name(tmp, name, MAX_BUF);
1053  "You orate to the %s.",
1054  name);
1055 
1056  /* the following conditions limit who may be 'charmed' */
1057 
1058  /* it's hostile! */
1059  if (!QUERY_FLAG(tmp, FLAG_UNAGGRESSIVE) && !QUERY_FLAG(tmp, FLAG_FRIENDLY)) {
1060  query_name(tmp, name, MAX_BUF);
1062  "Too bad the %s isn't listening!",
1063  name);
1064  return 0;
1065  }
1066 
1067  /* it's already allied! */
1068  if (QUERY_FLAG(tmp, FLAG_FRIENDLY) && tmp->attack_movement == PETMOVE) {
1069  if (object_get_owner(tmp) == pl) {
1071  "Your follower loves your speech.");
1072  return 0;
1073  }
1074 
1075  if (skill->level > tmp->level) {
1076  /* you steal the follower. Perhaps we should really look at the
1077  * level of the owner above?
1078  */
1079  object_set_owner(tmp, pl);
1080  query_name(tmp, name, MAX_BUF);
1082  "You convince the %s to follow you instead!",
1083  name);
1084 
1085  FREE_AND_COPY(tmp->skill, skill->skill);
1086 
1087  /* Abuse fix - don't give exp since this can otherwise
1088  * be used by a couple players to gets lots of exp.
1089  */
1090  return 0;
1091  }
1092 
1093  /* In this case, you can't steal it from the other player */
1094  return 0;
1095  } /* Creature was already a pet of someone */
1096 
1097  chance = skill->level*2+(pl->stats.Cha-2*tmp->stats.Int)/2;
1098 
1099  /* Ok, got a 'sucker' lets try to make them a follower */
1100  if (chance > 0 && tmp->level < random_roll(0, chance-1, pl, PREFER_HIGH)-1) {
1101  int64_t exp;
1102  query_name(tmp, name, MAX_BUF);
1104  "You convince the %s to become your follower.",
1105  name);
1106 
1107  object_set_owner(tmp, pl);
1108  /* compute exp before setting to 0, else the monster's experience is not taken into account. */
1109  tmp->stats.exp /= 5; /* why 5? because. */
1110  exp = calc_skill_exp(pl, tmp, skill);
1111  tmp->stats.exp = 0;
1112  add_friendly_object(tmp);
1113  SET_FLAG(tmp, FLAG_FRIENDLY);
1114  tmp->attack_movement = PETMOVE;
1115  /* keep oratory skill, so exp goes where it should if the pet kills something */
1116  FREE_AND_COPY(tmp->skill, skill->skill);
1117  return exp;
1118  }
1119 
1120  /* Charm failed. Creature may be angry now */
1121  if (skill->level+(pl->stats.Cha-10)/2 < random_roll(1, 2*tmp->level, pl, PREFER_LOW)) {
1122  query_name(tmp, name, MAX_BUF);
1124  "Your speech angers the %s!",
1125  name);
1126 
1127  if (QUERY_FLAG(tmp, FLAG_FRIENDLY)) {
1128  CLEAR_FLAG(tmp, FLAG_FRIENDLY);
1130  tmp->attack_movement = 0; /* needed? */
1131  }
1133  }
1134 
1135  return 0; /* Fall through - if we get here, we didn't charm anything */
1136 }
1137 
1158 int singing(object *pl, int dir, object *skill) {
1159  int i, exp = 0, chance, mflags;
1160  object *tmp;
1161  mapstruct *m;
1162  int16_t x, y;
1163  char name[MAX_BUF];
1164 
1165  if (pl->type != PLAYER)
1166  return 0; /* only players use this skill */
1167 
1169  "You sing");
1170  for (i = dir; i < (dir+MIN(skill->level, SIZEOFFREE)); i++) {
1171  x = pl->x+freearr_x[i];
1172  y = pl->y+freearr_y[i];
1173  m = pl->map;
1174 
1175  mflags = get_map_flags(m, &m, x, y, &x, &y);
1176  if (mflags&P_OUT_OF_MAP)
1177  continue;
1178  if (!(mflags&P_IS_ALIVE))
1179  continue;
1180 
1181  tmp = NULL;
1182  FOR_MAP_PREPARE(m, x, y, tmp2) {
1183  tmp2 = HEAD(tmp2);
1184  if (QUERY_FLAG(tmp2, FLAG_MONSTER)) {
1185  tmp = tmp2;
1186  break;
1187  }
1188  /* can't affect players */
1189  if (tmp2->type == PLAYER) {
1190  tmp = tmp2;
1191  break;
1192  }
1193  } FOR_MAP_FINISH();
1194 
1195  /* Whole bunch of checks to see if this is a type of monster that would
1196  * listen to singing.
1197  */
1198  if (tmp
1199  && QUERY_FLAG(tmp, FLAG_MONSTER)
1200  && !QUERY_FLAG(tmp, FLAG_NO_STEAL) /* Been charmed or abused before */
1201  && !QUERY_FLAG(tmp, FLAG_SPLITTING) /* no ears */
1202  && !QUERY_FLAG(tmp, FLAG_HITBACK) /* was here before */
1203  && (tmp->level <= skill->level)
1204  && !QUERY_FLAG(tmp, FLAG_UNDEAD)
1205  && !QUERY_FLAG(tmp, FLAG_UNAGGRESSIVE) /* already calm */
1206  && !QUERY_FLAG(tmp, FLAG_FRIENDLY)) { /* already calm */
1207  /* stealing isn't really related (although, maybe it should
1208  * be). This is mainly to prevent singing to the same monster
1209  * over and over again and getting exp for it.
1210  */
1211  chance = skill->level*2+(pl->stats.Cha-5-tmp->stats.Int)/2;
1212 
1213  if (object_value_set(tmp, "no_mood_change"))
1214  chance = 0;
1215 
1216  if (chance && tmp->level*2 < random_roll(0, chance-1, pl, PREFER_HIGH)) {
1218  query_name(tmp, name, MAX_BUF);
1220  "You calm down the %s",
1221  name);
1222 
1223  /* Give exp only if they are not aware */
1224  if (!QUERY_FLAG(tmp, FLAG_NO_STEAL))
1225  exp += calc_skill_exp(pl, tmp, skill);
1226  SET_FLAG(tmp, FLAG_NO_STEAL);
1227  } else {
1228  query_name(tmp, name, MAX_BUF);
1230  "Too bad the %s isn't listening!",
1231  name);
1232  SET_FLAG(tmp, FLAG_NO_STEAL);
1233  }
1234  }
1235  }
1236  return exp;
1237 }
1238 
1249 int find_traps(object *pl, object *skill) {
1250  int i, expsum = 0, mflags;
1251  int16_t x, y;
1252  mapstruct *m;
1253 
1254  /* First we search all around us for runes and traps, which are
1255  * all type RUNE
1256  */
1257 
1258  for (i = 0; i < 9; i++) {
1259  x = pl->x+freearr_x[i];
1260  y = pl->y+freearr_y[i];
1261  m = pl->map;
1262 
1263  mflags = get_map_flags(m, &m, x, y, &x, &y);
1264  if (mflags&P_OUT_OF_MAP)
1265  continue;
1266 
1267  /* Check everything in the square for trapness */
1268  FOR_MAP_PREPARE(m, x, y, tmp) {
1269  /* And now we'd better do an inventory traversal of each
1270  * of these objects' inventory
1271  * We can narrow this down a bit - no reason to search through
1272  * the players inventory or monsters for that matter.
1273  */
1274  if (tmp->type != PLAYER && !QUERY_FLAG(tmp, FLAG_MONSTER)) {
1275  FOR_INV_PREPARE(tmp, tmp2)
1276  if (tmp2->type == RUNE || tmp2->type == TRAP)
1277  if (trap_see(pl, tmp2)) {
1278  trap_show(tmp2, tmp);
1279  if (tmp2->stats.Cha > 1) {
1280  object *owner;
1281 
1282  owner = object_get_owner(tmp2);
1283  if (owner == NULL || owner->type != PLAYER)
1284  expsum += calc_skill_exp(pl, tmp2, skill);
1285 
1286  tmp2->stats.Cha = 1; /* unhide the trap */
1287  }
1288  }
1289  FOR_INV_FINISH();
1290  }
1291  if ((tmp->type == RUNE || tmp->type == TRAP) && trap_see(pl, tmp)) {
1292  trap_show(tmp, tmp);
1293  if (tmp->stats.Cha > 1) {
1294  object *owner;
1295 
1296  owner = object_get_owner(tmp);
1297  if (owner == NULL || owner->type != PLAYER)
1298  expsum += calc_skill_exp(pl, tmp, skill);
1299  tmp->stats.Cha = 1; /* unhide the trap */
1300  }
1301  }
1302  } FOR_MAP_FINISH();
1303  }
1305  "You search the area.");
1306  return expsum;
1307 }
1308 
1320 int remove_trap(object *op, object *skill) {
1321  int i, success = 0, mflags;
1322  mapstruct *m;
1323  int16_t x, y;
1324 
1325  for (i = 0; i < 9; i++) {
1326  x = op->x+freearr_x[i];
1327  y = op->y+freearr_y[i];
1328  m = op->map;
1329 
1330  mflags = get_map_flags(m, &m, x, y, &x, &y);
1331  if (mflags&P_OUT_OF_MAP)
1332  continue;
1333 
1334  /* Check everything in the square for trapness */
1335  FOR_MAP_PREPARE(m, x, y, tmp) {
1336  /* And now we'd better do an inventory traversal of each
1337  * of these objects inventory. Like above, only
1338  * do this for interesting objects.
1339  */
1340 
1341  if (tmp->type != PLAYER && !QUERY_FLAG(tmp, FLAG_MONSTER)) {
1342  FOR_INV_PREPARE(tmp, tmp2)
1343  if ((tmp2->type == RUNE || tmp2->type == TRAP) && tmp2->stats.Cha <= 1) {
1344  object *owner;
1345 
1346  trap_show(tmp2, tmp);
1347  if (trap_disarm(op, tmp2, 1, skill) && ((owner = object_get_owner(tmp2)) == NULL || owner->type != PLAYER)) {
1348  tmp2->stats.exp = tmp2->stats.Cha*tmp2->level;
1349  success += calc_skill_exp(op, tmp2, skill);
1350  } else {
1351  /* Can't continue to disarm after failure */
1352  return success;
1353  }
1354  }
1355  FOR_INV_FINISH();
1356  }
1357  if ((tmp->type == RUNE || tmp->type == TRAP) && tmp->stats.Cha <= 1) {
1358  object *owner;
1359 
1360  trap_show(tmp, tmp);
1361  if (trap_disarm(op, tmp, 1, skill) && ((owner = object_get_owner(tmp)) == NULL || owner->type != PLAYER)) {
1362  tmp->stats.exp = tmp->stats.Cha*tmp->level;
1363  success += calc_skill_exp(op, tmp, skill);
1364  } else {
1365  /* Can't continue to disarm after failure */
1366  return success;
1367  }
1368  }
1369  } FOR_MAP_FINISH();
1370  }
1371  return success;
1372 }
1373 
1374 
1388 int pray(object *pl, object *skill) {
1389  char buf[MAX_BUF];
1390 
1391  if (pl->type != PLAYER)
1392  return 0;
1393 
1394  snprintf(buf, sizeof(buf), "You pray.");
1395 
1396  /* Check all objects - we could stop at floor objects,
1397  * but if someone buries an altar, I don't see a problem with
1398  * going through all the objects, and it shouldn't be much slower
1399  * than extra checks on object attributes.
1400  */
1401  FOR_BELOW_PREPARE(pl, tmp)
1402  /* Only if the altar actually belongs to someone do you get special benefits */
1403  if (tmp->type == HOLY_ALTAR && tmp->other_arch) {
1404  snprintf(buf, sizeof(buf), "You pray over the %s.", tmp->name);
1405  pray_at_altar(pl, tmp, skill);
1406  break; /* Only pray at one altar */
1407  }
1408  FOR_BELOW_FINISH();
1409 
1411  buf);
1412 
1413  if (pl->stats.grace < pl->stats.maxgrace) {
1414  pl->stats.grace++;
1415  pl->last_grace = -1;
1416  }
1417  return 1;
1418 }
1419 
1437 int meditate(object *pl, object *skill) {
1438  if (pl->type != PLAYER)
1439  return 0; /* players only */
1440 
1441  /* check if pl has removed encumbering armour and weapons */
1442  if (QUERY_FLAG(pl, FLAG_READY_WEAPON) && skill->level < 6) {
1444  "You can't concentrate while wielding a weapon!");
1445  return 0;
1446  }
1447 
1448  FOR_INV_PREPARE(pl, tmp)
1449  if (((tmp->type == ARMOUR && skill->level < 12)
1450  || (tmp->type == HELMET && skill->level < 10)
1451  || (tmp->type == SHIELD && skill->level < 6)
1452  || (tmp->type == BOOTS && skill->level < 4)
1453  || (tmp->type == GLOVES && skill->level < 2))
1454  && QUERY_FLAG(tmp, FLAG_APPLIED)) {
1456  "You can't concentrate while wearing so much armour!");
1457  return 0;
1458  }
1459  FOR_INV_FINISH();
1460 
1461  /* ok let's meditate! Spell points are regained first, then once
1462  * they are maxed we get back hp. Actual incrementing of values
1463  * is handled by the do_some_living() (in player.c). This way magical
1464  * bonuses for healing/sp regeneration are included properly
1465  * No matter what, we will eat up some playing time trying to
1466  * meditate. (see 'factor' variable for what sets the amount of time)
1467  */
1468 
1470  "You meditate.");
1471 
1472  if (pl->stats.sp < pl->stats.maxsp) {
1473  pl->stats.sp++;
1474  pl->last_sp = -1;
1475  } else if (pl->stats.hp < pl->stats.maxhp) {
1476  pl->stats.hp++;
1477  pl->last_heal = -1;
1478  }
1479  return 1;
1480 }
1481 
1495 static int write_note(object *pl, object *item, const char *msg) {
1496  char buf[BOOK_BUF];
1497  object *newBook = NULL;
1498 
1499  // The item should exist and be a book, but check it just in case.
1500  if (!item || item->type != BOOK) {
1502  "That was interesting...");
1503  // TODO: Print a scary log message.
1504  return 0;
1505  }
1506 
1507  // The message should never be NULL, but check it just in case.
1508  if (!msg) {
1510  "Hmm... what was I going to write?");
1511  // TODO: Print a scary log message.
1512  return 0;
1513  }
1514 
1515  // Don't let the player write a reserved keyword.
1516  if (strcasestr_local(msg, "endmsg")) {
1518  "Trying to cheat now are we?");
1519  return 0;
1520  }
1521 
1522  if (events_execute_object_event(item, EVENT_TRIGGER, pl, NULL, msg, SCRIPT_FIX_ALL) != 0)
1523  return strlen(msg);
1524 
1525  buf[0] = 0;
1526 
1527  // Write the message in the book if it doesn't overflow the buffer.
1528  if (!book_overflow(item->msg, msg, BOOK_BUF)) {
1529  // TODO: Garble some characters depending on intelligence/skill.
1530 
1531  // If there was already text, append the new message on the end.
1532  if (item->msg) {
1533  snprintf(buf, sizeof(buf), "%s%s\n", item->msg, msg);
1534  } else {
1535  snprintf(buf, sizeof(buf), "%s\n", msg);
1536  }
1537 
1538  // If there were multiple items in a stack, unstack one and write.
1539  if (item->nrof > 1) {
1540  newBook = object_new();
1541  object_copy(item, newBook);
1543  newBook->nrof = 1;
1544  object_set_msg(newBook, buf);
1545  newBook = object_insert_in_ob(newBook, pl);
1546  } else {
1547  object_set_msg(item, buf);
1548 
1549  // This shouldn't be necessary; the object hasn't changed visibly.
1550  //esrv_send_item(pl, item);
1551  }
1552 
1553  // Tell the player that he/she wrote in the object.
1554  query_short_name(item, buf, BOOK_BUF);
1557  "You write in the %s.", buf);
1558 
1559  // Give the player experience for writing.
1560  return strlen(msg);
1561  } else {
1562  query_short_name(item, buf, BOOK_BUF);
1565  "Your message won't fit in the %s!", buf);
1566  return 0;
1567  }
1568 }
1569 
1584 static int write_scroll(object *pl, object *scroll, object *skill) {
1585  int success = 0, confused = 0, grace_cost = 0;
1586  object *newscroll, *chosen_spell, *tmp;
1587 
1588  // The item should exist and be a scroll, but check it just in case.
1589  if (!scroll || scroll->type != SCROLL) {
1591  "A spell must be written on a magic scroll!");
1592  // TODO: Print a scary log message.
1593  return 0;
1594  }
1595 
1596  // The player must have a spell readied to inscribe.
1597  chosen_spell = pl->contr->ranges[range_magic];
1598  if (!chosen_spell) {
1600  "You should ready the spell you wish to inscribe.");
1601  return 0;
1602  }
1603 
1604  // Make sure the player has enough SP or grace to write the spell.
1605  grace_cost = SP_level_spellpoint_cost(pl, chosen_spell, SPELL_GRACE);
1606  if (grace_cost > 0 && grace_cost > pl->stats.grace) {
1609  "You don't have enough grace to write a scroll of %s.",
1610  chosen_spell->name);
1611  return 0;
1612  }
1613 
1614  if (SP_level_spellpoint_cost(pl, chosen_spell, SPELL_MANA) > pl->stats.sp) {
1617  "You don't have enough mana to write a scroll of %s.",
1618  chosen_spell->name);
1619  return 0;
1620  }
1621 
1622  // Prevent players from writing spells that they are denied.
1623  if (chosen_spell->path_attuned & pl->path_denied
1625  char name[MAX_BUF];
1626 
1627  query_name(chosen_spell, name, MAX_BUF);
1630  "Just the idea of writing a scroll of %s makes you sick!",
1631  name);
1632  return 0;
1633  }
1634 
1635  // If the scroll already had a spell written on it, the player could
1636  // accidentally read it while trying to write a new one. Give the player
1637  // a 50% chance to overwrite a spell at their own level.
1638  if ((scroll->stats.sp || scroll->inv) &&
1639  random_roll(0, scroll->level*2, pl, PREFER_LOW) > skill->level) {
1641  "Oops! You accidently read it while trying to write on it.");
1642  apply_manual(pl, scroll, 0);
1643  return 0;
1644  }
1645 
1646  if (events_execute_object_event(scroll, EVENT_TRIGGER, pl, chosen_spell, NULL, 0) != 0) {
1647  return 0;
1648  }
1649 
1650  // Find out if the player is confused or not.
1651  if (QUERY_FLAG(pl, FLAG_CONFUSED)) {
1652  confused = 1;
1653  }
1654 
1655  // Mana or grace is lost no matter if the inscription is successful.
1656  pl->stats.grace -= SP_level_spellpoint_cost(pl, chosen_spell, SPELL_GRACE);
1657  pl->stats.sp -= SP_level_spellpoint_cost(pl, chosen_spell, SPELL_MANA);
1658 
1659  if (random_roll(0, chosen_spell->level * 4 - 1, pl, PREFER_LOW) <
1660  skill->level) {
1661  // If there were multiple items in a stack, unstack one.
1662  if (scroll->nrof > 1) {
1663  newscroll = object_new();
1664  object_copy(scroll, newscroll);
1666  newscroll->nrof = 1;
1667  } else {
1668  newscroll = scroll;
1669  }
1670 
1671  // Write spell if not confused; otherwise write random spell.
1672  newscroll->level = MAX(skill->level, chosen_spell->level);
1673 
1674  if (!confused) {
1675  draw_ext_info(
1677  "You succeed in writing a new scroll.");
1678  } else {
1679  chosen_spell = find_random_spell_in_ob(pl, NULL);
1680  if (!chosen_spell) {
1681  return 0;
1682  }
1683 
1684  draw_ext_info(
1686  "In your confused state, you write down some odd spell.");
1687  }
1688 
1689  if (newscroll->inv) {
1690  object *ninv;
1691  ninv = newscroll->inv;
1692  object_remove(ninv);
1694  }
1695 
1696  tmp = object_new();
1697  object_copy(chosen_spell, tmp);
1698  object_insert_in_ob(tmp, newscroll);
1699 
1700  // This is needed so casting from the scroll works correctly with
1701  // moving_ball types, which checks attunements.
1702  newscroll->path_attuned = tmp->path_repelled;
1703 
1704  // Same code as from treasure.c - so they can better merge.
1705  // If players want to sell them, so be it.
1706  newscroll->value = newscroll->arch->clone.value *
1707  newscroll->inv->value * (newscroll->level + 50 ) /
1708  (newscroll->inv->level + 50);
1709  newscroll->stats.exp = newscroll->value / 5;
1710 
1711  // Finish manipulating the scroll before inserting it.
1712  if (newscroll == scroll) {
1713  // Remove object to stack correctly with other items.
1714  object_remove(newscroll);
1715  }
1716 
1717  newscroll = object_insert_in_ob(newscroll, pl);
1718  success = calc_skill_exp(pl, newscroll, skill);
1719 
1720  if (!confused) {
1721  success *= 2;
1722  }
1723 
1724  success = success * skill->level;
1725  return success;
1726  }
1727 
1728  // Inscription wasn't successful; do something bad to the player.
1729  if (chosen_spell->level > skill->level || confused) {
1730  draw_ext_info(
1732  "Ouch! Your attempt to write a new scroll strains your mind!");
1733 
1734  // Either drain a stat or subtract experience.
1735  if (random_roll(0, 1, pl, PREFER_LOW) == 1) {
1736  drain_specific_stat(pl, 4);
1737  } else {
1738  confuse_living(pl, pl, 99);
1739  return -30 * chosen_spell->level;
1740  }
1741  } else if (random_roll(0, pl->stats.Int-1, pl, PREFER_HIGH) < 15) {
1742  draw_ext_info(
1744  "Your attempt to write a new scroll rattles your mind!");
1745  confuse_living(pl, pl, 99);
1746  } else {
1747  draw_ext_info(
1749  "You fail to write a new scroll.");
1750  }
1751 
1752  return 0;
1753 }
1754 
1768 int write_on_item(object *pl, const char *params, object *skill) {
1769  object *item;
1770  const char *string = params;
1771  int msgtype;
1772  archetype *skat;
1773 
1774  // Only players can use the inscription skill.
1775  if (pl->type != PLAYER) {
1776  return 0;
1777  }
1778 
1779  // No message was given, so both strings are set to empty.
1780  if (!params) {
1781  params = "";
1782  string = params;
1783  }
1784 
1785  // You must be able to read before you can write.
1787 
1788  if (!find_skill_by_name(pl, skat->clone.skill)) {
1790  "You must learn to read before you can write!");
1791  return 0;
1792  }
1793 
1794  // You must not be blind to write, unless you're a DM.
1795  if (QUERY_FLAG(pl, FLAG_BLIND) && !QUERY_FLAG(pl, FLAG_WIZ)) {
1797  "You are unable to write while blind.");
1798  return 0;
1799  }
1800 
1801  // If a message was given, write a book. Otherwise, write a scroll.
1802  if (string[0] != '\0') {
1803  msgtype = BOOK;
1804  } else {
1805  msgtype = SCROLL;
1806  }
1807 
1808  // Find and attempt to write on the player's marked item.
1809  item = find_marked_object(pl);
1810  if (item == NULL) {
1812  "You haven't marked any items to write on yet.");
1813  return 0;
1814  }
1815 
1816  // Don't let the player write on an unpaid item.
1817  if (QUERY_FLAG(item, FLAG_UNPAID)) {
1819  "You had better pay for that before you write on it!");
1820  return 0;
1821  }
1822 
1823  // Check if the marked item is the type of item we're writing.
1824  if (msgtype != item->type) {
1827  "You must mark a %s to write %s.",
1828  msgtype == BOOK ? "book" : "magic scroll",
1829  msgtype == BOOK ? "your message on" : "your spell down");
1830  return 0;
1831  }
1832 
1833  if (msgtype == BOOK) {
1834  return write_note(pl, item, string);
1835  } else if (msgtype == SCROLL) {
1836  return write_scroll(pl, item, skill);
1837  } else {
1838  // This case should never be reached.
1839  abort();
1840  }
1841 }
1842 
1855 static object *find_throw_ob(object *op, sstring race) {
1856  object *tmp;
1857  char name[MAX_BUF];
1858 
1859  if (!op) { /* safety */
1860  LOG(llevError, "find_throw_ob(): confused! have a NULL thrower!\n");
1861  return (object *)NULL;
1862  }
1863 
1864  /* prefer marked item */
1865  tmp = find_marked_object(op);
1866  if (tmp != NULL) {
1867  /* can't toss invisible or inv-locked items */
1868  if (tmp->invisible || QUERY_FLAG(tmp, FLAG_INV_LOCKED)) {
1869  tmp = NULL;
1870  }
1871  }
1872 
1873  /* look through the inventory if no marked found */
1874  if (tmp == NULL) {
1875  FOR_INV_PREPARE(op, tmp2) {
1876  /* can't toss invisible items */
1877  if (tmp2->invisible)
1878  continue;
1879 
1880  if (tmp2->type == CONTAINER && QUERY_FLAG(tmp2, FLAG_APPLIED) && tmp2->race == race) {
1881  tmp = find_throw_ob(tmp2, race);
1882  if (tmp != NULL) {
1883  break;
1884  }
1885  }
1886 
1887  /* if not a container, then don't look if locked */
1888  if (tmp2->type == CONTAINER || QUERY_FLAG(tmp2, FLAG_INV_LOCKED))
1889  continue;
1890 
1891  if (tmp2->race == race) {
1892  tmp = tmp2;
1893  break;
1894  }
1895 
1896  } FOR_INV_FINISH();
1897  }
1898 
1899  /* this should prevent us from throwing away
1900  * cursed items, worn armour, etc. Only weapons
1901  * can be thrown from 'hand'.
1902  */
1903  if (!tmp)
1904  return NULL;
1905 
1906  if (QUERY_FLAG(tmp, FLAG_APPLIED)) {
1907  if (tmp->type != WEAPON) {
1908  query_name(tmp, name, MAX_BUF);
1910  "You can't throw %s.",
1911  name);
1912  tmp = NULL;
1913  } else if (QUERY_FLAG(tmp, FLAG_CURSED) || QUERY_FLAG(tmp, FLAG_DAMNED)) {
1914  query_name(tmp, name, MAX_BUF);
1917  "The %s sticks to your hand!",
1918  name);
1919  tmp = NULL;
1920  } else {
1921  if (apply_special(op, tmp, AP_UNAPPLY|AP_NO_MERGE)) {
1922  LOG(llevError, "BUG: find_throw_ob(): couldn't unapply\n");
1923  tmp = NULL;
1924  }
1925  }
1926  } else if (QUERY_FLAG(tmp, FLAG_UNPAID)) {
1927  query_name(tmp, name, MAX_BUF);
1929  "You should pay for the %s first.",
1930  name);
1931  tmp = NULL;
1932  }
1933 
1934  if (tmp && QUERY_FLAG(tmp, FLAG_INV_LOCKED)) {
1935  LOG(llevError, "BUG: find_throw_ob(): object is locked\n");
1936  tmp = NULL;
1937  }
1938  return tmp;
1939 }
1940 
1952 static object *make_throw_ob(object *orig) {
1953  object *toss_item;
1954 
1955  if (!orig)
1956  return NULL;
1957 
1958  toss_item = object_new();
1959  if (QUERY_FLAG(orig, FLAG_APPLIED)) {
1960  LOG(llevError, "BUG: make_throw_ob(): ob is applied\n");
1961  /* insufficient workaround, but better than nothing */
1962  CLEAR_FLAG(orig, FLAG_APPLIED);
1963  }
1964  object_copy(orig, toss_item);
1965  toss_item->type = THROWN_OBJ;
1966  CLEAR_FLAG(toss_item, FLAG_CHANGING);
1967  toss_item->stats.dam = 0; /* default damage */
1968  object_insert_in_ob(orig, toss_item);
1969  return toss_item;
1970 }
1971 
1972 
1993 static int do_throw(object *op, object *part, object *toss_item, int dir, object *skill) {
1994  object *throw_ob = toss_item, *left = NULL;
1995  int eff_str = 0, str = op->stats.Str, dam = 0;
1996  int pause_f, weight_f = 0, mflags;
1997  float str_factor = 1.0, load_factor = 1.0, item_factor = 1.0;
1998  mapstruct *m;
1999  int16_t sx, sy;
2000  tag_t tag;
2001  char name[MAX_BUF];
2002 
2003  if (throw_ob == NULL) {
2004  if (op->type == PLAYER) {
2006  "You have nothing to throw.");
2007  }
2008  return 0;
2009  }
2010  if (QUERY_FLAG(throw_ob, FLAG_STARTEQUIP)) {
2011  if (op->type == PLAYER) {
2013  "The gods won't let you throw that.");
2014  }
2015  return 0;
2016  }
2017 
2018  tag = throw_ob->count;
2020  if (object_was_destroyed(throw_ob, tag)) {
2021  return 1;
2022  }
2023 
2024  /* Because throwing effectiveness must be reduced by the
2025  * encumbrance of the thrower and weight of the object. THus,
2026  * we use the concept of 'effective strength' as defined below.
2027  */
2028 
2029  /* if str exceeds settings.max_stat (30, eg giants), lets assign a str_factor > 1 */
2030  if (str > settings.max_stat) {
2031  str_factor = (float)str/(float)settings.max_stat;
2032  str = settings.max_stat;
2033  }
2034 
2035  /* the more we carry, the less we can throw. Limit only on players */
2036  if (op->type == PLAYER
2038  && (FREE_PLAYER_LOAD_PERCENT < 1.0)) {
2053  load_factor = 2.0f - (float)(op->carrying) / (float)(get_weight_limit(op->stats.Str)*FREE_PLAYER_LOAD_PERCENT);
2054  // Only clip to 1.0 if we get in here, since it is 1.0 if we do not get in here.
2055  load_factor = MIN(load_factor, 1.0f);
2056  }
2057 
2058  /* lighter items are thrown harder, farther, faster */
2059  if (throw_ob->weight > 0)
2060  item_factor = (float)(get_weight_limit(op->stats.Str)*FREE_PLAYER_LOAD_PERCENT)/(float)(3.0*throw_ob->weight);
2061  else { /* 0 or negative weight?!? Odd object, can't throw it */
2062  query_name(throw_ob, name, MAX_BUF);
2064  "You can't throw %s.",
2065  name);
2066  return 0;
2067  }
2068 
2069  eff_str = str*load_factor;
2070  eff_str = (float)eff_str*item_factor*str_factor;
2071 
2072  /* alas, arrays limit us to a value of settings.max_stat (30). Use str_factor to
2073  * account for super-strong throwers. */
2074  if (eff_str > settings.max_stat)
2075  eff_str = settings.max_stat;
2076 
2077 #ifdef DEBUG_THROW
2078  LOG(llevDebug, "%s carries %d, eff_str=%d\n", op->name, op->carrying, eff_str);
2079  LOG(llevDebug, " max_c=%d, item_f=%f, load_f=%f, str=%d\n", (get_weight_limit(op->stats.Str)*FREE_PLAYER_LOAD_PERCENT), item_factor, load_factor, op->stats.Str);
2080  LOG(llevDebug, " str_factor=%f\n", str_factor);
2081  LOG(llevDebug, " item %s weight= %d\n", throw_ob->name, throw_ob->weight);
2082 #endif
2083 
2084  /* 3 things here prevent a throw, you aimed at your feet, you
2085  * have no effective throwing strength, or you threw at something
2086  * that flying objects can't get through.
2087  */
2088  mflags = get_map_flags(part->map, &m, part->x+freearr_x[dir], part->y+freearr_y[dir], &sx, &sy);
2089 
2090  if (!dir
2091  || (eff_str <= 1)
2092  || (mflags&P_OUT_OF_MAP)
2093  || (GET_MAP_MOVE_BLOCK(m, sx, sy)&MOVE_FLY_LOW)) {
2094  /* bounces off 'wall', and drops to feet */
2095  object_remove(throw_ob);
2096  object_insert_in_map_at(throw_ob, part->map, op, 0, part->x, part->y);
2097  if (op->type == PLAYER) {
2098  if (eff_str <= 1) {
2099  query_name(throw_ob, name, MAX_BUF);
2101  "Your load is so heavy you drop %s to the ground.",
2102  name);
2103  } else if (!dir) {
2104  query_name(throw_ob, name, MAX_BUF);
2106  "You throw %s at the ground.",
2107  name);
2108  } else
2110  "Something is in the way.");
2111  }
2112  return 0;
2113  } /* if object can't be thrown */
2114 
2115  left = throw_ob; /* these are throwing objects left to the player */
2116 
2117  /* sometimes object_split() can't split an object (because op->nrof==0?)
2118  * and returns NULL. We must use 'left' then
2119  */
2120  throw_ob = object_split(throw_ob, 1, NULL, 0);
2121  if (throw_ob == NULL) {
2122  throw_ob = left;
2123  object_remove(left);
2124  }
2125 
2126  /* special case: throwing powdery substances like dust, dirt */
2127  if (throw_ob->type == POTION && throw_ob->subtype == POT_DUST) {
2128  cast_dust(op, throw_ob, dir);
2129  return 1;
2130  }
2131 
2132  /* Make a thrown object -- insert real object in a 'carrier' object.
2133  * If unsuccessfull at making the "thrown_obj", we just reinsert
2134  * the original object back into inventory and exit
2135  */
2136  toss_item = make_throw_ob(throw_ob);
2137  if (toss_item) {
2138  throw_ob = toss_item;
2139  if (throw_ob->skill)
2140  free_string(throw_ob->skill);
2141  throw_ob->skill = add_string(skill->skill);
2142  } else {
2143  object_insert_in_ob(throw_ob, op);
2144  return 0;
2145  }
2146 
2147  object_set_owner(throw_ob, op);
2148  /* At some point in the attack code, the actual real object (op->inv)
2149  * becomes the hitter. As such, we need to make sure that has a proper
2150  * owner value so exp goes to the right place.
2151  */
2152  object_set_owner(throw_ob->inv, op);
2153  throw_ob->direction = dir;
2154 
2155  /* If the thrown item has reflecting flag, it can ricochet off walls.
2156  * Make sure this gets copied to the thrown object.
2157  * The common projectile code should then handle the reflection from there.
2158  */
2159  if (QUERY_FLAG(throw_ob->inv, FLAG_REFLECTING))
2160  SET_FLAG(throw_ob, FLAG_REFLECTING);
2161 
2162  /* the damage bonus from the force of the throw */
2163  dam = str_factor*get_dam_bonus(eff_str);
2164 
2165  /* Now, lets adjust the properties of the thrown_ob. */
2166 
2167  /* how far to fly */
2168  throw_ob->last_sp = (eff_str*3)/5;
2169 
2170  /* speed */
2171  throw_ob->speed = (get_speed_bonus(eff_str)+1.0)/1.5;
2172  throw_ob->speed = MIN(1.0, throw_ob->speed); /* no faster than an arrow! */
2173 
2174  /* item damage. Eff_str and item weight influence damage done */
2175  weight_f = MIN(throw_ob->weight/2000, settings.max_stat);
2176  throw_ob->stats.dam += (dam/3)+get_dam_bonus(weight_f)+(throw_ob->weight/15000)-2;
2177 
2178  /* chance of breaking. Proportional to force used and weight of item */
2179  throw_ob->stats.food = (dam/2)+(throw_ob->weight/60000);
2180 
2181  /* replace 25 with a call to clone.arch wc? messes up w/ NPC */
2182  throw_ob->stats.wc = 25-get_dex_bonus(op->stats.Dex)-get_thaco_bonus(eff_str)-skill->level;
2183 
2184 
2185  /* the properties of objects which are meant to be thrown (ie dart,
2186  * throwing knife, etc) will differ from ordinary items. Lets tailor
2187  * this stuff in here.
2188  */
2189 
2190  if (QUERY_FLAG(throw_ob->inv, FLAG_IS_THROWN)) {
2191  throw_ob->last_sp += eff_str/3; /* fly a little further */
2192  throw_ob->stats.dam += throw_ob->inv->stats.dam+throw_ob->magic+2;
2193  throw_ob->stats.wc -= throw_ob->magic+throw_ob->inv->stats.wc;
2194  /* only throw objects get directional faces */
2195  if (GET_ANIM_ID(throw_ob) && NUM_ANIMATIONS(throw_ob))
2196  object_update_turn_face(throw_ob);
2197  } else {
2198  /* some materials will adjust properties.. */
2199  if (throw_ob->material&M_LEATHER) {
2200  throw_ob->stats.dam -= 1;
2201  throw_ob->stats.food -= 10;
2202  }
2203  if (throw_ob->material&M_GLASS)
2204  throw_ob->stats.food += 60;
2205 
2206  if (throw_ob->material&M_ORGANIC) {
2207  throw_ob->stats.dam -= 3;
2208  throw_ob->stats.food += 55;
2209  }
2210  if (throw_ob->material&M_PAPER || throw_ob->material&M_CLOTH) {
2211  throw_ob->stats.dam -= 5;
2212  throw_ob->speed *= 0.8;
2213  throw_ob->stats.wc += 3;
2214  throw_ob->stats.food -= 30;
2215  }
2216  /* light obj have more wind resistance, fly slower*/
2217  if (throw_ob->weight > 500)
2218  throw_ob->speed *= 0.8;
2219  if (throw_ob->weight > 50)
2220  throw_ob->speed *= 0.5;
2221  } /* else tailor thrown object */
2222 
2223  /* some limits, and safeties (needed?) */
2224  if (throw_ob->stats.dam < 0)
2225  throw_ob->stats.dam = 0;
2226  if (throw_ob->last_sp > eff_str)
2227  throw_ob->last_sp = eff_str;
2228  if (throw_ob->stats.food < 0)
2229  throw_ob->stats.food = 0;
2230  if (throw_ob->stats.food > 100)
2231  throw_ob->stats.food = 100;
2232  if (throw_ob->stats.wc > 30)
2233  throw_ob->stats.wc = 30;
2234 
2235  /* how long to pause the thrower. Higher values mean less pause */
2236  pause_f = ((2*eff_str)/3)+20+skill->level;
2237 
2238  /* Put a lower limit on this */
2239  if (pause_f < 10)
2240  pause_f = 10;
2241  if (pause_f > 100)
2242  pause_f = 100;
2243 
2244  /* Changed in 0.94.2 - the calculation before was really goofy.
2245  * In short summary, a throw can take anywhere between speed 5 and
2246  * speed 0.5
2247  */
2248  op->speed_left -= 50.0/pause_f;
2249 
2250  object_update_speed(throw_ob);
2251  throw_ob->speed_left = 0;
2252 
2253  throw_ob->move_type = MOVE_FLY_LOW;
2254  throw_ob->move_on = MOVE_FLY_LOW|MOVE_WALK;
2255 
2256 #ifdef DEBUG_THROW
2257  LOG(llevDebug, " pause_f=%d \n", pause_f);
2258  LOG(llevDebug, " %s stats: wc=%d dam=%d dist=%d spd=%f break=%d\n", throw_ob->name, throw_ob->stats.wc, throw_ob->stats.dam, throw_ob->last_sp, throw_ob->speed, throw_ob->stats.food);
2259  LOG(llevDebug, "inserting tossitem (%d) into map\n", throw_ob->count);
2260 #endif
2261  tag = throw_ob->count;
2262  object_insert_in_map_at(throw_ob, part->map, op, 0, part->x, part->y);
2263  if (!object_was_destroyed(throw_ob, tag))
2264  ob_process(throw_ob);
2265  return 1;
2266 }
2267 
2283 int skill_throw(object *op, object *part, int dir, object *skill) {
2284  object *throw_ob;
2285 
2286  if (op->type == PLAYER)
2287  throw_ob = find_throw_ob(op, find_string("throwing"));
2288  else
2289  throw_ob = monster_find_throw_ob(op);
2290 
2291  return do_throw(op, part, throw_ob, dir, skill);
2292 }
object_was_destroyed
#define object_was_destroyed(op, old_tag)
Checks if an object still exists.
Definition: object.h:70
object_value_set
bool object_value_set(const object *op, const char *const key)
Determine if an extra value is set.
Definition: object.cpp:4361
UNARMED_SKILLS_COUNT
#define UNARMED_SKILLS_COUNT
Definition: skills.h:129
GET_MAP_OB
#define GET_MAP_OB(M, X, Y)
Gets the bottom object on a map.
Definition: map.h:175
living::exp
int64_t exp
Experience.
Definition: living.h:47
PLAYER
@ PLAYER
Definition: object.h:112
object_get_owner
object * object_get_owner(object *op)
Returns the object which this object marks as being the owner.
Definition: object.cpp:789
global.h
settings
struct Settings settings
Global settings.
Definition: init.cpp:139
MOVE_WALK
#define MOVE_WALK
Object walks.
Definition: define.h:383
object_update_turn_face
void object_update_turn_face(object *op)
If an object with the IS_TURNABLE() flag needs to be turned due to the closest player being on the ot...
Definition: object.cpp:1317
FOR_MAP_FINISH
#define FOR_MAP_FINISH()
Finishes FOR_MAP_PREPARE().
Definition: define.h:714
remove_friendly_object
void remove_friendly_object(object *op)
Removes the specified object from the linked list of friendly objects.
Definition: friend.cpp:52
living::maxhp
int16_t maxhp
Max hit points.
Definition: living.h:41
BOW
@ BOW
Definition: object.h:123
llevError
@ llevError
Problems requiring server admin to fix.
Definition: logger.h:11
mapstruct::difficulty
uint16_t difficulty
What level the player should be to play here.
Definition: map.h:337
object::path_attuned
uint32_t path_attuned
Paths the object is attuned to.
Definition: object.h:353
LOG
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:82
strcasestr_local
#define strcasestr_local
Definition: compat.h:28
singing
int singing(object *pl, int dir, object *skill)
Singing skill handling.
Definition: skills.cpp:1158
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:369
drain_specific_stat
void drain_specific_stat(object *op, int deplete_stats)
Drain a specified stat from op.
Definition: living.cpp:728
FLAG_HITBACK
#define FLAG_HITBACK
Object will hit back when hit.
Definition: define.h:254
monster_can_detect_enemy
int monster_can_detect_enemy(object *op, object *enemy, rv_vector *rv)
Determine if we can 'detect' the enemy.
Definition: monster.cpp:2690
esrv_map_scroll
void esrv_map_scroll(socket_struct *ns, int dx, int dy)
Definition: request.cpp:1759
GLOVES
@ GLOVES
Definition: object.h:218
object::inv
object * inv
Pointer to the first object in the inventory.
Definition: object.h:298
M_PAPER
#define M_PAPER
Paper.
Definition: material.h:14
find_throw_ob
static object * find_throw_ob(object *op, sstring race)
Find an object to throw.
Definition: skills.cpp:1855
find_random_spell_in_ob
object * find_random_spell_in_ob(object *ob, const char *skill)
This returns a random spell from 'ob'.
Definition: spell_util.cpp:48
MSG_TYPE_SKILL
#define MSG_TYPE_SKILL
Messages related to skill use.
Definition: newclient.h:411
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:371
M_LEATHER
#define M_LEATHER
Leather.
Definition: material.h:17
SK_CLAWING
@ SK_CLAWING
Clawing.
Definition: skills.h:50
confuse_living
void confuse_living(object *op, object *hitter, int dam)
Confuse a living thing.
Definition: attack.cpp:2315
object_merge
object * object_merge(object *op, object *top)
This function goes through all objects below and including top, and merges op to the first matching o...
Definition: object.cpp:2036
make_visible
void make_visible(object *op)
Makes an object visible again.
Definition: player.cpp:3986
pick_up
bool pick_up(object *op, object *alt)
Try to pick up an item.
Definition: c_object.cpp:470
MSG_TYPE_ATTRIBUTE_GOOD_EFFECT_END
#define MSG_TYPE_ATTRIBUTE_GOOD_EFFECT_END
End of a good effect.
Definition: newclient.h:578
M_ORGANIC
#define M_ORGANIC
General organic.
Definition: material.h:19
object::item_power
int8_t item_power
Power rating of the object.
Definition: object.h:372
FLAG_FRIENDLY
#define FLAG_FRIENDLY
Will help players.
Definition: define.h:233
object::arch
struct archetype * arch
Pointer to archetype.
Definition: object.h:424
EVENT_TRIGGER
#define EVENT_TRIGGER
Button pushed, lever pulled, etc.
Definition: events.h:42
object::attack_movement
uint16_t attack_movement
What kind of attack movement.
Definition: object.h:401
SK_DET_MAGIC
@ SK_DET_MAGIC
Detect magic.
Definition: skills.h:30
FOR_BELOW_PREPARE
#define FOR_BELOW_PREPARE(op_, it_)
Constructs a loop iterating over all objects below an object.
Definition: define.h:688
object::speed
float speed
Frequency of object 'moves' relative to server tick rate.
Definition: object.h:337
if
if(!(yy_init))
Definition: loader.cpp:36440
object::invisible
int16_t invisible
How much longer the object will be invis.
Definition: object.h:370
living::Dex
int8_t Dex
Definition: living.h:36
TRAP
@ TRAP
Definition: object.h:246
object::x
int16_t x
Definition: object.h:335
spring_trap
void spring_trap(object *trap, object *victim)
This function generalizes attacks by runes/traps.
Definition: rune.cpp:214
ARMOUR
@ ARMOUR
Definition: object.h:125
player::transport
object * transport
Transport the player is in.
Definition: player.h:216
object::speed_left
float speed_left
How much speed is left to spend this round.
Definition: object.h:338
PREFER_LOW
#define PREFER_LOW
Definition: define.h:548
unarmed_skills
uint8_t unarmed_skills[UNARMED_SKILLS_COUNT]
Table of unarmed attack skills.
Definition: skills.cpp:31
object::map
struct mapstruct * map
Pointer to the map in which this object is present.
Definition: object.h:305
WEAPON
@ WEAPON
Definition: object.h:124
AP_UNAPPLY
#define AP_UNAPPLY
Item is to be remvoed.
Definition: define.h:559
use_oratory
int use_oratory(object *pl, int dir, object *skill)
Oratory skill handling.
Definition: skills.cpp:1005
typedata::identifyskill
int identifyskill
Skill used to identify this object class.
Definition: define.h:93
object_set_owner
void object_set_owner(object *op, object *owner)
Sets the owner and sets the skill and exp pointers to owner's current skill and experience objects.
Definition: object.cpp:825
MSG_TYPE_ATTRIBUTE
#define MSG_TYPE_ATTRIBUTE
Changes to attributes (stats, resistances, etc)
Definition: newclient.h:409
do_throw
static int do_throw(object *op, object *part, object *toss_item, int dir, object *skill)
Op throws any object toss_item.
Definition: skills.cpp:1993
FLAG_BLIND
#define FLAG_BLIND
If set, object cannot see (visually)
Definition: define.h:323
FLAG_IS_CAULDRON
#define FLAG_IS_CAULDRON
container can make alchemical stuff
Definition: define.h:325
draw_ext_info_format
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...) PRINTF_ARGS(6
FLAG_WIZ
#define FLAG_WIZ
Object has special privilegies.
Definition: define.h:218
MIN
#define MIN(x, y)
Definition: compat.h:21
detect_magic_on_item
int detect_magic_on_item(object *pl, object *tmp, object *skill)
Runs a 'detect magic' check on a given item.
Definition: skills.cpp:761
SKILL
@ SKILL
Also see SKILL_TOOL (74) below.
Definition: object.h:148
object::direction
int8_t direction
Means the object is moving that way.
Definition: object.h:344
object::count
tag_t count
Unique object number for this object.
Definition: object.h:307
BODY_ARMS
#define BODY_ARMS
This should be the index of the arms.
Definition: object.h:16
object::last_grace
int16_t last_grace
As last_sp, except for grace.
Definition: object.h:369
RUNE
@ RUNE
Definition: object.h:245
object_copy
void object_copy(const object *src_ob, object *dest_ob)
Copy object first frees everything allocated by the second object, and then copies the contents of th...
Definition: object.cpp:1177
FLAG_MAKE_INVIS
#define FLAG_MAKE_INVIS
(Item) gives invisibility when applied
Definition: define.h:315
do_skill_detect_magic
static int do_skill_detect_magic(object *pl, object *skill)
Check for magic object with the 'detect magic' skill.
Definition: skills.cpp:781
fix_object
void fix_object(object *op)
Updates all abilities given by applied objects in the inventory of the given object.
Definition: living.cpp:1132
SK_KARATE
@ SK_KARATE
Karate.
Definition: skills.h:38
SCRIPT_FIX_ALL
#define SCRIPT_FIX_ALL
Definition: global.h:381
player::hidden
uint32_t hidden
If True, player (DM) is hidden from view.
Definition: player.h:149
rndm
int rndm(int min, int max)
Returns a number between min and max.
Definition: utils.cpp:162
skills.h
object::hide
uint8_t hide
The object is hidden, not invisible.
Definition: object.h:397
pray
int pray(object *pl, object *skill)
Praying skill handling.
Definition: skills.cpp:1388
apply_manual
int apply_manual(object *op, object *tmp, int aflag)
Main apply handler.
Definition: apply.cpp:259
FOR_OB_AND_ABOVE_FINISH
#define FOR_OB_AND_ABOVE_FINISH()
Finishes FOR_OB_AND_ABOVE_PREPARE().
Definition: define.h:727
FLAG_CURSED
#define FLAG_CURSED
The object is cursed.
Definition: define.h:303
object::level
int16_t level
Level of creature or object.
Definition: object.h:361
events_execute_object_event
int events_execute_object_event(object *op, int eventcode, object *activator, object *third, const char *message, int fix)
Execute an event on the specified object.
Definition: events.cpp:309
FLAG_NO_SKILL_IDENT
#define FLAG_NO_SKILL_IDENT
If set, item cannot be identified w/ a skill.
Definition: define.h:322
buf
StringBuffer * buf
Definition: readable.cpp:1564
object_insert_in_ob
object * object_insert_in_ob(object *op, object *where)
This function inserts the object op in the linked list inside the object environment.
Definition: object.cpp:2842
object::above
object * above
Pointer to the object stacked above this one.
Definition: object.h:296
HUGE_BUF
#define HUGE_BUF
Used for messages - some can be quite long.
Definition: define.h:37
MSG_TYPE_VICTIM
#define MSG_TYPE_VICTIM
Something bad is happening to the player.
Definition: newclient.h:419
MAX
#define MAX(x, y)
Definition: compat.h:24
find_traps
int find_traps(object *pl, object *skill)
Checks for traps on the spaces around the player or in certain objects.
Definition: skills.cpp:1249
cast_dust
void cast_dust(object *op, object *throw_ob, int dir)
Handles op throwing objects of type 'DUST'.
Definition: player.cpp:3957
name
Plugin animator file specs[Config] name
Definition: animfiles.txt:4
FOR_BELOW_FINISH
#define FOR_BELOW_FINISH()
Finishes FOR_BELOW_PREPARE().
Definition: define.h:695
FLAG_KNOWN_CURSED
#define FLAG_KNOWN_CURSED
The object is known to be cursed.
Definition: define.h:307
object::path_denied
uint32_t path_denied
Paths the object is denied access to.
Definition: object.h:355
FOR_OB_AND_ABOVE_PREPARE
#define FOR_OB_AND_ABOVE_PREPARE(op_)
Constructs a loop iterating over an object and all objects above it in the same pile.
Definition: define.h:723
object::carrying
int32_t carrying
How much weight this object contains.
Definition: object.h:377
typedata
Link an object type with skill needed to identify, and general name.
Definition: define.h:89
remove_door
void remove_door(object *op)
Remove non locked doors.
Definition: time.cpp:38
object::path_repelled
uint32_t path_repelled
Paths the object is repelled from.
Definition: object.h:354
object::y
int16_t y
Position in the map for this object.
Definition: object.h:335
m
static event_registration m
Definition: citylife.cpp:424
object_update
void object_update(object *op, int action)
object_update() updates the array which represents the map.
Definition: object.cpp:1419
object::contr
struct player * contr
Pointer to the player which control this object.
Definition: object.h:284
NROF
static uint32_t NROF(const object *const ob)
Returns ob->nrof, unless it is 0, in which case return 1.
Definition: object.h:625
PREFER_HIGH
#define PREFER_HIGH
Definition: define.h:547
HELMET
@ HELMET
Definition: object.h:141
object_decrease_nrof_by_one
#define object_decrease_nrof_by_one(xyz)
Definition: compat.h:32
object::last_heal
int32_t last_heal
Last healed.
Definition: object.h:367
object::subtype
uint8_t subtype
Subtype of object.
Definition: object.h:349
FLAG_KNOWN_MAGICAL
#define FLAG_KNOWN_MAGICAL
The object is known to be magical.
Definition: define.h:306
freearr_y
short freearr_y[SIZEOFFREE]
Y offset when searching around a spot.
Definition: object.cpp:305
make_throw_ob
static object * make_throw_ob(object *orig)
We construct the 'carrier' object in which we will insert the object that is being thrown.
Definition: skills.cpp:1952
get_typedata
const typedata * get_typedata(int itemtype)
Definition: item.cpp:328
FLAG_UNPAID
#define FLAG_UNPAID
Object hasn't been paid for yet.
Definition: define.h:223
monster_find_throw_ob
object * monster_find_throw_ob(object *op)
Find an item for the monster to throw.
Definition: monster.cpp:2651
pick_lock
int pick_lock(object *pl, int dir, object *skill)
Lock pick handling.
Definition: skills.cpp:400
query_name
void query_name(const object *op, char *buf, size_t size)
Describes an item.
Definition: item.cpp:593
POT_DUST
#define POT_DUST
Definition: spells.h:133
FREE_OBJ_NO_DESTROY_CALLBACK
#define FREE_OBJ_NO_DESTROY_CALLBACK
Do not run the destroy callback.
Definition: object.h:545
POTION
@ POTION
Definition: object.h:116
can_see_monsterP
int can_see_monsterP(mapstruct *m, int x, int y, int dir)
Recursive routine to see if we can find a path to a certain point.
Definition: object.cpp:3807
player::ranges
object * ranges[range_size]
Object for each range.
Definition: player.h:118
SK_LITERACY
@ SK_LITERACY
Literacy.
Definition: skills.h:27
calc_skill_exp
int64_t calc_skill_exp(const object *who, const object *op, const object *skill)
Calculates amount of experience can be gained for successful use of a skill.
Definition: skill_util.cpp:699
archetype::clone
object clone
An object from which to do object_copy()
Definition: object.h:487
SK_DET_CURSE
@ SK_DET_CURSE
Detect curse.
Definition: skills.h:33
FLAG_NO_STEAL
#define FLAG_NO_STEAL
Item can't be stolen.
Definition: define.h:329
add_string
sstring add_string(const char *str)
Share a string.
Definition: shstr.cpp:137
FLAG_MONSTER
#define FLAG_MONSTER
Will attack players.
Definition: define.h:232
FOR_OB_AND_BELOW_FINISH
#define FOR_OB_AND_BELOW_FINISH()
Finishes FOR_OB_AND_BELOW_PREPARE().
Definition: define.h:738
HEAD
#define HEAD(op)
Returns the head part of an object.
Definition: object.h:607
range_magic
@ range_magic
Spells.
Definition: player.h:32
CONTAINER
@ CONTAINER
Definition: object.h:236
FLAG_UNAGGRESSIVE
#define FLAG_UNAGGRESSIVE
Monster doesn't attack players.
Definition: define.h:259
object::move_type
MoveType move_type
Type of movement this object uses.
Definition: object.h:436
query_short_name
void query_short_name(const object *op, char *buf, size_t size)
query_short_name(object) is similar to query_name(), but doesn't contain any information about object...
Definition: item.cpp:518
LOCKED_DOOR
@ LOCKED_DOOR
Definition: object.h:128
SPELL_GRACE
#define SPELL_GRACE
Definition: spells.h:59
MSG_TYPE_ITEM
#define MSG_TYPE_ITEM
Item related information.
Definition: newclient.h:416
find_string
sstring find_string(const char *str)
Searches a string in the shared strings.
Definition: shstr.cpp:250
object::value
int32_t value
How much money it is worth (or contains)
Definition: object.h:360
is_identified
int is_identified(const object *op)
Return true if the item is identified, either because it is of a type that doesn't ever need identifi...
Definition: item.cpp:1355
ob_describe
char * ob_describe(const object *op, const object *observer, int use_media_tags, char *buf, size_t size)
Returns the description (short item name) of an object, as seen by the given observer.
Definition: ob_methods.cpp:92
isqrt
int isqrt(int n)
Compute the square root.
Definition: utils.cpp:567
object_update_speed
void object_update_speed(object *op)
Updates the speed of an object.
Definition: object.cpp:1334
FREE_AND_COPY
#define FREE_AND_COPY(sv, nv)
Release the shared string if not NULL, and make it a reference to nv.
Definition: global.h:210
player::tmp_invis
uint32_t tmp_invis
Will invis go away when we attack?
Definition: player.h:142
object::type
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:348
living::dam
int16_t dam
How much damage this object does when hitting.
Definition: living.h:46
object::magic
int8_t magic
Any magical bonuses to this item.
Definition: object.h:358
hide
int hide(object *op, object *skill)
Main hide handling.
Definition: skills.cpp:505
adj_stealchance
static int adj_stealchance(object *op, object *victim, int roll)
Computes stealing chance.
Definition: skills.cpp:54
attempt_pick_lock
static int attempt_pick_lock(object *door, object *pl, object *skill)
Attempt to pick a lock.
Definition: skills.cpp:364
FLAG_CHANGING
#define FLAG_CHANGING
Changes to other_arch when anim is done.
Definition: define.h:250
UPD_FLAGS
#define UPD_FLAGS
Definition: newclient.h:319
M_GLASS
#define M_GLASS
Glass.
Definition: material.h:16
trap_disarm
int trap_disarm(object *disarmer, object *trap, int risk, object *skill)
Try to disarm a trap/rune.
Definition: rune.cpp:442
book.h
object_free
void object_free(object *ob, int flags)
Frees everything allocated by an object, removes it from the list of used objects,...
Definition: object.cpp:1577
GET_MAP_MOVE_BLOCK
#define GET_MAP_MOVE_BLOCK(M, X, Y)
Gets the blocking state of a square.
Definition: map.h:197
FOR_INV_FINISH
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:661
object::move_on
MoveType move_on
Move types affected moving on to this space.
Definition: object.h:439
living::food
int32_t food
How much food in stomach.
Definition: living.h:48
MSG_TYPE_SKILL_MISSING
#define MSG_TYPE_SKILL_MISSING
Don't have the skill.
Definition: newclient.h:591
do_skill_cb_data::skill
object * skill
Definition: skill_util.cpp:409
tag_t
uint32_t tag_t
Object tag, unique during the whole game.
Definition: object.h:14
archetype
The archetype structure is a set of rules on how to generate and manipulate objects which point to ar...
Definition: object.h:483
skill_throw
int skill_throw(object *op, object *part, int dir, object *skill)
Throwing skill handling.
Definition: skills.cpp:2283
P_OUT_OF_MAP
#define P_OUT_OF_MAP
This space is outside the map.
Definition: map.h:254
sproto.h
living::sp
int16_t sp
Spell points.
Definition: living.h:42
FOR_OB_AND_BELOW_PREPARE
#define FOR_OB_AND_BELOW_PREPARE(op_)
Constructs a loop iterating over an object and all objects below it in the same pile.
Definition: define.h:734
GET_ANIM_ID
#define GET_ANIM_ID(ob)
Definition: global.h:171
living::Int
int8_t Int
Definition: living.h:36
BOOK
@ BOOK
Definition: object.h:119
SP_level_spellpoint_cost
int16_t SP_level_spellpoint_cost(object *caster, object *spell, int flags)
Scales the spellpoint cost of a spell by it's increased effectiveness.
Definition: spell_util.cpp:236
random_roll
int random_roll(int min, int max, const object *op, int goodbad)
Roll a random number between min and max.
Definition: utils.cpp:42
object::facing
int8_t facing
Object is oriented/facing that way.
Definition: object.h:345
get_dam_bonus
int get_dam_bonus(int stat)
Definition: living.cpp:2389
skill_ident
int skill_ident(object *pl, object *skill)
Main identification skill handling.
Definition: skills.cpp:936
NDI_BLACK
#define NDI_BLACK
Definition: newclient.h:246
object_insert_in_map_at
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Same as object_insert_in_map() except it handle separate coordinates and do a clean job preparing mul...
Definition: object.cpp:2085
FLAG_INV_LOCKED
#define FLAG_INV_LOCKED
Item will not be dropped from inventory.
Definition: define.h:316
find_skill_by_name
object * find_skill_by_name(object *who, const char *name)
This returns the skill pointer of the given name (the one that accumulates exp, has the level,...
Definition: skill_util.cpp:209
SIZEOFFREE
#define SIZEOFFREE
Definition: define.h:155
MSG_TYPE_VICTIM_STEAL
#define MSG_TYPE_VICTIM_STEAL
Someone tried to steal from the player.
Definition: newclient.h:656
get_dex_bonus
int get_dex_bonus(int stat)
Definition: living.cpp:2365
MAX_BUF
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
object_new
object * object_new(void)
Grabs an object from the list of unused objects, makes sure it is initialised, and returns it.
Definition: object.cpp:1258
get_weight_limit
uint32_t get_weight_limit(int stat)
Definition: living.cpp:2373
SK_FLAME_TOUCH
@ SK_FLAME_TOUCH
Flame-touch.
Definition: skills.h:37
object::weight
int32_t weight
Attributes of the object.
Definition: object.h:375
free_string
void free_string(sstring str)
This will reduce the refcount, and if it has reached 0, str will be freed.
Definition: shstr.cpp:294
living::wc
int8_t wc
Weapon Class, lower WC increases probability of hitting.
Definition: living.h:37
trap_show
int trap_show(object *trap, object *where)
Handles showing a trap/rune detonation.
Definition: rune.cpp:412
living::maxgrace
int16_t maxgrace
Maximum grace.
Definition: living.h:45
FLAG_DAMNED
#define FLAG_DAMNED
The object is very cursed.
Definition: define.h:304
FOR_MAP_PREPARE
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Constructs a loop iterating over all objects of a map tile.
Definition: define.h:707
OUT_OF_REAL_MAP
#define OUT_OF_REAL_MAP(M, X, Y)
Checks if a square is out of the map.
Definition: map.h:222
living::Wis
int8_t Wis
Definition: living.h:36
stop_jump
static void stop_jump(object *pl)
End of jump.
Definition: skills.cpp:545
do_skill_cb_data::part
object * part
Definition: skill_util.cpp:408
identify_object_with_skill
int identify_object_with_skill(object *tmp, object *pl, object *skill, int print_on_success)
Helper function for do_skill_ident, so that we can loop over inventory AND objects on the ground conv...
Definition: skills.cpp:819
Settings::allow_denied_spells_writing
int allow_denied_spells_writing
If set, players can write spells they can't cast.
Definition: global.h:317
P_IS_ALIVE
#define P_IS_ALIVE
Something alive is on this space.
Definition: map.h:242
MSG_TYPE_SKILL_ERROR
#define MSG_TYPE_SKILL_ERROR
Doing something wrong.
Definition: newclient.h:592
hideability
int hideability(object *ob)
Look at the surrounding terrain to determine the hideability of this object.
Definition: player.cpp:4022
FLAG_SLEEP
#define FLAG_SLEEP
NPC is sleeping.
Definition: define.h:294
NDI_UNIQUE
#define NDI_UNIQUE
Print immediately, don't buffer.
Definition: newclient.h:266
spells.h
FLAG_READY_WEAPON
#define FLAG_READY_WEAPON
(Monster or Player) has a weapon readied
Definition: define.h:321
object::name
sstring name
The name of the object, obviously...
Definition: object.h:319
ob_process
method_ret ob_process(object *op)
Processes an object, giving it the opportunity to move or react.
Definition: ob_methods.cpp:67
MSG_TYPE_SKILL_FAILURE
#define MSG_TYPE_SKILL_FAILURE
Failure in using skill.
Definition: newclient.h:594
attempt_steal
static int attempt_steal(object *op, object *who, object *skill)
Steal objects.
Definition: skills.cpp:122
steal
int steal(object *op, int dir, object *skill)
Main stealing function.
Definition: skills.cpp:288
OBJECT_TYPE_MAX
@ OBJECT_TYPE_MAX
Try to find a fire/heat source to light this when applied.
Definition: object.h:256
get_thaco_bonus
int get_thaco_bonus(int stat)
Definition: living.cpp:2369
M_CLOTH
#define M_CLOTH
Cloth.
Definition: material.h:21
SK_PUNCHING
@ SK_PUNCHING
Punching.
Definition: skills.h:36
object_can_pick
int object_can_pick(const object *who, const object *item)
Finds out if an object can be picked up.
Definition: object.cpp:3852
add_friendly_object
void add_friendly_object(object *op)
Add a new friendly object to the list of friendly objects.
Definition: friend.cpp:32
FLAG_REFLECTING
#define FLAG_REFLECTING
Object reflects from walls (lightning)
Definition: define.h:249
SK_WRAITH_FEED
@ SK_WRAITH_FEED
Wraith feed.
Definition: skills.h:57
get_map_flags
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, int16_t x, int16_t y, int16_t *nx, int16_t *ny)
This rolls up wall, blocks_magic, blocks_view, etc, all into one function that just returns a P_.
Definition: map.cpp:280
MSG_TYPE_ITEM_REMOVE
#define MSG_TYPE_ITEM_REMOVE
Item removed from inv.
Definition: newclient.h:646
living::maxsp
int16_t maxsp
Max spell points.
Definition: living.h:43
is_magical
int is_magical(const object *op)
Checks whether object is magical.
Definition: item.cpp:1234
mapstruct
This is a game-map.
Definition: map.h:320
object::env
object * env
Pointer to the object which is the environment.
Definition: object.h:301
write_note
static int write_note(object *pl, object *item, const char *msg)
Called by write_on_item() to inscribe a message in an ordinary book.
Definition: skills.cpp:1495
object::last_sp
int32_t last_sp
As last_heal, but for spell points.
Definition: object.h:368
FLAG_IS_THROWN
#define FLAG_IS_THROWN
Object is designed to be thrown.
Definition: define.h:236
sstring
const typedef char * sstring
Definition: sstring.h:2
living::Cha
int8_t Cha
Definition: living.h:36
FLAG_UNDEAD
#define FLAG_UNDEAD
Monster is undead.
Definition: define.h:257
monster_npc_call_help
void monster_npc_call_help(object *op)
A monster calls for help against its enemy.
Definition: monster.cpp:2014
object::skill
sstring skill
Name of the skill this object uses/grants.
Definition: object.h:329
object_split
object * object_split(object *orig_ob, uint32_t nr, char *err, size_t size)
object_split(ob,nr) splits up ob into two parts.
Definition: object.cpp:2622
check_pick
int check_pick(object *op)
Sees if there is stuff to be picked up/picks up stuff, for players only.
Definition: player.cpp:1732
FLAG_APPLIED
#define FLAG_APPLIED
Object is ready for use by living.
Definition: define.h:222
get_speed_bonus
float get_speed_bonus(int stat)
Definition: living.cpp:2393
object_set_msg
void object_set_msg(object *op, const char *msg)
Set the message field of an object.
Definition: object.cpp:4796
esrv_update_item
void esrv_update_item(int flags, object *pl, object *op)
Updates object *op for player *pl.
Definition: main.cpp:367
EVENT_THROW
#define EVENT_THROW
Object is thrown.
Definition: events.h:41
Settings::max_stat
uint8_t max_stat
Maximum stat value - 255 should be sufficient.
Definition: global.h:326
object::msg
sstring msg
If this is a book/sign/magic mouth/etc.
Definition: object.h:330
rv_vector
This is used by get_rangevector to determine where the other creature is.
Definition: map.h:375
BOOK_BUF
#define BOOK_BUF
Maximum message buf size for books.
Definition: book.h:16
AP_NO_MERGE
#define AP_NO_MERGE
Don't try to merge object after (un)applying it.
Definition: define.h:565
CLEAR_FLAG
#define CLEAR_FLAG(xyz, p)
Definition: define.h:370
apply_special
int apply_special(object *who, object *op, int aflags)
Apply an object.
Definition: apply.cpp:818
FLAG_STARTEQUIP
#define FLAG_STARTEQUIP
Object was given to player at start.
Definition: define.h:255
meditate
int meditate(object *pl, object *skill)
Meditation skill handling.
Definition: skills.cpp:1437
NUM_ANIMATIONS
#define NUM_ANIMATIONS(ob)
Definition: global.h:177
die_roll
int die_roll(int num, int size, const object *op, int goodbad)
Roll a number of dice (2d3, 4d6).
Definition: utils.cpp:122
stats
Player Stats effect how well a character can survie and interact inside the crossfire world This section discusses the various stats
Definition: stats.txt:2
UP_OBJ_FACE
#define UP_OBJ_FACE
Only thing that changed was the face.
Definition: object.h:533
write_on_item
int write_on_item(object *pl, const char *params, object *skill)
Implement the 'inscription' skill, which checks for the required skills and marked items before runni...
Definition: skills.cpp:1768
detect_curse_on_item
int detect_curse_on_item(object *pl, object *tmp, object *skill)
Runs a 'detect curse' check on a given item.
Definition: skills.cpp:712
player::party
partylist * party
Party this player is part of.
Definition: player.h:205
PETMOVE
#define PETMOVE
If the upper four bits of attack_movement are set to this number, the monster follows a player until ...
Definition: define.h:485
typedata::identifyskill2
int identifyskill2
Second skill used to identify this object class.
Definition: define.h:94
FLAG_CONFUSED
#define FLAG_CONFUSED
Will also be unable to cast spells.
Definition: define.h:298
object::body_info
int8_t body_info[NUM_BODY_LOCATIONS]
Body info as loaded from the file.
Definition: object.h:382
do_skill_cb_data::op
object * op
Definition: skill_util.cpp:407
do_skill_cb_data::dir
int dir
Definition: skill_util.cpp:410
draw_ext_info
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Sends message to player(s).
Definition: main.cpp:316
book_overflow
int book_overflow(const char *buf1, const char *buf2, size_t booksize)
Checks if buf1 and buf2 can be combined.
Definition: readable.cpp:719
get_archetype_by_type_subtype
archetype * get_archetype_by_type_subtype(int type, int subtype)
Retrieves an archetype by type and subtype.
Definition: arch.cpp:97
object_remove
void object_remove(object *op)
This function removes the object op from the linked list of objects which it is currently tied to.
Definition: object.cpp:1818
trap_see
int trap_see(object *op, object *trap)
Should op see trap?
Definition: rune.cpp:385
FLAG_SPLITTING
#define FLAG_SPLITTING
Object splits into stats.food other objs.
Definition: define.h:253
DOOR
@ DOOR
Definition: object.h:131
MOVE_FLY_LOW
#define MOVE_FLY_LOW
Low flying object.
Definition: define.h:384
OB_TYPE_MOVE_BLOCK
#define OB_TYPE_MOVE_BLOCK(ob1, type)
Basic macro to see if if ob1 can not move onto a space based on the 'type' move_block parameter Add c...
Definition: define.h:418
write_scroll
static int write_scroll(object *pl, object *scroll, object *skill)
Called by write_on_item() to inscribe spell scrolls that the player can cast.
Definition: skills.cpp:1584
attempt_jump
static int attempt_jump(object *pl, int dir, int spaces, object *skill)
Someone is trying to jump.
Definition: skills.cpp:566
do_skill_detect_curse
static int do_skill_detect_curse(object *pl, object *skill)
Check for cursed object with the 'detect curse' skill.
Definition: skills.cpp:732
do_skill_ident
static int do_skill_ident(object *pl, int obj_class, object *skill)
Workhorse for skill_ident() -b.t.
Definition: skills.cpp:883
SCROLL
@ SCROLL
Definition: object.h:226
object::nrof
uint32_t nrof
Number of objects.
Definition: object.h:342
FLAG_WAS_WIZ
#define FLAG_WAS_WIZ
Player was once a wiz.
Definition: define.h:221
player::socket
socket_struct * socket
Socket information for this player.
Definition: player.h:109
object::body_used
int8_t body_used[NUM_BODY_LOCATIONS]
Calculated value based on items equipped.
Definition: object.h:383
chance
bool chance(int a, int b)
Return true with a probability of a/b.
Definition: treasure.cpp:893
Settings::no_player_stealing
uint8_t no_player_stealing
If 1, can not steal from other players.
Definition: global.h:312
living::grace
int16_t grace
Grace.
Definition: living.h:44
object::stats
living stats
Str, Con, Dex, etc.
Definition: object.h:378
MSG_TYPE_SKILL_SUCCESS
#define MSG_TYPE_SKILL_SUCCESS
Successfully used skill.
Definition: newclient.h:593
FLAG_IDENTIFIED
#define FLAG_IDENTIFIED
Item is identifiable (e.g.
Definition: define.h:248
stand_near_hostile
int stand_near_hostile(object *who)
Determine if who is standing near a hostile creature.
Definition: player.cpp:4104
freearr_x
short freearr_x[SIZEOFFREE]
X offset when searching around a spot.
Definition: object.cpp:299
BOOTS
@ BOOTS
Definition: object.h:217
SPELL
@ SPELL
Definition: object.h:219
SHIELD
@ SHIELD
Definition: object.h:140
jump
int jump(object *pl, int dir, object *skill)
Jump skill handling.
Definition: skills.cpp:675
living.h
THROWN_OBJ
@ THROWN_OBJ
Definition: object.h:151
object::material
uint16_t material
What materials this object consist of.
Definition: object.h:357
MSG_TYPE_ITEM_INFO
#define MSG_TYPE_ITEM_INFO
Information related to items.
Definition: newclient.h:649
find_marked_object
object * find_marked_object(object *op)
Return the object the player has marked with the 'mark' command below.
Definition: c_object.cpp:1472
object::move_block
MoveType move_block
What movement types this blocks.
Definition: object.h:437
FOR_INV_PREPARE
#define FOR_INV_PREPARE(op_, it_)
Constructs a loop iterating over the inventory of an object.
Definition: define.h:654
living::hp
int16_t hp
Hit Points.
Definition: living.h:40
HOLY_ALTAR
@ HOLY_ALTAR
Definition: object.h:166
SCRIPT_FIX_ACTIVATOR
#define SCRIPT_FIX_ACTIVATOR
Definition: global.h:380
object.h
llevDebug
@ llevDebug
Only for debugging purposes.
Definition: logger.h:15
remove_trap
int remove_trap(object *op, object *skill)
This skill will disarm any previously discovered trap.
Definition: skills.cpp:1320
INS_BELOW_ORIGINATOR
#define INS_BELOW_ORIGINATOR
Insert new object immediately below originator.
Definition: object.h:584
living::Str
int8_t Str
Definition: living.h:36
skill_attack
void skill_attack(object *tmp, object *pl, int dir, const char *string, object *skill)
Core routine for use when we attack using a skills system.
Definition: skill_util.cpp:1302
SPELL_MANA
#define SPELL_MANA
Definition: spells.h:58
FREE_PLAYER_LOAD_PERCENT
#define FREE_PLAYER_LOAD_PERCENT
Definition: config.h:98
pray_at_altar
void pray_at_altar(object *pl, object *altar, object *skill)
Player prays at altar.
Definition: gods.cpp:258
attempt_hide
static int attempt_hide(object *op, object *skill)
Someone is trying to hide.
Definition: skills.cpp:474
identify
object * identify(object *op)
Identifies an item.
Definition: item.cpp:1443