ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/skill_util.C
(Generate patch)

Comparing deliantra/server/server/skill_util.C (file contents):
Revision 1.9 by root, Sun Sep 10 15:59:57 2006 UTC vs.
Revision 1.17 by root, Mon Dec 11 02:54:57 2006 UTC

1
2/*
3 * static char *rcsid_skill_util_c =
4 * "$Id: skill_util.C,v 1.9 2006/09/10 15:59:57 root Exp $";
5 */
6
7/* 1/*
8 CrossFire, A Multiplayer game for X-windows 2 CrossFire, A Multiplayer game for X-windows
9 3
10 Copryight (C) 2002 Mark Wedel & Crossfire Development Team 4 Copryight (C) 2002 Mark Wedel & Crossfire Development Team
11 Copyright (C) 1992 Frank Tore Johansen 5 Copyright (C) 1992 Frank Tore Johansen
22 16
23 You should have received a copy of the GNU General Public License 17 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software 18 along with this program; if not, write to the Free Software
25 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 20
27 The author can be reached via e-mail to crossfire-devel@real-time.com 21 The author can be reached via e-mail to <crossfire@schmorp.de>
28*/ 22*/
29 23
30/* Created July 95 to separate skill utilities from actual skills -b.t. */ 24/* Created July 95 to separate skill utilities from actual skills -b.t. */
31 25
32/* Reconfigured skills code to allow linking of skills to experience 26/* Reconfigured skills code to allow linking of skills to experience
42 */ 36 */
43 37
44/* define the following for skills utility debuging */ 38/* define the following for skills utility debuging */
45 39
46/* #define SKILL_UTIL_DEBUG */ 40/* #define SKILL_UTIL_DEBUG */
47
48#define WANT_UNARMED_SKILLS
49 41
50#include <global.h> 42#include <global.h>
51#include <object.h> 43#include <object.h>
52#ifndef __CEXTRACT__ 44#ifndef __CEXTRACT__
53# include <sproto.h> 45# include <sproto.h>
54#endif 46#endif
55#include <living.h> /* for defs of STR,CON,DEX,etc. -b.t. */ 47#include <living.h> /* for defs of STR,CON,DEX,etc. -b.t. */
56#include <spells.h> 48#include <spells.h>
57 49
50/* Table of unarmed attack skills. Terminated by -1. This
51 * is also the list that we should try to use skills when
52 * automatically applying one for the player.
53 */
54static uint8 unarmed_skills[] = {
55 SK_KARATE,
56 SK_CLAWING,
57 SK_FLAME_TOUCH,
58 SK_SPARK_TOUCH,
59 SK_SHIVER,
60 SK_ACID_SPLASH,
61 SK_POISON_NAIL,
62 SK_PUNCHING,
63 (uint8)-1
64};
65
58static int attack_hth (object *pl, int dir, const char *string, object *skill); 66static int attack_hth (object *pl, int dir, const char *string, object *skill);
59static int attack_melee_weapon (object *op, int dir, const char *string, object *skill); 67static int attack_melee_weapon (object *op, int dir, const char *string, object *skill);
60
61shstr skill_names[NUM_SKILLS];
62 68
63/* init_skills basically just sets up the skill_names table 69/* init_skills basically just sets up the skill_names table
64 * above. The index into the array is set up by the 70 * above. The index into the array is set up by the
65 * subtypes. 71 * subtypes.
66 */ 72 */
69{ 75{
70 int i; 76 int i;
71 archetype *at; 77 archetype *at;
72 78
73 for (at = first_archetype; at != NULL; at = at->next) 79 for (at = first_archetype; at != NULL; at = at->next)
74 {
75 if (at->clone.type == SKILL) 80 if (at->clone.type == SKILL)
76 { 81 {
77 if (skill_names[at->clone.subtype] != NULL) 82 if (skill_names[at->clone.subtype] != NULL)
78 {
79 LOG (llevError, "init_skills: multiple skill using same subtype %d, %s, %s\n", 83 LOG (llevError, "init_skills: multiple skill using same subtype %d, %s, %s\n",
80 at->clone.subtype, &skill_names[at->clone.subtype], &at->clone.skill); 84 at->clone.subtype, &skill_names[at->clone.subtype], &at->clone.skill);
81 }
82 else 85 else
83 {
84 skill_names[at->clone.subtype] = at->clone.skill; 86 skill_names[at->clone.subtype] = at->clone.skill;
85 }
86 } 87 }
87 }
88 88
89 /* This isn't really an error if there is no skill subtype set, but 89 /* This isn't really an error if there is no skill subtype set, but
90 * checking for this may catch some user errors. 90 * checking for this may catch some user errors.
91 */ 91 */
92 for (i = 1; i < NUM_SKILLS; i++) 92 for (i = 1; i < NUM_SKILLS; i++)
239 if (!QUERY_FLAG (skill_tool, FLAG_APPLIED)) 239 if (!QUERY_FLAG (skill_tool, FLAG_APPLIED))
240 { 240 {
241 if (apply_special (who, skill_tool, 0)) 241 if (apply_special (who, skill_tool, 0))
242 return NULL; 242 return NULL;
243 } 243 }
244
244 if (!skill) 245 if (!skill)
245 { 246 {
246 skill = give_skill_by_name (who, skill_tool->skill); 247 skill = give_skill_by_name (who, skill_tool->skill);
247 link_player_skills (who); 248 link_player_skills (who);
248 } 249 }
250
249 return skill; 251 return skill;
250 } 252 }
253
251 return NULL; 254 return NULL;
252} 255}
253 256
254/* This changes the objects skill to new_skill. 257/* This changes the objects skill to new_skill.
255 * note that this function doesn't always need to get used - 258 * note that this function doesn't always need to get used -
276 if (who->chosen_skill && who->chosen_skill == new_skill) 279 if (who->chosen_skill && who->chosen_skill == new_skill)
277 { 280 {
278 /* optimization for changing skill to current skill */ 281 /* optimization for changing skill to current skill */
279 if (who->type == PLAYER && !(flag & 0x1)) 282 if (who->type == PLAYER && !(flag & 0x1))
280 who->contr->shoottype = range_skill; 283 who->contr->shoottype = range_skill;
284
281 return 1; 285 return 1;
282 } 286 }
287
288 // move skill to front, so it will be preferred next time
289 new_skill->remove ();
290 who->insert (new_skill);
283 291
284 if (!new_skill || who->chosen_skill) 292 if (!new_skill || who->chosen_skill)
285 if (who->chosen_skill) 293 if (who->chosen_skill)
286 apply_special (who, who->chosen_skill, AP_UNAPPLY); 294 apply_special (who, who->chosen_skill, AP_UNAPPLY);
287 295
288 /* Only goal in this case was to unapply a skill */ 296 /* Only goal in this case was to unapply a skill */
289 if (!new_skill) 297 if (!new_skill)
290 return 0; 298 return 0;
291 299
292 if (apply_special (who, new_skill, AP_APPLY)) 300 if (apply_special (who, new_skill, AP_APPLY))
293 {
294 return 0; 301 return 0;
295 } 302
296 if (flag & 0x1) 303 if (flag & 0x1)
297 who->contr->shoottype = (rangetype) old_range; 304 who->contr->shoottype = (rangetype)old_range;
298 305
299 return 1; 306 return 1;
300} 307}
301 308
302/* This function just clears the chosen_skill and range_skill values 309/* This function just clears the chosen_skill and range_skill values
465 * failing that, we go and identify stuff. 472 * failing that, we go and identify stuff.
466 */ 473 */
467 for (tmp = get_map_ob (op->map, op->x, op->y); tmp != NULL; tmp = next) 474 for (tmp = get_map_ob (op->map, op->x, op->y); tmp != NULL; tmp = next)
468 { 475 {
469 next = tmp->above; 476 next = tmp->above;
477
470 if (QUERY_FLAG (tmp, FLAG_IS_CAULDRON)) 478 if (QUERY_FLAG (tmp, FLAG_IS_CAULDRON))
471 { 479 {
472 attempt_do_alchemy (op, tmp); 480 attempt_do_alchemy (op, tmp);
481
473 if (QUERY_FLAG (tmp, FLAG_APPLIED)) 482 if (QUERY_FLAG (tmp, FLAG_APPLIED))
474 esrv_send_inventory (op, tmp); 483 esrv_send_inventory (op, tmp);
484
475 did_alc = 1; 485 did_alc = 1;
476 } 486 }
477 } 487 }
488
478 if (did_alc == 0) 489 if (did_alc == 0)
479 exp = success = skill_ident (op, skill); 490 exp = success = skill_ident (op, skill);
491
480 break; 492 break;
481 493
482 case SK_DET_MAGIC: 494 case SK_DET_MAGIC:
483 case SK_DET_CURSE: 495 case SK_DET_CURSE:
484 exp = success = skill_ident (op, skill); 496 exp = success = skill_ident (op, skill);
689 701
690 /* player already knows it */ 702 /* player already knows it */
691 if (tmp && QUERY_FLAG (tmp, FLAG_CAN_USE_SKILL)) 703 if (tmp && QUERY_FLAG (tmp, FLAG_CAN_USE_SKILL))
692 return 0; 704 return 0;
693 705
694
695
696 /* now a random change to learn, based on player Int. 706 /* now a random change to learn, based on player Int.
697 * give bonus based on level - otherwise stupid characters 707 * give bonus based on level - otherwise stupid characters
698 * might never be able to learn anything. 708 * might never be able to learn anything.
699 */ 709 */
700 if (random_roll (0, 99, pl, PREFER_LOW) > (learn_spell[pl->stats.Int] + (pl->level / 5))) 710 if (random_roll (0, 99, pl, PREFER_LOW) > (learn_spell[pl->stats.Int] + (pl->level / 5)))
874 return 1; 884 return 1;
875 885
876 return 0; 886 return 0;
877} 887}
878 888
889static bool
890hth_skill_p (object *skill)
891{
892 for (int i = 0; i < sizeof (unarmed_skills); ++i)
893 if (skill->subtype == unarmed_skills[i])
894 return 1;
879 895
896 return 0;
897}
880 898
881/* This finds the best unarmed skill the player has, and returns 899/* This finds the first unarmed skill the player has, and returns it.
882 * it. Best can vary a little - we consider clawing to always
883 * be the best for dragons.
884 * This could be more intelligent, eg, look at the skill level
885 * of the skill and go from there (eg, a level 40 puncher is
886 * is probably better than level 1 karate). OTOH, if you
887 * don't bother to set up your skill properly, that is the players
888 * problem (although, it might be nice to have a preferred skill
889 * field the player can set.
890 * Unlike the old code, we don't give out any skills - it is
891 * possible you just don't have any ability to get into unarmed
892 * combat. If everyone race/class should have one, this should
893 * be handled in the starting treasurelists, not in the code.
894 */ 900 */
895static object * 901static object *
896find_best_player_hth_skill (object *op) 902find_player_hth_skill (object *op)
897{ 903{
898 object *tmp, *best_skill = NULL;
899 int dragon = is_dragon_pl (op), last_skill = sizeof (unarmed_skills), i;
900
901 for (tmp = op->inv; tmp; tmp = tmp->below) 904 for (object *tmp = op->inv; tmp; tmp = tmp->below)
902 { 905 if (tmp->type == SKILL && QUERY_FLAG (tmp, FLAG_CAN_USE_SKILL) && hth_skill_p (tmp))
903 if (tmp->type == SKILL)
904 {
905 if (dragon && tmp->subtype == SK_CLAWING)
906 return tmp; 906 return tmp;
907 907
908 /* The order in the array is preferred order. So basically, 908 return 0;
909 * we just cut down the number to search - eg, if we find a skill
910 * early on in flame touch, then we only need to look into the unarmed_array
911 * to the entry before flame touch - don't care about the entries afterward,
912 * because they are infrerior skills.
913 * if we end up finding the best skill (i==0) might as well return
914 * right away - can't get any better than that.
915 */
916 for (i = 0; i < last_skill; i++)
917 {
918 if (tmp->subtype == unarmed_skills[i] && QUERY_FLAG (tmp, FLAG_CAN_USE_SKILL))
919 {
920 best_skill = tmp;
921 last_skill = i;
922 if (i == 0)
923 return best_skill;
924 }
925 }
926 }
927 }
928 return best_skill;
929} 909}
930 910
931/* do_skill_attack() - We have got an appropriate opponent from either 911/* do_skill_attack() - We have got an appropriate opponent from either
932 * move_player_attack() or skill_attack(). In this part we get on with 912 * move_player_attack() or skill_attack(). In this part we get on with
933 * attacking, take care of messages from the attack and changes in invisible. 913 * attacking, take care of messages from the attack and changes in invisible.
954 */ 934 */
955 if (op->type == PLAYER) 935 if (op->type == PLAYER)
956 { 936 {
957 if (!QUERY_FLAG (op, FLAG_READY_WEAPON)) 937 if (!QUERY_FLAG (op, FLAG_READY_WEAPON))
958 { 938 {
959 size_t i;
960
961 if (!skill) 939 if (!skill)
962 { 940 {
963 /* See if the players chosen skill is a combat skill, and use 941 /* See if the players chosen skill is a combat skill, and use
964 * it if appropriate. 942 * it if appropriate.
965 */ 943 */
944 if (op->chosen_skill && hth_skill_p (op->chosen_skill))
966 if (op->chosen_skill) 945 skill = op->chosen_skill;
946 else
967 { 947 {
968 for (i = 0; i < sizeof (unarmed_skills); i++)
969 if (op->chosen_skill->subtype == unarmed_skills[i])
970 {
971 skill = op->chosen_skill;
972 break;
973 }
974 }
975 /* If we didn't find a skill above, look harder for a good skill */
976 if (!skill)
977 {
978 skill = find_best_player_hth_skill (op); 948 skill = find_player_hth_skill (op);
979 949
980 if (!skill) 950 if (!skill)
981 { 951 {
982 new_draw_info (NDI_BLACK, 0, op, "You have no unarmed combat skills!"); 952 new_draw_info (NDI_BLACK, 0, op, "You have no unarmed combat skills!");
983 return 0; 953 return 0;
984 } 954 }
985 } 955 }
986 } 956 }
987 if (skill != op->chosen_skill) 957
988 {
989 /* now try to ready the new skill */ 958 /* now try to ready the new skill */
990 if (!change_skill (op, skill, 0)) 959 if (!change_skill (op, skill, 0))
991 { /* oh oh, trouble! */ 960 { /* oh oh, trouble! */
992 new_draw_info_format (NDI_UNIQUE, 0, tmp, "Couldn't change to skill %s", &skill->name); 961 new_draw_info_format (NDI_UNIQUE, 0, tmp, "Couldn't change to skill %s", &skill->name);
993 return 0; 962 return 0;
994 }
995 } 963 }
996 } 964 }
997 else 965 else
998 { 966 {
999 /* Seen some crashes below where current_weapon is not set, 967 /* Seen some crashes below where current_weapon is not set,
1019 { 987 {
1020 op->current_weapon = tmp; 988 op->current_weapon = tmp;
1021 } 989 }
1022 } 990 }
1023 991
1024 /* Has ready weapon - make sure chosen_skill is set up properly */
1025 if (!op->chosen_skill || op->current_weapon->skill != op->chosen_skill->skill)
1026 {
1027 change_skill (op, find_skill_by_name (op, op->current_weapon->skill), 1); 992 change_skill (op, find_skill_by_name (op, op->current_weapon->skill), 1);
1028 }
1029 } 993 }
1030 } 994 }
1031 995
1032 /* lose invisiblity/hiding status for running attacks */ 996 /* lose invisiblity/hiding status for running attacks */
1033 997
1068 1032
1069int 1033int
1070skill_attack (object *tmp, object *pl, int dir, const char *string, object *skill) 1034skill_attack (object *tmp, object *pl, int dir, const char *string, object *skill)
1071{ 1035{
1072 sint16 tx, ty; 1036 sint16 tx, ty;
1073 mapstruct *m; 1037 maptile *m;
1074 int mflags; 1038 int mflags;
1075 1039
1076 if (!dir) 1040 if (!dir)
1077 dir = pl->facing; 1041 dir = pl->facing;
1042
1078 tx = freearr_x[dir]; 1043 tx = freearr_x[dir];
1079 ty = freearr_y[dir]; 1044 ty = freearr_y[dir];
1080 1045
1081 /* If we don't yet have an opponent, find if one exists, and attack. 1046 /* If we don't yet have an opponent, find if one exists, and attack.
1082 * Legal opponents are the same as outlined in move_player_attack() 1047 * Legal opponents are the same as outlined in move_player_attack()

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines