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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines