Crossfire Server  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 #include "global.h"
36 
37 #include <assert.h>
38 #include <ctype.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <math.h>
42 
43 #include "living.h"
44 #include "object.h"
45 #include "shop.h"
46 #include "skills.h"
47 #include "spells.h"
48 #include "sproto.h"
49 #include "assets.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[MAX_SKILLS];
62 
68 
69 static int free_skill_index() {
70  int i;
71  for (i = 0; i < MAX_SKILLS; i++) {
72  if (skill_names[i] == NULL && skill_faces[i] == NULL) {
73  break;
74  }
75  }
76  return i;
77 }
78 static void do_each_skill(archetype *at) {
79  if (at->clone.type == SKILL) {
80  int i = free_skill_index();
81  if (i == MAX_SKILLS) {
82  LOG(llevError, "init_skills: too many skills, increase MAX_SKILLS and rebuild server!");
84  }
86  if (at->clone.face != NULL)
87  skill_faces[i] = at->clone.face;
88  if (at->clone.msg)
90  }
91 }
92 
97 void init_skills(void) {
98  int i;
99 
100  for (i = 0; i < MAX_SKILLS; i++) {
101  skill_names[i] = NULL;
102  skill_faces[i] = NULL;
103  skill_messages[i] = NULL;
104  }
105 
107 }
108 
114 int get_skill_client_code(const char *skill_name)
115 {
116  int index;
117  for (index = 0; index < MAX_SKILLS && skill_names[index] != NULL; index++)
118  if (strcmp(skill_names[index], skill_name) == 0)
119  return index;
120 
121  assert("invalid skill!");
122  return 0;
123 }
124 
147 static object *adjust_skill_tool(object *who, object *skill, object *skill_tool) {
148  if (!skill && !skill_tool)
149  return NULL;
150 
151  /* If this is a skill that can be used without a tool and no tool found, return it */
152  if (skill && QUERY_FLAG(skill, FLAG_CAN_USE_SKILL) && (!skill_tool || QUERY_FLAG(skill_tool, FLAG_APPLIED) || strcmp(skill->skill, "clawing") == 0))
153  return skill;
154 
155  /* Player has a tool to use the skill. If not applied, apply it -
156  * if not successful, return skill if can be used. If they do have the skill tool
157  * but not the skill itself, give it to them.
158  */
159  if (skill_tool) {
160  if (!QUERY_FLAG(skill_tool, FLAG_APPLIED)) {
161  if (apply_special(who, skill_tool, 0)) {
162  if (skill && QUERY_FLAG(skill, FLAG_CAN_USE_SKILL))
163  return skill;
164  else
165  return NULL;
166  }
167  }
168  if (!skill) {
169  skill = give_skill_by_name(who, skill_tool->skill);
170  link_player_skills(who);
171  }
172  return skill;
173  }
174  if (skill && QUERY_FLAG(skill, FLAG_CAN_USE_SKILL))
175  return skill;
176  else
177  return NULL;
178 }
179 
209 object *find_skill_by_name(object *who, const char *name) {
210  object *skill = NULL, *skills[MAX_SKILLS], *skill_tools[MAX_SKILLS];
211  const char *skill_names[MAX_SKILLS];
212  char *ourname=NULL;
213  int num_names, highest_level_skill=0, i;
214 
215  if (!name)
216  return NULL;
217 
218  /* Simple case - no commas in past in name, so don't need to tokenize */
219  if (!strchr(name, ',')) {
220  skill_names[0] = name;
221  skill_tools[0] = NULL;
222  skills[0] = NULL;
223  num_names = 1;
224  } else {
225  /* strtok_r is destructive, so we need our own copy */
226  char *lasts;
227  ourname = strdup(name);
228 
229  if ((skill_names[0] = strtok_r(ourname, ",", &lasts)) == NULL) {
230  /* This should really never happen */
231  LOG(llevError, "find_skill_by_name: strtok_r returned null, but strchr did not?\n");
232  free(ourname);
233  return NULL;
234  } else {
235  skill_tools[0] = NULL;
236  skills[0] = NULL;
237  /* we already have the first name from the strtok_r above */
238  num_names=1;
239  while ((skill_names[num_names] = strtok_r(NULL, ",", &lasts)) != NULL) {
240  /* Clean out any leading spacing. typical string would be
241  * skill1, skill2, skill3, ...
242  */
243  while (isspace(*skill_names[num_names]))
244  skill_names[num_names]++;
245  skills[num_names] = NULL;
246  skill_tools[num_names] = NULL;
247  num_names++;
248  }
249  }
250  /* While we don't use ourname below this point, the skill_names[] points into
251  * it, so we can't free it yet.
252  */
253  }
254 
255  FOR_INV_PREPARE(who, tmp) {
256  /* We make sure the length of the string in the object is greater
257  * in length than the passed string. Eg, if we have a skill called
258  * 'hi', we don't want to match if the user passed 'high'
259  */
260  if (tmp->type == SKILL || (tmp->type == SKILL_TOOL && !QUERY_FLAG(tmp, FLAG_UNPAID))) {
261  for (i = 0; i<num_names; i++) {
262  if (!strncasecmp(skill_names[i], tmp->skill, strlen(skill_names[i])) &&
263  strlen(tmp->skill) >= strlen(skill_names[i])) {
264  if (tmp->type == SKILL) {
265  skills[i] = tmp;
266  if (!skill || tmp->level > skill->level) {
267  skill = tmp;
268  highest_level_skill=i;
269  }
270  }
271  else {
272  /* Skill tools don't have levels, so we basically find the
273  * 'best' skill tool for this skill.
274  */
275  if (QUERY_FLAG(tmp, FLAG_APPLIED) || !skill_tools[i] ||
276  !QUERY_FLAG(skill_tools[i], FLAG_APPLIED)) {
277  skill_tools[i] = tmp;
278  }
279  }
280  /* Got a matching name - no reason to look through rest of names */
281  break;
282  }
283  }
284  }
285  } FOR_INV_FINISH();
286  free(ourname);
287  return adjust_skill_tool(who, skills[highest_level_skill], skill_tools[highest_level_skill]);
288 }
289 
312 object *find_skill_by_number(object *who, int skillno) {
313  object *skill = NULL, *skill_tool = NULL;
314 
315  if (skillno <= 0 || skillno > MAX_SKILLS) {
316  return NULL;
317  }
318 
319  FOR_INV_PREPARE(who, tmp) {
320  if (tmp->type == SKILL && tmp->subtype == skillno)
321  skill = tmp;
322 
323  /* Try to find appropriate skilltool. If the player has one already
324  * applied, we try to keep using that one.
325  */
326  else if (tmp->type == SKILL_TOOL && tmp->subtype == skillno) {
327  if (QUERY_FLAG(tmp, FLAG_APPLIED))
328  skill_tool = tmp;
329  else if (!skill_tool || !QUERY_FLAG(skill_tool, FLAG_APPLIED))
330  skill_tool = tmp;
331  }
332  } FOR_INV_FINISH();
333 
334  return adjust_skill_tool(who, skill, skill_tool);
335 }
336 
357 int change_skill(object *who, object *new_skill, int flag) {
358  rangetype old_range;
359 
360  if (who->type != PLAYER)
361  return 0;
362 
363  old_range = who->contr->shoottype;
364 
365  /* The readied skill can be a skill tool, so check on actual skill instead of object. */
366  if (new_skill && who->chosen_skill && who->chosen_skill->skill == new_skill->skill) {
367  /* optimization for changing skill to current skill */
368  if (!(flag&0x1))
369  who->contr->shoottype = range_skill;
370  return 1;
371  }
372 
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 
407  object *op;
408  object *part;
409  object *skill;
410  int dir;
411  const char *string;
412 };
413 
414 bool do_skill_cb(player *pl, void *data) {
415  struct do_skill_cb_data *args = (struct do_skill_cb_data *)data;
416  do_skill(args->op, args->part, args->skill, args->dir, args->string);
417  return true;
418 }
419 
443 int do_skill(object *op, object *part, object *skill, int dir, const char *string) {
444  int success = 0, exp = 0;
445 
446  if (!skill)
447  return 0;
448 
449  /* The code below presumes that the skill points to the object that
450  * holds the exp, level, etc of the skill. So if this is a player
451  * go and try to find the actual real skill pointer, and if the
452  * the player doesn't have a bucket for that, create one.
453  */
454  if (skill->type != SKILL && op->type == PLAYER) {
455  object *tmp;
456 
457  tmp = object_find_by_type_and_skill(op, SKILL, skill->skill);
458  if (!tmp) {
459  tmp = give_skill_by_name(op, skill->skill);
460  if (!tmp) {
461  LOG(llevError, "do_skill: asked for skill %s but couldn't find matching SKILL archetype.\n", skill->skill);
462  return 0;
463  }
464  }
465  skill = tmp;
466  }
467 
468  if (skill->anim_suffix)
469  apply_anim_suffix(op, skill->anim_suffix);
470 
471  switch (skill->subtype) {
472  case SK_LEVITATION:
473  /* Not 100% sure if this will work with new movement code -
474  * the levitation skill has move_type for flying, so when
475  * equipped, that should transfer to player, when not,
476  * shouldn't.
477  */
478  if (QUERY_FLAG(skill, FLAG_APPLIED)) {
479  CLEAR_FLAG(skill, FLAG_APPLIED);
481  "You come to earth.");
482  } else {
483  SET_FLAG(skill, FLAG_APPLIED);
485  "You rise into the air!.");
486  }
487  fix_object(op);
488  success = 1;
489  break;
490 
491  case SK_STEALING:
492  exp = success = steal(op, dir, skill);
493  break;
494 
495  case SK_LOCKPICKING:
496  exp = success = pick_lock(op, dir, skill);
497  break;
498 
499  case SK_HIDING:
500  exp = success = hide(op, skill);
501  break;
502 
503  case SK_JUMPING:
504  success = jump(op, dir, skill);
505  break;
506 
507  case SK_INSCRIPTION:
508  exp = success = write_on_item(op, string, skill);
509  break;
510 
511  case SK_MEDITATION:
512  meditate(op, skill);
513  success = 1;
514  break;
515  /* note that the following 'attack' skills gain exp through hit_player() */
516 
517  case SK_KARATE:
518  attack_hth(op, dir, "karate-chopped", skill);
519  break;
520 
521  case SK_PUNCHING:
522  attack_hth(op, dir, "punched", skill);
523  break;
524 
525  case SK_FLAME_TOUCH:
526  attack_hth(op, dir, "flamed", skill);
527  break;
528 
529  case SK_CLAWING:
530  attack_hth(op, dir, "clawed", skill);
531  break;
532 
533  case SK_WRAITH_FEED:
534  attack_hth(op, dir, "fed upon", skill);
535  break;
536 
539  (void)attack_melee_weapon(op, dir, NULL, skill);
540  break;
541 
542  case SK_FIND_TRAPS:
543  exp = success = find_traps(op, skill);
544  break;
545 
546  case SK_SINGING:
547  exp = success = singing(op, dir, skill);
548  break;
549 
550  case SK_ORATORY:
551  exp = success = use_oratory(op, dir, skill);
552  break;
553 
554  case SK_SMITHERY:
555  case SK_BOWYER:
556  case SK_JEWELER:
557  case SK_ALCHEMY:
558  case SK_THAUMATURGY:
559  case SK_LITERACY:
560  case SK_WOODSMAN:
561  if (use_alchemy(op) == 0)
562  exp = success = skill_ident(op, skill);
563  break;
564 
565  case SK_DET_MAGIC:
566  case SK_DET_CURSE:
567  exp = success = skill_ident(op, skill);
568  break;
569 
570  case SK_DISARM_TRAPS:
571  exp = success = remove_trap(op, skill);
572  break;
573 
574  case SK_THROWING:
575  success = skill_throw(op, part, dir, skill);
576  break;
577 
578  case SK_SET_TRAP:
580  "This skill is not currently implemented.");
581  break;
582 
583  case SK_USE_MAGIC_ITEM:
584  case SK_MISSILE_WEAPON:
586  "There is no special attack for this skill.");
587  break;
588 
589  case SK_PRAYING:
590  if (op->contr) {
591  player_start_repeat(op->contr, "praying", do_skill_cb);
592  op->contr->repeat_func_data = calloc(1, sizeof(struct do_skill_cb_data));
593  struct do_skill_cb_data *data = (struct do_skill_cb_data *)op->contr->repeat_func_data;
594  *data = {op, part, skill, dir, string};
595  }
596  success = pray(op, skill);
597  break;
598 
599  case SK_BARGAINING:
600  success = shop_describe(op);
601  break;
602 
603  case SK_SORCERY:
604  case SK_EVOCATION:
605  case SK_PYROMANCY:
606  case SK_SUMMONING:
607  case SK_CLIMBING:
608  case SK_EARTH_MAGIC:
609  case SK_AIR_MAGIC:
610  case SK_FIRE_MAGIC:
611  case SK_WATER_MAGIC:
613  "This skill is already in effect.");
614  break;
615 
616  case SK_HARVESTING:
617  if (op->contr) {
619  op->contr->repeat_func_data = calloc(1, sizeof(struct do_skill_cb_data));
620  struct do_skill_cb_data *data = (struct do_skill_cb_data *)op->contr->repeat_func_data;
621  *data = {op, part, skill, dir, string};
622  }
623  do_harvest(op, dir, skill);
624  success = 0;
625  break;
626 
627  default: {
628  char name[MAX_BUF];
629 
630  query_name(op, name, MAX_BUF);
631  LOG(llevDebug, "%s attempted to use unknown skill: %d\n", name, op->chosen_skill->stats.sp);
632  break;
633  }
634  }
635 
636  /* For players we now update the speed_left from using the skill.
637  * Monsters have no skill use time because of the random nature in
638  * which use_monster_skill is called already simulates this.
639  * If certain skills should take more/less time, that should be
640  * in the code for the skill itself.
641  */
642 
643  if (op->type == PLAYER)
644  op->speed_left -= 1.0;
645 
646  /* this is a good place to add experience for successful use of skills.
647  * Note that add_exp() will figure out player/monster experience
648  * gain problems.
649  */
650 
651  if (success && exp)
653 
654  return success;
655 }
656 
691 int64_t calc_skill_exp(const object *who, const object *op, const object *skill) {
692  int64_t op_exp;
693  int op_lvl;
694  float base, value, lvl_mult;
695 
696  if (!skill)
697  skill = who;
698 
699  /* Oct 95 - where we have an object, I expanded our treatment
700  * to 3 cases:
701  * non-living magic obj, runes and everything else.
702  *
703  * If an object is not alive and magical we set the base exp higher to
704  * help out exp awards for skill_ident skills. Also, if
705  * an item is type RUNE, we give out exp based on stats.Cha
706  * and level (this was the old system) -b.t.
707  */
708 
709  if (!op) { /* no item/creature */
710  op_lvl = MAX(who->map->difficulty, 1);
711  op_exp = 0;
712  } else if (op->type == RUNE || op->type == TRAP) { /* all traps. If stats.Cha > 1 we use that
713  * for the amount of experience */
714  op_exp = op->stats.Cha > 1 ? op->stats.Cha : op->stats.exp;
715  op_lvl = op->level;
716  } else { /* all other items/living creatures */
717  op_exp = op->stats.exp;
718  op_lvl = op->level;
719  if (!QUERY_FLAG(op, FLAG_ALIVE)) { /* for ident/make items */
720  op_lvl += 5*abs(op->magic);
721  }
722  }
723 
724  if (op_lvl < 1)
725  op_lvl = 1;
726 
727  if (who->type != PLAYER) { /* for monsters only */
728  return ((int64_t)(op_exp*0.1)+1); /* we add one to insure positive value is returned */
729  }
730 
731  /* for players */
732  base = op_exp;
733  /* if skill really is a skill, then we can look at the skill archetype for
734  * base reward value (exp) and level multiplier factor.
735  */
736  if (skill->type == SKILL) {
737  base += skill->arch->clone.stats.exp;
738  if (settings.simple_exp) {
739  if (skill->arch->clone.level)
740  lvl_mult = (float)skill->arch->clone.level/100.0;
741  else
742  lvl_mult = 1.0; /* no adjustment */
743  } else {
744  if (skill->level)
745  lvl_mult = ((float)skill->arch->clone.level*(float)op_lvl)/((float)skill->level*100.0);
746  else
747  lvl_mult = 1.0;
748  }
749  } else {
750  /* Don't divide by zero here! */
751  lvl_mult = (float)op_lvl/(float)(skill->level ? skill->level : 1);
752  }
753 
754  /* assemble the exp total, and return value */
755 
756  value = base*lvl_mult;
757  if (value < 1)
758  value = 1; /* Always give at least 1 exp point */
759 
760 #ifdef SKILL_UTIL_DEBUG
761  LOG(llevDebug, "calc_skill_exp(): who: %s(lvl:%d) op:%s(lvl:%d)\n", who->name, skill->level, op ? op->name : "", op_lvl);
762 #endif
763  return ((int64_t)value);
764 }
765 
783 int learn_skill(object *pl, object *scroll) {
784  object *tmp;
785 
786  if (!scroll->skill) {
787  LOG(llevError, "skill scroll %s does not have skill pointer set.\n", scroll->name);
788  return 2;
789  }
790 
791  /* can't use find_skill_by_name because we want skills the player knows
792  * but can't use natively.
793  */
794 
795  tmp = NULL;
796  FOR_INV_PREPARE(pl, inv)
797  if (inv->type == SKILL && !strncasecmp(scroll->skill, inv->skill, strlen(scroll->skill))) {
798  tmp = inv;
799  break;
800  }
801  FOR_INV_FINISH();
802 
803  /* player already knows it */
804  if (tmp && QUERY_FLAG(tmp, FLAG_CAN_USE_SKILL))
805  return 0;
806 
807  /* now a random change to learn, based on player Int.
808  * give bonus based on level - otherwise stupid characters
809  * might never be able to learn anything.
810  */
811  if (random_roll(0, 99, pl, PREFER_LOW) > (get_learn_spell(pl->stats.Int)+(pl->level/5)))
812  return 2; /* failure :< */
813 
814  if (!tmp)
815  tmp = give_skill_by_name(pl, scroll->skill);
816 
817  if (!tmp) {
818  LOG(llevError, "skill scroll %s does not have valid skill name (%s).\n", scroll->name, scroll->skill);
819  return 2;
820  }
821 
823  link_player_skills(pl);
824  return 1;
825 }
826 
838 static int clipped_percent(int64_t a, int64_t b) {
839  int rv;
840 
841  if (b <= 0)
842  return 0;
843 
844  rv = (int)((100.0f*((float)a)/((float)b))+0.5f);
845 
846  if (rv < 0)
847  return 0;
848  else if (rv > 100)
849  return 100;
850 
851  return rv;
852 }
853 
854 
863 static int digits_in_long(int64_t num)
864 {
865  return num == 0 ? 1 : floor( log10( labs(num) ) ) + 1;
866 }
867 
884 void show_skills(object *op, const char *parms) {
885  const char *cp;
886  int i, num_skills_found = 0;
887  /* Need to have a pointer and use strdup for qsort to work properly */
888  char skills[MAX_SKILLS][MAX_BUF];
889  const char *search = parms;
890  bool long_format = false;
891 
892  if ( parms && strncmp(parms,"-l",2) == 0 ) {
893  long_format = true;
894  search += 2;
895  while ( *search && *search != ' ' ) ++search; /* move past other parameters */
896  while ( *search == ' ' ) ++search;
897  }
898  FOR_INV_PREPARE(op, tmp) {
899  if (tmp->type == SKILL) {
900  if (search && strstr(tmp->name, search) == NULL)
901  continue;
902 
904  if ( long_format ) {
905  int perm_level = exp_level(tmp->total_exp * settings.permanent_exp_ratio / 100);
906  snprintf(skills[num_skills_found++], MAX_BUF, "[fixed]%-20slvl:%3d (xp:%" FMT64 "/%" FMT64 ")%-*sperm lvl:%3d (xp:%" FMT64 "/%" FMT64 ") ",
907  tmp->name, tmp->level,
908  tmp->stats.exp,
909  level_exp(tmp->level+1, op->expmul),
910  1+2*digits_in_long(op->stats.exp)-digits_in_long(tmp->stats.exp)-digits_in_long(level_exp(tmp->level+1, op->expmul)),
911  "",
912  perm_level,
913  tmp->total_exp * settings.permanent_exp_ratio / 100,
914  level_exp(perm_level+1, op->expmul));
915  } else {
916  snprintf(skills[num_skills_found++], MAX_BUF, "[fixed]%-20slvl:%3d (xp:%" FMT64 "/%" FMT64 "/%d%%)",
917  tmp->name, tmp->level,
918  tmp->stats.exp,
919  level_exp(tmp->level+1, op->expmul),
920  clipped_percent(PERM_EXP(tmp->total_exp), tmp->stats.exp));
921  }
922  } else {
923  snprintf(skills[num_skills_found++], MAX_BUF, "[fixed]%-20slvl:%3d (xp:%" FMT64 "/%" FMT64 ")",
924  tmp->name, tmp->level,
925  tmp->stats.exp,
926  level_exp(tmp->level+1, op->expmul));
927  }
928  /* I don't know why some characters get a bunch of skills, but
929  * it sometimes happens (maybe a leftover from buggier earlier code
930  * and those character are still about). In any case, lets handle
931  * it so it doesn't crash the server - otherwise, one character may
932  * crash the server numerous times.
933  */
934  if (num_skills_found >= MAX_SKILLS) {
936  "Your character has too many skills.\n"
937  "Something isn't right - contact the server admin");
938  break;
939  }
940  }
941  } FOR_INV_FINISH();
942 
943  if ( search && *search ) {
945  "Player skills%s: (matching '%s')", long_format ? " (long format)":"",search);
946  } else {
948  "Player skills%s:", long_format ? " (long format)":"");
949  }
950 
951  if (num_skills_found > 1)
952  qsort(skills, num_skills_found, MAX_BUF, (int (*)(const void *, const void *))strcmp);
953 
954  for (i = 0; i < num_skills_found; i++) {
956  skills[i]);
957  }
958 
959  cp = determine_god(op);
960  if (strcmp(cp, "none") == 0)
961  cp = NULL;
962 
964  "You can handle %d weapon improvements.\n"
965  "You worship %s.\n"
966  "Your equipped item power is %d out of %d\n",
967  op->level/5+5,
968  cp ? cp : "no god at current time",
969  op->contr->item_power, op->level);
970 }
971 
988 int use_skill(object *op, const char *string) {
989  object *skop;
990  size_t len;
991 
992  if (!string)
993  return 0;
994 
995  skop = NULL;
996  FOR_INV_PREPARE(op, tmp) {
997  if (tmp->type == SKILL
999  && !strncasecmp(string, tmp->skill, MIN(strlen(string), strlen(tmp->skill)))) {
1000  skop = tmp;
1001  break;
1002  } else if (tmp->type == SKILL_TOOL
1003  && !QUERY_FLAG(tmp, FLAG_UNPAID) /* Holy symbols could be used unpaid w/o this */
1004  && !strncasecmp(string, tmp->skill, MIN(strlen(string), strlen(tmp->skill)))) {
1005  skop = tmp;
1006  break;
1007  }
1008  } FOR_INV_FINISH();
1009  if (!skop) {
1011  "Unable to find skill %s",
1012  string);
1013  return 0;
1014  }
1015 
1016  len = strlen(skop->skill);
1017 
1018  /* All this logic goes and skips over the skill name to find any
1019  * options given to the skill. Its pretty simple - if there
1020  * are extra parameters (as determined by string length), we
1021  * want to skip over any leading spaces.
1022  */
1023  if (len >= strlen(string)) {
1024  string = NULL;
1025  } else {
1026  string += len;
1027  while (*string == 0x20)
1028  string++;
1029  if (strlen(string) == 0)
1030  string = NULL;
1031  }
1032 
1033 #ifdef SKILL_UTIL_DEBUG
1034  LOG(llevDebug, "use_skill() got skill: %s\n", sknum > -1 ? skills[sknum].name : "none");
1035 #endif
1036 
1037  /* Change to the new skill, then execute it. */
1038  if (do_skill(op, op, skop, op->facing, string))
1039  return 1;
1040 
1041  return 0;
1042 }
1043 
1066 static object *find_best_player_hth_skill(object *op) {
1067  object *best_skill = NULL;
1068  int last_skill;
1069 
1070  if (op->contr->unarmed_skill) {
1071  /* command_unarmed_skill() already does these checks, and right
1072  * now I do not think there is any way to lose unarmed skills.
1073  * But maybe in the future there will be (polymorph?) so handle
1074  * it appropriately. MSW 2009-07-03
1075  *
1076  * Note that the error messages should only print out once when
1077  * the initial failure to switch skills happens, so the player
1078  * should not get spammed with tons of messages unless they have
1079  * no valid unarmed skill
1080  */
1081 
1082  best_skill = find_skill_by_name(op, op->contr->unarmed_skill);
1083 
1084  if (!best_skill) {
1086  "Unable to find skill %s - using default unarmed skill",
1087  op->contr->unarmed_skill);
1088  } else {
1089  size_t i;
1090 
1091  for (i = 0; i < sizeof(unarmed_skills); i++)
1092  if (best_skill->subtype == unarmed_skills[i])
1093  break;
1094  if (i < sizeof(unarmed_skills))
1095  return(best_skill);
1096  }
1097  /* If for some reason the unarmed_skill is not valid, we fall
1098  * through the processing below.
1099  */
1100  }
1101 
1102 
1103  /* Dragons are a special case - gros 25th July 2006 */
1104  /* Perhaps this special case should be removed and unarmed_skill
1105  * set to clawing for dragon characters? MSW 2009-07-03
1106  */
1107  if (is_dragon_pl(op)) {
1108  object *tmp;
1109 
1110  tmp = find_skill_by_number(op, SK_CLAWING);
1111  if (tmp) /* I suppose it should always be true - but maybe there's
1112  * draconic toothache ? :) */
1113  return tmp;
1114  }
1115 
1116  last_skill = sizeof(unarmed_skills);
1117  FOR_INV_PREPARE(op, tmp) {
1118  if (tmp->type == SKILL) {
1119  int i;
1120 
1121  /* The order in the array is preferred order. So basically,
1122  * we just cut down the number to search - eg, if we find a skill
1123  * early on in flame touch, then we only need to look into the unarmed_array
1124  * to the entry before flame touch - don't care about the entries afterward,
1125  * because they are inferior skills.
1126  * if we end up finding the best skill (i==0) might as well return
1127  * right away - can't get any better than that.
1128  */
1129  for (i = 0; i < last_skill; i++) {
1130  if (tmp->subtype == unarmed_skills[i] && QUERY_FLAG(tmp, FLAG_CAN_USE_SKILL)) {
1131  best_skill = tmp;
1132  last_skill = i;
1133  if (i == 0)
1134  return best_skill;
1135  }
1136  }
1137  }
1138  } FOR_INV_FINISH();
1139  return best_skill;
1140 }
1141 
1155 static void do_skill_attack(object *tmp, object *op, const char *string, object *skill) {
1156  int success;
1157 
1158  /* For Players only: if there is no ready weapon, and no "attack" skill
1159  * is readied either then try to find a skill for the player to use.
1160  * it is presumed that if skill is set, it is a valid attack skill (eg,
1161  * the caller should have set it appropriately). We still want to pass
1162  * through that code if skill is set to change to the skill.
1163  */
1164  if (op->type == PLAYER) {
1165  if (!QUERY_FLAG(op, FLAG_READY_WEAPON)) {
1166  size_t i;
1167 
1168  if (!skill) {
1169  /* See if the players chosen skill is a combat skill, and use
1170  * it if appropriate.
1171  */
1172  if (op->chosen_skill) {
1173  /* the list is 0-terminated, and talismans, which can be in chosen_skill,
1174  * have a subtype of 0, therefore don't check the 0 */
1175  for (i = 0; unarmed_skills[i] != 0; i++)
1176  if (op->chosen_skill->subtype == unarmed_skills[i]) {
1177  skill = op->chosen_skill;
1178  break;
1179  }
1180  }
1181  /* If we didn't find a skill above, look harder for a good skill */
1182  if (!skill) {
1183  skill = find_best_player_hth_skill(op);
1184 
1185  if (!skill) {
1186  draw_ext_info(NDI_BLACK, 0, op,
1188  "You have no unarmed combat skills!");
1189  return;
1190  }
1191  }
1192  }
1193  if (skill != op->chosen_skill) {
1194  /* now try to ready the new skill */
1195  if (!change_skill(op, skill, 1)) { /* oh oh, trouble! */
1198  "Couldn't change to skill %s",
1199  skill->name);
1200  return;
1201  }
1202  }
1203  } else {
1204  /* Seen some crashes below where current_weapon is not set,
1205  * even though the flag says it is. So if current weapon isn't set,
1206  * do some work in trying to find the object to use.
1207  */
1208  if (!op->current_weapon) {
1209  object *tmp;
1210 
1211  LOG(llevError, "Player %s does not have current weapon set but flag_ready_weapon is set\n", op->name);
1213  if (!tmp) {
1214  LOG(llevError, "Could not find applied weapon on %s\n", op->name);
1215  op->current_weapon = NULL;
1216  return;
1217  } else {
1218  char weapon[MAX_BUF];
1219 
1220  query_name(tmp, weapon, MAX_BUF);
1221  op->current_weapon = tmp;
1222  }
1223  }
1224 
1225  /* Has ready weapon - make sure chosen_skill is set up properly */
1226  if (!op->chosen_skill || op->current_weapon->skill != op->chosen_skill->skill) {
1227  object *found_skill = find_skill_by_name(op, op->current_weapon->skill);
1228  // found_skill can be NULL -- TOCTTOU when item has mutated, e.g. dipping a bottle in a fountain
1229  change_skill(op, found_skill, 1);
1230  }
1231  }
1232  }
1233 
1234  /* lose invisibility/hiding status for running attacks */
1235 
1236  if (op->type == PLAYER && op->contr->tmp_invis) {
1237  op->contr->tmp_invis = 0;
1238  op->invisible = 0;
1239  op->hide = 0;
1241  }
1242 
1243  success = attack_ob(tmp, op);
1244 
1245  if (tmp && !QUERY_FLAG(tmp, FLAG_FREED)) {
1246  char op_name[MAX_BUF];
1247  if (!success) { // In case of miss, attack_ob didn't print anything
1248  query_name(tmp, op_name, MAX_BUF);
1251  "You miss %s!",
1252  op_name);
1253  } else if (string != NULL) { // If string is NULL, message was already displayed
1254  if (op->type == PLAYER) {
1255  query_name(tmp, op_name, MAX_BUF);
1258  "You %s %s!",
1259  string, op_name);
1260  } else if (tmp->type == PLAYER) {
1261  query_name(op, op_name, MAX_BUF);
1264  "%s %s you!",
1265  op_name, string);
1266  }
1267  }
1268  }
1269 }
1270 
1294 void skill_attack(object *tmp, object *pl, int dir, const char *string, object *skill) {
1295  int16_t tx, ty;
1296  mapstruct *m;
1297  int mflags;
1298 
1299  if (!dir)
1300  dir = pl->facing;
1301  tx = freearr_x[dir];
1302  ty = freearr_y[dir];
1303 
1304  /* If we don't yet have an opponent, find if one exists, and attack.
1305  * Legal opponents are the same as outlined in move_player_attack()
1306  */
1307 
1308  if (tmp == NULL) {
1309  m = pl->map;
1310  tx = pl->x+freearr_x[dir];
1311  ty = pl->y+freearr_y[dir];
1312 
1313  mflags = get_map_flags(m, &m, tx, ty, &tx, &ty);
1314  if (mflags&P_OUT_OF_MAP)
1315  return;
1316 
1317  /* space must be blocked for there to be anything interesting to do */
1318  if (!(mflags&P_IS_ALIVE)
1319  && !OB_TYPE_MOVE_BLOCK(pl, GET_MAP_MOVE_BLOCK(m, tx, ty))) {
1320  return;
1321  }
1322 
1323  FOR_MAP_PREPARE(m, tx, ty, tmp2)
1324  if ((QUERY_FLAG(tmp2, FLAG_ALIVE) && tmp2->stats.hp >= 0)
1325  || QUERY_FLAG(tmp2, FLAG_CAN_ROLL)
1326  || tmp2->type == LOCKED_DOOR) {
1327  /* Don't attack party members */
1328  if ((pl->type == PLAYER && tmp2->type == PLAYER)
1329  && (pl->contr->party != NULL && pl->contr->party == tmp2->contr->party))
1330  return;
1331  tmp = tmp2;
1332  break;
1333  }
1334  FOR_MAP_FINISH();
1335  }
1336  if (!tmp) {
1337  if (pl->type == PLAYER)
1339  "There is nothing to attack!");
1340  return;
1341  }
1342 
1343  do_skill_attack(tmp, pl, string, skill);
1344 }
1345 
1364 static void attack_hth(object *pl, int dir, const char *string, object *skill) {
1365  object *weapon;
1366 
1367  if (QUERY_FLAG(pl, FLAG_READY_WEAPON)) {
1368  weapon = object_find_by_type_applied(pl, WEAPON);
1369  if (weapon != NULL) {
1370  if (apply_special(pl, weapon, AP_UNAPPLY|AP_NOPRINT)) {
1371  char weaponname[MAX_BUF];
1372 
1373  query_name(weapon, weaponname, MAX_BUF);
1376  "You are unable to unwield %s in order to attack with %s.",
1377  weaponname, skill->name);
1378  return;
1379  } else {
1381  "You unwield your weapon in order to attack.");
1382  }
1383  }
1384  }
1385  skill_attack(NULL, pl, dir, string, skill);
1386 }
1387 
1408 static void attack_melee_weapon(object *op, int dir, const char *string, object *skill) {
1409  if (!QUERY_FLAG(op, FLAG_READY_WEAPON)) {
1410  if (op->type == PLAYER)
1412  "You have no ready weapon to attack with!");
1413  return;
1414  }
1415  skill_attack(NULL, op, dir, string, skill);
1416 }
Error, serious thing.
Definition: logger.h:11
#define AP_UNAPPLY
Item is to be remvoed.
Definition: define.h:596
Flame-touch.
Definition: skills.h:37
Use skill.
Definition: player.h:35
void show_skills(object *op, const char *parms)
Displays a player&#39;s skill list, and some other non skill related info (god, max weapon improvements...
Definition: skill_util.cpp:884
int apply_special(object *who, object *op, int aflags)
Apply an object.
Definition: apply.cpp:818
const char * determine_god(object *op)
Determines if op worships a god.
Definition: gods.cpp:55
object * ranges[range_size]
Object for each range.
Definition: player.h:118
int change_skill(object *who, object *new_skill, int flag)
This changes the object&#39;s skill to new_skill.
Definition: skill_util.cpp:357
#define FLAG_UNPAID
Object hasn&#39;t been paid for yet.
Definition: define.h:223
#define UP_OBJ_FACE
Only thing that changed was the face.
Definition: object.h:533
Stealing.
Definition: skills.h:26
Air magic, unused.
Definition: skills.h:59
Spell-related defines: spellpath, subtypes, ...
static void attack_hth(object *pl, int dir, const char *string, object *skill)
This handles all hand-to-hand attacks.
int skill_ident(object *pl, object *skill)
Main identification skill handling.
Definition: skills.cpp:936
Harvesting.
Definition: skills.h:58
struct archetype * arch
Pointer to archetype.
Definition: object.h:424
Thaumaturgy.
Definition: skills.h:48
Missile weapon.
Definition: skills.h:43
#define MSG_TYPE_SKILL_LIST
List of skills.
Definition: newclient.h:628
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:58
#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:433
Wraith feed.
Definition: skills.h:57
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:443
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...) PRINTF_ARGS(6
int attack_ob(object *op, object *hitter)
Simple wrapper for attack_ob_simple(), will use hitter&#39;s values.
Definition: attack.cpp:937
void fix_object(object *op)
Updates all abilities given by applied objects in the inventory of the given object.
Definition: living.cpp:1132
No range selected.
Definition: player.h:30
Climbing.
Definition: skills.h:39
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:863
void archetypes_for_each(arch_op op)
Definition: assets.cpp:305
New face structure - this enforces the notion that data is face by face only - you can not change the...
Definition: face.h:14
int shop_describe(const object *op)
Give the player a description of the shop on their current map.
Definition: shop.cpp:1128
int64_t calc_skill_exp(const object *who, const object *op, const object *skill)
Calculates amount of experience can be gained for successful use of a skill.
Definition: skill_util.cpp:691
partylist * party
Party this player is part of.
Definition: player.h:205
Earth magic, unused.
Definition: skills.h:60
sstring add_string(const char *str)
Share a string.
Definition: shstr.cpp:137
#define PREFER_LOW
Definition: define.h:585
int pick_lock(object *pl, int dir, object *skill)
Lock pick handling.
Definition: skills.cpp:400
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.
See Rune.
Definition: object.h:245
Detect curse.
Definition: skills.h:33
Jumping.
Definition: skills.h:29
See Weapon.
Definition: object.h:124
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:288
void change_exp(object *op, int64_t exp, const char *skill_name, int flag)
Changes experience to a player/monster.
Definition: living.cpp:2179
#define MSG_TYPE_SKILL_MISSING
Don&#39;t have the skill.
Definition: newclient.h:623
Bowyer.
Definition: skills.h:23
int16_t y
Position in the map for this object.
Definition: object.h:335
object * object_find_by_type_applied(const object *who, int type)
Find applied object in inventory.
Definition: object.cpp:4068
int8_t magic
Any magical bonuses to this item.
Definition: object.h:358
int is_dragon_pl(const object *op)
Checks if player is a dragon.
Definition: player.cpp:123
sstring add_refcount(sstring str)
Like add_string(), but the string is already a shared string.
Definition: shstr.cpp:224
#define MSG_TYPE_SKILL_ERROR
Doing something wrong.
Definition: newclient.h:624
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
int jump(object *pl, int dir, object *skill)
Jump skill handling.
Definition: skills.cpp:675
object * chosen_skill
The skill chosen to use.
Definition: object.h:396
int remove_trap(object *op, object *skill)
This skill will disarm any previously discovered trap.
Definition: skills.cpp:1320
#define MAX(x, y)
Definition: compat.h:24
int16_t x
Definition: object.h:335
#define NDI_BLACK
Definition: newclient.h:246
void clear_skill(object *who)
This function just clears the chosen_skill and range_skill values in the player.
Definition: skill_util.cpp:396
Global type definitions and header inclusions.
#define AP_APPLY
Item is to be applied.
Definition: define.h:595
struct player * contr
Pointer to the player which control this object.
Definition: object.h:284
double expmul
needed experience = (calc_exp*expmul) - means some races/classes can need less/more exp to gain level...
Definition: object.h:407
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Sends message to player(s).
Definition: main.cpp:308
Bargaining.
Definition: skills.h:28
Smithery.
Definition: skills.h:22
#define MIN(x, y)
Definition: compat.h:21
int exp_level(int64_t exp)
Returns the level for a given exp.
Definition: living.cpp:1897
Lockpicking.
Definition: skills.h:20
#define FLAG_CAN_ROLL
Object can be rolled.
Definition: define.h:241
Woodsman.
Definition: skills.h:40
Clawing.
Definition: skills.h:50
rangetype shoottype
Which range-attack is being used by player.
Definition: player.h:114
int use_alchemy(object *op)
Handle use_skill for alchemy-like items.
Definition: alchemy.cpp:1062
Allows the use of a skill.
Definition: object.h:194
static int free_skill_index()
Definition: skill_util.cpp:69
Throwing.
Definition: skills.h:44
#define FLAG_READY_SKILL
(Monster or Player) has a skill readied
Definition: define.h:321
See Trap.
Definition: object.h:246
int16_t level
Level of creature or object.
Definition: object.h:361
int16_t sp
Spell points.
Definition: living.h:42
#define NDI_RED
Definition: newclient.h:249
int skill_throw(object *op, object *part, int dir, object *skill)
Throwing skill handling.
Definition: skills.cpp:2286
const char * skill_names[MAX_SKILLS]
Will contain a number-name mapping for skills, initialized by init_skills().
Definition: skill_util.cpp:57
Inscription.
Definition: skills.h:41
uint8_t hide
The object is hidden, not invisible.
Definition: object.h:397
Disarm traps.
Definition: skills.h:46
#define FLAG_ALIVE
Object can fight (or be fought)
Definition: define.h:217
#define MSG_TYPE_VICTIM
Something bad is happening to the player.
Definition: newclient.h:433
The archetype structure is a set of rules on how to generate and manipulate objects which point to ar...
Definition: object.h:483
void player_start_repeat(player *pl, const char *action, repeat_cb cb)
Start repeating an action.
Definition: player.cpp:4545
void init_skills(void)
This just sets up the skill_names table above.
Definition: skill_util.cpp:97
#define FLAG_CAN_USE_SKILL
The monster can use skills.
Definition: define.h:309
#define SET_FLAG(xyz, p)
Definition: define.h:384
Fire magic, unused.
Definition: skills.h:62
int hide(object *op, object *skill)
Main hide handling.
Definition: skills.cpp:505
#define QUERY_FLAG(xyz, p)
Definition: define.h:386
uint8_t unarmed_skills[UNARMED_SKILLS_COUNT]
Table of unarmed attack skills.
Definition: skills.cpp:31
One handed weapon.
Definition: skills.h:42
sstring anim_suffix
Used to determine combined animations.
Definition: object.h:324
void query_name(const object *op, char *buf, size_t size)
Describes an item.
Definition: item.cpp:594
#define PERM_EXP(exptotal)
Convert saved total experience into permanent experience.
Definition: global.h:232
short freearr_x[SIZEOFFREE]
X offset when searching around a spot.
Definition: object.cpp:299
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:700
sstring msg
If this is a book/sign/magic mouth/etc.
Definition: object.h:330
#define FMT64
Definition: compat.h:16
Use magic item.
Definition: skills.h:45
Set traps, unused.
Definition: skills.h:47
This is a game-map.
Definition: map.h:320
const Face * skill_faces[MAX_SKILLS]
Will contain the face numbers for the skills, initialized by init_skill().
Definition: skill_util.cpp:61
Summoning.
Definition: skills.h:52
Alchemy.
Definition: skills.h:25
Sorcery.
Definition: skills.h:55
bool do_skill_cb(player *pl, void *data)
Definition: skill_util.cpp:414
#define MSG_TYPE_VICTIM_WAS_HIT
Player was hit by something.
Definition: newclient.h:688
int steal(object *op, int dir, object *skill)
Main stealing function.
Definition: skills.cpp:288
const Face * face
Face with colors.
Definition: object.h:341
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:607
#define P_OUT_OF_MAP
This space is outside the map.
Definition: map.h:254
#define GET_MAP_MOVE_BLOCK(M, X, Y)
Gets the blocking state of a square.
Definition: map.h:195
#define MSG_TYPE_ATTACK_MISS
attack didn&#39;t hit
Definition: newclient.h:656
Find traps.
Definition: skills.h:34
struct Settings settings
Global settings.
Definition: init.cpp:139
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:147
#define MSG_TYPE_SKILL_FAILURE
Failure in using skill.
Definition: newclient.h:626
Levitation.
Definition: skills.h:51
uint8_t simple_exp
If true, use the simple experience system.
Definition: global.h:264
int random_roll(int min, int max, const object *op, int goodbad)
Roll a random number between min and max.
Definition: utils.cpp:42
Meditation.
Definition: skills.h:35
Praying.
Definition: skills.h:49
int get_learn_spell(int stat)
Definition: living.cpp:2377
void do_harvest(object *pl, int dir, object *skill)
Player is trying to harvest something.
Definition: c_misc.cpp:2258
object * pl
Definition: shop.cpp:677
void fatal(enum fatal_error err)
fatal() is meant to be called whenever a fatal signal is intercepted.
Definition: utils.cpp:590
See Locked Door.
Definition: object.h:128
living stats
Str, Con, Dex, etc.
Definition: object.h:378
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
#define MSG_TYPE_ATTACK
Attack related messages.
Definition: newclient.h:426
sstring skill_messages[MAX_SKILLS]
Will contain the message for the skills, initialized by init_skill().
Definition: skill_util.cpp:67
int16_t invisible
How much longer the object will be invis.
Definition: object.h:370
#define MSG_TYPE_ATTACK_DID_HIT
Player hit something else.
Definition: newclient.h:648
Punching.
Definition: skills.h:36
Literacy.
Definition: skills.h:27
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:312
float speed_left
How much speed is left to spend this round.
Definition: object.h:338
Karate.
Definition: skills.h:38
const char * string
Definition: skill_util.cpp:411
struct mapstruct * map
Pointer to the map in which this object is present.
Definition: object.h:305
Water magic, unused.
Definition: skills.h:61
Skill-related defines, including subtypes.
object * find_skill_by_name(object *who, const char *name)
This returns the skill pointer of the given name (the one that accumulates exp, has the level...
Definition: skill_util.cpp:209
Oratory.
Definition: skills.h:31
#define FLAG_READY_WEAPON
(Monster or Player) has a weapon readied
Definition: define.h:322
static int clipped_percent(int64_t a, int64_t b)
Gives a percentage clipped to 0% -> 100% of a/b.
Definition: skill_util.cpp:838
short freearr_y[SIZEOFFREE]
Y offset when searching around a spot.
Definition: object.cpp:305
#define FOR_MAP_FINISH()
Finishes FOR_MAP_PREPARE().
Definition: define.h:753
int8_t facing
Object is oriented/facing that way.
Definition: object.h:345
static void do_each_skill(archetype *at)
Definition: skill_util.cpp:78
uint8_t permanent_exp_ratio
How much exp should be &#39;permenant&#39; and unable to be lost.
Definition: global.h:259
See Player.
Definition: object.h:112
int pray(object *pl, object *skill)
Praying skill handling.
Definition: skills.cpp:1393
Object structure, the core of Crossfire.
Jeweler.
Definition: skills.h:24
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:988
static event_registration m
Definition: citylife.cpp:424
Also see SKILL_TOOL (74) below.
Definition: object.h:148
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().
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:4168
sstring name
The name of the object, obviously...
Definition: object.h:319
Only for debugging purposes.
Definition: logger.h:13
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
Hiding.
Definition: skills.h:21
int8_t Cha
Use
Definition: living.h:36
int singing(object *pl, int dir, object *skill)
Singing skill handling.
Definition: skills.cpp:1158
#define CLEAR_FLAG(xyz, p)
Definition: define.h:385
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:348
Singing.
Definition: skills.h:32
rangetype
What range is currently selected by the player.
Definition: player.h:28
#define FLAG_APPLIED
Object is ready for use by living.
Definition: define.h:222
Two handed weapons.
Definition: skills.h:56
int find_traps(object *pl, object *skill)
Checks for traps on the spaces around the player or in certain objects.
Definition: skills.cpp:1249
int learn_skill(object *pl, object *scroll)
Player is trying to learn a skill.
Definition: skill_util.cpp:783
int64_t exp
Experience.
Definition: living.h:47
sstring skill
Name of the skill this object uses/grants.
Definition: object.h:329
#define MSG_TYPE_SKILL
Messages related to skill use.
Definition: newclient.h:424
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
#define NDI_UNIQUE
Print immediately, don&#39;t buffer.
Definition: newclient.h:270
int use_oratory(object *pl, int dir, object *skill)
Oratory skill handling.
Definition: skills.cpp:1005
uint32_t tmp_invis
Will invis go away when we attack?
Definition: player.h:142
C function wrappers to interact with assets.
One player.
Definition: player.h:107
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Constructs a loop iterating over all objects of a map tile.
Definition: define.h:746
Evocation.
Definition: skills.h:54
object * current_weapon
Pointer to the weapon currently used.
Definition: object.h:380
Structure containing object statistics.
#define MSG_TYPE_SKILL_SUCCESS
Successfully used skill.
Definition: newclient.h:625
const char * unarmed_skill
Prefered skill to use in unarmed combat.
Definition: player.h:223
uint8_t subtype
Subtype of object.
Definition: object.h:349
uint16_t difficulty
What level the player should be to play here.
Definition: map.h:338
#define MAX_SKILLS
This is the maximum number of skills the game may handle.
Definition: skills.h:70
#define SK_SUBTRACT_SKILL_EXP
Used when removing exp.
Definition: skills.h:81
int16_t item_power
Total item power of objects equipped.
Definition: player.h:132
const char * sstring
Definition: sstring.h:2
#define P_IS_ALIVE
Something alive is on this space.
Definition: map.h:240
int8_t Int
Use
Definition: living.h:36
void object_update(object *op, int action)
object_update() updates the array which represents the map.
Definition: object.cpp:1419
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:114
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.cpp:1771
static void attack_melee_weapon(object *op, int dir, const char *string, object *skill)
This handles melee weapon attacks -b.t.
Pyromancy.
Definition: skills.h:53
void meditate(object *pl, object *skill)
Meditation skill handling.
Definition: skills.cpp:1441
object clone
An object from which to do object_copy()
Definition: object.h:487
static object * find_best_player_hth_skill(object *op)
Finds the best unarmed skill the player has, and returns it.
#define FOR_INV_PREPARE(op_, it_)
Constructs a loop iterating over the inventory of an object.
Definition: define.h:693
void * repeat_func_data
Arguments to pass into repeat_func.
Definition: player.h:233
void apply_anim_suffix(object *who, const char *suffix)
Applies a compound animation to an object.
Definition: anim.cpp:150
#define FLAG_FREED
Object is in the list of free objects.
Definition: define.h:220