Crossfire Server, Trunk  R20513
skill_util.c
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2014 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, please
9  * see COPYING and LICENSE.
10  *
11  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
12  */
13 
32 /* define the following for skills utility debugging */
33 /* #define SKILL_UTIL_DEBUG */
34 
35 #define WANT_UNARMED_SKILLS
36 
37 #include "global.h"
38 
39 #include <assert.h>
40 #include <ctype.h>
41 #include <stdlib.h>
42 #include <string.h>
43 
44 #include "living.h"
45 #include "object.h"
46 #include "shop.h"
47 #include "skills.h"
48 #include "spells.h"
49 #include "sproto.h"
50 
51 static void attack_hth(object *pl, int dir, const char *string, object *skill);
52 static void attack_melee_weapon(object *op, int dir, const char *string, object *skill);
53 
57 const char *skill_names[NUM_SKILLS];
62 
67 void init_skills(void) {
68  int i;
69  archetype *at;
70 
71  for (i = 0; i < NUM_SKILLS; i++) {
72  skill_names[i] = NULL;
73  skill_faces[i] = -1;
74  }
75 
76  for (at = first_archetype; at != NULL; at = at->next) {
77  if (at->clone.type == SKILL) {
78  if (at->clone.subtype >= sizeof(skill_names)/sizeof(*skill_names)) {
79  LOG(llevError, "init_skills: invalid skill subtype %d for skill %s\n", at->clone.subtype, at->clone.skill);
80  } else if (skill_names[at->clone.subtype] != NULL) {
81  LOG(llevError, "init_skills: multiple skill using same subtype %d, %s, %s\n",
83  } else {
85  if (at->clone.face != NULL)
87  }
88  }
89  }
90 
91  /* This isn't really an error if there is no skill subtype set, but
92  * checking for this may catch some user errors.
93  * On the other hand, it'll crash later on, which is not nice. Thus giving a dummy name.
94  */
95  for (i = 1; i < NUM_SKILLS; i++) {
96  if (!skill_names[i]) {
97  LOG(llevError, "init_skills: skill subtype %d doesn't have a name?\n", i);
98  skill_names[i] = add_string("dummy skill");
99  }
100  }
101 }
102 
112 void link_player_skills(object *op) {
113  FOR_INV_PREPARE(op, tmp) {
114  if (tmp->type == SKILL) {
115  /* This is really a warning, hence no else below */
116  if (op->contr->last_skill_ob[tmp->subtype] && op->contr->last_skill_ob[tmp->subtype] != tmp) {
117  LOG(llevError, "Multiple skills with the same subtype? %s, %s\n", op->contr->last_skill_ob[tmp->subtype]->skill, tmp->skill);
118  }
119  if (tmp->subtype >= NUM_SKILLS) {
120  LOG(llevError, "Invalid subtype number %d (range 0-%d)\n", tmp->subtype, NUM_SKILLS);
121  } else {
122  op->contr->last_skill_ob[tmp->subtype] = tmp;
123  op->contr->last_skill_exp[tmp->subtype] = -1;
124  }
125  }
126  } FOR_INV_FINISH();
127 }
128 
151 static object *adjust_skill_tool(object *who, object *skill, object *skill_tool) {
152  if (!skill && !skill_tool)
153  return NULL;
154 
155  /* If this is a skill that can be used without a tool and no tool found, return it */
156  if (skill && QUERY_FLAG(skill, FLAG_CAN_USE_SKILL) && (!skill_tool || QUERY_FLAG(skill_tool, FLAG_APPLIED) || strcmp(skill->skill, "clawing") == 0))
157  return skill;
158 
159  /* Player has a tool to use the skill. If not applied, apply it -
160  * if not successful, return skill if can be used. If they do have the skill tool
161  * but not the skill itself, give it to them.
162  */
163  if (skill_tool) {
164  if (!QUERY_FLAG(skill_tool, FLAG_APPLIED)) {
165  if (apply_special(who, skill_tool, 0)) {
166  if (skill && QUERY_FLAG(skill, FLAG_CAN_USE_SKILL))
167  return skill;
168  else
169  return NULL;
170  }
171  }
172  if (!skill) {
173  skill = give_skill_by_name(who, skill_tool->skill);
174  link_player_skills(who);
175  }
176  return skill;
177  }
178  if (skill && QUERY_FLAG(skill, FLAG_CAN_USE_SKILL))
179  return skill;
180  else
181  return NULL;
182 }
183 
213 object *find_skill_by_name(object *who, const char *name) {
214  object *skill = NULL, *skills[NUM_SKILLS], *skill_tools[NUM_SKILLS];
215  const char *skill_names[NUM_SKILLS];
216  char *ourname=NULL;
217  int num_names, highest_level_skill=0, i;
218 
219  if (!name)
220  return NULL;
221 
222  /* Simple case - no commas in past in name, so don't need to tokenize */
223  if (!strchr(name, ',')) {
224  skill_names[0] = name;
225  skill_tools[0] = NULL;
226  skills[0] = NULL;
227  num_names = 1;
228  } else {
229  /* strtok_r is destructive, so we need our own copy */
230  char *lasts;
231  ourname = strdup(name);
232 
233  if ((skill_names[0] = strtok_r(ourname, ",", &lasts)) == NULL) {
234  /* This should really never happen */
235  LOG(llevError, "find_skill_by_name: strtok_r returned null, but strchr did not?\n");
236  free(ourname);
237  return NULL;
238  } else {
239  skill_tools[0] = NULL;
240  skills[0] = NULL;
241  /* we already have the first name from the strtok_r above */
242  num_names=1;
243  while ((skill_names[num_names] = strtok_r(NULL, ",", &lasts)) != NULL) {
244  /* Clean out any leading spacing. typical string would be
245  * skill1, skill2, skill3, ...
246  */
247  while (isspace(*skill_names[num_names]))
248  skill_names[num_names]++;
249  skills[num_names] = NULL;
250  skill_tools[num_names] = NULL;
251  num_names++;
252  }
253  }
254  /* While we don't use ourname below this point, the skill_names[] points into
255  * it, so we can't free it yet.
256  */
257  }
258 
259  FOR_INV_PREPARE(who, tmp) {
260  /* We make sure the length of the string in the object is greater
261  * in length than the passed string. Eg, if we have a skill called
262  * 'hi', we don't want to match if the user passed 'high'
263  */
264  if (tmp->type == SKILL || tmp->type == SKILL_TOOL) {
265  for (i = 0; i<num_names; i++) {
266  if (!strncasecmp(skill_names[i], tmp->skill, strlen(skill_names[i])) &&
267  strlen(tmp->skill) >= strlen(skill_names[i])) {
268  if (tmp->type == SKILL) {
269  skills[i] = tmp;
270  if (!skill || tmp->level > skill->level) {
271  skill = tmp;
272  highest_level_skill=i;
273  }
274  }
275  else {
276  /* Skill tools don't have levels, so we basically find the
277  * 'best' skill tool for this skill.
278  */
279  if (QUERY_FLAG(tmp, FLAG_APPLIED) || !skill_tools[i] ||
280  !QUERY_FLAG(skill_tools[i], FLAG_APPLIED)) {
281  skill_tools[i] = tmp;
282  }
283  }
284  /* Got a matching name - no reason to look through rest of names */
285  break;
286  }
287  }
288  }
289  } FOR_INV_FINISH();
290  free(ourname);
291  return adjust_skill_tool(who, skills[highest_level_skill], skill_tools[highest_level_skill]);
292 }
293 
312 object *find_skill_by_number(object *who, int skillno) {
313  object *skill = NULL, *skill_tool = NULL;
314 
315  if (skillno < 1 || skillno >= NUM_SKILLS)
316  return NULL;
317 
318  FOR_INV_PREPARE(who, tmp) {
319  if (tmp->type == SKILL && tmp->subtype == skillno)
320  skill = tmp;
321 
322  /* Try to find appropriate skilltool. If the player has one already
323  * applied, we try to keep using that one.
324  */
325  else if (tmp->type == SKILL_TOOL && tmp->subtype == skillno) {
326  if (QUERY_FLAG(tmp, FLAG_APPLIED))
327  skill_tool = tmp;
328  else if (!skill_tool || !QUERY_FLAG(skill_tool, FLAG_APPLIED))
329  skill_tool = tmp;
330  }
331  } FOR_INV_FINISH();
332 
333  return adjust_skill_tool(who, skill, skill_tool);
334 }
335 
356 int change_skill(object *who, object *new_skill, int flag) {
357  rangetype old_range;
358 
359  if (who->type != PLAYER)
360  return 0;
361 
362  old_range = who->contr->shoottype;
363 
364  /* The readied skill can be a skill tool, so check on actual skill instead of object. */
365  if (who->chosen_skill && who->chosen_skill->skill == new_skill->skill) {
366  /* optimization for changing skill to current skill */
367  if (!(flag&0x1))
368  who->contr->shoottype = range_skill;
369  return 1;
370  }
371 
372  if (!new_skill || who->chosen_skill)
373  if (who->chosen_skill)
374  apply_special(who, who->chosen_skill, AP_UNAPPLY|(flag&AP_NOPRINT));
375 
376  /* Only goal in this case was to unapply a skill */
377  if (!new_skill)
378  return 0;
379 
380  if (apply_special(who, new_skill, AP_APPLY|(flag&AP_NOPRINT))) {
381  return 0;
382  }
383  if (flag&0x1)
384  who->contr->shoottype = old_range;
385 
386  return 1;
387 }
388 
396 void clear_skill(object *who) {
397  who->chosen_skill = NULL;
399  if (who->type == PLAYER) {
400  who->contr->ranges[range_skill] = NULL;
401  if (who->contr->shoottype == range_skill)
402  who->contr->shoottype = range_none;
403  }
404 }
405 
429 int do_skill(object *op, object *part, object *skill, int dir, const char *string) {
430  int success = 0, exp = 0;
431 
432  if (!skill)
433  return 0;
434 
435  /* The code below presumes that the skill points to the object that
436  * holds the exp, level, etc of the skill. So if this is a player
437  * go and try to find the actual real skill pointer, and if the
438  * the player doesn't have a bucket for that, create one.
439  */
440  if (skill->type != SKILL && op->type == PLAYER) {
441  object *tmp;
442 
443  tmp = object_find_by_type_and_skill(op, SKILL, skill->skill);
444  if (!tmp)
445  tmp = give_skill_by_name(op, skill->skill);
446  skill = tmp;
447  }
448 
449  if (skill->anim_suffix)
450  apply_anim_suffix(op, skill->anim_suffix);
451 
452  switch (skill->subtype) {
453  case SK_LEVITATION:
454  /* Not 100% sure if this will work with new movement code -
455  * the levitation skill has move_type for flying, so when
456  * equipped, that should transfer to player, when not,
457  * shouldn't.
458  */
459  if (QUERY_FLAG(skill, FLAG_APPLIED)) {
460  CLEAR_FLAG(skill, FLAG_APPLIED);
462  "You come to earth.");
463  } else {
464  SET_FLAG(skill, FLAG_APPLIED);
466  "You rise into the air!.");
467  }
468  fix_object(op);
469  success = 1;
470  break;
471 
472  case SK_STEALING:
473  exp = success = steal(op, dir, skill);
474  break;
475 
476  case SK_LOCKPICKING:
477  exp = success = pick_lock(op, dir, skill);
478  break;
479 
480  case SK_HIDING:
481  exp = success = hide(op, skill);
482  break;
483 
484  case SK_JUMPING:
485  success = jump(op, dir, skill);
486  break;
487 
488  case SK_INSCRIPTION:
489  exp = success = write_on_item(op, string, skill);
490  break;
491 
492  case SK_MEDITATION:
493  meditate(op, skill);
494  success = 1;
495  break;
496  /* note that the following 'attack' skills gain exp through hit_player() */
497 
498  case SK_KARATE:
499  attack_hth(op, dir, "karate-chopped", skill);
500  break;
501 
502  case SK_PUNCHING:
503  attack_hth(op, dir, "punched", skill);
504  break;
505 
506  case SK_FLAME_TOUCH:
507  attack_hth(op, dir, "flamed", skill);
508  break;
509 
510  case SK_CLAWING:
511  attack_hth(op, dir, "clawed", skill);
512  break;
513 
514  case SK_WRAITH_FEED:
515  attack_hth(op, dir, "fed upon", skill);
516  break;
517 
520  (void)attack_melee_weapon(op, dir, NULL, skill);
521  break;
522 
523  case SK_FIND_TRAPS:
524  exp = success = find_traps(op, skill);
525  break;
526 
527  case SK_SINGING:
528  exp = success = singing(op, dir, skill);
529  break;
530 
531  case SK_ORATORY:
532  exp = success = use_oratory(op, dir, skill);
533  break;
534 
535  case SK_SMITHERY:
536  case SK_BOWYER:
537  case SK_JEWELER:
538  case SK_ALCHEMY:
539  case SK_THAUMATURGY:
540  case SK_LITERACY:
541  case SK_WOODSMAN:
542  if (use_alchemy(op) == 0)
543  exp = success = skill_ident(op, skill);
544  break;
545 
546  case SK_DET_MAGIC:
547  case SK_DET_CURSE:
548  exp = success = skill_ident(op, skill);
549  break;
550 
551  case SK_DISARM_TRAPS:
552  exp = success = remove_trap(op, skill);
553  break;
554 
555  case SK_THROWING:
556  success = skill_throw(op, part, dir, skill);
557  break;
558 
559  case SK_SET_TRAP:
561  "This skill is not currently implemented.");
562  break;
563 
564  case SK_USE_MAGIC_ITEM:
565  case SK_MISSILE_WEAPON:
567  "There is no special attack for this skill.");
568  break;
569 
570  case SK_PRAYING:
571  success = pray(op, skill);
572  break;
573 
574  case SK_BARGAINING:
575  success = shop_describe(op);
576  break;
577 
578  case SK_SORCERY:
579  case SK_EVOCATION:
580  case SK_PYROMANCY:
581  case SK_SUMMONING:
582  case SK_CLIMBING:
583  case SK_EARTH_MAGIC:
584  case SK_AIR_MAGIC:
585  case SK_FIRE_MAGIC:
586  case SK_WATER_MAGIC:
588  "This skill is already in effect.");
589  break;
590 
591  case SK_HARVESTING:
592  do_harvest(op, dir, skill);
593  success = 0;
594  break;
595 
596  default: {
597  char name[MAX_BUF];
598 
599  query_name(op, name, MAX_BUF);
600  LOG(llevDebug, "%s attempted to use unknown skill: %d\n", name, op->chosen_skill->stats.sp);
601  break;
602  }
603  }
604 
605  /* For players we now update the speed_left from using the skill.
606  * Monsters have no skill use time because of the random nature in
607  * which use_monster_skill is called already simulates this.
608  * If certain skills should take more/less time, that should be
609  * in the code for the skill itself.
610  */
611 
612  if (op->type == PLAYER)
613  op->speed_left -= 1.0;
614 
615  /* this is a good place to add experience for successful use of skills.
616  * Note that add_exp() will figure out player/monster experience
617  * gain problems.
618  */
619 
620  if (success && exp)
621  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
622 
623  return success;
624 }
625 
658 int64_t calc_skill_exp(const object *who, const object *op, const object *skill) {
659  int64_t op_exp;
660  int op_lvl;
661  float base, value, lvl_mult;
662 
663  if (!skill)
664  skill = who;
665 
666  /* Oct 95 - where we have an object, I expanded our treatment
667  * to 3 cases:
668  * non-living magic obj, runes and everything else.
669  *
670  * If an object is not alive and magical we set the base exp higher to
671  * help out exp awards for skill_ident skills. Also, if
672  * an item is type RUNE, we give out exp based on stats.Cha
673  * and level (this was the old system) -b.t.
674  */
675 
676  if (!op) { /* no item/creature */
677  op_lvl = MAX(who->map->difficulty, 1);
678  op_exp = 0;
679  } else if (op->type == RUNE || op->type == TRAP) { /* all traps. If stats.Cha > 1 we use that
680  * for the amount of experience */
681  op_exp = op->stats.Cha > 1 ? op->stats.Cha : op->stats.exp;
682  op_lvl = op->level;
683  } else { /* all other items/living creatures */
684  op_exp = op->stats.exp;
685  op_lvl = op->level;
686  if (!QUERY_FLAG(op, FLAG_ALIVE)) { /* for ident/make items */
687  op_lvl += 5*abs(op->magic);
688  }
689  }
690 
691  if (op_lvl < 1)
692  op_lvl = 1;
693 
694  if (who->type != PLAYER) { /* for monsters only */
695  return ((int64_t)(op_exp*0.1)+1); /* we add one to insure positive value is returned */
696  }
697 
698  /* for players */
699  base = op_exp;
700  /* if skill really is a skill, then we can look at the skill archetype for
701  * base reward value (exp) and level multiplier factor.
702  */
703  if (skill->type == SKILL) {
704  base += skill->arch->clone.stats.exp;
705  if (settings.simple_exp) {
706  if (skill->arch->clone.level)
707  lvl_mult = (float)skill->arch->clone.level/100.0;
708  else
709  lvl_mult = 1.0; /* no adjustment */
710  } else {
711  if (skill->level)
712  lvl_mult = ((float)skill->arch->clone.level*(float)op_lvl)/((float)skill->level*100.0);
713  else
714  lvl_mult = 1.0;
715  }
716  } else {
717  /* Don't divide by zero here! */
718  lvl_mult = (float)op_lvl/(float)(skill->level ? skill->level : 1);
719  }
720 
721  /* assemble the exp total, and return value */
722 
723  value = base*lvl_mult;
724  if (value < 1)
725  value = 1; /* Always give at least 1 exp point */
726 
727 #ifdef SKILL_UTIL_DEBUG
728  LOG(llevDebug, "calc_skill_exp(): who: %s(lvl:%d) op:%s(lvl:%d)\n", who->name, skill->level, op->name, op_lvl);
729 #endif
730  return ((int64_t)value);
731 }
732 
750 int learn_skill(object *pl, object *scroll) {
751  object *tmp;
752 
753  if (!scroll->skill) {
754  LOG(llevError, "skill scroll %s does not have skill pointer set.\n", scroll->name);
755  return 2;
756  }
757 
758  /* can't use find_skill_by_name because we want skills the player knows
759  * but can't use natively.
760  */
761 
762  tmp = NULL;
763  FOR_INV_PREPARE(pl, inv)
764  if (inv->type == SKILL && !strncasecmp(scroll->skill, inv->skill, strlen(scroll->skill))) {
765  tmp = inv;
766  break;
767  }
768  FOR_INV_FINISH();
769 
770  /* player already knows it */
771  if (tmp && QUERY_FLAG(tmp, FLAG_CAN_USE_SKILL))
772  return 0;
773 
774  /* now a random change to learn, based on player Int.
775  * give bonus based on level - otherwise stupid characters
776  * might never be able to learn anything.
777  */
778  if (random_roll(0, 99, pl, PREFER_LOW) > (get_learn_spell(pl->stats.Int)+(pl->level/5)))
779  return 2; /* failure :< */
780 
781  if (!tmp)
782  tmp = give_skill_by_name(pl, scroll->skill);
783 
784  if (!tmp) {
785  LOG(llevError, "skill scroll %s does not have valid skill name (%s).\n", scroll->name, scroll->skill);
786  return 2;
787  }
788 
790  link_player_skills(pl);
791  return 1;
792 }
793 
805 static int clipped_percent(int64_t a, int64_t b) {
806  int rv;
807 
808  if (b <= 0)
809  return 0;
810 
811  rv = (int)((100.0f*((float)a)/((float)b))+0.5f);
812 
813  if (rv < 0)
814  return 0;
815  else if (rv > 100)
816  return 100;
817 
818  return rv;
819 }
820 
837 void show_skills(object *op, const char *search) {
838  const char *cp;
839  int i, num_skills_found = 0;
840  static const char *const periods = "........................................";
841  /* Need to have a pointer and use strdup for qsort to work properly */
842  char skills[NUM_SKILLS][MAX_BUF];
843 
844  FOR_INV_PREPARE(op, tmp) {
845  if (tmp->type == SKILL) {
846  char buf[MAX_BUF];
847 
848  if (search && strstr(tmp->name, search) == NULL)
849  continue;
850  /* Basically want to fill this out to 40 spaces with periods */
851  snprintf(buf, sizeof(buf), "%s%s", tmp->name, periods);
852  buf[40] = 0;
853 
855  snprintf(skills[num_skills_found++], MAX_BUF, "%slvl:%3d (xp:%"FMT64"/%"FMT64"/%d%%)",
856  buf, tmp->level,
857  tmp->stats.exp,
858  level_exp(tmp->level+1, op->expmul),
859  clipped_percent(tmp->perm_exp, tmp->stats.exp));
860  } else {
861  snprintf(skills[num_skills_found++], MAX_BUF, "%slvl:%3d (xp:%"FMT64"/%"FMT64")",
862  buf, tmp->level,
863  tmp->stats.exp,
864  level_exp(tmp->level+1, op->expmul));
865  }
866  /* I don't know why some characters get a bunch of skills, but
867  * it sometimes happens (maybe a leftover from buggier earlier code
868  * and those character are still about). In any case, lets handle
869  * it so it doesn't crash the server - otherwise, one character may
870  * crash the server numerous times.
871  */
872  if (num_skills_found >= NUM_SKILLS) {
874  "Your character has too many skills. "
875  "Something isn't right - contact the server admin");
876  break;
877  }
878  }
879  } FOR_INV_FINISH();
880 
882  "Player skills:");
883 
884  if (num_skills_found > 1)
885  qsort(skills, num_skills_found, MAX_BUF, (int (*)(const void *, const void *))strcmp);
886 
887  for (i = 0; i < num_skills_found; i++) {
889  skills[i]);
890  }
891 
893  "You can handle %d weapon improvements.",
894  op->level/5+5);
895 
896  cp = determine_god(op);
897  if (strcmp(cp, "none") == 0)
898  cp = NULL;
900  "You worship %s.",
901  cp ? cp : "no god at current time");
902 
904  "Your equipped item power is %d out of %d\n",
905  op->contr->item_power, op->level);
906 }
907 
924 int use_skill(object *op, const char *string) {
925  object *skop;
926  size_t len;
927 
928  if (!string)
929  return 0;
930 
931  skop = NULL;
932  FOR_INV_PREPARE(op, tmp) {
933  if (tmp->type == SKILL
935  && !strncasecmp(string, tmp->skill, MIN(strlen(string), strlen(tmp->skill)))) {
936  skop = tmp;
937  break;
938  } else if (tmp->type == SKILL_TOOL
939  && !strncasecmp(string, tmp->skill, MIN(strlen(string), strlen(tmp->skill)))) {
940  skop = tmp;
941  break;
942  }
943  } FOR_INV_FINISH();
944  if (!skop) {
946  "Unable to find skill %s",
947  string);
948  return 0;
949  }
950 
951  len = strlen(skop->skill);
952 
953  /* All this logic goes and skips over the skill name to find any
954  * options given to the skill. Its pretty simple - if there
955  * are extra parameters (as determined by string length), we
956  * want to skip over any leading spaces.
957  */
958  if (len >= strlen(string)) {
959  string = NULL;
960  } else {
961  string += len;
962  while (*string == 0x20)
963  string++;
964  if (strlen(string) == 0)
965  string = NULL;
966  }
967 
968 #ifdef SKILL_UTIL_DEBUG
969  LOG(llevDebug, "use_skill() got skill: %s\n", sknum > -1 ? skills[sknum].name : "none");
970 #endif
971 
972  /* Change to the new skill, then execute it. */
973  if (do_skill(op, op, skop, op->facing, string))
974  return 1;
975 
976  return 0;
977 }
978 
1001 static object *find_best_player_hth_skill(object *op) {
1002  object *best_skill = NULL;
1003  int last_skill;
1004 
1005  if (op->contr->unarmed_skill) {
1006  /* command_unarmed_skill() already does these checks, and right
1007  * now I do not think there is any way to lose unarmed skills.
1008  * But maybe in the future there will be (polymorph?) so handle
1009  * it appropriately. MSW 2009-07-03
1010  *
1011  * Note that the error messages should only print out once when
1012  * the initial failure to switch skills happens, so the player
1013  * should not get spammed with tons of messages unless they have
1014  * no valid unarmed skill
1015  */
1016 
1017  best_skill = find_skill_by_name(op, op->contr->unarmed_skill);
1018 
1019  if (!best_skill) {
1021  "Unable to find skill %s - using default unarmed skill",
1022  op->contr->unarmed_skill);
1023  } else {
1024  size_t i;
1025 
1026  for (i = 0; i < sizeof(unarmed_skills); i++)
1027  if (best_skill->subtype == unarmed_skills[i])
1028  break;
1029  if (i < sizeof(unarmed_skills))
1030  return(best_skill);
1031  }
1032  /* If for some reason the unarmed_skill is not valid, we fall
1033  * through the processing below.
1034  */
1035  }
1036 
1037 
1038  /* Dragons are a special case - gros 25th July 2006 */
1039  /* Perhaps this special case should be removed and unarmed_skill
1040  * set to clawing for dragon characters? MSW 2009-07-03
1041  */
1042  if (is_dragon_pl(op)) {
1043  object *tmp;
1044 
1045  tmp = find_skill_by_number(op, SK_CLAWING);
1046  if (tmp) /* I suppose it should always be true - but maybe there's
1047  * draconic toothache ? :) */
1048  return tmp;
1049  }
1050 
1051  last_skill = sizeof(unarmed_skills);
1052  FOR_INV_PREPARE(op, tmp) {
1053  if (tmp->type == SKILL) {
1054  int i;
1055 
1056  /* The order in the array is preferred order. So basically,
1057  * we just cut down the number to search - eg, if we find a skill
1058  * early on in flame touch, then we only need to look into the unarmed_array
1059  * to the entry before flame touch - don't care about the entries afterward,
1060  * because they are inferior skills.
1061  * if we end up finding the best skill (i==0) might as well return
1062  * right away - can't get any better than that.
1063  */
1064  for (i = 0; i < last_skill; i++) {
1065  if (tmp->subtype == unarmed_skills[i] && QUERY_FLAG(tmp, FLAG_CAN_USE_SKILL)) {
1066  best_skill = tmp;
1067  last_skill = i;
1068  if (i == 0)
1069  return best_skill;
1070  }
1071  }
1072  }
1073  } FOR_INV_FINISH();
1074  return best_skill;
1075 }
1076 
1090 static void do_skill_attack(object *tmp, object *op, const char *string, object *skill) {
1091  int success;
1092 
1093  /* For Players only: if there is no ready weapon, and no "attack" skill
1094  * is readied either then try to find a skill for the player to use.
1095  * it is presumed that if skill is set, it is a valid attack skill (eg,
1096  * the caller should have set it appropriately). We still want to pass
1097  * through that code if skill is set to change to the skill.
1098  */
1099  if (op->type == PLAYER) {
1100  if (!QUERY_FLAG(op, FLAG_READY_WEAPON)) {
1101  size_t i;
1102 
1103  if (!skill) {
1104  /* See if the players chosen skill is a combat skill, and use
1105  * it if appropriate.
1106  */
1107  if (op->chosen_skill) {
1108  /* the list is 0-terminated, and talismans, which can be in chosen_skill,
1109  * have a subtype of 0, therefore don't check the 0 */
1110  for (i = 0; unarmed_skills[i] != 0; i++)
1111  if (op->chosen_skill->subtype == unarmed_skills[i]) {
1112  skill = op->chosen_skill;
1113  break;
1114  }
1115  }
1116  /* If we didn't find a skill above, look harder for a good skill */
1117  if (!skill) {
1118  skill = find_best_player_hth_skill(op);
1119 
1120  if (!skill) {
1121  draw_ext_info(NDI_BLACK, 0, op,
1123  "You have no unarmed combat skills!");
1124  return;
1125  }
1126  }
1127  }
1128  if (skill != op->chosen_skill) {
1129  /* now try to ready the new skill */
1130  if (!change_skill(op, skill, 1)) { /* oh oh, trouble! */
1133  "Couldn't change to skill %s",
1134  skill->name);
1135  return;
1136  }
1137  }
1138  } else {
1139  /* Seen some crashes below where current_weapon is not set,
1140  * even though the flag says it is. So if current weapon isn't set,
1141  * do some work in trying to find the object to use.
1142  */
1143  if (!op->current_weapon) {
1144  object *tmp;
1145 
1146  LOG(llevError, "Player %s does not have current weapon set but flag_ready_weapon is set\n", op->name);
1148  if (!tmp) {
1149  LOG(llevError, "Could not find applied weapon on %s\n", op->name);
1150  op->current_weapon = NULL;
1151  return;
1152  } else {
1153  char weapon[MAX_BUF];
1154 
1155  query_name(tmp, weapon, MAX_BUF);
1156  op->current_weapon = tmp;
1157  }
1158  }
1159 
1160  /* Has ready weapon - make sure chosen_skill is set up properly */
1161  if (!op->chosen_skill || op->current_weapon->skill != op->chosen_skill->skill) {
1162  object *found_skill = find_skill_by_name(op, op->current_weapon->skill);
1163  assert(found_skill != NULL);
1164  change_skill(op, found_skill, 1);
1165  }
1166  }
1167  }
1168 
1169  /* lose invisibility/hiding status for running attacks */
1170 
1171  if (op->type == PLAYER && op->contr->tmp_invis) {
1172  op->contr->tmp_invis = 0;
1173  op->invisible = 0;
1174  op->hide = 0;
1176  }
1177 
1178  success = attack_ob(tmp, op);
1179 
1180  /*
1181  * print appropriate messages to the player
1182  *
1183  * If no string, then we aren't dealing with the
1184  * skill attack directly, so the message is printed elsewhere.
1185  *
1186  * Only print hit/miss if we've got a Fire+Attack.
1187  * Otherwise, don't print here at all.
1188  */
1189 
1190  if (string != NULL && tmp && !QUERY_FLAG(tmp, FLAG_FREED)) {
1191  char op_name[MAX_BUF];
1192  if (success){
1193  if (op->type == PLAYER) {
1194  query_name(tmp, op_name, MAX_BUF);
1197  "You %s %s!",
1198  string, op_name);
1199  } else if (tmp->type == PLAYER) {
1200  query_name(op, op_name, MAX_BUF);
1203  "%s %s you!",
1204  op_name, string);
1205  }
1206  }
1207  else{
1208  query_name(tmp, op_name, MAX_BUF);
1211  "You miss %s!",
1212  op_name);
1213  }
1214  }
1215 }
1216 
1240 void skill_attack(object *tmp, object *pl, int dir, const char *string, object *skill) {
1241  int16_t tx, ty;
1242  mapstruct *m;
1243  int mflags;
1244 
1245  if (!dir)
1246  dir = pl->facing;
1247  tx = freearr_x[dir];
1248  ty = freearr_y[dir];
1249 
1250  /* If we don't yet have an opponent, find if one exists, and attack.
1251  * Legal opponents are the same as outlined in move_player_attack()
1252  */
1253 
1254  if (tmp == NULL) {
1255  m = pl->map;
1256  tx = pl->x+freearr_x[dir];
1257  ty = pl->y+freearr_y[dir];
1258 
1259  mflags = get_map_flags(m, &m, tx, ty, &tx, &ty);
1260  if (mflags&P_OUT_OF_MAP)
1261  return;
1262 
1263  /* space must be blocked for there to be anything interesting to do */
1264  if (!(mflags&P_IS_ALIVE)
1265  && !OB_TYPE_MOVE_BLOCK(pl, GET_MAP_MOVE_BLOCK(m, tx, ty))) {
1266  return;
1267  }
1268 
1269  FOR_MAP_PREPARE(m, tx, ty, tmp2)
1270  if ((QUERY_FLAG(tmp2, FLAG_ALIVE) && tmp2->stats.hp >= 0)
1271  || QUERY_FLAG(tmp2, FLAG_CAN_ROLL)
1272  || tmp2->type == LOCKED_DOOR) {
1273  /* Don't attack party members */
1274  if ((pl->type == PLAYER && tmp2->type == PLAYER)
1275  && (pl->contr->party != NULL && pl->contr->party == tmp2->contr->party))
1276  return;
1277  tmp = tmp2;
1278  break;
1279  }
1280  FOR_MAP_FINISH();
1281  }
1282  if (!tmp) {
1283  if (pl->type == PLAYER)
1285  "There is nothing to attack!");
1286  return;
1287  }
1288 
1289  do_skill_attack(tmp, pl, string, skill);
1290 }
1291 
1310 static void attack_hth(object *pl, int dir, const char *string, object *skill) {
1311  object *weapon;
1312 
1313  if (QUERY_FLAG(pl, FLAG_READY_WEAPON)) {
1314  weapon = object_find_by_type_applied(pl, WEAPON);
1315  if (weapon != NULL) {
1316  if (apply_special(pl, weapon, AP_UNAPPLY|AP_NOPRINT)) {
1317  char weaponname[MAX_BUF];
1318 
1319  query_name(weapon, weaponname, MAX_BUF);
1322  "You are unable to unwield %s in order to attack with %s.",
1323  weaponname, skill->name);
1324  return;
1325  } else {
1327  "You unwield your weapon in order to attack.");
1328  }
1329  }
1330  }
1331  skill_attack(NULL, pl, dir, string, skill);
1332 }
1333 
1354 static void attack_melee_weapon(object *op, int dir, const char *string, object *skill) {
1355  if (!QUERY_FLAG(op, FLAG_READY_WEAPON)) {
1356  if (op->type == PLAYER)
1358  "You have no ready weapon to attack with!");
1359  return;
1360  }
1361  skill_attack(NULL, op, dir, string, skill);
1362 }
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...)
Sends message to player(s).
Definition: main.c:315
Error, serious thing.
Definition: logger.h:11
#define AP_UNAPPLY
Item is to be remvoed.
Definition: define.h:611
Flame-touch.
Definition: skills.h:37
Use skill.
Definition: player.h:22
int8_t Int
Definition: living.h:35
One player.
Definition: player.h:92
int apply_special(object *who, object *op, int aflags)
Apply an object.
Definition: apply.c:1082
const char * determine_god(object *op)
Determines if op worships a god.
Definition: gods.c:106
#define UP_OBJ_FACE
Only thing that changed was the face.
Definition: object.h:519
Stealing.
Definition: skills.h:26
Air magic, unused.
Definition: skills.h:59
Spell-related defines: spellpath, subtypes, ...
int skill_ident(object *pl, object *skill)
Main identification skill handling.
Definition: skills.c:895
Harvesting.
Definition: skills.h:58
int64_t level_exp(int level, double expmul)
Returns how much experience is needed for a player to become the given level.
Definition: living.c:1822
Thaumaturgy.
Definition: skills.h:48
static void attack_melee_weapon(object *op, int dir, const char *string, object *skill)
This handles melee weapon attacks -b.t.
Definition: skill_util.c:1354
Missile weapon.
Definition: skills.h:43
#define SET_FLAG(xyz, p)
Definition: define.h:223
#define MSG_TYPE_SKILL_LIST
List of skills.
Definition: newclient.h:587
sstring add_refcount(sstring str)
This will increase the refcount of the string str.
Definition: shstr.c:210
object * object_find_by_type_applied(const object *who, int type)
Find applied object in inventory.
Definition: object.c:3974
Wraith feed.
Definition: skills.h:57
static int clipped_percent(int64_t a, int64_t b)
Gives a percentage clipped to 0% -> 100% of a/b.
Definition: skill_util.c:805
int attack_ob(object *op, object *hitter)
Simple wrapper for attack_ob_simple(), will use hitter&#39;s values.
Definition: attack.c:903
No range selected.
Definition: player.h:17
Climbing.
Definition: skills.h:39
int shop_describe(const object *op)
Give the player a description of the shop on their current map.
Definition: shop.c:1137
Earth magic, unused.
Definition: skills.h:60
int use_skill(object *op, const char *string)
Similar to invoke command, it executes the skill in the direction that the user is facing...
Definition: skill_util.c:924
object clone
An object from which to do object_copy()
Definition: object.h:470
int16_t invisible
How much longer the object will be invis.
Definition: object.h:360
short freearr_x[SIZEOFFREE]
X offset when searching around a spot.
Definition: object.c:65
#define PREFER_LOW
Definition: define.h:600
int pick_lock(object *pl, int dir, object *skill)
Lock pick handling.
Definition: skills.c:386
static object * adjust_skill_tool(object *who, object *skill, object *skill_tool)
This returns specified skill if it can be used, potentially using tool to help.
Definition: skill_util.c:151
rangetype shoottype
Which range-attack is being used by player.
Definition: player.h:99
See Rune.
Definition: object.h:240
Detect curse.
Definition: skills.h:33
Jumping.
Definition: skills.h:29
See Weapon.
Definition: object.h:119
int change_skill(object *who, object *new_skill, int flag)
This changes the object&#39;s skill to new_skill.
Definition: skill_util.c:356
#define MSG_TYPE_SKILL_MISSING
Don&#39;t have the skill.
Definition: newclient.h:582
Bowyer.
Definition: skills.h:23
object * ranges[range_size]
Object for each range.
Definition: player.h:103
uint8_t subtype
Subtype of object.
Definition: object.h:339
int do_skill(object *op, object *part, object *skill, int dir, const char *string)
Main skills use function-similar in scope to cast_spell().
Definition: skill_util.c:429
uint8_t hide
The object is hidden, not invisible.
Definition: object.h:387
int64_t exp
Experience.
Definition: living.h:46
double expmul
needed experience = (calc_exp*expmul) - means some races/classes can need less/more exp to gain level...
Definition: object.h:395
#define MSG_TYPE_SKILL_ERROR
Doing something wrong.
Definition: newclient.h:583
int jump(object *pl, int dir, object *skill)
Jump skill handling.
Definition: skills.c:658
int remove_trap(object *op, object *skill)
This skill will disarm any previously discovered trap.
Definition: skills.c:1283
#define MAX(x, y)
Definition: compat.h:20
void object_update(object *op, int action)
object_update() updates the array which represents the map.
Definition: object.c:1239
int64_t calc_skill_exp(const object *who, const object *op, const object *skill)
Calculates amount of experience can be gained for successful use of a skill.
Definition: skill_util.c:658
int16_t sp
Spell points.
Definition: living.h:41
#define NDI_BLACK
Definition: newclient.h:221
Global type definitions and header inclusions.
#define AP_APPLY
Item is to be applied.
Definition: define.h:610
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Sends message to player(s).
Definition: main.c:310
The archetype structure is a set of rules on how to generate and manipulate objects which point to ar...
Definition: object.h:465
Bargaining.
Definition: skills.h:28
Smithery.
Definition: skills.h:22
#define MIN(x, y)
Definition: compat.h:17
Lockpicking.
Definition: skills.h:20
#define FLAG_CAN_ROLL
Object can be rolled.
Definition: define.h:254
short freearr_y[SIZEOFFREE]
Y offset when searching around a spot.
Definition: object.c:71
partylist * party
Party this player is part of.
Definition: player.h:186
Woodsman.
Definition: skills.h:40
uint16_t number
This is the image id.
Definition: face.h:15
Clawing.
Definition: skills.h:50
object * give_skill_by_name(object *op, const char *skill_name)
Given the skill name skill_name, we find the skill archetype/object, set appropriate values...
Definition: living.c:1727
int use_alchemy(object *op)
Handle use_skill for alchemy-like items.
Definition: alchemy.c:1020
Allows the use of a skill.
Definition: object.h:189
Throwing.
Definition: skills.h:44
#define FLAG_READY_SKILL
(Monster or Player) has a skill readied
Definition: define.h:334
See Trap.
Definition: object.h:241
struct obj * chosen_skill
The skill chosen to use.
Definition: object.h:386
int16_t y
Position in the map for this object.
Definition: object.h:326
#define NDI_RED
Definition: newclient.h:224
int skill_throw(object *op, object *part, int dir, object *skill)
Throwing skill handling.
Definition: skills.c:2230
Inscription.
Definition: skills.h:41
#define strtok_r(x, y, z)
Definition: win32.h:62
Disarm traps.
Definition: skills.h:46
#define FLAG_ALIVE
Object can fight (or be fought)
Definition: define.h:230
#define MSG_TYPE_VICTIM
Something bad is happening to the player.
Definition: newclient.h:392
float speed_left
How much speed is left to spend this round.
Definition: object.h:329
int skill_faces[NUM_SKILLS]
Will contain the face numbers for the skills, initialized by init_skill().
Definition: skill_util.c:61
signed short int16_t
Definition: win32.h:160
#define FLAG_CAN_USE_SKILL
The monster can use skills.
Definition: define.h:322
const char * anim_suffix
Used to determine combined animations.
Definition: object.h:316
uint32_t tmp_invis
Will invis go away when we attack?
Definition: player.h:125
Fire magic, unused.
Definition: skills.h:62
int hide(object *op, object *skill)
Main hide handling.
Definition: skills.c:491
One handed weapon.
Definition: skills.h:42
struct mapdef * map
Pointer to the map in which this object is present.
Definition: object.h:297
int is_dragon_pl(const object *op)
Checks if player is a dragon.
Definition: player.c:114
#define snprintf
Definition: win32.h:46
static void attack_hth(object *pl, int dir, const char *string, object *skill)
This handles all hand-to-hand attacks.
Definition: skill_util.c:1310
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:712
#define FMT64
Definition: compat.h:12
Use magic item.
Definition: skills.h:45
Set traps, unused.
Definition: skills.h:47
const char * name
The name of the object, obviously...
Definition: object.h:311
Summoning.
Definition: skills.h:52
Alchemy.
Definition: skills.h:25
void link_player_skills(object *op)
This function goes through the player inventory and sets up the last_skills[] array in the player obj...
Definition: skill_util.c:112
Sorcery.
Definition: skills.h:55
#define MSG_TYPE_VICTIM_WAS_HIT
Player was hit by something.
Definition: newclient.h:647
int steal(object *op, int dir, object *skill)
Main stealing function.
Definition: skills.c:276
struct obj * current_weapon
Pointer to the weapon currently used.
Definition: object.h:370
int8_t Cha
Definition: living.h:35
#define OB_TYPE_MOVE_BLOCK(ob1, type)
Basic macro to see if if ob1 can not move onto a space based on the &#39;type&#39; move_block parameter Add c...
Definition: define.h:447
Detect magic.
Definition: skills.h:30
#define AP_NOPRINT
Don&#39;t print messages - caller will do that may be some that still print.
Definition: define.h:621
#define P_OUT_OF_MAP
This space is outside the map.
Definition: map.h:251
#define GET_MAP_MOVE_BLOCK(M, X, Y)
Gets the blocking state of a square.
Definition: map.h:192
#define MSG_TYPE_ATTACK_MISS
attack didn&#39;t hit
Definition: newclient.h:615
static object * find_best_player_hth_skill(object *op)
Finds the best unarmed skill the player has, and returns it.
Definition: skill_util.c:1001
struct pl * contr
Pointer to the player which control this object.
Definition: object.h:276
Find traps.
Definition: skills.h:34
#define MSG_TYPE_SKILL_FAILURE
Failure in using skill.
Definition: newclient.h:585
Levitation.
Definition: skills.h:51
uint8_t simple_exp
If true, use the simple experience system.
Definition: global.h:261
Meditation.
Definition: skills.h:35
Praying.
Definition: skills.h:49
void do_harvest(object *pl, int dir, object *skill)
Player is trying to harvest something.
Definition: c_misc.c:2208
#define QUERY_FLAG(xyz, p)
Definition: define.h:225
#define CLEAR_FLAG(xyz, p)
Definition: define.h:224
void change_exp(object *op, int64_t exp, const char *skill_name, int flag)
Changes experience to a player/monster.
Definition: living.c:2076
See Locked Door.
Definition: object.h:123
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
#define MSG_TYPE_ATTACK
Attack related messages.
Definition: newclient.h:385
#define MSG_TYPE_ATTACK_DID_HIT
Player hit something else.
Definition: newclient.h:607
int16_t x
Definition: object.h:326
Punching.
Definition: skills.h:36
Literacy.
Definition: skills.h:27
int strncasecmp(const char *s1, const char *s2, int n)
Case-insensitive comparaison of strings.
Definition: porting.c:224
Karate.
Definition: skills.h:38
const char * skill
Name of the skill this object uses/grants.
Definition: object.h:321
Water magic, unused.
Definition: skills.h:61
Skill-related defines, including subtypes.
#define NUM_SKILLS
This is the highest number skill in the table +1 This is used to store pointers to the actual skills ...
Definition: skills.h:71
void init_skills(void)
This just sets up the skill_names table above.
Definition: skill_util.c:67
Oratory.
Definition: skills.h:31
int learn_skill(object *pl, object *scroll)
Player is trying to learn a skill.
Definition: skill_util.c:750
uint16_t difficulty
What level the player should be to play here.
Definition: map.h:343
signed __int64 int64_t
Definition: win32.h:168
#define FLAG_READY_WEAPON
(Monster or Player) has a weapon readied
Definition: define.h:335
#define FOR_MAP_FINISH()
Finishes FOR_MAP_PREPARE().
Definition: define.h:765
uint8_t permanent_exp_ratio
How much exp should be &#39;permenant&#39; and unable to be lost.
Definition: global.h:256
See Player.
Definition: object.h:107
int pray(object *pl, object *skill)
Praying skill handling.
Definition: skills.c:1356
Object structure, the core of Crossfire.
Jeweler.
Definition: skills.h:24
object * object_find_by_type_and_skill(const object *who, int type, const char *skill)
Find object in inventory by type and skill.
Definition: object.c:4074
Also see SKILL_TOOL (74) below.
Definition: object.h:143
void show_skills(object *op, const char *search)
Displays a player&#39;s skill list, and some other non skill related info (god, max weapon improvements...
Definition: skill_util.c:837
living stats
Str, Con, Dex, etc.
Definition: object.h:368
struct archt * arch
Pointer to archetype.
Definition: object.h:412
Only for debugging purposes.
Definition: logger.h:13
Hiding.
Definition: skills.h:21
int singing(object *pl, int dir, object *skill)
Singing skill handling.
Definition: skills.c:1119
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:338
struct Settings settings
Server settings.
Definition: init.c:40
Singing.
Definition: skills.h:32
struct archt * next
Next archetype in a linked list.
Definition: object.h:467
rangetype
What range is currently selected by the player.
Definition: player.h:15
#define FLAG_APPLIED
Object is ready for use by living.
Definition: define.h:235
Two handed weapons.
Definition: skills.h:56
int64_t last_skill_exp[NUM_SKILLS]
Last exp sent to client.
Definition: player.h:138
int find_traps(object *pl, object *skill)
Checks for traps on the spaces around the player or in certain objects.
Definition: skills.c:1212
sstring add_string(const char *str)
This will add &#39;str&#39; to the hash table.
Definition: shstr.c:124
#define MSG_TYPE_SKILL
Messages related to skill use.
Definition: newclient.h:383
char * strdup(const char *str)
Portable implementation of strdup(3).
Definition: porting.c:200
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, int16_t x, int16_t y, int16_t *nx, int16_t *ny)
This rolls up wall, blocks_magic, blocks_view, etc, all into one function that just returns a P_...
Definition: map.c:302
#define NDI_UNIQUE
Print immediately, don&#39;t buffer.
Definition: newclient.h:245
void apply_anim_suffix(object *who, sstring suffix)
Applies a compound animation to an object.
Definition: anim.c:292
int use_oratory(object *pl, int dir, object *skill)
Oratory skill handling.
Definition: skills.c:965
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.c:51
int16_t item_power
Total item power of objects equipped.
Definition: player.h:117
int get_learn_spell(int stat)
Definition: living.c:2259
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.c:213
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Constructs a loop iterating over all objects of a map tile.
Definition: define.h:758
Evocation.
Definition: skills.h:54
object * last_skill_ob[NUM_SKILLS]
Exp objects sent to client.
Definition: player.h:137
Structure containing object statistics.
#define MSG_TYPE_SKILL_SUCCESS
Successfully used skill.
Definition: newclient.h:584
void query_name(const object *op, char *buf, size_t size)
Describes an item.
Definition: item.c:625
#define SK_SUBTRACT_SKILL_EXP
Used when removing exp.
Definition: skills.h:82
This is a game-map.
Definition: map.h:325
#define P_IS_ALIVE
Something alive is on this space.
Definition: map.h:237
int random_roll(int min, int max, const object *op, int goodbad)
Roll a random number between min and max.
Definition: utils.c:42
const New_Face * face
Face with colors.
Definition: object.h:332
void clear_skill(object *who)
This function just clears the chosen_skill and range_skill values in the player.
Definition: skill_util.c:396
object * find_skill_by_number(object *who, int skillno)
This returns the skill pointer of the given name (the one that accumulates exp, has the level...
Definition: skill_util.c:312
int write_on_item(object *pl, const char *params, object *skill)
Implement the &#39;inscription&#39; skill, which checks for the required skills and marked items before runni...
Definition: skills.c:1735
const char * skill_names[NUM_SKILLS]
Will contain a number-name mapping for skills, initialized by init_skills().
Definition: skill_util.c:57
const char * unarmed_skill
Prefered skill to use in unarmed combat.
Definition: player.h:202
int16_t level
Level of creature or object.
Definition: object.h:351
int8_t facing
Object is oriented/facing that way.
Definition: object.h:335
void fix_object(object *op)
Updates all abilities given by applied objects in the inventory of the given object.
Definition: living.c:1120
Pyromancy.
Definition: skills.h:53
void meditate(object *pl, object *skill)
Meditation skill handling.
Definition: skills.c:1404
EXTERN archetype * first_archetype
First archetype.
Definition: global.h:122
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.c:1240
int8_t magic
Any magical bonuses to this item.
Definition: object.h:348
#define FOR_INV_PREPARE(op_, it_)
Constructs a loop iterating over the inventory of an object.
Definition: define.h:705
static void do_skill_attack(object *tmp, object *op, const char *string, object *skill)
We have got an appropriate opponent from either move_player_attack() or skill_attack().
Definition: skill_util.c:1090
#define FLAG_FREED
Object is in the list of free objects.
Definition: define.h:233