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.3 by root, Sat Aug 26 08:44:07 2006 UTC vs.
Revision 1.25 by root, Mon Jan 8 18:18:35 2007 UTC

1/*
2 * static char *rcsid_skill_util_c =
3 * "$Id: skill_util.C,v 1.3 2006/08/26 08:44:07 root Exp $";
4 */
5/* 1/*
6 CrossFire, A Multiplayer game for X-windows 2 CrossFire, A Multiplayer game for X-windows
7 3
4 Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team
8 Copryight (C) 2002 Mark Wedel & Crossfire Development Team 5 Copryight (C) 2002 Mark Wedel & Crossfire Development Team
9 Copyright (C) 1992 Frank Tore Johansen 6 Copyright (C) 1992 Frank Tore Johansen
10 7
11 This program is free software; you can redistribute it and/or modify 8 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by 9 it under the terms of the GNU General Public License as published by
20 17
21 You should have received a copy of the GNU General Public License 18 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software 19 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 21
25 The author can be reached via e-mail to crossfire-devel@real-time.com 22 The author can be reached via e-mail to <crossfire@schmorp.de>
26*/ 23*/
27 24
28/* Created July 95 to separate skill utilities from actual skills -b.t. */ 25/* Created July 95 to separate skill utilities from actual skills -b.t. */
29 26
30/* Reconfigured skills code to allow linking of skills to experience 27/* Reconfigured skills code to allow linking of skills to experience
38 * experience. Calc_skill_exp() handles the gained experience using 35 * experience. Calc_skill_exp() handles the gained experience using
39 * modifications in the skills[] table. - b.t. 36 * modifications in the skills[] table. - b.t.
40 */ 37 */
41 38
42/* define the following for skills utility debuging */ 39/* define the following for skills utility debuging */
40
43/* #define SKILL_UTIL_DEBUG */ 41/* #define SKILL_UTIL_DEBUG */
44
45#define WANT_UNARMED_SKILLS
46 42
47#include <global.h> 43#include <global.h>
48#include <object.h> 44#include <object.h>
49#ifndef __CEXTRACT__
50#include <sproto.h> 45#include <sproto.h>
51#endif
52#include <living.h> /* for defs of STR,CON,DEX,etc. -b.t.*/ 46#include <living.h> /* for defs of STR,CON,DEX,etc. -b.t. */
53#include <spells.h> 47#include <spells.h>
54 48
49/* Table of unarmed attack skills. Terminated by -1. This
50 * is also the list that we should try to use skills when
51 * automatically applying one for the player.
52 */
53static uint8 unarmed_skills[] = {
54 SK_KARATE,
55 SK_CLAWING,
56 SK_FLAME_TOUCH,
57 SK_SPARK_TOUCH,
58 SK_SHIVER,
59 SK_ACID_SPLASH,
60 SK_POISON_NAIL,
61 SK_PUNCHING,
62 (uint8)-1
63};
64
55static int attack_hth(object *pl, int dir, const char *string, object *skill); 65static int attack_hth (object *pl, int dir, const char *string, object *skill);
56static int attack_melee_weapon(object *op, int dir, const char *string, object *skill); 66static int attack_melee_weapon (object *op, int dir, const char *string, object *skill);
57
58const char *skill_names[NUM_SKILLS];
59 67
60/* init_skills basically just sets up the skill_names table 68/* init_skills basically just sets up the skill_names table
61 * above. The index into the array is set up by the 69 * above. The index into the array is set up by the
62 * subtypes. 70 * subtypes.
63 */ 71 */
72void
64void init_skills(void) { 73init_skills (void)
74{
65 int i; 75 int i;
66 archetype *at; 76 archetype *at;
67 77
68 for (i=0; i<NUM_SKILLS; i++)
69 skill_names[i] = NULL;
70
71 for(at = first_archetype;at!=NULL;at=at->next) { 78 for (at = first_archetype; at != NULL; at = at->next)
72 if (at->clone.type == SKILL) { 79 if (at->clone.type == SKILL)
80 {
73 if (skill_names[at->clone.subtype] != NULL) { 81 if (skill_names[at->clone.subtype] != NULL)
74 LOG(llevError, "init_skills: multiple skill using same subtype %d, %s, %s\n", 82 LOG (llevError, "init_skills: multiple skill using same subtype %d, %s, %s\n",
75 at->clone.subtype, skill_names[at->clone.subtype], at->clone.skill); 83 at->clone.subtype, &skill_names[at->clone.subtype], &at->clone.skill);
76 } else { 84 else
77 skill_names[at->clone.subtype] = add_refcount(at->clone.skill); 85 skill_names[at->clone.subtype] = at->clone.skill;
78 }
79 }
80 } 86 }
81 87
82 /* This isn't really an error if there is no skill subtype set, but 88 /* This isn't really an error if there is no skill subtype set, but
83 * checking for this may catch some user errors. 89 * checking for this may catch some user errors.
84 */ 90 */
85 for (i=1; i<NUM_SKILLS; i++) { 91 for (i = 1; i < NUM_SKILLS; i++)
92 {
86 if (!skill_names[i]) 93 if (!skill_names[i])
87 LOG(llevError, "init_skills: skill subtype %d doesn't have a name?\n", 94 LOG (llevError, "init_skills: skill subtype %d doesn't have a name?\n", i);
88 i);
89 } 95 }
90} 96}
91
92 97
93/* This function goes through the player inventory and sets 98/* This function goes through the player inventory and sets
94 * up the last_skills[] array in the player object. 99 * up the last_skills[] array in the player object.
95 * the last_skills[] is used to more quickly lookup skills - 100 * the last_skills[] is used to more quickly lookup skills -
96 * mostly used for sending exp. 101 * mostly used for sending exp.
97 */ 102 */
103void
98void link_player_skills(object *op) 104link_player_skills (object *op)
99{ 105{
100 object *tmp;
101
102 for (tmp=op->inv; tmp; tmp=tmp->below) { 106 for (object *tmp = op->inv; tmp; tmp = tmp->below)
103 if (tmp->type == SKILL) { 107 if (tmp->type == SKILL)
108 {
104 /* This is really a warning, hence no else below */ 109 /* This is really a warning, hence no else below */
105 if (op->contr->last_skill_ob[tmp->subtype] && op->contr->last_skill_ob[tmp->subtype] != tmp) { 110 if (op->contr->last_skill_ob[tmp->subtype] && op->contr->last_skill_ob[tmp->subtype] != tmp)
106 LOG(llevError,"Multiple skills with the same subtype? %s, %s\n", 111 LOG (llevError, "Multiple skills with the same subtype? %s, %s\n",
107 op->contr->last_skill_ob[tmp->subtype]->skill, tmp->skill); 112 &op->contr->last_skill_ob[tmp->subtype]->skill, &tmp->skill);
108 } 113
109 if (tmp->subtype >= NUM_SKILLS) { 114 if (tmp->subtype >= NUM_SKILLS)
110 LOG(llevError,"Invalid subtype number %d (range 0-%d)\n", 115 LOG (llevError, "Invalid subtype number %d (range 0-%d)\n", tmp->subtype, NUM_SKILLS);
111 tmp->subtype, NUM_SKILLS); 116 else
112 } else { 117 {
113 op->contr->last_skill_ob[tmp->subtype] = tmp; 118 op->contr->last_skill_ob[tmp->subtype] = tmp;
114 op->contr->last_skill_exp[tmp->subtype] = -1; 119 op->contr->ns->last_skill_exp[tmp->subtype] = -1; //TODO: this should go
115 } 120 }
116 }
117 } 121 }
118} 122}
119 123
120/* This returns the skill pointer of the given name (the 124/* This returns the skill pointer of the given name (the
121 * one that accumlates exp, has the level, etc). 125 * one that accumlates exp, has the level, etc).
122 * 126 *
123 * It is presumed that the player will be needing to actually 127 * It is presumed that the player will be needing to actually
124 * use the skill, so thus if use of the skill requires a skill 128 * use the skill, so thus if use of the skill requires a skill
125 * tool, this code will equip it. 129 * tool, this code will equip it.
126 */ 130 */
131object *
127object *find_skill_by_name(object *who, const char *name) 132find_skill_by_name (object *who, const char *name)
128{ 133{
129 object *skill=NULL, *skill_tool=NULL, *tmp; 134 object *skill = NULL, *skill_tool = NULL, *tmp;
130 135
131 if (!name) return NULL; 136 if (!name)
132
133 /* We make sure the length of the string in the object is greater
134 * in length than the passed string. Eg, if we have a skill called
135 * 'hi', we don't want to match if the user passed 'high'
136 */
137 for (tmp=who->inv; tmp!=NULL; tmp=tmp->below) {
138 if (tmp->type == SKILL && !strncasecmp(name, tmp->skill, strlen(name)) &&
139 strlen(tmp->skill) >= strlen(name)) skill = tmp;
140
141 /* Try to find appropriate skilltool. If the player has one already
142 * applied, we try to keep using that one.
143 */
144 else if (tmp->type == SKILL_TOOL && !strncasecmp(name, tmp->skill, strlen(name)) &&
145 strlen(tmp->skill) >= strlen(name)) {
146 if (QUERY_FLAG(tmp, FLAG_APPLIED)) skill_tool = tmp;
147 else if (!skill_tool || !QUERY_FLAG(skill_tool, FLAG_APPLIED))
148 skill_tool = tmp;
149 }
150 }
151 /* If this is a skill that can be used without a tool, return it */
152 if (skill && QUERY_FLAG(skill, FLAG_CAN_USE_SKILL)) return skill;
153
154 /* Player has a tool to use the skill. IF not applied, apply it -
155 * if not successful, return null. If they do have the skill tool
156 * but not the skill itself, give it to them.
157 */
158 if (skill_tool) {
159 if (!QUERY_FLAG(skill_tool, FLAG_APPLIED)) {
160 if (apply_special(who, skill_tool, 0)) return NULL;
161 }
162 if (!skill) {
163 skill = give_skill_by_name(who, skill_tool->skill);
164 link_player_skills(who);
165 }
166 return skill;
167 }
168 return NULL; 137 return NULL;
138
139 /* We make sure the length of the string in the object is greater
140 * in length than the passed string. Eg, if we have a skill called
141 * 'hi', we don't want to match if the user passed 'high'
142 */
143 for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
144 {
145 if (tmp->type == SKILL && !strncasecmp (name, tmp->skill, strlen (name)) && (size_t) strlen (tmp->skill) >= strlen (name))
146 skill = tmp;
147
148 /* Try to find appropriate skilltool. If the player has one already
149 * applied, we try to keep using that one.
150 */
151 else if (tmp->type == SKILL_TOOL && !strncasecmp (name, tmp->skill, strlen (name)) && (size_t) strlen (tmp->skill) >= strlen (name))
152 {
153 if (QUERY_FLAG (tmp, FLAG_APPLIED))
154 skill_tool = tmp;
155 else if (!skill_tool || !QUERY_FLAG (skill_tool, FLAG_APPLIED))
156 skill_tool = tmp;
157 }
158 }
159 /* If this is a skill that can be used without a tool, return it */
160 if (skill && QUERY_FLAG (skill, FLAG_CAN_USE_SKILL))
161 return skill;
162
163 /* Player has a tool to use the skill. IF not applied, apply it -
164 * if not successful, return null. If they do have the skill tool
165 * but not the skill itself, give it to them.
166 */
167 if (skill_tool)
168 {
169 if (!QUERY_FLAG (skill_tool, FLAG_APPLIED))
170 {
171 if (apply_special (who, skill_tool, 0))
172 return NULL;
173 }
174 if (!skill)
175 {
176 skill = give_skill_by_name (who, skill_tool->skill);
177 link_player_skills (who);
178 }
179 return skill;
180 }
181 return NULL;
169} 182}
170 183
171 184
172/* This returns the skill pointer of the given name (the 185/* This returns the skill pointer of the given name (the
173 * one that accumlates exp, has the level, etc). 186 * one that accumlates exp, has the level, etc).
178 * 191 *
179 * This code is basically the same as find_skill_by_name() above, 192 * This code is basically the same as find_skill_by_name() above,
180 * but instead a skill name, we search by matching number. 193 * but instead a skill name, we search by matching number.
181 * this replaces find_skill. 194 * this replaces find_skill.
182 */ 195 */
196object *
183object *find_skill_by_number(object *who, int skillno) 197find_skill_by_number (object *who, int skillno)
184{ 198{
185 object *skill=NULL, *skill_tool=NULL, *tmp; 199 object *skill = NULL, *skill_tool = NULL, *tmp;
186 200
187 if (skillno < 1 || skillno >= NUM_SKILLS) return NULL; 201 if (skillno < 1 || skillno >= NUM_SKILLS)
188
189 for (tmp=who->inv; tmp!=NULL; tmp=tmp->below) {
190 if (tmp->type == SKILL && tmp->subtype == skillno) skill = tmp;
191
192 /* Try to find appropriate skilltool. If the player has one already
193 * applied, we try to keep using that one.
194 */
195 else if (tmp->type == SKILL_TOOL && tmp->subtype == skillno) {
196 if (QUERY_FLAG(tmp, FLAG_APPLIED)) skill_tool = tmp;
197 else if (!skill_tool || !QUERY_FLAG(skill_tool, FLAG_APPLIED))
198 skill_tool = tmp;
199 }
200 }
201 /* If this is a skill that can be used without a tool, return it */
202 if (skill && QUERY_FLAG(skill, FLAG_CAN_USE_SKILL)) return skill;
203
204 /* Player has a tool to use the skill. IF not applied, apply it -
205 * if not successful, return null. If they do have the skill tool
206 * but not the skill itself, give it to them.
207 */
208 if (skill_tool) {
209 if (!QUERY_FLAG(skill_tool, FLAG_APPLIED)) {
210 if (apply_special(who, skill_tool, 0)) return NULL;
211 }
212 if (!skill) {
213 skill = give_skill_by_name(who, skill_tool->skill);
214 link_player_skills(who);
215 }
216 return skill;
217 }
218 return NULL; 202 return NULL;
203
204 for (tmp = who->inv; tmp != NULL; tmp = tmp->below)
205 {
206 if (tmp->type == SKILL && tmp->subtype == skillno)
207 skill = tmp;
208
209 /* Try to find appropriate skilltool. If the player has one already
210 * applied, we try to keep using that one.
211 */
212 else if (tmp->type == SKILL_TOOL && tmp->subtype == skillno)
213 {
214 if (QUERY_FLAG (tmp, FLAG_APPLIED))
215 skill_tool = tmp;
216 else if (!skill_tool || !QUERY_FLAG (skill_tool, FLAG_APPLIED))
217 skill_tool = tmp;
218 }
219 }
220 /* If this is a skill that can be used without a tool, return it */
221 if (skill && QUERY_FLAG (skill, FLAG_CAN_USE_SKILL))
222 return skill;
223
224 /* Player has a tool to use the skill. IF not applied, apply it -
225 * if not successful, return null. If they do have the skill tool
226 * but not the skill itself, give it to them.
227 */
228 if (skill_tool)
229 {
230 if (!QUERY_FLAG (skill_tool, FLAG_APPLIED))
231 {
232 if (apply_special (who, skill_tool, 0))
233 return NULL;
234 }
235
236 if (!skill)
237 {
238 skill = give_skill_by_name (who, skill_tool->skill);
239 link_player_skills (who);
240 }
241
242 return skill;
243 }
244
245 return NULL;
219} 246}
220 247
221/* This changes the objects skill to new_skill. 248/* This changes the objects skill to new_skill.
222 * note that this function doesn't always need to get used - 249 * note that this function doesn't always need to get used -
223 * you can now add skill exp to the player without the chosen_skill being 250 * you can now add skill exp to the player without the chosen_skill being
228 * 0x1: If set, don't update the range pointer. This is useful when we 255 * 0x1: If set, don't update the range pointer. This is useful when we
229 * need to ready a new skill, but don't want to clobber range. 256 * need to ready a new skill, but don't want to clobber range.
230 * return 1 on success, 0 on error 257 * return 1 on success, 0 on error
231 */ 258 */
232 259
260int
233int change_skill (object *who, object *new_skill, int flag) 261change_skill (object *who, object *new_skill, int flag)
234{ 262{
235 int old_range; 263 int old_range;
236 264
237 if ( who->type != PLAYER ) 265 if (who->type != PLAYER)
238 return 0; 266 return 0;
239 267
240 old_range = who->contr->shoottype; 268 old_range = who->contr->shoottype;
241 269
242 if (who->chosen_skill && who->chosen_skill == new_skill) 270 if (who->chosen_skill && who->chosen_skill == new_skill)
243 { 271 {
244 /* optimization for changing skill to current skill */ 272 /* optimization for changing skill to current skill */
245 if (who->type == PLAYER && !(flag & 0x1)) 273 if (who->type == PLAYER && !(flag & 0x1))
246 who->contr->shoottype = range_skill; 274 who->contr->shoottype = range_skill;
275
247 return 1; 276 return 1;
248 } 277 }
249 278
279 // move skill to front, so it will be preferred next time
280 new_skill->remove ();
281 who->insert (new_skill);
282
250 if (!new_skill || who->chosen_skill) 283 if (!new_skill || who->chosen_skill)
284 if (who->chosen_skill)
251 if (who->chosen_skill) apply_special(who, who->chosen_skill, AP_UNAPPLY); 285 apply_special (who, who->chosen_skill, AP_UNAPPLY);
252 286
253 /* Only goal in this case was to unapply a skill */ 287 /* Only goal in this case was to unapply a skill */
254 if (!new_skill) return 0; 288 if (!new_skill)
289 return 0;
255 290
256 if (apply_special (who, new_skill, AP_APPLY)) { 291 if (apply_special (who, new_skill, AP_APPLY))
257 return 0; 292 return 0;
258 } 293
259 if (flag & 0x1) 294 if (flag & 0x1)
260 who->contr->shoottype = (rangetype) old_range; 295 who->contr->shoottype = (rangetype)old_range;
261 296
262 return 1; 297 return 1;
263} 298}
264 299
265/* This function just clears the chosen_skill and range_skill values 300/* This function just clears the chosen_skill and range_skill values
266 * inthe player. 301 * inthe player.
267 */ 302 */
303void
268void clear_skill(object *who) 304clear_skill (object *who)
269{ 305{
270 who->chosen_skill = NULL; 306 who->chosen_skill = NULL;
271 CLEAR_FLAG(who, FLAG_READY_SKILL); 307 CLEAR_FLAG (who, FLAG_READY_SKILL);
272 if (who->type == PLAYER) { 308 if (who->type == PLAYER)
309 {
273 who->contr->ranges[range_skill] = NULL; 310 who->contr->ranges[range_skill] = NULL;
274 if (who->contr->shoottype == range_skill) 311 if (who->contr->shoottype == range_skill)
275 who->contr->shoottype = range_none; 312 who->contr->shoottype = range_none;
276 } 313 }
277} 314}
278 315
279/* do_skill() - Main skills use function-similar in scope to cast_spell(). 316/* do_skill() - Main skills use function-similar in scope to cast_spell().
280 * We handle all requests for skill use outside of some combat here. 317 * We handle all requests for skill use outside of some combat here.
285 * from know if a skill was actually used, as many skills don't 322 * from know if a skill was actually used, as many skills don't
286 * give any exp for their direct use (eg, throwing). 323 * give any exp for their direct use (eg, throwing).
287 * It returns 0 if no skill was used. 324 * It returns 0 if no skill was used.
288 */ 325 */
289 326
327int
290int do_skill (object *op, object *part, object *skill, int dir, const char *string) { 328do_skill (object *op, object *part, object *skill, int dir, const char *string)
329{
291 int success=0, exp=0; 330 int success = 0, exp = 0;
292 int did_alc = 0; 331 int did_alc = 0;
293 object *tmp, *next; 332 object *tmp, *next;
294 333
295 if (!skill) return 0; 334 if (!skill)
335 return 0;
296 336
297 /* The code below presumes that the skill points to the object that 337 /* The code below presumes that the skill points to the object that
298 * holds the exp, level, etc of the skill. So if this is a player 338 * holds the exp, level, etc of the skill. So if this is a player
299 * go and try to find the actual real skill pointer, and if the 339 * go and try to find the actual real skill pointer, and if the
300 * the player doesn't have a bucket for that, create one. 340 * the player doesn't have a bucket for that, create one.
301 */ 341 */
302 if (skill->type != SKILL && op->type == PLAYER) { 342 if (skill->type != SKILL && op->type == PLAYER)
343 {
303 for (tmp = op->inv; tmp!=NULL; tmp=tmp->below) { 344 for (tmp = op->inv; tmp != NULL; tmp = tmp->below)
345 {
304 if (tmp->type == SKILL && tmp->skill == skill->skill) break; 346 if (tmp->type == SKILL && tmp->skill == skill->skill)
305 } 347 break;
348 }
349 if (!tmp)
306 if (!tmp) tmp=give_skill_by_name(op, skill->skill); 350 tmp = give_skill_by_name (op, skill->skill);
307 skill = tmp; 351 skill = tmp;
308 } 352 }
309 353
310 // skill, by_whom, on_which_object, which direction, skill_argument 354 // skill, by_whom, on_which_object, which direction, skill_argument
311 if (INVOKE_OBJECT (USE_SKILL, skill, ARG_OBJECT (op), ARG_OBJECT (part), ARG_INT (dir), ARG_STRING (string))) 355 if (INVOKE_OBJECT (USE_SKILL, skill, ARG_OBJECT (op), ARG_OBJECT (part), ARG_INT (dir), ARG_STRING (string)))
312 return 0; 356 return 0;
313 357
314 switch(skill->subtype) { 358 switch (skill->subtype)
359 {
315 case SK_LEVITATION: 360 case SK_LEVITATION:
316 /* Not 100% sure if this will work with new movement code - 361 /* Not 100% sure if this will work with new movement code -
317 * the levitation skill has move_type for flying, so when 362 * the levitation skill has move_type for flying, so when
318 * equipped, that should transfer to player, when not, 363 * equipped, that should transfer to player, when not,
319 * shouldn't. 364 * shouldn't.
320 */ 365 */
321 if(QUERY_FLAG(skill,FLAG_APPLIED)) { 366 if (QUERY_FLAG (skill, FLAG_APPLIED))
367 {
322 CLEAR_FLAG(skill,FLAG_APPLIED); 368 CLEAR_FLAG (skill, FLAG_APPLIED);
323 new_draw_info(NDI_UNIQUE,0,op,"You come to earth."); 369 new_draw_info (NDI_UNIQUE, 0, op, "You come to earth.");
324 } 370 }
325 else { 371 else
372 {
326 SET_FLAG(skill,FLAG_APPLIED); 373 SET_FLAG (skill, FLAG_APPLIED);
327 new_draw_info(NDI_UNIQUE,0,op,"You rise into the air!."); 374 new_draw_info (NDI_UNIQUE, 0, op, "You rise into the air!.");
328 } 375 }
329 fix_player(op); 376 op->update_stats ();
330 success=1; 377 success = 1;
331 break; 378 break;
332 379
333 case SK_STEALING: 380 case SK_STEALING:
334 exp = success = steal(op, dir, skill); 381 exp = success = steal (op, dir, skill);
335 break; 382 break;
336 383
337 case SK_LOCKPICKING: 384 case SK_LOCKPICKING:
338 exp = success = pick_lock(op, dir, skill); 385 exp = success = pick_lock (op, dir, skill);
339 break; 386 break;
340 387
341 case SK_HIDING: 388 case SK_HIDING:
342 exp = success = hide(op, skill); 389 exp = success = hide (op, skill);
343 break; 390 break;
344 391
345 case SK_JUMPING: 392 case SK_JUMPING:
346 success = jump(op, dir, skill); 393 success = jump (op, dir, skill);
347 break; 394 break;
348 395
349 case SK_INSCRIPTION: 396 case SK_INSCRIPTION:
350 exp = success = write_on_item(op,string, skill); 397 exp = success = write_on_item (op, string, skill);
351 break; 398 break;
352 399
353 case SK_MEDITATION: 400 case SK_MEDITATION:
354 meditate(op, skill); 401 meditate (op, skill);
355 success=1; 402 success = 1;
356 break; 403 break;
357 /* note that the following 'attack' skills gain exp through hit_player() */ 404 /* note that the following 'attack' skills gain exp through hit_player() */
358 405
359 case SK_KARATE: 406 case SK_KARATE:
360 (void) attack_hth(op,dir,"karate-chopped", skill); 407 (void) attack_hth (op, dir, "karate-chopped", skill);
361 break; 408 break;
362 409
363 case SK_PUNCHING: 410 case SK_PUNCHING:
364 (void) attack_hth(op,dir,"punched", skill); 411 (void) attack_hth (op, dir, "punched", skill);
365 break; 412 break;
366 413
367 case SK_FLAME_TOUCH: 414 case SK_FLAME_TOUCH:
368 (void) attack_hth(op,dir,"flamed", skill); 415 (void) attack_hth (op, dir, "flamed", skill);
369 break; 416 break;
370 417
371 case SK_SPARK_TOUCH: 418 case SK_SPARK_TOUCH:
372 (void) attack_hth(op,dir,"zapped", skill); 419 (void) attack_hth (op, dir, "zapped", skill);
373 break; 420 break;
374 421
375 case SK_SHIVER: 422 case SK_SHIVER:
376 (void) attack_hth(op,dir,"froze", skill); 423 (void) attack_hth (op, dir, "froze", skill);
377 break; 424 break;
378 425
379 case SK_ACID_SPLASH: 426 case SK_ACID_SPLASH:
380 (void) attack_hth(op,dir,"dissolved", skill); 427 (void) attack_hth (op, dir, "dissolved", skill);
381 break; 428 break;
382 429
383 case SK_POISON_NAIL: 430 case SK_POISON_NAIL:
384 (void) attack_hth(op,dir,"injected poison into", skill); 431 (void) attack_hth (op, dir, "injected poison into", skill);
385 break; 432 break;
386 433
387 case SK_CLAWING: 434 case SK_CLAWING:
388 (void) attack_hth(op,dir,"clawed", skill); 435 (void) attack_hth (op, dir, "clawed", skill);
389 break; 436 break;
390 437
391 case SK_ONE_HANDED_WEAPON: 438 case SK_ONE_HANDED_WEAPON:
392 case SK_TWO_HANDED_WEAPON: 439 case SK_TWO_HANDED_WEAPON:
393 (void) attack_melee_weapon(op,dir,NULL, skill); 440 (void) attack_melee_weapon (op, dir, NULL, skill);
394 break; 441 break;
395 442
396 case SK_FIND_TRAPS: 443 case SK_FIND_TRAPS:
397 exp = success = find_traps(op, skill); 444 exp = success = find_traps (op, skill);
398 break; 445 break;
399 446
400 case SK_SINGING: 447 case SK_SINGING:
401 exp = success = singing(op,dir, skill); 448 exp = success = singing (op, dir, skill);
402 break; 449 break;
403 450
404 case SK_ORATORY: 451 case SK_ORATORY:
405 exp = success = use_oratory(op,dir, skill); 452 exp = success = use_oratory (op, dir, skill);
406 break; 453 break;
407 454
408 case SK_SMITHERY: 455 case SK_SMITHERY:
409 case SK_BOWYER: 456 case SK_BOWYER:
410 case SK_JEWELER: 457 case SK_JEWELER:
411 case SK_ALCHEMY: 458 case SK_ALCHEMY:
412 case SK_THAUMATURGY: 459 case SK_THAUMATURGY:
413 case SK_LITERACY: 460 case SK_LITERACY:
414 case SK_WOODSMAN: 461 case SK_WOODSMAN:
415 /* first, we try to find a cauldron, and do the alchemy thing. 462 /* first, we try to find a cauldron, and do the alchemy thing.
416 * failing that, we go and identify stuff. 463 * failing that, we go and identify stuff.
417 */ 464 */
418 for (tmp=get_map_ob(op->map, op->x, op->y); tmp != NULL;tmp=next) { 465 for (tmp = GET_MAP_OB (op->map, op->x, op->y); tmp != NULL; tmp = next)
419 next=tmp->above; 466 {
467 next = tmp->above;
468
420 if(QUERY_FLAG(tmp, FLAG_IS_CAULDRON)) { 469 if (QUERY_FLAG (tmp, FLAG_IS_CAULDRON))
470 {
421 attempt_do_alchemy(op, tmp); 471 attempt_do_alchemy (op, tmp);
472
422 if (QUERY_FLAG(tmp, FLAG_APPLIED)) 473 if (QUERY_FLAG (tmp, FLAG_APPLIED))
423 esrv_send_inventory(op, tmp); 474 esrv_send_inventory (op, tmp);
424 did_alc=1; 475
425 } 476 did_alc = 1;
426 } 477 }
478 }
479
427 if (did_alc == 0) 480 if (did_alc == 0)
428 exp = success = skill_ident(op,skill); 481 exp = success = skill_ident (op, skill);
429 break;
430 482
483 break;
484
431 case SK_DET_MAGIC: 485 case SK_DET_MAGIC:
432 case SK_DET_CURSE: 486 case SK_DET_CURSE:
433 exp = success = skill_ident(op,skill); 487 exp = success = skill_ident (op, skill);
434 break; 488 break;
435 489
436 case SK_DISARM_TRAPS: 490 case SK_DISARM_TRAPS:
437 exp = success = remove_trap(op,dir, skill); 491 exp = success = remove_trap (op, dir, skill);
438 break; 492 break;
439 493
440 case SK_THROWING: 494 case SK_THROWING:
441 success = skill_throw(op,part,dir,string, skill); 495 success = skill_throw (op, part, dir, string, skill);
442 break; 496 break;
443 497
444 case SK_SET_TRAP: 498 case SK_SET_TRAP:
445 new_draw_info(NDI_UNIQUE, 0,op,"This skill is not currently implemented."); 499 new_draw_info (NDI_UNIQUE, 0, op, "This skill is not currently implemented.");
446 break; 500 break;
447 501
448 case SK_USE_MAGIC_ITEM: 502 case SK_USE_MAGIC_ITEM:
449 case SK_MISSILE_WEAPON: 503 case SK_MISSILE_WEAPON:
450 new_draw_info(NDI_UNIQUE, 0,op,"There is no special attack for this skill."); 504 new_draw_info (NDI_UNIQUE, 0, op, "There is no special attack for this skill.");
451 break; 505 break;
452 506
453 case SK_PRAYING: 507 case SK_PRAYING:
454 success = pray(op, skill); 508 success = pray (op, skill);
455 break; 509 break;
456 510
457 case SK_BARGAINING: 511 case SK_BARGAINING:
458 success = describe_shop(op); 512 success = describe_shop (op);
459 break; 513 break;
460 514
461 case SK_SORCERY: 515 case SK_SORCERY:
462 case SK_EVOCATION: 516 case SK_EVOCATION:
463 case SK_PYROMANCY: 517 case SK_PYROMANCY:
464 case SK_SUMMONING: 518 case SK_SUMMONING:
465 case SK_CLIMBING: 519 case SK_CLIMBING:
466 new_draw_info(NDI_UNIQUE, 0,op,"This skill is already in effect."); 520 new_draw_info (NDI_UNIQUE, 0, op, "This skill is already in effect.");
467 break; 521 break;
468 522
469 default: 523 default:
470 LOG(llevDebug,"%s attempted to use unknown skill: %d\n" 524 LOG (llevDebug, "%s attempted to use unknown skill: %d\n", query_name (op), op->chosen_skill->stats.sp);
471 ,query_name(op), op->chosen_skill->stats.sp); 525 break;
472 break;
473 } 526 }
474 527
475 /* For players we now update the speed_left from using the skill. 528 /* For players we now update the speed_left from using the skill.
476 * Monsters have no skill use time because of the random nature in 529 * Monsters have no skill use time because of the random nature in
477 * which use_monster_skill is called already simulates this. 530 * which use_monster_skill is called already simulates this.
478 * If certain skills should take more/less time, that should be 531 * If certain skills should take more/less time, that should be
479 * in the code for the skill itself. 532 * in the code for the skill itself.
480 */ 533 */
481
482 if(op->type==PLAYER) op->speed_left -= 1.0;
483 534
535 if (op->type == PLAYER)
536 op->speed_left -= 1.0;
537
484 /* this is a good place to add experience for successfull use of skills. 538 /* this is a good place to add experience for successfull use of skills.
485 * Note that add_exp() will figure out player/monster experience 539 * Note that add_exp() will figure out player/monster experience
486 * gain problems. 540 * gain problems.
487 */ 541 */
488 542
543 if (success && exp)
489 if(success && exp) change_exp(op,exp, skill->skill, 0); 544 change_exp (op, exp, skill->skill, 0);
490 545
491 return success; 546 return success;
492} 547}
493 548
494/* calc_skill_exp() - calculates amount of experience can be gained for 549/* calc_skill_exp() - calculates amount of experience can be gained for
495 * successfull use of a skill. Returns value of experience gain. 550 * successfull use of a skill. Returns value of experience gain.
496 * Here we take the view that a player must 'overcome an opponent' 551 * Here we take the view that a player must 'overcome an opponent'
515 * skill is the skill used. If no skill is used, it should just 570 * skill is the skill used. If no skill is used, it should just
516 * point back to who. 571 * point back to who.
517 * 572 *
518 */ 573 */
519 574
575int
520int calc_skill_exp(object *who, object *op, object *skill) { 576calc_skill_exp (object *who, object *op, object *skill)
577{
521 int op_exp=0,op_lvl= 0; 578 int op_exp = 0, op_lvl = 0;
522 float base,value,lvl_mult=0.0; 579 float base, value, lvl_mult = 0.0;
523 580
524 if (!skill) skill = who; 581 if (!skill)
582 skill = who;
525 583
526 /* Oct 95 - where we have an object, I expanded our treatment 584 /* Oct 95 - where we have an object, I expanded our treatment
527 * to 3 cases: 585 * to 3 cases:
528 * non-living magic obj, runes and everything else. 586 * non-living magic obj, runes and everything else.
529 * 587 *
530 * If an object is not alive and magical we set the base exp higher to 588 * If an object is not alive and magical we set the base exp higher to
531 * help out exp awards for skill_ident skills. Also, if 589 * help out exp awards for skill_ident skills. Also, if
532 * an item is type RUNE, we give out exp based on stats.Cha 590 * an item is type RUNE, we give out exp based on stats.Cha
533 * and level (this was the old system) -b.t. 591 * and level (this was the old system) -b.t.
534 */ 592 */
535 593
536 if(!op) { /* no item/creature */ 594 if (!op)
595 { /* no item/creature */
537 op_lvl= who->map->difficulty < 1 ? 1: who->map->difficulty; 596 op_lvl = who->map->difficulty < 1 ? 1 : who->map->difficulty;
538 op_exp = 0; 597 op_exp = 0;
539 } else if(op->type==RUNE || op->type==TRAP) { /* all traps. If stats.Cha > 1 we use that 598 }
540 * for the amount of experience */ 599 else if (op->type == RUNE || op->type == TRAP)
600 { /* all traps. If stats.Cha > 1 we use that
601 * for the amount of experience */
541 op_exp = op->stats.Cha>1 ? op->stats.Cha : op->stats.exp; 602 op_exp = op->stats.Cha > 1 ? op->stats.Cha : op->stats.exp;
542 op_lvl = op->level; 603 op_lvl = op->level;
543 } else { /* all other items/living creatures */ 604 }
605 else
606 { /* all other items/living creatures */
544 op_exp = op->stats.exp; 607 op_exp = op->stats.exp;
545 op_lvl = op->level; 608 op_lvl = op->level;
546 if(!QUERY_FLAG(op,FLAG_ALIVE)) { /* for ident/make items */ 609 if (!QUERY_FLAG (op, FLAG_ALIVE))
610 { /* for ident/make items */
547 op_lvl += 5 * abs(op->magic); 611 op_lvl += 5 * abs (op->magic);
548 } 612 }
549 } 613 }
550 614
551 if(op_lvl<1) op_lvl = 1; 615 if (op_lvl < 1)
616 op_lvl = 1;
552 617
553 if(who->type!=PLAYER) { /* for monsters only */ 618 if (who->type != PLAYER)
619 { /* for monsters only */
554 return ((int) (op_exp*0.1)+1); /* we add one to insure positive value is returned */ 620 return ((int) (op_exp * 0.1) + 1); /* we add one to insure positive value is returned */
621 }
622 else
555 } else { /* for players */ 623 { /* for players */
556 base = op_exp; 624 base = op_exp;
557 /* if skill really is a skill, then we can look at the skill archetype for 625 /* if skill really is a skill, then we can look at the skill archetype for
558 * bse reward value (exp) and level multiplier factor. 626 * bse reward value (exp) and level multiplier factor.
559 */ 627 */
560 if (skill->type == SKILL) { 628 if (skill->type == SKILL)
629 {
561 base += skill->arch->clone.stats.exp; 630 base += skill->arch->clone.stats.exp;
562 if (settings.simple_exp) { 631 if (settings.simple_exp)
632 {
563 if (skill->arch->clone.level) 633 if (skill->arch->clone.level)
564 lvl_mult = (float) skill->arch->clone.level / 100.0; 634 lvl_mult = (float) skill->arch->clone.level / 100.0;
565 else 635 else
566 lvl_mult = 1.0; /* no adjustment */ 636 lvl_mult = 1.0; /* no adjustment */
567 } 637 }
568 else { 638 else
569 if (skill->level) 639 {
640 if (skill->level)
570 lvl_mult = ((float) skill->arch->clone.level * (float) op_lvl) / ((float) skill->level * 100.0); 641 lvl_mult = ((float) skill->arch->clone.level * (float) op_lvl) / ((float) skill->level * 100.0);
571 else 642 else
572 lvl_mult = 1.0; 643 lvl_mult = 1.0;
573 } 644 }
574 } else { 645 }
646 else
647 {
575 /* Don't divide by zero here! */ 648 /* Don't divide by zero here! */
576 lvl_mult = (float) op_lvl / (float) (skill->level?skill->level:1); 649 lvl_mult = (float) op_lvl / (float) (skill->level ? skill->level : 1);
577 } 650 }
578 } 651 }
579 652
580 /* assemble the exp total, and return value */ 653 /* assemble the exp total, and return value */
581 654
582 value = base * lvl_mult; 655 value = base * lvl_mult;
656 if (value < 1)
583 if (value < 1) value=1; /* Always give at least 1 exp point */ 657 value = 1; /* Always give at least 1 exp point */
584 658
585#ifdef SKILL_UTIL_DEBUG 659#ifdef SKILL_UTIL_DEBUG
586 LOG(llevDebug,"calc_skill_exp(): who: %s(lvl:%d) op:%s(lvl:%d)\n", 660 LOG (llevDebug, "calc_skill_exp(): who: %s(lvl:%d) op:%s(lvl:%d)\n", who->name, skill->level, op->name, op_lvl);
587 who->name,skill->level,op->name,op_lvl);
588#endif 661#endif
589 return ( (int) value); 662 return ((int) value);
590} 663}
591 664
592/* Learn skill. This inserts the requested skill in the player's 665/* Learn skill. This inserts the requested skill in the player's
593 * inventory. The skill field of the scroll should have the 666 * inventory. The skill field of the scroll should have the
594 * exact name of the requested skill. 667 * exact name of the requested skill.
595 * This one actually teaches the player the skill as something 668 * This one actually teaches the player the skill as something
596 * they can equip. 669 * they can equip.
597 * Return 0 if the player knows the skill, 1 if the 670 * Return 0 if the player knows the skill, 1 if the
598 * player learns the skill, 2 otherwise. 671 * player learns the skill, 2 otherwise.
599 */ 672 */
600 673
601int 674int
602learn_skill (object *pl, object *scroll) { 675learn_skill (object *pl, object *scroll)
676{
603 object *tmp; 677 object *tmp;
604 678
605 if (!scroll->skill) { 679 if (!scroll->skill)
680 {
606 LOG(llevError,"skill scroll %s does not have skill pointer set.\n", scroll->name); 681 LOG (llevError, "skill scroll %s does not have skill pointer set.\n", &scroll->name);
607 return 2; 682 return 2;
608 } 683 }
609 684
610 /* can't use find_skill_by_name because we want skills the player knows 685 /* can't use find_skill_by_name because we want skills the player knows
611 * but can't use natively. 686 * but can't use natively.
612 */ 687 */
613 688
614 for (tmp=pl->inv; tmp!=NULL; tmp=tmp->below) 689 for (tmp = pl->inv; tmp != NULL; tmp = tmp->below)
615 if (tmp->type == SKILL && !strncasecmp(scroll->skill, tmp->skill, strlen(scroll->skill))) break; 690 if (tmp->type == SKILL && !strncasecmp (scroll->skill, tmp->skill, strlen (scroll->skill)))
691 break;
616 692
617 /* player already knows it */ 693 /* player already knows it */
618 if (tmp && QUERY_FLAG(tmp, FLAG_CAN_USE_SKILL)) return 0; 694 if (tmp && QUERY_FLAG (tmp, FLAG_CAN_USE_SKILL))
695 return 0;
619 696
620
621
622 /* now a random change to learn, based on player Int. 697 /* now a random change to learn, based on player Int.
623 * give bonus based on level - otherwise stupid characters 698 * give bonus based on level - otherwise stupid characters
624 * might never be able to learn anything. 699 * might never be able to learn anything.
625 */ 700 */
626 if(random_roll(0, 99, pl, PREFER_LOW)>(learn_spell[pl->stats.Int] + (pl->level/5))) 701 if (random_roll (0, 99, pl, PREFER_LOW) > (learn_spell[pl->stats.Int] + (pl->level / 5)))
627 return 2; /* failure :< */ 702 return 2; /* failure :< */
628 703
629 if (!tmp) 704 if (!tmp)
630 tmp = give_skill_by_name(pl, scroll->skill); 705 tmp = give_skill_by_name (pl, scroll->skill);
631 706
632 if (!tmp) { 707 if (!tmp)
708 {
633 LOG(llevError,"skill scroll %s does not have valid skill name (%s).\n", scroll->name, scroll->skill); 709 LOG (llevError, "skill scroll %s does not have valid skill name (%s).\n", &scroll->name, &scroll->skill);
634 return 2; 710 return 2;
635 } 711 }
636 712
637 SET_FLAG(tmp, FLAG_CAN_USE_SKILL); 713 SET_FLAG (tmp, FLAG_CAN_USE_SKILL);
638 link_player_skills(pl); 714 link_player_skills (pl);
639 return 1; 715 return 1;
640} 716}
641 717
642/* Gives a percentage clipped to 0% -> 100% of a/b. */ 718/* Gives a percentage clipped to 0% -> 100% of a/b. */
719
643/* Probably belongs in some global utils-type file? */ 720/* Probably belongs in some global utils-type file? */
721static int
644static int clipped_percent(sint64 a, sint64 b) 722clipped_percent (sint64 a, sint64 b)
645{ 723{
646 int rv; 724 int rv;
647 725
648 if (b <= 0) 726 if (b <= 0)
649 return 0; 727 return 0;
650 728
651 rv = (int)((100.0f * ((float)a) / ((float)b) ) + 0.5f); 729 rv = (int) ((100.0f * ((float) a) / ((float) b)) + 0.5f);
652 730
653 if (rv < 0) 731 if (rv < 0)
654 return 0; 732 return 0;
655 else if (rv > 100) 733 else if (rv > 100)
656 return 100; 734 return 100;
657 735
658 return rv; 736 return rv;
659} 737}
660 738
661/* show_skills() - Meant to allow players to examine 739/* show_skills() - Meant to allow players to examine
662 * their current skill list. 740 * their current skill list.
666 * Note this function is a bit more complicated becauase we 744 * Note this function is a bit more complicated becauase we
667 * we want ot sort the skills before printing them. If we 745 * we want ot sort the skills before printing them. If we
668 * just dumped this as we found it, this would be a bit 746 * just dumped this as we found it, this would be a bit
669 * simpler. 747 * simpler.
670 */ 748 */
671 749
750void
672void show_skills(object *op, const char* search) { 751show_skills (object *op, const char *search)
752{
673 object *tmp=NULL; 753 object *tmp = NULL;
674 char buf[MAX_BUF]; 754 char buf[MAX_BUF];
675 const char *cp; 755 const char *cp;
676 int i,num_skills_found=0; 756 int i, num_skills_found = 0;
677 static const char *const periods = "........................................"; 757 static const char *const periods = "........................................";
758
678 /* Need to have a pointer and use strdup for qsort to work properly */ 759 /* Need to have a pointer and use strdup for qsort to work properly */
679 char skills[NUM_SKILLS][MAX_BUF]; 760 char skills[NUM_SKILLS][MAX_BUF];
680 761
681 762
682 for (tmp=op->inv; tmp!=NULL; tmp=tmp->below) { 763 for (tmp = op->inv; tmp != NULL; tmp = tmp->below)
764 {
683 if (tmp->type == SKILL) { 765 if (tmp->type == SKILL)
766 {
684 if ( search && strstr(tmp->name,search)==NULL ) continue; 767 if (search && strstr (tmp->name, search) == NULL)
768 continue;
685 /* Basically want to fill this out to 40 spaces with periods */ 769 /* Basically want to fill this out to 40 spaces with periods */
686 sprintf(buf,"%s%s", tmp->name, periods); 770 sprintf (buf, "%s%s", &tmp->name, periods);
687 buf[40] = 0; 771 buf[40] = 0;
688 772
689 if (settings.permanent_exp_ratio) { 773 if (settings.permanent_exp_ratio)
690#ifdef WIN32 774 {
691 sprintf(skills[num_skills_found++],"%slvl:%3d (xp:%I64d/%I64d/%d%%)", 775 sprintf (skills[num_skills_found++], "%slvl:%3d (xp:%" PRId64 "/%" PRId64 "/%d%%)",
692 buf,tmp->level, 776 buf, tmp->level, tmp->stats.exp,
693 tmp->stats.exp, 777 level_exp (tmp->level + 1, op->expmul), clipped_percent (tmp->perm_exp, tmp->stats.exp));
694 level_exp(tmp->level+1, op->expmul), 778 }
695 clipped_percent(tmp->perm_exp,tmp->stats.exp)); 779 else
696#else 780 {
697 sprintf(skills[num_skills_found++],"%slvl:%3d (xp:%lld/%lld/%d%%)",
698 buf,tmp->level,
699 tmp->stats.exp,
700 level_exp(tmp->level+1, op->expmul),
701 clipped_percent(tmp->perm_exp,tmp->stats.exp));
702#endif
703 } else {
704#ifdef WIN32
705 sprintf(skills[num_skills_found++], "%slvl:%3d (xp:%I64d/%I64d)", 781 sprintf (skills[num_skills_found++], "%slvl:%3d (xp:%" PRId64 "/%" PRId64 ")",
706 buf,tmp->level, 782 buf, tmp->level, tmp->stats.exp, level_exp (tmp->level + 1, op->expmul));
707 tmp->stats.exp, 783 }
708 level_exp(tmp->level+1, op->expmul));
709#else
710 sprintf(skills[num_skills_found++], "%slvl:%3d (xp:%lld/%lld)",
711 buf,tmp->level,
712 tmp->stats.exp,
713 level_exp(tmp->level+1, op->expmul));
714#endif
715 }
716 /* I don't know why some characters get a bunch of skills, but 784 /* I don't know why some characters get a bunch of skills, but
717 * it sometimes happens (maybe a leftover from bugier earlier code 785 * it sometimes happens (maybe a leftover from bugier earlier code
718 * and those character are still about). In any case, lets handle 786 * and those character are still about). In any case, lets handle
719 * it so it doesn't crash the server - otherwise, one character may 787 * it so it doesn't crash the server - otherwise, one character may
720 * crash the server numerous times. 788 * crash the server numerous times.
721 */ 789 */
722 if (num_skills_found >= NUM_SKILLS) { 790 if (num_skills_found >= NUM_SKILLS)
791 {
723 new_draw_info(NDI_RED, 0, op, "Your character has too many skills."); 792 new_draw_info (NDI_RED, 0, op, "Your character has too many skills.");
724 new_draw_info(NDI_RED, 0, op, "Something isn't right - contact the server admin"); 793 new_draw_info (NDI_RED, 0, op, "Something isn't right - contact the server admin");
725 break; 794 break;
795 }
796 }
726 } 797 }
727 }
728 }
729 798
730 clear_win_info(op); 799 clear_win_info (op);
731 new_draw_info(NDI_UNIQUE, 0,op,"Player skills:"); 800 new_draw_info (NDI_UNIQUE, 0, op, "Player skills:");
801 if (num_skills_found > 1)
732 if (num_skills_found > 1) qsort(skills, num_skills_found, MAX_BUF, (int (*)(const void*, const void*))strcmp); 802 qsort (skills, num_skills_found, MAX_BUF, (int (*)(const void *, const void *)) strcmp);
733 803
734 for (i=0; i<num_skills_found; i++) { 804 for (i = 0; i < num_skills_found; i++)
805 {
735 new_draw_info(NDI_UNIQUE, 0, op, skills[i]); 806 new_draw_info (NDI_UNIQUE, 0, op, skills[i]);
736 } 807 }
737 808
738 new_draw_info_format(NDI_UNIQUE, 0, op, 809 new_draw_info_format (NDI_UNIQUE, 0, op, "You can handle %d weapon improvements.", op->level / 5 + 5);
739 "You can handle %d weapon improvements.",op->level/5+5);
740 810
741 cp = determine_god(op); 811 cp = determine_god (op);
742 new_draw_info_format(NDI_UNIQUE, 0, op, 812 new_draw_info_format (NDI_UNIQUE, 0, op, "You worship %s.", cp ? cp : "no god at current time");
743 "You worship %s.", cp?cp:"no god at current time");
744 813
745 new_draw_info_format(NDI_UNIQUE,0,op, "Your equipped item power is %d out of %d\n", 814 new_draw_info_format (NDI_UNIQUE, 0, op, "Your equipped item power is %d out of %d\n",
746 op->contr->item_power, (int) (op->level * settings.item_power_factor)); 815 op->contr->item_power, (int) (op->level * settings.item_power_factor));
747} 816}
748 817
749/* use_skill() - similar to invoke command, it executes the skill in the 818/* use_skill() - similar to invoke command, it executes the skill in the
750 * direction that the user is facing. Returns false if we are unable to 819 * direction that the user is facing. Returns false if we are unable to
751 * change to the requested skill, or were unable to use the skill properly. 820 * change to the requested skill, or were unable to use the skill properly.
752 * This is tricky because skills can have spaces. We basically roll 821 * This is tricky because skills can have spaces. We basically roll
753 * our own find_skill_by_name so we can try to do better string matching. 822 * our own find_skill_by_name so we can try to do better string matching.
754 */ 823 */
755 824
825int
756int use_skill(object *op, const char *string) { 826use_skill (object *op, const char *string)
827{
757 object *skop; 828 object *skop;
758 size_t len; 829 size_t len;
759 830
760 if (!string) return 0; 831 if (!string)
832 return 0;
761 833
762 for (skop = op->inv; skop != NULL; skop=skop->below) { 834 for (skop = op->inv; skop != NULL; skop = skop->below)
835 {
763 if (skop->type == SKILL && QUERY_FLAG(skop, FLAG_CAN_USE_SKILL) && 836 if (skop->type == SKILL && QUERY_FLAG (skop, FLAG_CAN_USE_SKILL) &&
764 !strncasecmp(string, skop->skill, MIN(strlen(string), strlen(skop->skill)))) 837 !strncasecmp (string, skop->skill, MIN (strlen (string), (size_t) strlen (skop->skill))))
765 break; 838 break;
766 else if (skop->type == SKILL_TOOL && 839 else if (skop->type == SKILL_TOOL && !strncasecmp (string, skop->skill, MIN (strlen (string), (size_t) strlen (skop->skill))))
767 !strncasecmp(string, skop->skill, MIN(strlen(string), strlen(skop->skill))))
768 break; 840 break;
769 } 841 }
770 if (!skop) { 842 if (!skop)
771 new_draw_info_format(NDI_UNIQUE, 0, op,
772 "Unable to find skill %s", string);
773 return 0;
774 } 843 {
844 new_draw_info_format (NDI_UNIQUE, 0, op, "Unable to find skill %s", string);
845 return 0;
846 }
775 847
776 len=strlen(skop->skill); 848 len = strlen (skop->skill);
777 849
778 /* All this logic goes and skips over the skill name to find any 850 /* All this logic goes and skips over the skill name to find any
779 * options given to the skill. Its pretty simple - if there 851 * options given to the skill. Its pretty simple - if there
780 * are extra parameters (as deteremined by string length), we 852 * are extra parameters (as deteremined by string length), we
781 * want to skip over any leading spaces. 853 * want to skip over any leading spaces.
782 */ 854 */
783 if(len>=strlen(string)) { 855 if (len >= strlen (string))
784 string=NULL;
785 } else {
786 string += len;
787 while(*string==0x20) string++;
788 if(strlen(string)==0) string = NULL;
789 } 856 {
857 string = NULL;
790 858 }
859 else
860 {
861 string += len;
862 while (*string == 0x20)
863 string++;
864 if (strlen (string) == 0)
865 string = NULL;
866 }
867
791#ifdef SKILL_UTIL_DEBUG 868#ifdef SKILL_UTIL_DEBUG
792 LOG(llevDebug,"use_skill() got skill: %s\n",sknum>-1?skills[sknum].name:"none"); 869 LOG (llevDebug, "use_skill() got skill: %s\n", sknum > -1 ? skills[sknum].name : "none");
793#endif 870#endif
794 871
795 /* Change to the new skill, then execute it. */ 872 /* Change to the new skill, then execute it. */
796 if(do_skill(op,op,skop, op->facing,string)) return 1; 873 if (do_skill (op, op, skop, op->facing, string))
797
798 return 0; 874 return 1;
799}
800 875
876 return 0;
877}
801 878
879static bool
880hth_skill_p (object *skill)
881{
882 for (unsigned int i = 0; i < sizeof (unarmed_skills); ++i)
883 if (skill->subtype == unarmed_skills[i])
884 return 1;
802 885
886 return 0;
887}
888
803/* This finds the best unarmed skill the player has, and returns 889/* This finds the first unarmed skill the player has, and returns it.
804 * it. Best can vary a little - we consider clawing to always
805 * be the best for dragons.
806 * This could be more intelligent, eg, look at the skill level
807 * of the skill and go from there (eg, a level 40 puncher is
808 * is probably better than level 1 karate). OTOH, if you
809 * don't bother to set up your skill properly, that is the players
810 * problem (although, it might be nice to have a preferred skill
811 * field the player can set.
812 * Unlike the old code, we don't give out any skills - it is
813 * possible you just don't have any ability to get into unarmed
814 * combat. If everyone race/class should have one, this should
815 * be handled in the starting treasurelists, not in the code.
816 */ 890 */
891static object *
817static object *find_best_player_hth_skill(object *op) 892find_player_hth_skill (object *op)
818{ 893{
819 object *tmp, *best_skill=NULL;
820 int dragon = is_dragon_pl(op), last_skill=sizeof(unarmed_skills), i;
821
822 for (tmp=op->inv; tmp; tmp=tmp->below) { 894 for (object *tmp = op->inv; tmp; tmp = tmp->below)
823 if (tmp->type == SKILL) { 895 if (tmp->type == SKILL && QUERY_FLAG (tmp, FLAG_CAN_USE_SKILL) && hth_skill_p (tmp))
824 if (dragon && tmp->subtype == SK_CLAWING) return tmp; 896 return tmp;
825 897
826 /* The order in the array is preferred order. So basically, 898 return 0;
827 * we just cut down the number to search - eg, if we find a skill
828 * early on in flame touch, then we only need to look into the unarmed_array
829 * to the entry before flame touch - don't care about the entries afterward,
830 * because they are infrerior skills.
831 * if we end up finding the best skill (i==0) might as well return
832 * right away - can't get any better than that.
833 */
834 for (i=0; i<last_skill; i++) {
835 if (tmp->subtype == unarmed_skills[i] && QUERY_FLAG(tmp, FLAG_CAN_USE_SKILL)) {
836 best_skill = tmp;
837 last_skill = i;
838 if (i==0) return best_skill;
839 }
840 }
841 }
842 }
843 return best_skill;
844} 899}
845 900
846/* do_skill_attack() - We have got an appropriate opponent from either 901/* do_skill_attack() - We have got an appropriate opponent from either
847 * move_player_attack() or skill_attack(). In this part we get on with 902 * move_player_attack() or skill_attack(). In this part we get on with
848 * attacking, take care of messages from the attack and changes in invisible. 903 * attacking, take care of messages from the attack and changes in invisible.
850 * tmp is the targetted monster. 905 * tmp is the targetted monster.
851 * op is what is attacking 906 * op is what is attacking
852 * string is passed along to describe what messages to describe 907 * string is passed along to describe what messages to describe
853 * the damage. 908 * the damage.
854 */ 909 */
855 910
911static int
856static int do_skill_attack(object *tmp, object *op, const char *string, object *skill) { 912do_skill_attack (object *tmp, object *op, const char *string, object *skill)
913{
857 int success; 914 int success;
858 915
916 if (INVOKE_OBJECT (SKILL_ATTACK, op, ARG_OBJECT (tmp), ARG_STRING (string), ARG_OBJECT (skill)))
917 return RESULT_INT (0);
918
859 /* For Players only: if there is no ready weapon, and no "attack" skill 919 /* For Players only: if there is no ready weapon, and no "attack" skill
860 * is readied either then try to find a skill for the player to use. 920 * is readied either then try to find a skill for the player to use.
861 * it is presumed that if skill is set, it is a valid attack skill (eg, 921 * it is presumed that if skill is set, it is a valid attack skill (eg,
862 * the caller should have set it appropriately). We still want to pass 922 * the caller should have set it appropriately). We still want to pass
863 * through that code if skill is set to change to the skill. 923 * through that code if skill is set to change to the skill.
864 */ 924 */
865 if(op->type==PLAYER) { 925 if (op->type == PLAYER)
926 {
866 if (!QUERY_FLAG(op,FLAG_READY_WEAPON)) { 927 if (!QUERY_FLAG (op, FLAG_READY_WEAPON))
867 size_t i; 928 {
868
869 if (!skill) { 929 if (!skill)
930 {
870 /* See if the players chosen skill is a combat skill, and use 931 /* See if the players chosen skill is a combat skill, and use
871 * it if appropriate. 932 * it if appropriate.
872 */ 933 */
873 if (op->chosen_skill) { 934 if (op->chosen_skill && hth_skill_p (op->chosen_skill))
874 for (i=0; i<sizeof(unarmed_skills); i++)
875 if (op->chosen_skill->subtype == unarmed_skills[i]) {
876 skill = op->chosen_skill; 935 skill = op->chosen_skill;
877 break; 936 else
878 } 937 {
879 }
880 /* If we didn't find a skill above, look harder for a good skill */
881 if (!skill) {
882 skill = find_best_player_hth_skill(op); 938 skill = find_player_hth_skill (op);
883 939
884 if (!skill) { 940 if (!skill)
941 {
885 new_draw_info(NDI_BLACK, 0, op, "You have no unarmed combat skills!"); 942 new_draw_info (NDI_BLACK, 0, op, "You have no unarmed combat skills!");
886 return 0; 943 return 0;
887 } 944 }
888 } 945 }
889 } 946 }
890 if (skill != op->chosen_skill) { 947
891 /* now try to ready the new skill */ 948 /* now try to ready the new skill */
892 if(!change_skill(op,skill,0)) { /* oh oh, trouble! */ 949 if (!change_skill (op, skill, 0))
950 { /* oh oh, trouble! */
893 new_draw_info_format(NDI_UNIQUE, 0, tmp, "Couldn't change to skill %s", skill->name); 951 new_draw_info_format (NDI_UNIQUE, 0, tmp, "Couldn't change to skill %s", &skill->name);
894 return 0; 952 return 0;
895 } 953 }
896 } 954 }
897 } else { 955 else
956 {
898 /* Seen some crashes below where current_weapon is not set, 957 /* Seen some crashes below where current_weapon is not set,
899 * even though the flag says it is. So if current weapon isn't set, 958 * even though the flag says it is. So if current weapon isn't set,
900 * do some work in trying to find the object to use. 959 * do some work in trying to find the object to use.
901 */ 960 */
902 if (!op->current_weapon) { 961 if (!op->current_weapon)
903 object *tmp; 962 {
963 object *tmp;
904 964
905 LOG(llevError,"Player %s does not have current weapon set but flag_ready_weapon is set\n", 965 LOG (llevError, "Player %s does not have current weapon set but flag_ready_weapon is set\n", &op->name);
906 op->name);
907 for (tmp=op->inv; tmp; tmp=tmp->below) 966 for (tmp = op->inv; tmp; tmp = tmp->below)
908 if (tmp->type == WEAPON && QUERY_FLAG(tmp, FLAG_APPLIED)) break; 967 if (tmp->type == WEAPON && QUERY_FLAG (tmp, FLAG_APPLIED))
968 break;
909 969
910 if (op->current_weapon_script) 970 if (!tmp)
911 FREE_AND_CLEAR_STR(op->current_weapon_script); 971 {
912 if (!tmp) {
913 LOG(llevError,"Could not find applied weapon on %s\n", 972 LOG (llevError, "Could not find applied weapon on %s\n", &op->name);
914 op->name);
915 op->current_weapon=NULL; 973 op->current_weapon = NULL;
916 return 0; 974 return 0;
917 } else { 975 }
976 else
977 {
918 op->current_weapon = tmp; 978 op->current_weapon = tmp;
919 op->current_weapon_script=add_string(query_name(tmp)); 979 }
920 } 980 }
921 }
922 981
923 /* Has ready weapon - make sure chosen_skill is set up properly */
924 if (!op->chosen_skill || op->current_weapon->skill != op->chosen_skill->skill) {
925 change_skill(op, find_skill_by_name(op, op->current_weapon->skill), 1); 982 change_skill (op, find_skill_by_name (op, op->current_weapon->skill), 1);
983 }
926 } 984 }
927 }
928 }
929 985
930 /* lose invisiblity/hiding status for running attacks */ 986 /* lose invisiblity/hiding status for running attacks */
931 987
932 if(op->type==PLAYER && op->contr->tmp_invis) { 988 if (op->type == PLAYER && op->contr->tmp_invis)
989 {
933 op->contr->tmp_invis=0; 990 op->contr->tmp_invis = 0;
934 op->invisible=0; 991 op->invisible = 0;
935 op->hide=0; 992 op->hide = 0;
936 update_object(op,UP_OBJ_FACE); 993 update_object (op, UP_OBJ_FACE);
937 } 994 }
938 995
939 success = attack_ob(tmp,op); 996 success = attack_ob (tmp, op);
940 997
941 /* print appropriate messages to the player */ 998 /* print appropriate messages to the player */
942 999
943 if(success && string!=NULL && tmp && !QUERY_FLAG(tmp,FLAG_FREED)) { 1000 if (success && string != NULL && tmp && !QUERY_FLAG (tmp, FLAG_FREED))
1001 {
944 if(op->type==PLAYER) 1002 if (op->type == PLAYER)
945 new_draw_info_format(NDI_UNIQUE, 0,op, 1003 new_draw_info_format (NDI_UNIQUE, 0, op, "You %s %s!", string, query_name (tmp));
946 "You %s %s!",string,query_name(tmp));
947 else if(tmp->type==PLAYER) 1004 else if (tmp->type == PLAYER)
948 new_draw_info_format(NDI_UNIQUE, 0,tmp, 1005 new_draw_info_format (NDI_UNIQUE, 0, tmp, "%s %s you!", query_name (op), string);
949 "%s %s you!",query_name(op),string);
950 } 1006 }
951 return success; 1007 return success;
952} 1008}
953 1009
954 1010
955/* skill_attack() - Core routine for use when we attack using a skills 1011/* skill_attack() - Core routine for use when we attack using a skills
956 * system. In essence, this code handles 1012 * system. In essence, this code handles
957 * all skill-based attacks, ie hth, missile and melee weapons should be 1013 * all skill-based attacks, ie hth, missile and melee weapons should be
961 * 1017 *
962 * This is called by move_player() and attack_hth() 1018 * This is called by move_player() and attack_hth()
963 * 1019 *
964 * Initial implementation by -bt thomas@astro.psu.edu 1020 * Initial implementation by -bt thomas@astro.psu.edu
965 */ 1021 */
966 1022
1023int
967int skill_attack (object *tmp, object *pl, int dir, const char *string, object *skill) { 1024skill_attack (object *tmp, object *pl, int dir, const char *string, object *skill)
1025{
968 sint16 tx,ty; 1026 sint16 tx, ty;
969 mapstruct *m; 1027 maptile *m;
970 int mflags; 1028 int mflags;
971 1029
1030 if (!dir)
972 if(!dir) dir=pl->facing; 1031 dir = pl->facing;
1032
973 tx=freearr_x[dir]; 1033 tx = freearr_x[dir];
974 ty=freearr_y[dir]; 1034 ty = freearr_y[dir];
975 1035
976 /* If we don't yet have an opponent, find if one exists, and attack. 1036 /* If we don't yet have an opponent, find if one exists, and attack.
977 * Legal opponents are the same as outlined in move_player_attack() 1037 * Legal opponents are the same as outlined in move_player_attack()
978 */ 1038 */
979 1039
980 if(tmp==NULL) { 1040 if (tmp == NULL)
1041 {
981 m = pl->map; 1042 m = pl->map;
982 tx = pl->x + freearr_x[dir]; 1043 tx = pl->x + freearr_x[dir];
983 ty = pl->y + freearr_y[dir]; 1044 ty = pl->y + freearr_y[dir];
984 1045
985 mflags = get_map_flags(m, &m, tx, ty, &tx, &ty); 1046 mflags = get_map_flags (m, &m, tx, ty, &tx, &ty);
986 if (mflags & P_OUT_OF_MAP) return 0; 1047 if (mflags & P_OUT_OF_MAP)
1048 return 0;
987 1049
988 /* space must be blocked for there to be anything interesting to do */ 1050 /* space must be blocked for there to be anything interesting to do */
989 if (!OB_TYPE_MOVE_BLOCK(pl, GET_MAP_MOVE_BLOCK(m, tx,ty))) return 0; 1051 if (!OB_TYPE_MOVE_BLOCK (pl, GET_MAP_MOVE_BLOCK (m, tx, ty)))
1052 return 0;
990 1053
991 for(tmp=get_map_ob(m, tx, ty); tmp; tmp=tmp->above) 1054 for (tmp = GET_MAP_OB (m, tx, ty); tmp; tmp = tmp->above)
992 if((QUERY_FLAG(tmp,FLAG_ALIVE) && tmp->stats.hp>=0) 1055 if ((QUERY_FLAG (tmp, FLAG_ALIVE) && tmp->stats.hp >= 0) || QUERY_FLAG (tmp, FLAG_CAN_ROLL) || tmp->type == LOCKED_DOOR)
993 || QUERY_FLAG(tmp, FLAG_CAN_ROLL) 1056 {
994 || tmp->type==LOCKED_DOOR ) {
995 /* Don't attack party members */ 1057 /* Don't attack party members */
996 if((pl->type==PLAYER && tmp->type==PLAYER) && (pl->contr->party!=NULL 1058 if ((pl->type == PLAYER && tmp->type == PLAYER) && (pl->contr->party != NULL && pl->contr->party == tmp->contr->party))
997 && pl->contr->party==tmp->contr->party)) 1059 return 0;
998 return 0;
999 break; 1060 break;
1061 }
1000 } 1062 }
1001 }
1002 if (!tmp) { 1063 if (!tmp)
1064 {
1003 if(pl->type==PLAYER) 1065 if (pl->type == PLAYER)
1004 new_draw_info(NDI_UNIQUE, 0,pl,"There is nothing to attack!"); 1066 new_draw_info (NDI_UNIQUE, 0, pl, "There is nothing to attack!");
1005 return 0; 1067 return 0;
1006 } 1068 }
1007 1069
1008 return do_skill_attack(tmp,pl,string, skill); 1070 return do_skill_attack (tmp, pl, string, skill);
1009} 1071}
1010 1072
1011 1073
1012/* attack_hth() - this handles all hand-to-hand attacks -b.t. */ 1074/* attack_hth() - this handles all hand-to-hand attacks -b.t. */
1075
1013/* July 5, 1995 - I broke up attack_hth() into 2 parts. In the first 1076/* July 5, 1995 - I broke up attack_hth() into 2 parts. In the first
1014 * (attack_hth) we check for weapon use, etc in the second (the new 1077 * (attack_hth) we check for weapon use, etc in the second (the new
1015 * function skill_attack() we actually attack. 1078 * function skill_attack() we actually attack.
1016 */ 1079 */
1017 1080
1081static int
1018static int attack_hth(object *pl, int dir, const char *string, object *skill) { 1082attack_hth (object *pl, int dir, const char *string, object *skill)
1083{
1019 object *enemy=NULL,*weapon; 1084 object *enemy = NULL, *weapon;
1020 1085
1021 if(QUERY_FLAG(pl, FLAG_READY_WEAPON)) 1086 if (QUERY_FLAG (pl, FLAG_READY_WEAPON))
1022 for(weapon=pl->inv;weapon;weapon=weapon->below) { 1087 for (weapon = pl->inv; weapon; weapon = weapon->below)
1088 {
1023 if (weapon->type==WEAPON && QUERY_FLAG(weapon, FLAG_APPLIED)) { 1089 if (weapon->type == WEAPON && QUERY_FLAG (weapon, FLAG_APPLIED))
1090 {
1024 CLEAR_FLAG(weapon,FLAG_APPLIED); 1091 CLEAR_FLAG (weapon, FLAG_APPLIED);
1025 CLEAR_FLAG(pl,FLAG_READY_WEAPON); 1092 CLEAR_FLAG (pl, FLAG_READY_WEAPON);
1026 fix_player(pl); 1093 pl->update_stats ();
1027 if(pl->type==PLAYER) { 1094 if (pl->type == PLAYER)
1095 {
1028 new_draw_info(NDI_UNIQUE, 0,pl,"You unwield your weapon in order to attack."); 1096 new_draw_info (NDI_UNIQUE, 0, pl, "You unwield your weapon in order to attack.");
1029 esrv_update_item(UPD_FLAGS, pl, weapon); 1097 esrv_update_item (UPD_FLAGS, pl, weapon);
1030 } 1098 }
1031 break; 1099 break;
1100 }
1032 } 1101 }
1033 }
1034 return skill_attack(enemy,pl,dir,string, skill); 1102 return skill_attack (enemy, pl, dir, string, skill);
1035} 1103}
1036 1104
1037 1105
1038/* attack_melee_weapon() - this handles melee weapon attacks -b.t. 1106/* attack_melee_weapon() - this handles melee weapon attacks -b.t.
1039 * For now we are just checking to see if we have a ready weapon here. 1107 * For now we are just checking to see if we have a ready weapon here.
1043 * we may make this routine handle 'special' melee weapons attacks 1111 * we may make this routine handle 'special' melee weapons attacks
1044 * (like disarming manuever with sai) based on player SK_level and 1112 * (like disarming manuever with sai) based on player SK_level and
1045 * weapon type. 1113 * weapon type.
1046 */ 1114 */
1047 1115
1116static int
1048static int attack_melee_weapon(object *op, int dir, const char *string, object *skill) { 1117attack_melee_weapon (object *op, int dir, const char *string, object *skill)
1118{
1049 1119
1050 if(!QUERY_FLAG(op, FLAG_READY_WEAPON)) { 1120 if (!QUERY_FLAG (op, FLAG_READY_WEAPON))
1121 {
1051 if(op->type==PLAYER) 1122 if (op->type == PLAYER)
1052 new_draw_info(NDI_UNIQUE, 0,op,"You have no ready weapon to attack with!"); 1123 new_draw_info (NDI_UNIQUE, 0, op, "You have no ready weapon to attack with!");
1053 return 0; 1124 return 0;
1054 } 1125 }
1055 return skill_attack(NULL,op,dir,string, skill); 1126 return skill_attack (NULL, op, dir, string, skill);
1056 1127
1057} 1128}

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines