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 
1393 int pray(object *pl, object *skill) {
1394  char buf[MAX_BUF];
1395 
1396  if (pl->type != PLAYER)
1397  return 0;
1398 
1399  snprintf(buf, sizeof(buf), "You pray.");
1400 
1401  /* Check all objects - we could stop at floor objects,
1402  * but if someone buries an altar, I don't see a problem with
1403  * going through all the objects, and it shouldn't be much slower
1404  * than extra checks on object attributes.
1405  */
1406  FOR_BELOW_PREPARE(pl, tmp)
1407  /* Only if the altar actually belongs to someone do you get special benefits */
1408  if (tmp->type == HOLY_ALTAR && tmp->other_arch) {
1409  snprintf(buf, sizeof(buf), "You pray over the %s.", tmp->name);
1410  pray_at_altar(pl, tmp, skill);
1411  break; /* Only pray at one altar */
1412  }
1413  FOR_BELOW_FINISH();
1414 
1416  buf);
1417 
1418  if (pl->stats.grace < pl->stats.maxgrace) {
1419  pl->stats.grace++;
1420  pl->last_grace = -1;
1421  }
1422  return 0;
1423 }
1424 
1441 void meditate(object *pl, object *skill) {
1442  if (pl->type != PLAYER)
1443  return; /* players only */
1444 
1445  /* check if pl has removed encumbering armour and weapons */
1446  if (QUERY_FLAG(pl, FLAG_READY_WEAPON) && skill->level < 6) {
1448  "You can't concentrate while wielding a weapon!");
1449  return;
1450  }
1451 
1452  FOR_INV_PREPARE(pl, tmp)
1453  if (((tmp->type == ARMOUR && skill->level < 12)
1454  || (tmp->type == HELMET && skill->level < 10)
1455  || (tmp->type == SHIELD && skill->level < 6)
1456  || (tmp->type == BOOTS && skill->level < 4)
1457  || (tmp->type == GLOVES && skill->level < 2))
1458  && QUERY_FLAG(tmp, FLAG_APPLIED)) {
1460  "You can't concentrate while wearing so much armour!");
1461  return;
1462  }
1463  FOR_INV_FINISH();
1464 
1465  /* ok let's meditate! Spell points are regained first, then once
1466  * they are maxed we get back hp. Actual incrementing of values
1467  * is handled by the do_some_living() (in player.c). This way magical
1468  * bonuses for healing/sp regeneration are included properly
1469  * No matter what, we will eat up some playing time trying to
1470  * meditate. (see 'factor' variable for what sets the amount of time)
1471  */
1472 
1474  "You meditate.");
1475 
1476  if (pl->stats.sp < pl->stats.maxsp) {
1477  pl->stats.sp++;
1478  pl->last_sp = -1;
1479  } else if (pl->stats.hp < pl->stats.maxhp) {
1480  pl->stats.hp++;
1481  pl->last_heal = -1;
1482  }
1483 }
1484 
1498 static int write_note(object *pl, object *item, const char *msg) {
1499  char buf[BOOK_BUF];
1500  object *newBook = NULL;
1501 
1502  // The item should exist and be a book, but check it just in case.
1503  if (!item || item->type != BOOK) {
1505  "That was interesting...");
1506  // TODO: Print a scary log message.
1507  return 0;
1508  }
1509 
1510  // The message should never be NULL, but check it just in case.
1511  if (!msg) {
1513  "Hmm... what was I going to write?");
1514  // TODO: Print a scary log message.
1515  return 0;
1516  }
1517 
1518  // Don't let the player write a reserved keyword.
1519  if (strcasestr_local(msg, "endmsg")) {
1521  "Trying to cheat now are we?");
1522  return 0;
1523  }
1524 
1525  if (events_execute_object_event(item, EVENT_TRIGGER, pl, NULL, msg, SCRIPT_FIX_ALL) != 0)
1526  return strlen(msg);
1527 
1528  buf[0] = 0;
1529 
1530  // Write the message in the book if it doesn't overflow the buffer.
1531  if (!book_overflow(item->msg, msg, BOOK_BUF)) {
1532  // TODO: Garble some characters depending on intelligence/skill.
1533 
1534  // If there was already text, append the new message on the end.
1535  if (item->msg) {
1536  snprintf(buf, sizeof(buf), "%s%s\n", item->msg, msg);
1537  } else {
1538  snprintf(buf, sizeof(buf), "%s\n", msg);
1539  }
1540 
1541  // If there were multiple items in a stack, unstack one and write.
1542  if (item->nrof > 1) {
1543  newBook = object_new();
1544  object_copy(item, newBook);
1546  newBook->nrof = 1;
1547  object_set_msg(newBook, buf);
1548  newBook = object_insert_in_ob(newBook, pl);
1549  } else {
1550  object_set_msg(item, buf);
1551 
1552  // This shouldn't be necessary; the object hasn't changed visibly.
1553  //esrv_send_item(pl, item);
1554  }
1555 
1556  // Tell the player that he/she wrote in the object.
1557  query_short_name(item, buf, BOOK_BUF);
1560  "You write in the %s.", buf);
1561 
1562  // Give the player experience for writing.
1563  return strlen(msg);
1564  } else {
1565  query_short_name(item, buf, BOOK_BUF);
1568  "Your message won't fit in the %s!", buf);
1569  return 0;
1570  }
1571 }
1572 
1587 static int write_scroll(object *pl, object *scroll, object *skill) {
1588  int success = 0, confused = 0, grace_cost = 0;
1589  object *newscroll, *chosen_spell, *tmp;
1590 
1591  // The item should exist and be a scroll, but check it just in case.
1592  if (!scroll || scroll->type != SCROLL) {
1594  "A spell must be written on a magic scroll!");
1595  // TODO: Print a scary log message.
1596  return 0;
1597  }
1598 
1599  // The player must have a spell readied to inscribe.
1600  chosen_spell = pl->contr->ranges[range_magic];
1601  if (!chosen_spell) {
1603  "You should ready the spell you wish to inscribe.");
1604  return 0;
1605  }
1606 
1607  // Make sure the player has enough SP or grace to write the spell.
1608  grace_cost = SP_level_spellpoint_cost(pl, chosen_spell, SPELL_GRACE);
1609  if (grace_cost > 0 && grace_cost > pl->stats.grace) {
1612  "You don't have enough grace to write a scroll of %s.",
1613  chosen_spell->name);
1614  return 0;
1615  }
1616 
1617  if (SP_level_spellpoint_cost(pl, chosen_spell, SPELL_MANA) > pl->stats.sp) {
1620  "You don't have enough mana to write a scroll of %s.",
1621  chosen_spell->name);
1622  return 0;
1623  }
1624 
1625  // Prevent players from writing spells that they are denied.
1626  if (chosen_spell->path_attuned & pl->path_denied
1628  char name[MAX_BUF];
1629 
1630  query_name(chosen_spell, name, MAX_BUF);
1633  "Just the idea of writing a scroll of %s makes you sick!",
1634  name);
1635  return 0;
1636  }
1637 
1638  // If the scroll already had a spell written on it, the player could
1639  // accidentally read it while trying to write a new one. Give the player
1640  // a 50% chance to overwrite a spell at their own level.
1641  if ((scroll->stats.sp || scroll->inv) &&
1642  random_roll(0, scroll->level*2, pl, PREFER_LOW) > skill->level) {
1644  "Oops! You accidently read it while trying to write on it.");
1645  apply_manual(pl, scroll, 0);
1646  return 0;
1647  }
1648 
1649  if (events_execute_object_event(scroll, EVENT_TRIGGER, pl, chosen_spell, NULL, 0) != 0) {
1650  return 0;
1651  }
1652 
1653  // Find out if the player is confused or not.
1654  if (QUERY_FLAG(pl, FLAG_CONFUSED)) {
1655  confused = 1;
1656  }
1657 
1658  // Mana or grace is lost no matter if the inscription is successful.
1659  pl->stats.grace -= SP_level_spellpoint_cost(pl, chosen_spell, SPELL_GRACE);
1660  pl->stats.sp -= SP_level_spellpoint_cost(pl, chosen_spell, SPELL_MANA);
1661 
1662  if (random_roll(0, chosen_spell->level * 4 - 1, pl, PREFER_LOW) <
1663  skill->level) {
1664  // If there were multiple items in a stack, unstack one.
1665  if (scroll->nrof > 1) {
1666  newscroll = object_new();
1667  object_copy(scroll, newscroll);
1669  newscroll->nrof = 1;
1670  } else {
1671  newscroll = scroll;
1672  }
1673 
1674  // Write spell if not confused; otherwise write random spell.
1675  newscroll->level = MAX(skill->level, chosen_spell->level);
1676 
1677  if (!confused) {
1678  draw_ext_info(
1680  "You succeed in writing a new scroll.");
1681  } else {
1682  chosen_spell = find_random_spell_in_ob(pl, NULL);
1683  if (!chosen_spell) {
1684  return 0;
1685  }
1686 
1687  draw_ext_info(
1689  "In your confused state, you write down some odd spell.");
1690  }
1691 
1692  if (newscroll->inv) {
1693  object *ninv;
1694  ninv = newscroll->inv;
1695  object_remove(ninv);
1697  }
1698 
1699  tmp = object_new();
1700  object_copy(chosen_spell, tmp);
1701  object_insert_in_ob(tmp, newscroll);
1702 
1703  // This is needed so casting from the scroll works correctly with
1704  // moving_ball types, which checks attunements.
1705  newscroll->path_attuned = tmp->path_repelled;
1706 
1707  // Same code as from treasure.c - so they can better merge.
1708  // If players want to sell them, so be it.
1709  newscroll->value = newscroll->arch->clone.value *
1710  newscroll->inv->value * (newscroll->level + 50 ) /
1711  (newscroll->inv->level + 50);
1712  newscroll->stats.exp = newscroll->value / 5;
1713 
1714  // Finish manipulating the scroll before inserting it.
1715  if (newscroll == scroll) {
1716  // Remove object to stack correctly with other items.
1717  object_remove(newscroll);
1718  }
1719 
1720  newscroll = object_insert_in_ob(newscroll, pl);
1721  success = calc_skill_exp(pl, newscroll, skill);
1722 
1723  if (!confused) {
1724  success *= 2;
1725  }
1726 
1727  success = success * skill->level;
1728  return success;
1729  }
1730 
1731  // Inscription wasn't successful; do something bad to the player.
1732  if (chosen_spell->level > skill->level || confused) {
1733  draw_ext_info(
1735  "Ouch! Your attempt to write a new scroll strains your mind!");
1736 
1737  // Either drain a stat or subtract experience.
1738  if (random_roll(0, 1, pl, PREFER_LOW) == 1) {
1739  drain_specific_stat(pl, 4);
1740  } else {
1741  confuse_living(pl, pl, 99);
1742  return -30 * chosen_spell->level;
1743  }
1744  } else if (random_roll(0, pl->stats.Int-1, pl, PREFER_HIGH) < 15) {
1745  draw_ext_info(
1747  "Your attempt to write a new scroll rattles your mind!");
1748  confuse_living(pl, pl, 99);
1749  } else {
1750  draw_ext_info(
1752  "You fail to write a new scroll.");
1753  }
1754 
1755  return 0;
1756 }
1757 
1771 int write_on_item(object *pl, const char *params, object *skill) {
1772  object *item;
1773  const char *string = params;
1774  int msgtype;
1775  archetype *skat;
1776 
1777  // Only players can use the inscription skill.
1778  if (pl->type != PLAYER) {
1779  return 0;
1780  }
1781 
1782  // No message was given, so both strings are set to empty.
1783  if (!params) {
1784  params = "";
1785  string = params;
1786  }
1787 
1788  // You must be able to read before you can write.
1790 
1791  if (!find_skill_by_name(pl, skat->clone.skill)) {
1793  "You must learn to read before you can write!");
1794  return 0;
1795  }
1796 
1797  // You must not be blind to write, unless you're a DM.
1798  if (QUERY_FLAG(pl, FLAG_BLIND) && !QUERY_FLAG(pl, FLAG_WIZ)) {
1800  "You are unable to write while blind.");
1801  return 0;
1802  }
1803 
1804  // If a message was given, write a book. Otherwise, write a scroll.
1805  if (string[0] != '\0') {
1806  msgtype = BOOK;
1807  } else {
1808  msgtype = SCROLL;
1809  }
1810 
1811  // Find and attempt to write on the player's marked item.
1812  item = find_marked_object(pl);
1813  if (item == NULL) {
1815  "You haven't marked any items to write on yet.");
1816  return 0;
1817  }
1818 
1819  // Don't let the player write on an unpaid item.
1820  if (QUERY_FLAG(item, FLAG_UNPAID)) {
1822  "You had better pay for that before you write on it!");
1823  return 0;
1824  }
1825 
1826  // Check if the marked item is the type of item we're writing.
1827  if (msgtype != item->type) {
1830  "You must mark a %s to write %s.",
1831  msgtype == BOOK ? "book" : "magic scroll",
1832  msgtype == BOOK ? "your message on" : "your spell down");
1833  return 0;
1834  }
1835 
1836  if (msgtype == BOOK) {
1837  return write_note(pl, item, string);
1838  } else if (msgtype == SCROLL) {
1839  return write_scroll(pl, item, skill);
1840  } else {
1841  // This case should never be reached.
1842  abort();
1843  }
1844 }
1845 
1858 static object *find_throw_ob(object *op, sstring race) {
1859  object *tmp;
1860  char name[MAX_BUF];
1861 
1862  if (!op) { /* safety */
1863  LOG(llevError, "find_throw_ob(): confused! have a NULL thrower!\n");
1864  return (object *)NULL;
1865  }
1866 
1867  /* prefer marked item */
1868  tmp = find_marked_object(op);
1869  if (tmp != NULL) {
1870  /* can't toss invisible or inv-locked items */
1871  if (tmp->invisible || QUERY_FLAG(tmp, FLAG_INV_LOCKED)) {
1872  tmp = NULL;
1873  }
1874  }
1875 
1876  /* look through the inventory if no marked found */
1877  if (tmp == NULL) {
1878  FOR_INV_PREPARE(op, tmp2) {
1879  /* can't toss invisible items */
1880  if (tmp2->invisible)
1881  continue;
1882 
1883  if (tmp2->type == CONTAINER && QUERY_FLAG(tmp2, FLAG_APPLIED) && tmp2->race == race) {
1884  tmp = find_throw_ob(tmp2, race);
1885  if (tmp != NULL) {
1886  break;
1887  }
1888  }
1889 
1890  /* if not a container, then don't look if locked */
1891  if (tmp2->type == CONTAINER || QUERY_FLAG(tmp2, FLAG_INV_LOCKED))
1892  continue;
1893 
1894  if (tmp2->race == race) {
1895  tmp = tmp2;
1896  break;
1897  }
1898 
1899  } FOR_INV_FINISH();
1900  }
1901 
1902  /* this should prevent us from throwing away
1903  * cursed items, worn armour, etc. Only weapons
1904  * can be thrown from 'hand'.
1905  */
1906  if (!tmp)
1907  return NULL;
1908 
1909  if (QUERY_FLAG(tmp, FLAG_APPLIED)) {
1910  if (tmp->type != WEAPON) {
1911  query_name(tmp, name, MAX_BUF);
1913  "You can't throw %s.",
1914  name);
1915  tmp = NULL;
1916  } else if (QUERY_FLAG(tmp, FLAG_CURSED) || QUERY_FLAG(tmp, FLAG_DAMNED)) {
1917  query_name(tmp, name, MAX_BUF);
1920  "The %s sticks to your hand!",
1921  name);
1922  tmp = NULL;
1923  } else {
1924  if (apply_special(op, tmp, AP_UNAPPLY|AP_NO_MERGE)) {
1925  LOG(llevError, "BUG: find_throw_ob(): couldn't unapply\n");
1926  tmp = NULL;
1927  }
1928  }
1929  } else if (QUERY_FLAG(tmp, FLAG_UNPAID)) {
1930  query_name(tmp, name, MAX_BUF);
1932  "You should pay for the %s first.",
1933  name);
1934  tmp = NULL;
1935  }
1936 
1937  if (tmp && QUERY_FLAG(tmp, FLAG_INV_LOCKED)) {
1938  LOG(llevError, "BUG: find_throw_ob(): object is locked\n");
1939  tmp = NULL;
1940  }
1941  return tmp;
1942 }
1943 
1955 static object *make_throw_ob(object *orig) {
1956  object *toss_item;
1957 
1958  if (!orig)
1959  return NULL;
1960 
1961  toss_item = object_new();
1962  if (QUERY_FLAG(orig, FLAG_APPLIED)) {
1963  LOG(llevError, "BUG: make_throw_ob(): ob is applied\n");
1964  /* insufficient workaround, but better than nothing */
1965  CLEAR_FLAG(orig, FLAG_APPLIED);
1966  }
1967  object_copy(orig, toss_item);
1968  toss_item->type = THROWN_OBJ;
1969  CLEAR_FLAG(toss_item, FLAG_CHANGING);
1970  toss_item->stats.dam = 0; /* default damage */
1971  object_insert_in_ob(orig, toss_item);
1972  return toss_item;
1973 }
1974 
1975 
1996 static int do_throw(object *op, object *part, object *toss_item, int dir, object *skill) {
1997  object *throw_ob = toss_item, *left = NULL;
1998  int eff_str = 0, str = op->stats.Str, dam = 0;
1999  int pause_f, weight_f = 0, mflags;
2000  float str_factor = 1.0, load_factor = 1.0, item_factor = 1.0;
2001  mapstruct *m;
2002  int16_t sx, sy;
2003  tag_t tag;
2004  char name[MAX_BUF];
2005 
2006  if (throw_ob == NULL) {
2007  if (op->type == PLAYER) {
2009  "You have nothing to throw.");
2010  }
2011  return 0;
2012  }
2013  if (QUERY_FLAG(throw_ob, FLAG_STARTEQUIP)) {
2014  if (op->type == PLAYER) {
2016  "The gods won't let you throw that.");
2017  }
2018  return 0;
2019  }
2020 
2021  tag = throw_ob->count;
2023  if (object_was_destroyed(throw_ob, tag)) {
2024  return 1;
2025  }
2026 
2027  /* Because throwing effectiveness must be reduced by the
2028  * encumbrance of the thrower and weight of the object. THus,
2029  * we use the concept of 'effective strength' as defined below.
2030  */
2031 
2032  /* if str exceeds settings.max_stat (30, eg giants), lets assign a str_factor > 1 */
2033  if (str > settings.max_stat) {
2034  str_factor = (float)str/(float)settings.max_stat;
2035  str = settings.max_stat;
2036  }
2037 
2038  /* the more we carry, the less we can throw. Limit only on players */
2039  if (op->type == PLAYER
2041  && (FREE_PLAYER_LOAD_PERCENT < 1.0)) {
2056  load_factor = 2.0f - (float)(op->carrying) / (float)(get_weight_limit(op->stats.Str)*FREE_PLAYER_LOAD_PERCENT);
2057  // Only clip to 1.0 if we get in here, since it is 1.0 if we do not get in here.
2058  load_factor = MIN(load_factor, 1.0f);
2059  }
2060 
2061  /* lighter items are thrown harder, farther, faster */
2062  if (throw_ob->weight > 0)
2063  item_factor = (float)(get_weight_limit(op->stats.Str)*FREE_PLAYER_LOAD_PERCENT)/(float)(3.0*throw_ob->weight);
2064  else { /* 0 or negative weight?!? Odd object, can't throw it */
2065  query_name(throw_ob, name, MAX_BUF);
2067  "You can't throw %s.",
2068  name);
2069  return 0;
2070  }
2071 
2072  eff_str = str*load_factor;
2073  eff_str = (float)eff_str*item_factor*str_factor;
2074 
2075  /* alas, arrays limit us to a value of settings.max_stat (30). Use str_factor to
2076  * account for super-strong throwers. */
2077  if (eff_str > settings.max_stat)
2078  eff_str = settings.max_stat;
2079 
2080 #ifdef DEBUG_THROW
2081  LOG(llevDebug, "%s carries %d, eff_str=%d\n", op->name, op->carrying, eff_str);
2082  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);
2083  LOG(llevDebug, " str_factor=%f\n", str_factor);
2084  LOG(llevDebug, " item %s weight= %d\n", throw_ob->name, throw_ob->weight);
2085 #endif
2086 
2087  /* 3 things here prevent a throw, you aimed at your feet, you
2088  * have no effective throwing strength, or you threw at something
2089  * that flying objects can't get through.
2090  */
2091  mflags = get_map_flags(part->map, &m, part->x+freearr_x[dir], part->y+freearr_y[dir], &sx, &sy);
2092 
2093  if (!dir
2094  || (eff_str <= 1)
2095  || (mflags&P_OUT_OF_MAP)
2096  || (GET_MAP_MOVE_BLOCK(m, sx, sy)&MOVE_FLY_LOW)) {
2097  /* bounces off 'wall', and drops to feet */
2098  object_remove(throw_ob);
2099  object_insert_in_map_at(throw_ob, part->map, op, 0, part->x, part->y);
2100  if (op->type == PLAYER) {
2101  if (eff_str <= 1) {
2102  query_name(throw_ob, name, MAX_BUF);
2104  "Your load is so heavy you drop %s to the ground.",
2105  name);
2106  } else if (!dir) {
2107  query_name(throw_ob, name, MAX_BUF);
2109  "You throw %s at the ground.",
2110  name);
2111  } else
2113  "Something is in the way.");
2114  }
2115  return 0;
2116  } /* if object can't be thrown */
2117 
2118  left = throw_ob; /* these are throwing objects left to the player */
2119 
2120  /* sometimes object_split() can't split an object (because op->nrof==0?)
2121  * and returns NULL. We must use 'left' then
2122  */
2123  throw_ob = object_split(throw_ob, 1, NULL, 0);
2124  if (throw_ob == NULL) {
2125  throw_ob = left;
2126  object_remove(left);
2127  }
2128 
2129  /* special case: throwing powdery substances like dust, dirt */
2130  if (throw_ob->type == POTION && throw_ob->subtype == POT_DUST) {
2131  cast_dust(op, throw_ob, dir);
2132  return 1;
2133  }
2134 
2135  /* Make a thrown object -- insert real object in a 'carrier' object.
2136  * If unsuccessfull at making the "thrown_obj", we just reinsert
2137  * the original object back into inventory and exit
2138  */
2139  toss_item = make_throw_ob(throw_ob);
2140  if (toss_item) {
2141  throw_ob = toss_item;
2142  if (throw_ob->skill)
2143  free_string(throw_ob->skill);
2144  throw_ob->skill = add_string(skill->skill);
2145  } else {
2146  object_insert_in_ob(throw_ob, op);
2147  return 0;
2148  }
2149 
2150  object_set_owner(throw_ob, op);
2151  /* At some point in the attack code, the actual real object (op->inv)
2152  * becomes the hitter. As such, we need to make sure that has a proper
2153  * owner value so exp goes to the right place.
2154  */
2155  object_set_owner(throw_ob->inv, op);
2156  throw_ob->direction = dir;
2157 
2158  /* If the thrown item has reflecting flag, it can ricochet off walls.
2159  * Make sure this gets copied to the thrown object.
2160  * The common projectile code should then handle the reflection from there.
2161  */
2162  if (QUERY_FLAG(throw_ob->inv, FLAG_REFLECTING))
2163  SET_FLAG(throw_ob, FLAG_REFLECTING);
2164 
2165  /* the damage bonus from the force of the throw */
2166  dam = str_factor*get_dam_bonus(eff_str);
2167 
2168  /* Now, lets adjust the properties of the thrown_ob. */
2169 
2170  /* how far to fly */
2171  throw_ob->last_sp = (eff_str*3)/5;
2172 
2173  /* speed */
2174  throw_ob->speed = (get_speed_bonus(eff_str)+1.0)/1.5;
2175  throw_ob->speed = MIN(1.0, throw_ob->speed); /* no faster than an arrow! */
2176 
2177  /* item damage. Eff_str and item weight influence damage done */
2178  weight_f = MIN(throw_ob->weight/2000, settings.max_stat);
2179  throw_ob->stats.dam += (dam/3)+get_dam_bonus(weight_f)+(throw_ob->weight/15000)-2;
2180 
2181  /* chance of breaking. Proportional to force used and weight of item */
2182  throw_ob->stats.food = (dam/2)+(throw_ob->weight/60000);
2183 
2184  /* replace 25 with a call to clone.arch wc? messes up w/ NPC */
2185  throw_ob->stats.wc = 25-get_dex_bonus(op->stats.Dex)-get_thaco_bonus(eff_str)-skill->level;
2186 
2187 
2188  /* the properties of objects which are meant to be thrown (ie dart,
2189  * throwing knife, etc) will differ from ordinary items. Lets tailor
2190  * this stuff in here.
2191  */
2192 
2193  if (QUERY_FLAG(throw_ob->inv, FLAG_IS_THROWN)) {
2194  throw_ob->last_sp += eff_str/3; /* fly a little further */
2195  throw_ob->stats.dam += throw_ob->inv->stats.dam+throw_ob->magic+2;
2196  throw_ob->stats.wc -= throw_ob->magic+throw_ob->inv->stats.wc;
2197  /* only throw objects get directional faces */
2198  if (GET_ANIM_ID(throw_ob) && NUM_ANIMATIONS(throw_ob))
2199  object_update_turn_face(throw_ob);
2200  } else {
2201  /* some materials will adjust properties.. */
2202  if (throw_ob->material&M_LEATHER) {
2203  throw_ob->stats.dam -= 1;
2204  throw_ob->stats.food -= 10;
2205  }
2206  if (throw_ob->material&M_GLASS)
2207  throw_ob->stats.food += 60;
2208 
2209  if (throw_ob->material&M_ORGANIC) {
2210  throw_ob->stats.dam -= 3;
2211  throw_ob->stats.food += 55;
2212  }
2213  if (throw_ob->material&M_PAPER || throw_ob->material&M_CLOTH) {
2214  throw_ob->stats.dam -= 5;
2215  throw_ob->speed *= 0.8;
2216  throw_ob->stats.wc += 3;
2217  throw_ob->stats.food -= 30;
2218  }
2219  /* light obj have more wind resistance, fly slower*/
2220  if (throw_ob->weight > 500)
2221  throw_ob->speed *= 0.8;
2222  if (throw_ob->weight > 50)
2223  throw_ob->speed *= 0.5;
2224  } /* else tailor thrown object */
2225 
2226  /* some limits, and safeties (needed?) */
2227  if (throw_ob->stats.dam < 0)
2228  throw_ob->stats.dam = 0;
2229  if (throw_ob->last_sp > eff_str)
2230  throw_ob->last_sp = eff_str;
2231  if (throw_ob->stats.food < 0)
2232  throw_ob->stats.food = 0;
2233  if (throw_ob->stats.food > 100)
2234  throw_ob->stats.food = 100;
2235  if (throw_ob->stats.wc > 30)
2236  throw_ob->stats.wc = 30;
2237 
2238  /* how long to pause the thrower. Higher values mean less pause */
2239  pause_f = ((2*eff_str)/3)+20+skill->level;
2240 
2241  /* Put a lower limit on this */
2242  if (pause_f < 10)
2243  pause_f = 10;
2244  if (pause_f > 100)
2245  pause_f = 100;
2246 
2247  /* Changed in 0.94.2 - the calculation before was really goofy.
2248  * In short summary, a throw can take anywhere between speed 5 and
2249  * speed 0.5
2250  */
2251  op->speed_left -= 50.0/pause_f;
2252 
2253  object_update_speed(throw_ob);
2254  throw_ob->speed_left = 0;
2255 
2256  throw_ob->move_type = MOVE_FLY_LOW;
2257  throw_ob->move_on = MOVE_FLY_LOW|MOVE_WALK;
2258 
2259 #ifdef DEBUG_THROW
2260  LOG(llevDebug, " pause_f=%d \n", pause_f);
2261  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);
2262  LOG(llevDebug, "inserting tossitem (%d) into map\n", throw_ob->count);
2263 #endif
2264  tag = throw_ob->count;
2265  object_insert_in_map_at(throw_ob, part->map, op, 0, part->x, part->y);
2266  if (!object_was_destroyed(throw_ob, tag))
2267  ob_process(throw_ob);
2268  return 1;
2269 }
2270 
2286 int skill_throw(object *op, object *part, int dir, object *skill) {
2287  object *throw_ob;
2288 
2289  if (op->type == PLAYER)
2290  throw_ob = find_throw_ob(op, find_string("throwing"));
2291  else
2292  throw_ob = monster_find_throw_ob(op);
2293 
2294  return do_throw(op, part, throw_ob, dir, skill);
2295 }
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:173
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
Error, serious thing.
Definition: logger.h:11
mapstruct::difficulty
uint16_t difficulty
What level the player should be to play here.
Definition: map.h:336
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:58
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:1753
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:1858
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:3982
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:36435
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:1996
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:380
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:1393
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:1565
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:3953
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
draw_ext_info
vs only yadda is in because all tags get reset on the next draw_ext_info In the second since it is all in one draw_ext_info
Definition: media-tags.txt:61
FLAG_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:1955
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:594
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:691
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:1357
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:562
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:206
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:195
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
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:2286
P_OUT_OF_MAP
#define P_OUT_OF_MAP
This space is outside the map.
Definition: map.h:252
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:167
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:220
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:316
P_IS_ALIVE
#define P_IS_ALIVE
Something alive is on this space.
Definition: map.h:240
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:4018
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:300
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:1236
mapstruct
This is a game-map.
Definition: map.h:318
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:1498
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:1731
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:359
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:325
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:373
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
NUM_ANIMATIONS
#define NUM_ANIMATIONS(ob)
Definition: global.h:173
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:1771
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
meditate
void meditate(object *pl, object *skill)
Meditation skill handling.
Definition: skills.cpp:1441
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
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
skill
skill
Definition: arch-handbook.txt:585
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:1587
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:890
Settings::no_player_stealing
uint8_t no_player_stealing
If 1, can not steal from other players.
Definition: global.h:311
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:4100
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:379
object.h
llevDebug
@ llevDebug
Only for debugging purposes.
Definition: logger.h:13
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:1294
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:1446