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.5 by root, Tue Aug 29 08:01:38 2006 UTC vs.
Revision 1.13 by root, Sat Sep 16 22:24:13 2006 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines