Crossfire Server, Trunk  1.75.0
skill_util.cpp
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2014 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, please
9  * see COPYING and LICENSE.
10  *
11  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
12  */
13 
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 #include <math.h>
44 
45 #include "living.h"
46 #include "object.h"
47 #include "shop.h"
48 #include "skills.h"
49 #include "spells.h"
50 #include "sproto.h"
51 #include "assets.h"
52 
53 static void attack_hth(object *pl, int dir, const char *string, object *skill);
54 static void attack_melee_weapon(object *op, int dir, const char *string, object *skill);
55 
59 const char *skill_names[MAX_SKILLS];
64 
70 
71 static int free_skill_index() {
72  int i;
73  for (i = 0; i < MAX_SKILLS; i++) {
74  if (skill_names[i] == NULL && skill_faces[i] == NULL) {
75  break;
76  }
77  }
78  return i;
79 }
80 static void do_each_skill(archetype *at) {
81  if (at->clone.type == SKILL) {
82  int i = free_skill_index();
83  if (i == MAX_SKILLS) {
84  LOG(llevError, "init_skills: too many skills, increase MAX_SKILLS and rebuild server!");
86  }
88  if (at->clone.face != NULL)
89  skill_faces[i] = at->clone.face;
90  if (at->clone.msg)
92  }
93 }
94 
99 void init_skills(void) {
100  int i;
101 
102  for (i = 0; i < MAX_SKILLS; i++) {
103  skill_names[i] = NULL;
104  skill_faces[i] = NULL;
105  skill_messages[i] = NULL;
106  }
107 
109 }
110 
116 int get_skill_client_code(const char *skill_name)
117 {
118  int index;
119  for (index = 0; index < MAX_SKILLS && skill_names[index] != NULL; index++)
120  if (strcmp(skill_names[index], skill_name) == 0)
121  return index;
122 
123  assert("invalid skill!");
124  return 0;
125 }
126 
149 static object *adjust_skill_tool(object *who, object *skill, object *skill_tool) {
150  if (!skill && !skill_tool)
151  return NULL;
152 
153  /* If this is a skill that can be used without a tool and no tool found, return it */
154  if (skill && QUERY_FLAG(skill, FLAG_CAN_USE_SKILL) && (!skill_tool || QUERY_FLAG(skill_tool, FLAG_APPLIED) || strcmp(skill->skill, "clawing") == 0))
155  return skill;
156 
157  /* Player has a tool to use the skill. If not applied, apply it -
158  * if not successful, return skill if can be used. If they do have the skill tool
159  * but not the skill itself, give it to them.
160  */
161  if (skill_tool) {
162  if (!QUERY_FLAG(skill_tool, FLAG_APPLIED)) {
163  if (apply_special(who, skill_tool, 0)) {
165  return skill;
166  else
167  return NULL;
168  }
169  }
170  if (!skill) {
171  skill = give_skill_by_name(who, skill_tool->skill);
172  link_player_skills(who);
173  }
174  return skill;
175  }
177  return skill;
178  else
179  return NULL;
180 }
181 
211 object *find_skill_by_name(object *who, const char *name) {
212  object *skill = NULL, *skills[MAX_SKILLS], *skill_tools[MAX_SKILLS];
213  const char *skill_names[MAX_SKILLS];
214  char *ourname=NULL;
215  int num_names, highest_level_skill=0, i;
216 
217  if (!name)
218  return NULL;
219 
220  /* Simple case - no commas in past in name, so don't need to tokenize */
221  if (!strchr(name, ',')) {
222  skill_names[0] = name;
223  skill_tools[0] = NULL;
224  skills[0] = NULL;
225  num_names = 1;
226  } else {
227  /* strtok_r is destructive, so we need our own copy */
228  char *lasts;
229  ourname = strdup(name);
230 
231  if ((skill_names[0] = strtok_r(ourname, ",", &lasts)) == NULL) {
232  /* This should really never happen */
233  LOG(llevError, "find_skill_by_name: strtok_r returned null, but strchr did not?\n");
234  free(ourname);
235  return NULL;
236  } else {
237  skill_tools[0] = NULL;
238  skills[0] = NULL;
239  /* we already have the first name from the strtok_r above */
240  num_names=1;
241  while ((skill_names[num_names] = strtok_r(NULL, ",", &lasts)) != NULL) {
242  /* Clean out any leading spacing. typical string would be
243  * skill1, skill2, skill3, ...
244  */
245  while (isspace(*skill_names[num_names]))
246  skill_names[num_names]++;
247  skills[num_names] = NULL;
248  skill_tools[num_names] = NULL;
249  num_names++;
250  }
251  }
252  /* While we don't use ourname below this point, the skill_names[] points into
253  * it, so we can't free it yet.
254  */
255  }
256 
257  FOR_INV_PREPARE(who, tmp) {
258  /* We make sure the length of the string in the object is greater
259  * in length than the passed string. Eg, if we have a skill called
260  * 'hi', we don't want to match if the user passed 'high'
261  */
262  if (tmp->type == SKILL || (tmp->type == SKILL_TOOL && !QUERY_FLAG(tmp, FLAG_UNPAID))) {
263  for (i = 0; i<num_names; i++) {
264  if (!strncasecmp(skill_names[i], tmp->skill, strlen(skill_names[i])) &&
265  strlen(tmp->skill) >= strlen(skill_names[i])) {
266  if (tmp->type == SKILL) {
267  skills[i] = tmp;
268  if (!skill || tmp->level > skill->level) {
269  skill = tmp;
270  highest_level_skill=i;
271  }
272  }
273  else {
274  /* Skill tools don't have levels, so we basically find the
275  * 'best' skill tool for this skill.
276  */
277  if (QUERY_FLAG(tmp, FLAG_APPLIED) || !skill_tools[i] ||
278  !QUERY_FLAG(skill_tools[i], FLAG_APPLIED)) {
279  skill_tools[i] = tmp;
280  }
281  }
282  /* Got a matching name - no reason to look through rest of names */
283  break;
284  }
285  }
286  }
287  } FOR_INV_FINISH();
288  free(ourname);
289  return adjust_skill_tool(who, skills[highest_level_skill], skill_tools[highest_level_skill]);
290 }
291 
314 object *find_skill_by_number(object *who, int skillno) {
315  object *skill = NULL, *skill_tool = NULL;
316 
317  if (skillno <= 0 || skillno > MAX_SKILLS) {
318  return NULL;
319  }
320 
321  FOR_INV_PREPARE(who, tmp) {
322  if (tmp->type == SKILL && tmp->subtype == skillno)
323  skill = tmp;
324 
325  /* Try to find appropriate skilltool. If the player has one already
326  * applied, we try to keep using that one.
327  */
328  else if (tmp->type == SKILL_TOOL && tmp->subtype == skillno) {
329  if (QUERY_FLAG(tmp, FLAG_APPLIED))
330  skill_tool = tmp;
331  else if (!skill_tool || !QUERY_FLAG(skill_tool, FLAG_APPLIED))
332  skill_tool = tmp;
333  }
334  } FOR_INV_FINISH();
335 
336  return adjust_skill_tool(who, skill, skill_tool);
337 }
338 
359 int change_skill(object *who, object *new_skill, int flag) {
360  rangetype old_range;
361 
362  if (who->type != PLAYER)
363  return 0;
364 
365  old_range = who->contr->shoottype;
366 
367  /* The readied skill can be a skill tool, so check on actual skill instead of object. */
368  if (new_skill && who->chosen_skill && who->chosen_skill->skill == new_skill->skill) {
369  /* optimization for changing skill to current skill */
370  if (!(flag&0x1))
371  who->contr->shoottype = range_skill;
372  return 1;
373  }
374 
375  if (who->chosen_skill)
376  apply_special(who, who->chosen_skill, AP_UNAPPLY|(flag&AP_NOPRINT));
377 
378  /* Only goal in this case was to unapply a skill */
379  if (!new_skill)
380  return 0;
381 
382  if (apply_special(who, new_skill, AP_APPLY|(flag&AP_NOPRINT))) {
383  return 0;
384  }
385  if (flag&0x1)
386  who->contr->shoottype = old_range;
387 
388  return 1;
389 }
390 
398 void clear_skill(object *who) {
399  who->chosen_skill = NULL;
401  if (who->type == PLAYER) {
402  who->contr->ranges[range_skill] = NULL;
403  if (who->contr->shoottype == range_skill)
404  who->contr->shoottype = range_none;
405  }
406 }
407 
431 int do_skill(object *op, object *part, object *skill, int dir, const char *string) {
432  int success = 0, exp = 0;
433 
434  if (!skill)
435  return 0;
436 
437  /* The code below presumes that the skill points to the object that
438  * holds the exp, level, etc of the skill. So if this is a player
439  * go and try to find the actual real skill pointer, and if the
440  * the player doesn't have a bucket for that, create one.
441  */
442  if (skill->type != SKILL && op->type == PLAYER) {
443  object *tmp;
444 
445  tmp = object_find_by_type_and_skill(op, SKILL, skill->skill);
446  if (!tmp) {
447  tmp = give_skill_by_name(op, skill->skill);
448  if (!tmp) {
449  LOG(llevError, "do_skill: asked for skill %s but couldn't find matching SKILL archetype.\n", skill->skill);
450  return 0;
451  }
452  }
453  skill = tmp;
454  }
455 
456  if (skill->anim_suffix)
457  apply_anim_suffix(op, skill->anim_suffix);
458 
459  switch (skill->subtype) {
460  case SK_LEVITATION:
461  /* Not 100% sure if this will work with new movement code -
462  * the levitation skill has move_type for flying, so when
463  * equipped, that should transfer to player, when not,
464  * shouldn't.
465  */
466  if (QUERY_FLAG(skill, FLAG_APPLIED)) {
469  "You come to earth.");
470  } else {
473  "You rise into the air!.");
474  }
475  fix_object(op);
476  success = 1;
477  break;
478 
479  case SK_STEALING:
480  exp = success = steal(op, dir, skill);
481  break;
482 
483  case SK_LOCKPICKING:
484  exp = success = pick_lock(op, dir, skill);
485  break;
486 
487  case SK_HIDING:
488  exp = success = hide(op, skill);
489  break;
490 
491  case SK_JUMPING:
492  success = jump(op, dir, skill);
493  break;
494 
495  case SK_INSCRIPTION:
496  exp = success = write_on_item(op, string, skill);
497  break;
498 
499  case SK_MEDITATION:
500  meditate(op, skill);
501  success = 1;
502  break;
503  /* note that the following 'attack' skills gain exp through hit_player() */
504 
505  case SK_KARATE:
506  attack_hth(op, dir, "karate-chopped", skill);
507  break;
508 
509  case SK_PUNCHING:
510  attack_hth(op, dir, "punched", skill);
511  break;
512 
513  case SK_FLAME_TOUCH:
514  attack_hth(op, dir, "flamed", skill);
515  break;
516 
517  case SK_CLAWING:
518  attack_hth(op, dir, "clawed", skill);
519  break;
520 
521  case SK_WRAITH_FEED:
522  attack_hth(op, dir, "fed upon", skill);
523  break;
524 
527  (void)attack_melee_weapon(op, dir, NULL, skill);
528  break;
529 
530  case SK_FIND_TRAPS:
531  exp = success = find_traps(op, skill);
532  break;
533 
534  case SK_SINGING:
535  exp = success = singing(op, dir, skill);
536  break;
537 
538  case SK_ORATORY:
539  exp = success = use_oratory(op, dir, skill);
540  break;
541 
542  case SK_SMITHERY:
543  case SK_BOWYER:
544  case SK_JEWELER:
545  case SK_ALCHEMY:
546  case SK_THAUMATURGY:
547  case SK_LITERACY:
548  case SK_WOODSMAN:
549  if (use_alchemy(op) == 0)
550  exp = success = skill_ident(op, skill);
551  break;
552 
553  case SK_DET_MAGIC:
554  case SK_DET_CURSE:
555  exp = success = skill_ident(op, skill);
556  break;
557 
558  case SK_DISARM_TRAPS:
559  exp = success = remove_trap(op, skill);
560  break;
561 
562  case SK_THROWING:
563  success = skill_throw(op, part, dir, skill);
564  break;
565 
566  case SK_SET_TRAP:
568  "This skill is not currently implemented.");
569  break;
570 
571  case SK_USE_MAGIC_ITEM:
572  case SK_MISSILE_WEAPON:
574  "There is no special attack for this skill.");
575  break;
576 
577  case SK_PRAYING:
578  success = pray(op, skill);
579  break;
580 
581  case SK_BARGAINING:
582  success = shop_describe(op);
583  break;
584 
585  case SK_SORCERY:
586  case SK_EVOCATION:
587  case SK_PYROMANCY:
588  case SK_SUMMONING:
589  case SK_CLIMBING:
590  case SK_EARTH_MAGIC:
591  case SK_AIR_MAGIC:
592  case SK_FIRE_MAGIC:
593  case SK_WATER_MAGIC:
595  "This skill is already in effect.");
596  break;
597 
598  case SK_HARVESTING:
599  do_harvest(op, dir, skill);
600  success = 0;
601  break;
602 
603  default: {
604  char name[MAX_BUF];
605 
606  query_name(op, name, MAX_BUF);
607  LOG(llevDebug, "%s attempted to use unknown skill: %d\n", name, op->chosen_skill->stats.sp);
608  break;
609  }
610  }
611 
612  /* For players we now update the speed_left from using the skill.
613  * Monsters have no skill use time because of the random nature in
614  * which use_monster_skill is called already simulates this.
615  * If certain skills should take more/less time, that should be
616  * in the code for the skill itself.
617  */
618 
619  if (op->type == PLAYER)
620  op->speed_left -= 1.0;
621 
622  /* this is a good place to add experience for successful use of skills.
623  * Note that add_exp() will figure out player/monster experience
624  * gain problems.
625  */
626 
627  if (success && exp)
628  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
629 
630  return success;
631 }
632 
667 int64_t calc_skill_exp(const object *who, const object *op, const object *skill) {
668  int64_t op_exp;
669  int op_lvl;
670  float base, value, lvl_mult;
671 
672  if (!skill)
673  skill = who;
674 
675  /* Oct 95 - where we have an object, I expanded our treatment
676  * to 3 cases:
677  * non-living magic obj, runes and everything else.
678  *
679  * If an object is not alive and magical we set the base exp higher to
680  * help out exp awards for skill_ident skills. Also, if
681  * an item is type RUNE, we give out exp based on stats.Cha
682  * and level (this was the old system) -b.t.
683  */
684 
685  if (!op) { /* no item/creature */
686  op_lvl = MAX(who->map->difficulty, 1);
687  op_exp = 0;
688  } else if (op->type == RUNE || op->type == TRAP) { /* all traps. If stats.Cha > 1 we use that
689  * for the amount of experience */
690  op_exp = op->stats.Cha > 1 ? op->stats.Cha : op->stats.exp;
691  op_lvl = op->level;
692  } else { /* all other items/living creatures */
693  op_exp = op->stats.exp;
694  op_lvl = op->level;
695  if (!QUERY_FLAG(op, FLAG_ALIVE)) { /* for ident/make items */
696  op_lvl += 5*abs(op->magic);
697  }
698  }
699 
700  if (op_lvl < 1)
701  op_lvl = 1;
702 
703  if (who->type != PLAYER) { /* for monsters only */
704  return ((int64_t)(op_exp*0.1)+1); /* we add one to insure positive value is returned */
705  }
706 
707  /* for players */
708  base = op_exp;
709  /* if skill really is a skill, then we can look at the skill archetype for
710  * base reward value (exp) and level multiplier factor.
711  */
712  if (skill->type == SKILL) {
713  base += skill->arch->clone.stats.exp;
714  if (settings.simple_exp) {
715  if (skill->arch->clone.level)
716  lvl_mult = (float)skill->arch->clone.level/100.0;
717  else
718  lvl_mult = 1.0; /* no adjustment */
719  } else {
720  if (skill->level)
721  lvl_mult = ((float)skill->arch->clone.level*(float)op_lvl)/((float)skill->level*100.0);
722  else
723  lvl_mult = 1.0;
724  }
725  } else {
726  /* Don't divide by zero here! */
727  lvl_mult = (float)op_lvl/(float)(skill->level ? skill->level : 1);
728  }
729 
730  /* assemble the exp total, and return value */
731 
732  value = base*lvl_mult;
733  if (value < 1)
734  value = 1; /* Always give at least 1 exp point */
735 
736 #ifdef SKILL_UTIL_DEBUG
737  LOG(llevDebug, "calc_skill_exp(): who: %s(lvl:%d) op:%s(lvl:%d)\n", who->name, skill->level, op ? op->name : "", op_lvl);
738 #endif
739  return ((int64_t)value);
740 }
741 
759 int learn_skill(object *pl, object *scroll) {
760  object *tmp;
761 
762  if (!scroll->skill) {
763  LOG(llevError, "skill scroll %s does not have skill pointer set.\n", scroll->name);
764  return 2;
765  }
766 
767  /* can't use find_skill_by_name because we want skills the player knows
768  * but can't use natively.
769  */
770 
771  tmp = NULL;
772  FOR_INV_PREPARE(pl, inv)
773  if (inv->type == SKILL && !strncasecmp(scroll->skill, inv->skill, strlen(scroll->skill))) {
774  tmp = inv;
775  break;
776  }
777  FOR_INV_FINISH();
778 
779  /* player already knows it */
780  if (tmp && QUERY_FLAG(tmp, FLAG_CAN_USE_SKILL))
781  return 0;
782 
783  /* now a random change to learn, based on player Int.
784  * give bonus based on level - otherwise stupid characters
785  * might never be able to learn anything.
786  */
787  if (random_roll(0, 99, pl, PREFER_LOW) > (get_learn_spell(pl->stats.Int)+(pl->level/5)))
788  return 2; /* failure :< */
789 
790  if (!tmp)
791  tmp = give_skill_by_name(pl, scroll->skill);
792 
793  if (!tmp) {
794  LOG(llevError, "skill scroll %s does not have valid skill name (%s).\n", scroll->name, scroll->skill);
795  return 2;
796  }
797 
800  return 1;
801 }
802 
814 static int clipped_percent(int64_t a, int64_t b) {
815  int rv;
816 
817  if (b <= 0)
818  return 0;
819 
820  rv = (int)((100.0f*((float)a)/((float)b))+0.5f);
821 
822  if (rv < 0)
823  return 0;
824  else if (rv > 100)
825  return 100;
826 
827  return rv;
828 }
829 
830 
839 static int digits_in_long(int64_t num)
840 {
841  return num == 0 ? 1 : floor( log10( labs(num) ) ) + 1;
842 }
843 
860 void show_skills(object *op, const char *parms) {
861  const char *cp;
862  int i, num_skills_found = 0;
863  /* Need to have a pointer and use strdup for qsort to work properly */
864  char skills[MAX_SKILLS][MAX_BUF];
865  const char *search = parms;
866  bool long_format = false;
867 
868  if ( parms && strncmp(parms,"-l",2) == 0 ) {
869  long_format = true;
870  search += 2;
871  while ( *search && *search != ' ' ) ++search; /* move past other parameters */
872  while ( *search == ' ' ) ++search;
873  }
874  FOR_INV_PREPARE(op, tmp) {
875  if (tmp->type == SKILL) {
876  if (search && strstr(tmp->name, search) == NULL)
877  continue;
878 
880  if ( long_format ) {
881  int perm_level = exp_level(tmp->total_exp * settings.permanent_exp_ratio / 100);
882  snprintf(skills[num_skills_found++], MAX_BUF, "[fixed]%-20slvl:%3d (xp:%" FMT64 "/%" FMT64 ")%-*sperm lvl:%3d (xp:%" FMT64 "/%" FMT64 ") ",
883  tmp->name, tmp->level,
884  tmp->stats.exp,
885  level_exp(tmp->level+1, op->expmul),
886  1+2*digits_in_long(op->stats.exp)-digits_in_long(tmp->stats.exp)-digits_in_long(level_exp(tmp->level+1, op->expmul)),
887  "",
888  perm_level,
889  tmp->total_exp * settings.permanent_exp_ratio / 100,
890  level_exp(perm_level+1, op->expmul));
891  } else {
892  snprintf(skills[num_skills_found++], MAX_BUF, "[fixed]%-20slvl:%3d (xp:%" FMT64 "/%" FMT64 "/%d%%)",
893  tmp->name, tmp->level,
894  tmp->stats.exp,
895  level_exp(tmp->level+1, op->expmul),
896  clipped_percent(PERM_EXP(tmp->total_exp), tmp->stats.exp));
897  }
898  } else {
899  snprintf(skills[num_skills_found++], MAX_BUF, "[fixed]%-20slvl:%3d (xp:%" FMT64 "/%" FMT64 ")",
900  tmp->name, tmp->level,
901  tmp->stats.exp,
902  level_exp(tmp->level+1, op->expmul));
903  }
904  /* I don't know why some characters get a bunch of skills, but
905  * it sometimes happens (maybe a leftover from buggier earlier code
906  * and those character are still about). In any case, lets handle
907  * it so it doesn't crash the server - otherwise, one character may
908  * crash the server numerous times.
909  */
910  if (num_skills_found >= MAX_SKILLS) {
912  "Your character has too many skills.\n"
913  "Something isn't right - contact the server admin");
914  break;
915  }
916  }
917  } FOR_INV_FINISH();
918 
919  if ( search && *search ) {
921  "Player skills%s: (matching '%s')", long_format ? " (long format)":"",search);
922  } else {
924  "Player skills%s:", long_format ? " (long format)":"");
925  }
926 
927  if (num_skills_found > 1)
928  qsort(skills, num_skills_found, MAX_BUF, (int (*)(const void *, const void *))strcmp);
929 
930  for (i = 0; i < num_skills_found; i++) {
932  skills[i]);
933  }
934 
935  cp = determine_god(op);
936  if (strcmp(cp, "none") == 0)
937  cp = NULL;
938 
940  "You can handle %d weapon improvements.\n"
941  "You worship %s.\n"
942  "Your equipped item power is %d out of %d\n",
943  op->level/5+5,
944  cp ? cp : "no god at current time",
945  op->contr->item_power, op->level);
946 }
947 
964 int use_skill(object *op, const char *string) {
965  object *skop;
966  size_t len;
967 
968  if (!string)
969  return 0;
970 
971  skop = NULL;
972  FOR_INV_PREPARE(op, tmp) {
973  if (tmp->type == SKILL
975  && !strncasecmp(string, tmp->skill, MIN(strlen(string), strlen(tmp->skill)))) {
976  skop = tmp;
977  break;
978  } else if (tmp->type == SKILL_TOOL
979  && !QUERY_FLAG(tmp, FLAG_UNPAID) /* Holy symbols could be used unpaid w/o this */
980  && !strncasecmp(string, tmp->skill, MIN(strlen(string), strlen(tmp->skill)))) {
981  skop = tmp;
982  break;
983  }
984  } FOR_INV_FINISH();
985  if (!skop) {
987  "Unable to find skill %s",
988  string);
989  return 0;
990  }
991 
992  len = strlen(skop->skill);
993 
994  /* All this logic goes and skips over the skill name to find any
995  * options given to the skill. Its pretty simple - if there
996  * are extra parameters (as determined by string length), we
997  * want to skip over any leading spaces.
998  */
999  if (len >= strlen(string)) {
1000  string = NULL;
1001  } else {
1002  string += len;
1003  while (*string == 0x20)
1004  string++;
1005  if (strlen(string) == 0)
1006  string = NULL;
1007  }
1008 
1009 #ifdef SKILL_UTIL_DEBUG
1010  LOG(llevDebug, "use_skill() got skill: %s\n", sknum > -1 ? skills[sknum].name : "none");
1011 #endif
1012 
1013  /* Change to the new skill, then execute it. */
1014  if (do_skill(op, op, skop, op->facing, string))
1015  return 1;
1016 
1017  return 0;
1018 }
1019 
1042 static object *find_best_player_hth_skill(object *op) {
1043  object *best_skill = NULL;
1044  int last_skill;
1045 
1046  if (op->contr->unarmed_skill) {
1047  /* command_unarmed_skill() already does these checks, and right
1048  * now I do not think there is any way to lose unarmed skills.
1049  * But maybe in the future there will be (polymorph?) so handle
1050  * it appropriately. MSW 2009-07-03
1051  *
1052  * Note that the error messages should only print out once when
1053  * the initial failure to switch skills happens, so the player
1054  * should not get spammed with tons of messages unless they have
1055  * no valid unarmed skill
1056  */
1057 
1058  best_skill = find_skill_by_name(op, op->contr->unarmed_skill);
1059 
1060  if (!best_skill) {
1062  "Unable to find skill %s - using default unarmed skill",
1063  op->contr->unarmed_skill);
1064  } else {
1065  size_t i;
1066 
1067  for (i = 0; i < sizeof(unarmed_skills); i++)
1068  if (best_skill->subtype == unarmed_skills[i])
1069  break;
1070  if (i < sizeof(unarmed_skills))
1071  return(best_skill);
1072  }
1073  /* If for some reason the unarmed_skill is not valid, we fall
1074  * through the processing below.
1075  */
1076  }
1077 
1078 
1079  /* Dragons are a special case - gros 25th July 2006 */
1080  /* Perhaps this special case should be removed and unarmed_skill
1081  * set to clawing for dragon characters? MSW 2009-07-03
1082  */
1083  if (is_dragon_pl(op)) {
1084  object *tmp;
1085 
1086  tmp = find_skill_by_number(op, SK_CLAWING);
1087  if (tmp) /* I suppose it should always be true - but maybe there's
1088  * draconic toothache ? :) */
1089  return tmp;
1090  }
1091 
1092  last_skill = sizeof(unarmed_skills);
1093  FOR_INV_PREPARE(op, tmp) {
1094  if (tmp->type == SKILL) {
1095  int i;
1096 
1097  /* The order in the array is preferred order. So basically,
1098  * we just cut down the number to search - eg, if we find a skill
1099  * early on in flame touch, then we only need to look into the unarmed_array
1100  * to the entry before flame touch - don't care about the entries afterward,
1101  * because they are inferior skills.
1102  * if we end up finding the best skill (i==0) might as well return
1103  * right away - can't get any better than that.
1104  */
1105  for (i = 0; i < last_skill; i++) {
1106  if (tmp->subtype == unarmed_skills[i] && QUERY_FLAG(tmp, FLAG_CAN_USE_SKILL)) {
1107  best_skill = tmp;
1108  last_skill = i;
1109  if (i == 0)
1110  return best_skill;
1111  }
1112  }
1113  }
1114  } FOR_INV_FINISH();
1115  return best_skill;
1116 }
1117 
1131 static void do_skill_attack(object *tmp, object *op, const char *string, object *skill) {
1132  int success;
1133 
1134  /* For Players only: if there is no ready weapon, and no "attack" skill
1135  * is readied either then try to find a skill for the player to use.
1136  * it is presumed that if skill is set, it is a valid attack skill (eg,
1137  * the caller should have set it appropriately). We still want to pass
1138  * through that code if skill is set to change to the skill.
1139  */
1140  if (op->type == PLAYER) {
1141  if (!QUERY_FLAG(op, FLAG_READY_WEAPON)) {
1142  size_t i;
1143 
1144  if (!skill) {
1145  /* See if the players chosen skill is a combat skill, and use
1146  * it if appropriate.
1147  */
1148  if (op->chosen_skill) {
1149  /* the list is 0-terminated, and talismans, which can be in chosen_skill,
1150  * have a subtype of 0, therefore don't check the 0 */
1151  for (i = 0; unarmed_skills[i] != 0; i++)
1152  if (op->chosen_skill->subtype == unarmed_skills[i]) {
1153  skill = op->chosen_skill;
1154  break;
1155  }
1156  }
1157  /* If we didn't find a skill above, look harder for a good skill */
1158  if (!skill) {
1160 
1161  if (!skill) {
1162  draw_ext_info(NDI_BLACK, 0, op,
1164  "You have no unarmed combat skills!");
1165  return;
1166  }
1167  }
1168  }
1169  if (skill != op->chosen_skill) {
1170  /* now try to ready the new skill */
1171  if (!change_skill(op, skill, 1)) { /* oh oh, trouble! */
1174  "Couldn't change to skill %s",
1175  skill->name);
1176  return;
1177  }
1178  }
1179  } else {
1180  /* Seen some crashes below where current_weapon is not set,
1181  * even though the flag says it is. So if current weapon isn't set,
1182  * do some work in trying to find the object to use.
1183  */
1184  if (!op->current_weapon) {
1185  object *tmp;
1186 
1187  LOG(llevError, "Player %s does not have current weapon set but flag_ready_weapon is set\n", op->name);
1189  if (!tmp) {
1190  LOG(llevError, "Could not find applied weapon on %s\n", op->name);
1191  op->current_weapon = NULL;
1192  return;
1193  } else {
1194  char weapon[MAX_BUF];
1195 
1196  query_name(tmp, weapon, MAX_BUF);
1197  op->current_weapon = tmp;
1198  }
1199  }
1200 
1201  /* Has ready weapon - make sure chosen_skill is set up properly */
1202  if (!op->chosen_skill || op->current_weapon->skill != op->chosen_skill->skill) {
1203  object *found_skill = find_skill_by_name(op, op->current_weapon->skill);
1204  assert(found_skill != NULL);
1205  change_skill(op, found_skill, 1);
1206  }
1207  }
1208  }
1209 
1210  /* lose invisibility/hiding status for running attacks */
1211 
1212  if (op->type == PLAYER && op->contr->tmp_invis) {
1213  op->contr->tmp_invis = 0;
1214  op->invisible = 0;
1215  op->hide = 0;
1217  }
1218 
1219  success = attack_ob(tmp, op);
1220 
1221  if (tmp && !QUERY_FLAG(tmp, FLAG_FREED)) {
1222  char op_name[MAX_BUF];
1223  if (!success) { // In case of miss, attack_ob didn't print anything
1224  query_name(tmp, op_name, MAX_BUF);
1227  "You miss %s!",
1228  op_name);
1229  } else if (string != NULL) { // If string is NULL, message was already displayed
1230  if (op->type == PLAYER) {
1231  query_name(tmp, op_name, MAX_BUF);
1234  "You %s %s!",
1235  string, op_name);
1236  } else if (tmp->type == PLAYER) {
1237  query_name(op, op_name, MAX_BUF);
1240  "%s %s you!",
1241  op_name, string);
1242  }
1243  }
1244  }
1245 }
1246 
1270 void skill_attack(object *tmp, object *pl, int dir, const char *string, object *skill) {
1271  int16_t tx, ty;
1272  mapstruct *m;
1273  int mflags;
1274 
1275  if (!dir)
1276  dir = pl->facing;
1277  tx = freearr_x[dir];
1278  ty = freearr_y[dir];
1279 
1280  /* If we don't yet have an opponent, find if one exists, and attack.
1281  * Legal opponents are the same as outlined in move_player_attack()
1282  */
1283 
1284  if (tmp == NULL) {
1285  m = pl->map;
1286  tx = pl->x+freearr_x[dir];
1287  ty = pl->y+freearr_y[dir];
1288 
1289  mflags = get_map_flags(m, &m, tx, ty, &tx, &ty);
1290  if (mflags&P_OUT_OF_MAP)
1291  return;
1292 
1293  /* space must be blocked for there to be anything interesting to do */
1294  if (!(mflags&P_IS_ALIVE)
1295  && !OB_TYPE_MOVE_BLOCK(pl, GET_MAP_MOVE_BLOCK(m, tx, ty))) {
1296  return;
1297  }
1298 
1299  FOR_MAP_PREPARE(m, tx, ty, tmp2)
1300  if ((QUERY_FLAG(tmp2, FLAG_ALIVE) && tmp2->stats.hp >= 0)
1301  || QUERY_FLAG(tmp2, FLAG_CAN_ROLL)
1302  || tmp2->type == LOCKED_DOOR) {
1303  /* Don't attack party members */
1304  if ((pl->type == PLAYER && tmp2->type == PLAYER)
1305  && (pl->contr->party != NULL && pl->contr->party == tmp2->contr->party))
1306  return;
1307  tmp = tmp2;
1308  break;
1309  }
1310  FOR_MAP_FINISH();
1311  }
1312  if (!tmp) {
1313  if (pl->type == PLAYER)
1315  "There is nothing to attack!");
1316  return;
1317  }
1318 
1319  do_skill_attack(tmp, pl, string, skill);
1320 }
1321 
1340 static void attack_hth(object *pl, int dir, const char *string, object *skill) {
1341  object *weapon;
1342 
1345  if (weapon != NULL) {
1346  if (apply_special(pl, weapon, AP_UNAPPLY|AP_NOPRINT)) {
1347  char weaponname[MAX_BUF];
1348 
1349  query_name(weapon, weaponname, MAX_BUF);
1352  "You are unable to unwield %s in order to attack with %s.",
1353  weaponname, skill->name);
1354  return;
1355  } else {
1357  "You unwield your weapon in order to attack.");
1358  }
1359  }
1360  }
1361  skill_attack(NULL, pl, dir, string, skill);
1362 }
1363 
1384 static void attack_melee_weapon(object *op, int dir, const char *string, object *skill) {
1385  if (!QUERY_FLAG(op, FLAG_READY_WEAPON)) {
1386  if (op->type == PLAYER)
1388  "You have no ready weapon to attack with!");
1389  return;
1390  }
1391  skill_attack(NULL, op, dir, string, skill);
1392 }
Face
New face structure - this enforces the notion that data is face by face only - you can not change the...
Definition: face.h:14
living::exp
int64_t exp
Experience.
Definition: living.h:47
UP_OBJ_FACE
#define UP_OBJ_FACE
Only thing that changed was the face.
Definition: object.h:533
skills
Player Stats effect how well a character can survie and interact inside the crossfire world This section discusses the various what they and how they effect the player s actions Also in this section are the stat modifiers that specific classes professions bring Player and sps the current and maximum the Current and Maximum The Current Sp can go somewhat negative When Sp is negative not all spells can be and a more negative Sp makes spell casting less likey to succeed can affect Damage and how the characters as well as how often the character can attack this affects the prices when buying and selling items if this drops the player will start losing hit points wd Cleric or Dwarf sm Elf wd Fireborn ft Human ra Mage C Monk se Ninja hi Priest C Quetzalcoatl mw Swashbuckler si Thief st Viking ba Warrior or Wizard C Wraith C Class Prof Str Dex Con Wis Cha Int Pow Net Skills Enclosed are codes used for the skills above The ones in and fighting should all be pretty self explanatory For the other skills
Definition: stats.txt:126
PLAYER
@ PLAYER
Definition: object.h:112
global.h
settings
struct Settings settings
Server settings.
Definition: init.cpp:139
Settings::simple_exp
uint8_t simple_exp
If true, use the simple experience system.
Definition: global.h:265
FOR_MAP_FINISH
#define FOR_MAP_FINISH()
Finishes FOR_MAP_PREPARE().
Definition: define.h:724
SK_FIRE_MAGIC
@ SK_FIRE_MAGIC
Fire magic, unused.
Definition: skills.h:62
object_find_by_type_applied
object * object_find_by_type_applied(const object *who, int type)
Find applied object in inventory.
Definition: object.cpp:4083
MSG_TYPE_ATTACK_MISS
#define MSG_TYPE_ATTACK_MISS
attack didn't hit
Definition: newclient.h:623
player::unarmed_skill
const char * unarmed_skill
Prefered skill to use in unarmed combat.
Definition: player.h:221
AP_APPLY
#define AP_APPLY
Item is to be applied.
Definition: define.h:568
llevError
@ llevError
Error, serious thing.
Definition: logger.h:11
learn_skill
int learn_skill(object *pl, object *scroll)
Player is trying to learn a skill.
Definition: skill_util.cpp:759
mapstruct::difficulty
uint16_t difficulty
What level the player should be to play here.
Definition: map.h:333
SK_INSCRIPTION
@ SK_INSCRIPTION
Inscription.
Definition: skills.h:41
LOG
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:58
use_alchemy
int use_alchemy(object *op)
Handle use_skill for alchemy-like items.
Definition: alchemy.cpp:1057
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:224
do_skill_attack
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.cpp:1131
SK_ALCHEMY
@ SK_ALCHEMY
Alchemy.
Definition: skills.h:25
MSG_TYPE_SKILL
#define MSG_TYPE_SKILL
Messages related to skill use.
Definition: newclient.h:410
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
archetypes_for_each
void archetypes_for_each(arch_op op)
Definition: assets.cpp:300
SK_CLAWING
@ SK_CLAWING
Clawing.
Definition: skills.h:50
Settings::permanent_exp_ratio
uint8_t permanent_exp_ratio
How much exp should be 'permenant' and unable to be lost.
Definition: global.h:260
MSG_TYPE_ATTACK_DID_HIT
#define MSG_TYPE_ATTACK_DID_HIT
Player hit something else.
Definition: newclient.h:615
SK_DET_MAGIC
@ SK_DET_MAGIC
Detect magic.
Definition: skills.h:30
object::invisible
int16_t invisible
How much longer the object will be invis.
Definition: object.h:370
TRAP
@ TRAP
Definition: object.h:246
object::x
int16_t x
Definition: object.h:335
SK_DISARM_TRAPS
@ SK_DISARM_TRAPS
Disarm traps.
Definition: skills.h:46
object::speed_left
float speed_left
How much speed is left to spend this round.
Definition: object.h:338
PREFER_LOW
#define PREFER_LOW
Definition: define.h:558
object::map
struct mapstruct * map
Pointer to the map in which this object is present.
Definition: object.h:305
give_skill_by_name
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.cpp:1788
WEAPON
@ WEAPON
Definition: object.h:124
object::expmul
double expmul
needed experience = (calc_exp*expmul) - means some races/classes can need less/more exp to gain level...
Definition: object.h:407
SK_PRAYING
@ SK_PRAYING
Praying.
Definition: skills.h:49
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:1762
range_none
@ range_none
No range selected.
Definition: player.h:30
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
use_oratory
int use_oratory(object *pl, int dir, object *skill)
Oratory skill handling.
Definition: skills.cpp:996
MIN
#define MIN(x, y)
Definition: compat.h:21
SKILL
@ SKILL
Also see SKILL_TOOL (74) below.
Definition: object.h:148
singing
int singing(object *pl, int dir, object *skill)
Singing skill handling.
Definition: skills.cpp:1149
RUNE
@ RUNE
Definition: object.h:245
skill_ident
int skill_ident(object *pl, object *skill)
Main identification skill handling.
Definition: skills.cpp:927
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
object_find_by_type_and_skill
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.cpp:4183
SK_KARATE
@ SK_KARATE
Karate.
Definition: skills.h:38
NDI_RED
#define NDI_RED
Definition: newclient.h:248
SEE_LAST_ERROR
@ SEE_LAST_ERROR
Definition: define.h:52
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:1240
SK_MEDITATION
@ SK_MEDITATION
Meditation.
Definition: skills.h:35
SK_SET_TRAP
@ SK_SET_TRAP
Set traps, unused.
Definition: skills.h:47
skills.h
object::hide
uint8_t hide
The object is hidden, not invisible.
Definition: object.h:397
find_skill_by_number
object * find_skill_by_number(object *who, int skillno)
This returns the first skill pointer of the given subtype (the one that accumulates exp,...
Definition: skill_util.cpp:314
skill_messages
sstring skill_messages[MAX_SKILLS]
Will contain the message for the skills, initialized by init_skill().
Definition: skill_util.cpp:69
P_IS_ALIVE
#define P_IS_ALIVE
Something alive is on this space.
Definition: map.h:237
FLAG_APPLIED
#define FLAG_APPLIED
Object is ready for use by living.
Definition: define.h:235
object::level
int16_t level
Level of creature or object.
Definition: object.h:361
SK_SINGING
@ SK_SINGING
Singing.
Definition: skills.h:32
SK_SORCERY
@ SK_SORCERY
Sorcery.
Definition: skills.h:55
digits_in_long
static int digits_in_long(int64_t num)
Gives the number of digits that ld will print for a long int.
Definition: skill_util.cpp:839
MSG_TYPE_VICTIM
#define MSG_TYPE_VICTIM
Something bad is happening to the player.
Definition: newclient.h:418
MAX
#define MAX(x, y)
Definition: compat.h:24
free_skill_index
static int free_skill_index()
Definition: skill_util.cpp:71
name
Plugin animator file specs[Config] name
Definition: animfiles.txt:4
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
SK_EARTH_MAGIC
@ SK_EARTH_MAGIC
Earth magic, unused.
Definition: skills.h:60
FLAG_ALIVE
#define FLAG_ALIVE
Object can fight (or be fought)
Definition: define.h:230
object::y
int16_t y
Position in the map for this object.
Definition: object.h:335
m
static event_registration m
Definition: citylife.cpp:422
skill_names
const char * skill_names[MAX_SKILLS]
Will contain a number-name mapping for skills, initialized by init_skills().
Definition: skill_util.cpp:59
object_update
void object_update(object *op, int action)
object_update() updates the array which represents the map.
Definition: object.cpp:1434
object::contr
struct player * contr
Pointer to the player which control this object.
Definition: object.h:284
FMT64
#define FMT64
Definition: compat.h:16
object::chosen_skill
object * chosen_skill
The skill chosen to use.
Definition: object.h:396
pick_lock
int pick_lock(object *pl, int dir, object *skill)
Lock pick handling.
Definition: skills.cpp:391
object::subtype
uint8_t subtype
Subtype of object.
Definition: object.h:349
SK_HARVESTING
@ SK_HARVESTING
Harvesting.
Definition: skills.h:58
change_skill
int change_skill(object *who, object *new_skill, int flag)
This changes the object's skill to new_skill.
Definition: skill_util.cpp:359
add_refcount
sstring add_refcount(sstring str)
This will increase the refcount of the string str.
Definition: shstr.cpp:210
SK_TWO_HANDED_WEAPON
@ SK_TWO_HANDED_WEAPON
Two handed weapons.
Definition: skills.h:56
determine_god
const char * determine_god(object *op)
Determines if op worships a god.
Definition: gods.cpp:55
freearr_y
short freearr_y[SIZEOFFREE]
Y offset when searching around a spot.
Definition: object.cpp:305
SK_JEWELER
@ SK_JEWELER
Jeweler.
Definition: skills.h:24
attack_hth
static void attack_hth(object *pl, int dir, const char *string, object *skill)
This handles all hand-to-hand attacks.
Definition: skill_util.cpp:1340
clipped_percent
static int clipped_percent(int64_t a, int64_t b)
Gives a percentage clipped to 0% -> 100% of a/b.
Definition: skill_util.cpp:814
query_name
void query_name(const object *op, char *buf, size_t size)
Describes an item.
Definition: item.cpp:588
shop_describe
int shop_describe(const object *op)
Give the player a description of the shop on their current map.
Definition: shop.cpp:1198
player::ranges
object * ranges[range_size]
Object for each range.
Definition: player.h:116
SK_LITERACY
@ SK_LITERACY
Literacy.
Definition: skills.h:27
remove_trap
int remove_trap(object *op, object *skill)
This skill will disarm any previously discovered trap.
Definition: skills.cpp:1311
SK_DET_CURSE
@ SK_DET_CURSE
Detect curse.
Definition: skills.h:33
archetype::clone
object clone
An object from which to do object_copy()
Definition: object.h:487
add_string
sstring add_string(const char *str)
This will add 'str' to the hash table.
Definition: shstr.cpp:124
apply_anim_suffix
void apply_anim_suffix(object *who, const char *suffix)
Applies a compound animation to an object.
Definition: anim.cpp:150
SK_BOWYER
@ SK_BOWYER
Bowyer.
Definition: skills.h:23
FLAG_FREED
#define FLAG_FREED
Object is in the list of free objects.
Definition: define.h:233
LOCKED_DOOR
@ LOCKED_DOOR
Definition: object.h:128
do_skill
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.cpp:431
skill_faces
const Face * skill_faces[MAX_SKILLS]
Will contain the face numbers for the skills, initialized by init_skill().
Definition: skill_util.cpp:63
object::face
const Face * face
Face with colors.
Definition: object.h:341
exp_level
int exp_level(int64_t exp)
Returns the level for a given exp.
Definition: living.cpp:1897
MSG_TYPE_ATTACK
#define MSG_TYPE_ATTACK
Attack related messages.
Definition: newclient.h:412
SK_EVOCATION
@ SK_EVOCATION
Evocation.
Definition: skills.h:54
player::tmp_invis
uint32_t tmp_invis
Will invis go away when we attack?
Definition: player.h:140
object::type
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:348
object::magic
int8_t magic
Any magical bonuses to this item.
Definition: object.h:358
GET_MAP_MOVE_BLOCK
#define GET_MAP_MOVE_BLOCK(M, X, Y)
Gets the blocking state of a square.
Definition: map.h:192
FOR_INV_FINISH
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:671
FLAG_CAN_ROLL
#define FLAG_CAN_ROLL
Object can be rolled.
Definition: define.h:254
player::item_power
int16_t item_power
Total item power of objects equipped.
Definition: player.h:130
MSG_TYPE_SKILL_MISSING
#define MSG_TYPE_SKILL_MISSING
Don't have the skill.
Definition: newclient.h:590
change_exp
void change_exp(object *op, int64_t exp, const char *skill_name, int flag)
Changes experience to a player/monster.
Definition: living.cpp:2179
rangetype
rangetype
What range is currently selected by the player.
Definition: player.h:28
SK_BARGAINING
@ SK_BARGAINING
Bargaining.
Definition: skills.h:28
level_exp
int64_t level_exp(int level, double expmul)
Returns how much experience is needed for a player to become the given level.
Definition: living.cpp:1885
archetype
The archetype structure is a set of rules on how to generate and manipulate objects which point to ar...
Definition: object.h:483
player::shoottype
rangetype shoottype
Which range-attack is being used by player.
Definition: player.h:112
pray
int pray(object *pl, object *skill)
Praying skill handling.
Definition: skills.cpp:1384
SK_SUMMONING
@ SK_SUMMONING
Summoning.
Definition: skills.h:52
sproto.h
SK_AIR_MAGIC
@ SK_AIR_MAGIC
Air magic, unused.
Definition: skills.h:59
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:1270
do_each_skill
static void do_each_skill(archetype *at)
Definition: skill_util.cpp:80
living::sp
int16_t sp
Spell points.
Definition: living.h:42
MAX_SKILLS
#define MAX_SKILLS
This is the maximum number of skills the game may handle.
Definition: skills.h:70
FLAG_CAN_USE_SKILL
#define FLAG_CAN_USE_SKILL
The monster can use skills.
Definition: define.h:321
MSG_TYPE_VICTIM_WAS_HIT
#define MSG_TYPE_VICTIM_WAS_HIT
Player was hit by something.
Definition: newclient.h:654
skill_throw
int skill_throw(object *op, object *part, int dir, object *skill)
Throwing skill handling.
Definition: skills.cpp:2277
get_skill_client_code
int get_skill_client_code(const char *skill_name)
Return the code of the skill for a client, the index in the skill_names array.
Definition: skill_util.cpp:116
living::Int
int8_t Int
Definition: living.h:36
clear_skill
void clear_skill(object *who)
This function just clears the chosen_skill and range_skill values in the player.
Definition: skill_util.cpp:398
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
attack_melee_weapon
static void attack_melee_weapon(object *op, int dir, const char *string, object *skill)
This handles melee weapon attacks -b.t.
Definition: skill_util.cpp:1384
NDI_BLACK
#define NDI_BLACK
Definition: newclient.h:245
fatal
void fatal(enum fatal_error err)
fatal() is meant to be called whenever a fatal signal is intercepted.
Definition: utils.cpp:590
P_OUT_OF_MAP
#define P_OUT_OF_MAP
This space is outside the map.
Definition: map.h:249
MAX_BUF
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
find_best_player_hth_skill
static object * find_best_player_hth_skill(object *op)
Finds the best unarmed skill the player has, and returns it.
Definition: skill_util.cpp:1042
adjust_skill_tool
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.cpp:149
object::current_weapon
object * current_weapon
Pointer to the weapon currently used.
Definition: object.h:380
SK_FLAME_TOUCH
@ SK_FLAME_TOUCH
Flame-touch.
Definition: skills.h:37
SK_JUMPING
@ SK_JUMPING
Jumping.
Definition: skills.h:29
SK_HIDING
@ SK_HIDING
Hiding.
Definition: skills.h:21
SK_LEVITATION
@ SK_LEVITATION
Levitation.
Definition: skills.h:51
FOR_MAP_PREPARE
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Constructs a loop iterating over all objects of a map tile.
Definition: define.h:717
FLAG_READY_SKILL
#define FLAG_READY_SKILL
(Monster or Player) has a skill readied
Definition: define.h:333
PERM_EXP
#define PERM_EXP(exptotal)
Convert saved total experience into permanent experience.
Definition: global.h:232
SK_LOCKPICKING
@ SK_LOCKPICKING
Lockpicking.
Definition: skills.h:20
MSG_TYPE_SKILL_ERROR
#define MSG_TYPE_SKILL_ERROR
Doing something wrong.
Definition: newclient.h:591
SK_WOODSMAN
@ SK_WOODSMAN
Woodsman.
Definition: skills.h:40
NDI_UNIQUE
#define NDI_UNIQUE
Print immediately, don't buffer.
Definition: newclient.h:265
spells.h
object::name
sstring name
The name of the object, obviously...
Definition: object.h:319
MSG_TYPE_SKILL_FAILURE
#define MSG_TYPE_SKILL_FAILURE
Failure in using skill.
Definition: newclient.h:593
use_skill
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.cpp:964
is_dragon_pl
int is_dragon_pl(const object *op)
Checks if player is a dragon.
Definition: player.cpp:122
get_learn_spell
int get_learn_spell(int stat)
Definition: living.cpp:2377
SK_PUNCHING
@ SK_PUNCHING
Punching.
Definition: skills.h:36
MSG_TYPE_SKILL_LIST
#define MSG_TYPE_SKILL_LIST
List of skills.
Definition: newclient.h:595
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
mapstruct
This is a game-map.
Definition: map.h:315
sstring
const typedef char * sstring
Definition: sstring.h:2
floor
Magical Runes Runes are magical inscriptions on the dungeon floor
Definition: runes-guide.txt:3
living::Cha
int8_t Cha
Definition: living.h:36
object::skill
sstring skill
Name of the skill this object uses/grants.
Definition: object.h:329
SK_STEALING
@ SK_STEALING
Stealing.
Definition: skills.h:26
shop.h
object::msg
sstring msg
If this is a book/sign/magic mouth/etc.
Definition: object.h:330
unpaid_count::pl
object * pl
Definition: shop.cpp:740
SKILL_TOOL
@ SKILL_TOOL
Allows the use of a skill.
Definition: object.h:194
assets.h
SK_MISSILE_WEAPON
@ SK_MISSILE_WEAPON
Missile weapon.
Definition: skills.h:43
CLEAR_FLAG
#define CLEAR_FLAG(xyz, p)
Definition: define.h:225
do_harvest
void do_harvest(object *pl, int dir, object *skill)
Player is trying to harvest something.
Definition: c_misc.cpp:2263
SK_SUBTRACT_SKILL_EXP
#define SK_SUBTRACT_SKILL_EXP
Used when removing exp.
Definition: skills.h:81
apply_special
int apply_special(object *who, object *op, int aflags)
Apply an object.
Definition: apply.cpp:1156
AP_NOPRINT
#define AP_NOPRINT
Don't print messages - caller will do that may be some that still print.
Definition: define.h:579
SK_ONE_HANDED_WEAPON
@ SK_ONE_HANDED_WEAPON
One handed weapon.
Definition: skills.h:42
show_skills
void show_skills(object *op, const char *parms)
Displays a player's skill list, and some other non skill related info (god, max weapon improvements,...
Definition: skill_util.cpp:860
player::party
partylist * party
Party this player is part of.
Definition: player.h:203
meditate
void meditate(object *pl, object *skill)
Meditation skill handling.
Definition: skills.cpp:1432
steal
int steal(object *op, int dir, object *skill)
Main stealing function.
Definition: skills.cpp:279
SK_PYROMANCY
@ SK_PYROMANCY
Pyromancy.
Definition: skills.h:53
calc_skill_exp
int64_t calc_skill_exp(const object *who, const object *op, const object *skill)
Calculates amount of experience can be gained for successful use of a skill.
Definition: skill_util.cpp:667
init_skills
void init_skills(void)
This just sets up the skill_names table above.
Definition: skill_util.cpp:99
SK_SMITHERY
@ SK_SMITHERY
Smithery.
Definition: skills.h:22
skill
skill
Definition: arch-handbook.txt:585
a
Magical Runes Runes are magical inscriptions on the dungeon which cast a spell or detonate when something steps on them Flying objects don t detonate runes Beware ! Runes are invisible most of the time They are only visible occasionally ! There are several runes which are there are some special runes which may only be called with the invoke and people may apply it to read it Maybe useful for mazes ! This rune will not nor is it ordinarily invisible Partial Visibility of they ll be visible only part of the time They have a(your level/2) chance of being visible in any given round
FLAG_UNPAID
#define FLAG_UNPAID
Object hasn't been paid for yet.
Definition: define.h:236
SK_THAUMATURGY
@ SK_THAUMATURGY
Thaumaturgy.
Definition: skills.h:48
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:426
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:592
AP_UNAPPLY
#define AP_UNAPPLY
Item is to be remvoed.
Definition: define.h:569
range_skill
@ range_skill
Use skill.
Definition: player.h:35
attack_ob
int attack_ob(object *op, object *hitter)
Simple wrapper for attack_ob_simple(), will use hitter's values.
Definition: attack.cpp:937
SK_FIND_TRAPS
@ SK_FIND_TRAPS
Find traps.
Definition: skills.h:34
SK_USE_MAGIC_ITEM
@ SK_USE_MAGIC_ITEM
Use magic item.
Definition: skills.h:45
freearr_x
short freearr_x[SIZEOFFREE]
X offset when searching around a spot.
Definition: object.cpp:299
link_player_skills
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: player.cpp:287
FLAG_READY_WEAPON
#define FLAG_READY_WEAPON
(Monster or Player) has a weapon readied
Definition: define.h:334
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:211
SK_CLIMBING
@ SK_CLIMBING
Climbing.
Definition: skills.h:39
living.h
SK_THROWING
@ SK_THROWING
Throwing.
Definition: skills.h:44
FOR_INV_PREPARE
#define FOR_INV_PREPARE(op_, it_)
Constructs a loop iterating over the inventory of an object.
Definition: define.h:664
object.h
SK_ORATORY
@ SK_ORATORY
Oratory.
Definition: skills.h:31
SK_WATER_MAGIC
@ SK_WATER_MAGIC
Water magic, unused.
Definition: skills.h:61
llevDebug
@ llevDebug
Only for debugging purposes.
Definition: logger.h:13
jump
int jump(object *pl, int dir, object *skill)
Jump skill handling.
Definition: skills.cpp:666
hide
uint32 hide
Definition: arch-handbook.txt:572