ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/apply.C
Revision: 1.76
Committed: Mon Apr 30 04:25:30 2007 UTC (17 years, 1 month ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.75: +82 -55 lines
Log Message:
This is the first rough cut of the skill use system (use the STABLE tag).

Details will likely change, and combat skills do not work very well, but
it works quite well.

Players no longer have a shoottype or range slots, instead, each player
has these members:

   combat_skill/combat_ob  the currently selected skill (and weapon)
                           for direct attacks.
   ranged_skill/ranged_ob  the currently selected ranged skill (and
                           bow/spell/item)
   golem                   the currently-controlled golem, if any.

File Contents

# User Rev Content
1 elmex 1.1 /*
2 pippijn 1.61 * CrossFire, A Multiplayer game for X-windows
3     *
4     * Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team
5     * Copyright (C) 2001 Mark Wedel & Crossfire Development Team
6     * Copyright (C) 1992 Frank Tore Johansen
7     *
8     * This program is free software; you can redistribute it and/or modify
9     * it under the terms of the GNU General Public License as published by
10     * the Free Software Foundation; either version 2 of the License, or
11     * (at your option) any later version.
12     *
13     * This program is distributed in the hope that it will be useful,
14     * but WITHOUT ANY WARRANTY; without even the implied warranty of
15     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16     * GNU General Public License for more details.
17     *
18     * You should have received a copy of the GNU General Public License
19     * along with this program; if not, write to the Free Software
20     * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21     *
22     * The authors can be reached via e-mail to <crossfire@schmorp.de>
23     */
24 elmex 1.1
25     #include <global.h>
26     #include <living.h>
27     #include <spells.h>
28     #include <skills.h>
29     #include <tod.h>
30    
31 root 1.51 #include <sproto.h>
32 elmex 1.1
33     /* Want this regardless of rplay. */
34     #include <sounds.h>
35    
36     /* need math lib for double-precision and pow() in dragon_eat_flesh() */
37     #include <math.h>
38    
39     /**
40     * Check if op should abort moving victim because of it's race or slaying.
41     * Returns 1 if it should abort, returns 0 if it should continue.
42     */
43 root 1.22 int
44     should_director_abort (object *op, object *victim)
45 elmex 1.1 {
46 root 1.22 int arch_flag, name_flag, race_flag;
47    
48     /* Get flags to determine what of arch, name, and race should be checked.
49     * This is stored in subtype, and is a bitmask, the LSB is the arch flag,
50     * the next is the name flag, and the last is the race flag. Also note,
51     * if subtype is set to zero, that also goes to defaults of all affecting
52     * it. Examples:
53     * subtype 1: only arch
54     * subtype 3: arch or name
55     * subtype 5: arch or race
56     * subtype 7: all three
57     */
58     if (op->subtype)
59     {
60     arch_flag = (op->subtype & 1);
61     name_flag = (op->subtype & 2);
62     race_flag = (op->subtype & 4);
63     }
64     else
65     {
66     arch_flag = 1;
67     name_flag = 1;
68     race_flag = 1;
69     }
70 root 1.66
71 root 1.22 /* If the director has race set, only affect objects with a arch,
72     * name or race that matches.
73     */
74     if ((op->race) &&
75 root 1.66 ((!(victim->arch && arch_flag && victim->arch->name) || op->race != victim->arch->name)) &&
76     ((!(victim->name && name_flag) || op->race != victim->name)) &&
77     ((!(victim->race && race_flag) || op->race != victim->race)))
78     return 1;
79    
80 root 1.22 /* If the director has slaying set, only affect objects where none
81     * of arch, name, or race match.
82     */
83 root 1.66 if ((op->slaying) && (((victim->arch && arch_flag && victim->arch->name && op->slaying == victim->arch->name))) ||
84     ((victim->name && name_flag && op->slaying == victim->name)) ||
85     ((victim->race && race_flag && op->slaying == victim->race)))
86     return 1;
87    
88 root 1.22 return 0;
89 elmex 1.1 }
90    
91     /**
92     * This handles a player dropping money on an altar to identify stuff.
93     * It'll identify marked item, if none all items up to dropped money.
94     * Return value: 1 if money was destroyed, 0 if not.
95     */
96 root 1.22 static int
97     apply_id_altar (object *money, object *altar, object *pl)
98 elmex 1.1 {
99 root 1.22 object *id, *marked;
100     int success = 0;
101    
102     if (pl == NULL || pl->type != PLAYER)
103     return 0;
104 elmex 1.1
105 root 1.22 /* Check for MONEY type is a special hack - it prevents 'nothing needs
106     * identifying' from being printed out more than it needs to be.
107     */
108     if (!check_altar_sacrifice (altar, money) || money->type != MONEY)
109     return 0;
110 elmex 1.1
111 root 1.22 marked = find_marked_object (pl);
112     /* if the player has a marked item, identify that if it needs to be
113     * identified. IF it doesn't, then go through the player inventory.
114     */
115     if (marked && !QUERY_FLAG (marked, FLAG_IDENTIFIED) && need_identify (marked))
116     {
117     if (operate_altar (altar, &money))
118     {
119     identify (marked);
120     new_draw_info_format (NDI_UNIQUE, 0, pl, "You have %s.", long_desc (marked, pl));
121     if (marked->msg)
122     {
123     new_draw_info (NDI_UNIQUE, 0, pl, "The item has a story:");
124     new_draw_info (NDI_UNIQUE, 0, pl, marked->msg);
125     }
126     return money == NULL;
127     }
128     }
129 elmex 1.1
130 root 1.22 for (id = pl->inv; id; id = id->below)
131     {
132     if (!QUERY_FLAG (id, FLAG_IDENTIFIED) && !id->invisible && need_identify (id))
133     {
134     if (operate_altar (altar, &money))
135     {
136     identify (id);
137     new_draw_info_format (NDI_UNIQUE, 0, pl, "You have %s.", long_desc (id, pl));
138     if (id->msg)
139     {
140     new_draw_info (NDI_UNIQUE, 0, pl, "The item has a story:");
141     new_draw_info (NDI_UNIQUE, 0, pl, id->msg);
142 root 1.14 }
143 root 1.22 success = 1;
144     /* If no more money, might as well quit now */
145     if (money == NULL || !check_altar_sacrifice (altar, money))
146     break;
147     }
148     else
149     {
150     LOG (llevError, "check_id_altar: Couldn't do sacrifice when we should have been able to\n");
151     break;
152     }
153 root 1.14 }
154 elmex 1.1 }
155 root 1.22 if (!success)
156     new_draw_info (NDI_UNIQUE, 0, pl, "You have nothing that needs identifying");
157     return money == NULL;
158 elmex 1.1 }
159    
160     /**
161     * This checks whether the object has a "on_use_yield" field, and if so generated and drops
162     * matching item.
163     **/
164 root 1.22 static void
165     handle_apply_yield (object *tmp)
166 elmex 1.1 {
167 root 1.22 const char *yield;
168 elmex 1.1
169 root 1.22 yield = get_ob_key_value (tmp, "on_use_yield");
170     if (yield != NULL)
171 elmex 1.1 {
172 root 1.22 object *drop = get_archetype (yield);
173    
174     if (tmp->env)
175 elmex 1.1 {
176 root 1.22 drop = insert_ob_in_ob (drop, tmp->env);
177     if (tmp->env->type == PLAYER)
178     esrv_send_item (tmp->env, drop);
179 elmex 1.1 }
180 root 1.22 else
181 elmex 1.1 {
182 root 1.22 drop->x = tmp->x;
183     drop->y = tmp->y;
184     insert_ob_in_map (drop, tmp->map, tmp, INS_BELOW_ORIGINATOR);
185 elmex 1.1 }
186     }
187     }
188    
189     /**
190     * Handles applying a potion.
191     */
192 root 1.22 int
193     apply_potion (object *op, object *tmp)
194 elmex 1.1 {
195 elmex 1.3 int got_one = 0, i;
196     object *force = 0, *floor = 0;
197    
198 root 1.48 floor = GET_MAP_OB (op->map, op->x, op->y);
199 elmex 1.3
200 root 1.22 if (get_map_flags (op->map, NULL, op->x, op->y, NULL, NULL) & P_SAFE)
201 elmex 1.3 {
202     if (op->type == PLAYER)
203 root 1.22 new_draw_info (NDI_UNIQUE, 0, op, "Gods prevent you from using this here, it's sacred ground!");
204 elmex 1.4 CLEAR_FLAG (tmp, FLAG_APPLIED);
205     return 0;
206     }
207 elmex 1.3
208 elmex 1.4 if (op->type == PLAYER)
209 root 1.37 if (!QUERY_FLAG (tmp, FLAG_IDENTIFIED))
210     identify (tmp);
211 elmex 1.3
212 elmex 1.4 handle_apply_yield (tmp);
213 elmex 1.1
214 elmex 1.4 /* Potion of restoration - only for players */
215     if (op->type == PLAYER && (tmp->attacktype & AT_DEPLETE))
216     {
217     object *depl;
218     archetype *at;
219 elmex 1.1
220 elmex 1.4 if (QUERY_FLAG (tmp, FLAG_CURSED) || QUERY_FLAG (tmp, FLAG_DAMNED))
221     {
222 root 1.51 op->drain_stat ();
223     op->update_stats ();
224 elmex 1.3 decrease_ob (tmp);
225     return 1;
226     }
227 root 1.37
228 root 1.51 if (!(at = archetype::find (ARCH_DEPLETION)))
229 elmex 1.4 {
230     LOG (llevError, "Could not find archetype depletion\n");
231     return 0;
232     }
233     depl = present_arch_in_ob (at, op);
234 root 1.37
235 root 1.51 if (depl)
236 elmex 1.4 {
237     for (i = 0; i < NUM_STATS; i++)
238     if (get_attr_value (&depl->stats, i))
239 root 1.37 new_draw_info (NDI_UNIQUE, 0, op, restore_msg[i]);
240    
241     depl->destroy ();
242 root 1.51 op->update_stats ();
243 elmex 1.4 }
244     else
245     new_draw_info (NDI_UNIQUE, 0, op, "You potion had no effect.");
246 elmex 1.1
247 elmex 1.4 decrease_ob (tmp);
248     return 1;
249     }
250    
251     /* improvement potion - only for players */
252     if (op->type == PLAYER && tmp->attacktype & AT_GODPOWER)
253     {
254     for (i = 1; i < MIN (11, op->level); i++)
255 elmex 1.3 {
256 elmex 1.4 if (QUERY_FLAG (tmp, FLAG_CURSED) || QUERY_FLAG (tmp, FLAG_DAMNED))
257 elmex 1.3 {
258 elmex 1.4 if (op->contr->levhp[i] != 1)
259 elmex 1.3 {
260 elmex 1.4 op->contr->levhp[i] = 1;
261     break;
262 elmex 1.3 }
263 elmex 1.4 if (op->contr->levsp[i] != 1)
264 elmex 1.3 {
265 elmex 1.4 op->contr->levsp[i] = 1;
266     break;
267     }
268     if (op->contr->levgrace[i] != 1)
269     {
270     op->contr->levgrace[i] = 1;
271     break;
272 elmex 1.3 }
273     }
274 elmex 1.4 else
275 elmex 1.3 {
276 elmex 1.4 if (op->contr->levhp[i] < 9)
277     {
278     op->contr->levhp[i] = 9;
279     break;
280     }
281     if (op->contr->levsp[i] < 6)
282 elmex 1.3 {
283 elmex 1.4 op->contr->levsp[i] = 6;
284     break;
285 elmex 1.3 }
286 elmex 1.4 if (op->contr->levgrace[i] < 3)
287 elmex 1.3 {
288 elmex 1.4 op->contr->levgrace[i] = 3;
289     break;
290 elmex 1.3 }
291     }
292     }
293 root 1.37
294 elmex 1.4 /* Just makes checking easier */
295     if (i < MIN (11, op->level))
296     got_one = 1;
297 root 1.37
298 elmex 1.4 if (!QUERY_FLAG (tmp, FLAG_CURSED) && !QUERY_FLAG (tmp, FLAG_DAMNED))
299 elmex 1.3 {
300 elmex 1.4 if (got_one)
301 elmex 1.3 {
302 root 1.51 op->update_stats ();
303 root 1.22 new_draw_info (NDI_UNIQUE, 0, op, "The Gods smile upon you and remake you");
304     new_draw_info (NDI_UNIQUE, 0, op, "a little more in their image.");
305     new_draw_info (NDI_UNIQUE, 0, op, "You feel a little more perfect.");
306 elmex 1.3 }
307     else
308 root 1.22 new_draw_info (NDI_UNIQUE, 0, op, "The potion had no effect - you are already perfect");
309 elmex 1.3 }
310 elmex 1.4 else
311     { /* cursed potion */
312     if (got_one)
313 elmex 1.3 {
314 root 1.51 op->update_stats ();
315 root 1.22 new_draw_info (NDI_UNIQUE, 0, op, "The Gods are angry and punish you.");
316 elmex 1.3 }
317 elmex 1.4 else
318 root 1.22 new_draw_info (NDI_UNIQUE, 0, op, "You are fortunate that you are so pathetic.");
319 elmex 1.3 }
320 root 1.37
321 elmex 1.4 decrease_ob (tmp);
322     return 1;
323     }
324    
325    
326     /* A potion that casts a spell. Healing, restore spellpoint (power potion)
327     * and heroism all fit into this category. Given the spell object code,
328     * there is no limit to the number of spells that potions can be cast,
329     * but direction is problematic to try and imbue fireball potions for example.
330     */
331     if (tmp->inv)
332     {
333     if (QUERY_FLAG (tmp, FLAG_CURSED) || QUERY_FLAG (tmp, FLAG_DAMNED))
334 elmex 1.3 {
335 elmex 1.4 object *fball;
336    
337     new_draw_info (NDI_UNIQUE, 0, op, "Yech! Your lungs are on fire!");
338     /* Explodes a fireball centered at player */
339     fball = get_archetype (EXPLODING_FIREBALL);
340 root 1.22 fball->dam_modifier = random_roll (1, op->level, op, PREFER_LOW) / 5 + 1;
341     fball->stats.maxhp = random_roll (1, op->level, op, PREFER_LOW) / 10 + 2;
342 elmex 1.4 fball->x = op->x;
343     fball->y = op->y;
344     insert_ob_in_map (fball, op->map, NULL, 0);
345 elmex 1.3 }
346 elmex 1.4 else
347     cast_spell (op, tmp, op->facing, tmp->inv, NULL);
348 elmex 1.1
349 elmex 1.4 decrease_ob (tmp);
350     /* if youre dead, no point in doing this... */
351     if (!QUERY_FLAG (op, FLAG_REMOVED))
352 root 1.51 op->update_stats ();
353 elmex 1.4 return 1;
354     }
355    
356     /* Deal with protection potions */
357     force = NULL;
358     for (i = 0; i < NROFATTACKS; i++)
359     {
360     if (tmp->resist[i])
361     {
362     if (!force)
363     force = get_archetype (FORCE_NAME);
364     memcpy (force->resist, tmp->resist, sizeof (tmp->resist));
365     force->type = POTION_EFFECT;
366     break; /* Only need to find one protection since we copy entire batch */
367 elmex 1.3 }
368 elmex 1.1 }
369 elmex 1.4 /* This is a protection potion */
370     if (force)
371 elmex 1.3 {
372 elmex 1.4 /* cursed items last longer */
373     if (QUERY_FLAG (tmp, FLAG_CURSED) || QUERY_FLAG (tmp, FLAG_DAMNED))
374     {
375     force->stats.food *= 10;
376     for (i = 0; i < NROFATTACKS; i++)
377     if (force->resist[i] > 0)
378     force->resist[i] = -force->resist[i]; /* prot => vuln */
379     }
380     force->speed_left = -1;
381     force = insert_ob_in_ob (force, op);
382     CLEAR_FLAG (tmp, FLAG_APPLIED);
383     SET_FLAG (force, FLAG_APPLIED);
384     change_abil (op, force);
385     decrease_ob (tmp);
386     return 1;
387     }
388    
389     /* Only thing left are the stat potions */
390     if (op->type == PLAYER)
391     { /* only for players */
392 root 1.22 if ((QUERY_FLAG (tmp, FLAG_CURSED) || QUERY_FLAG (tmp, FLAG_DAMNED)) && tmp->value != 0)
393 elmex 1.4 CLEAR_FLAG (tmp, FLAG_APPLIED);
394     else
395     SET_FLAG (tmp, FLAG_APPLIED);
396     if (!change_abil (op, tmp))
397     new_draw_info (NDI_UNIQUE, 0, op, "Nothing happened.");
398 elmex 1.1 }
399    
400 elmex 1.3 /* CLEAR_FLAG is so that if the character has other potions
401     * that were grouped with the one consumed, his
402     * stat will not be raised by them. fix_player just clears
403     * up all the stats.
404     */
405     CLEAR_FLAG (tmp, FLAG_APPLIED);
406 root 1.51 op->update_stats ();
407 elmex 1.3 decrease_ob (tmp);
408     return 1;
409 elmex 1.1 }
410    
411     /****************************************************************************
412     * Weapon improvement code follows
413     ****************************************************************************/
414    
415     /**
416     * This returns the sum of nrof of item (arch name).
417     */
418 root 1.22 static int
419     check_item (object *op, const char *item)
420 elmex 1.1 {
421 root 1.22 int count = 0;
422 elmex 1.1
423    
424 root 1.22 if (item == NULL)
425     return 0;
426 root 1.66
427 root 1.22 op = op->below;
428     while (op != NULL)
429     {
430     if (strcmp (op->arch->name, item) == 0)
431     {
432 root 1.14 if (!QUERY_FLAG (op, FLAG_CURSED) && !QUERY_FLAG (op, FLAG_DAMNED)
433 root 1.22 /* Loophole bug? -FD- */ && !QUERY_FLAG (op, FLAG_UNPAID))
434 root 1.14 {
435 root 1.22 if (op->nrof == 0) /* this is necessary for artifact sacrifices --FD-- */
436 root 1.14 count++;
437     else
438     count += op->nrof;
439     }
440 root 1.22 }
441 root 1.66
442 root 1.22 op = op->below;
443 elmex 1.1 }
444 root 1.66
445 elmex 1.1 return count;
446     }
447    
448     /**
449     * This removes 'nrof' of what item->slaying says to remove.
450     * op is typically the player, which is only
451     * really used to determine what space to look at.
452     * Modified to only eat 'nrof' of objects.
453     */
454 root 1.22 static void
455     eat_item (object *op, const char *item, uint32 nrof)
456 elmex 1.1 {
457 root 1.22 object *prev;
458 elmex 1.1
459 root 1.22 prev = op;
460     op = op->below;
461 elmex 1.1
462 root 1.22 while (op != NULL)
463     {
464     if (strcmp (op->arch->name, item) == 0)
465     {
466     if (op->nrof >= nrof)
467     {
468     decrease_ob_nr (op, nrof);
469     return;
470     }
471     else
472     {
473     decrease_ob_nr (op, op->nrof);
474     nrof -= op->nrof;
475 root 1.14 }
476 root 1.22 op = prev;
477 root 1.14 }
478 root 1.22 prev = op;
479     op = op->below;
480 elmex 1.1 }
481     }
482    
483     /**
484     * This checks to see of the player (who) is sufficient level to use a weapon
485     * with improvs improvements (typically last_eat). We take an int here
486     * instead of the object so that the improvement code can pass along the
487     * increased value to see if the object is usuable.
488     * we return 1 (true) if the player can use the weapon.
489     */
490 root 1.22 static int
491     check_weapon_power (const object *who, int improvs)
492 elmex 1.1 {
493 root 1.22
494 elmex 1.1 /* Old code is below (commented out). Basically, since weapons are the only
495     * object players really have any control to improve, it's a bit harsh to
496     * require high level in some combat skill, so we just use overall level.
497     */
498     #if 1
499 root 1.22 if (((who->level / 5) + 5) >= improvs)
500     return 1;
501     else
502     return 0;
503 elmex 1.1
504     #else
505 root 1.22 int level = 0;
506    
507     /* The skill system hands out wc and dam bonuses to fighters
508     * more generously than the old system (see fix_player). Thus
509     * we need to curtail the power of player enchanted weapons.
510     * I changed this to 1 improvement per "fighter" level/5 -b.t.
511     * Note: Nothing should break by allowing this ratio to be different or
512     * using normal level - it is just a matter of play balance.
513     */
514     if (who->type == PLAYER)
515     {
516     object *wc_obj = NULL;
517 elmex 1.1
518 root 1.22 for (wc_obj = who->inv; wc_obj; wc_obj = wc_obj->below)
519     if (wc_obj->type == SKILL && IS_COMBAT_SKILL (wc_obj->subtype) && wc_obj->level > level)
520     level = wc_obj->level;
521    
522     if (!level)
523     {
524     LOG (llevError, "Error: Player: %s lacks wc experience object\n", who->name);
525     level = who->level;
526 root 1.14 }
527 elmex 1.1 }
528 root 1.22 else
529     level = who->level;
530 elmex 1.1
531 root 1.22 return (improvs <= ((level / 5) + 5));
532 elmex 1.1 #endif
533     }
534    
535     /**
536     * Returns how many items of type improver->slaying there are under op.
537     * Will display a message if none found, and 1 if improver->slaying is NULL.
538     */
539 root 1.22 static int
540     check_sacrifice (object *op, const object *improver)
541 elmex 1.1 {
542 root 1.22 int count = 0;
543    
544     if (improver->slaying != NULL)
545     {
546     count = check_item (op, improver->slaying);
547     if (count < 1)
548     {
549     char buf[200];
550 elmex 1.1
551 root 1.22 sprintf (buf, "The gods want more %ss", &improver->slaying);
552     new_draw_info (NDI_UNIQUE, 0, op, buf);
553     return 0;
554 root 1.14 }
555 elmex 1.1 }
556 root 1.22 else
557     count = 1;
558 elmex 1.1
559 root 1.22 return count;
560 elmex 1.1 }
561    
562     /**
563     * Actually improves the weapon, and tells user.
564     */
565 root 1.22 int
566     improve_weapon_stat (object *op, object *improver, object *weapon, signed char *stat, int sacrifice_count, const char *statname)
567 elmex 1.1 {
568    
569 root 1.22 new_draw_info (NDI_UNIQUE, 0, op, "Your sacrifice was accepted.");
570 elmex 1.1 *stat += sacrifice_count;
571     weapon->last_eat++;
572 root 1.22 new_draw_info_format (NDI_UNIQUE, 0, op, "Weapon's bonus to %s improved by %d", statname, sacrifice_count);
573     decrease_ob (improver);
574 elmex 1.1
575     /* So it updates the players stats and the window */
576 root 1.51 op->update_stats ();
577 elmex 1.1 return 1;
578     }
579    
580     /* Types of improvements, hidden in the sp field. */
581     #define IMPROVE_PREPARE 1
582     #define IMPROVE_DAMAGE 2
583     #define IMPROVE_WEIGHT 3
584     #define IMPROVE_ENCHANT 4
585     #define IMPROVE_STR 5
586     #define IMPROVE_DEX 6
587     #define IMPROVE_CON 7
588     #define IMPROVE_WIS 8
589     #define IMPROVE_CHA 9
590     #define IMPROVE_INT 10
591     #define IMPROVE_POW 11
592    
593    
594     /**
595     * This does the prepare weapon scroll.
596     * Checks for sacrifice, and so on.
597     */
598    
599 root 1.22 int
600     prepare_weapon (object *op, object *improver, object *weapon)
601 elmex 1.1 {
602 root 1.22 int sacrifice_count, i;
603     char buf[MAX_BUF];
604 elmex 1.1
605 root 1.22 if (weapon->level != 0)
606     {
607     new_draw_info (NDI_UNIQUE, 0, op, "Weapon already prepared.");
608 elmex 1.1 return 0;
609     }
610 root 1.22 for (i = 0; i < NROFATTACKS; i++)
611     if (weapon->resist[i])
612     break;
613 elmex 1.1
614 root 1.22 /* If we break out, i will be less than nrofattacks, preventing
615     * improvement of items that already have protections.
616     */
617     if (i < NROFATTACKS || weapon->stats.hp || /* regeneration */
618     (weapon->stats.sp && weapon->type == WEAPON) || /* sp regeneration */
619     weapon->stats.exp || /* speed */
620     weapon->stats.ac) /* AC - only taifu's I think */
621 elmex 1.1 {
622 root 1.22 new_draw_info (NDI_UNIQUE, 0, op, "Cannot prepare magic weapons.");
623 elmex 1.1 return 0;
624     }
625 root 1.22 sacrifice_count = check_sacrifice (op, improver);
626     if (sacrifice_count <= 0)
627     return 0;
628     weapon->level = isqrt (sacrifice_count);
629     new_draw_info (NDI_UNIQUE, 0, op, "Your sacrifice was accepted.");
630     eat_item (op, improver->slaying, sacrifice_count);
631    
632     new_draw_info_format (NDI_UNIQUE, 0, op, "Your *%s may be improved %d times.", &weapon->name, weapon->level);
633    
634     sprintf (buf, "%s's %s", &op->name, &weapon->name);
635     weapon->name = weapon->name_pl = buf;
636     weapon->nrof = 0; /* prevents preparing n weapons in the same
637     slot at once! */
638     decrease_ob (improver);
639     weapon->last_eat = 0;
640     return 1;
641 elmex 1.1 }
642    
643    
644     /**
645     * Does the dirty job for 'improve weapon' scroll, prepare or add something.
646     * This is the new improve weapon code.
647     * Returns 0 if it was not able to work for some reason.
648     *
649     * Checks if weapon was prepared, if enough potions on the floor, ...
650     *
651     * We are hiding extra information about the weapon in the level and
652     * last_eat numbers for an object. Hopefully this won't break anything ??
653     * level == max improve last_eat == current improve
654     */
655 root 1.22 int
656     improve_weapon (object *op, object *improver, object *weapon)
657 elmex 1.1 {
658 root 1.22 int sacrifice_count, sacrifice_needed = 0;
659 elmex 1.1
660 root 1.22 if (improver->stats.sp == IMPROVE_PREPARE)
661     {
662     return prepare_weapon (op, improver, weapon);
663     }
664     if (weapon->level == 0)
665     {
666     new_draw_info (NDI_UNIQUE, 0, op, "This weapon has not been prepared.");
667     return 0;
668     }
669     if (weapon->level == weapon->last_eat && weapon->item_power >= 100)
670     {
671     new_draw_info (NDI_UNIQUE, 0, op, "This weapon cannot be improved any more.");
672     return 0;
673     }
674     if (QUERY_FLAG (weapon, FLAG_APPLIED) && !check_weapon_power (op, weapon->last_eat + 1))
675     {
676     new_draw_info (NDI_UNIQUE, 0, op, "Improving the weapon will make it too");
677     new_draw_info (NDI_UNIQUE, 0, op, "powerful for you to use. Unready it if you");
678     new_draw_info (NDI_UNIQUE, 0, op, "really want to improve it.");
679     return 0;
680     }
681 elmex 1.1 /* This just increases damage by 5 points, no matter what. No sacrifice
682     * is needed. Since stats.dam is now a 16 bit value and not 8 bit,
683     * don't put any maximum value on damage - the limit is how much the
684     * weapon can be improved.
685     */
686 root 1.22 if (improver->stats.sp == IMPROVE_DAMAGE)
687     {
688     weapon->stats.dam += 5;
689     weapon->weight += 5000; /* 5 KG's */
690     new_draw_info_format (NDI_UNIQUE, 0, op, "Damage has been increased by 5 to %d", weapon->stats.dam);
691     weapon->last_eat++;
692    
693     weapon->item_power++;
694     decrease_ob (improver);
695     return 1;
696     }
697     if (improver->stats.sp == IMPROVE_WEIGHT)
698     {
699     /* Reduce weight by 20% */
700     weapon->weight = (weapon->weight * 8) / 10;
701     if (weapon->weight < 1)
702     weapon->weight = 1;
703     new_draw_info_format (NDI_UNIQUE, 0, op, "Weapon weight reduced to %6.1f kg", (float) weapon->weight / 1000.0);
704     weapon->last_eat++;
705     weapon->item_power++;
706     decrease_ob (improver);
707     return 1;
708     }
709     if (improver->stats.sp == IMPROVE_ENCHANT)
710     {
711     weapon->magic++;
712     weapon->last_eat++;
713     new_draw_info_format (NDI_UNIQUE, 0, op, "Weapon magic increased to %d", weapon->magic);
714     decrease_ob (improver);
715     weapon->item_power++;
716     return 1;
717     }
718 root 1.14
719 root 1.22 sacrifice_needed = weapon->stats.Str + weapon->stats.Int + weapon->stats.Dex +
720     weapon->stats.Pow + weapon->stats.Con + weapon->stats.Cha + weapon->stats.Wis;
721    
722     if (sacrifice_needed < 1)
723     sacrifice_needed = 1;
724     sacrifice_needed *= 2;
725 elmex 1.1
726 root 1.22 sacrifice_count = check_sacrifice (op, improver);
727     if (sacrifice_count < sacrifice_needed)
728     {
729     new_draw_info_format (NDI_UNIQUE, 0, op, "You need at least %d %s", sacrifice_needed, &improver->slaying);
730     return 0;
731     }
732     eat_item (op, improver->slaying, sacrifice_needed);
733 elmex 1.1 weapon->item_power++;
734    
735 root 1.22 switch (improver->stats.sp)
736     {
737 root 1.24 case IMPROVE_STR:
738     return improve_weapon_stat (op, improver, weapon, (signed char *) &(weapon->stats.Str), 1, "strength");
739     case IMPROVE_DEX:
740     return improve_weapon_stat (op, improver, weapon, (signed char *) &(weapon->stats.Dex), 1, "dexterity");
741     case IMPROVE_CON:
742     return improve_weapon_stat (op, improver, weapon, (signed char *) &(weapon->stats.Con), 1, "constitution");
743     case IMPROVE_WIS:
744     return improve_weapon_stat (op, improver, weapon, (signed char *) &(weapon->stats.Wis), 1, "wisdom");
745     case IMPROVE_CHA:
746     return improve_weapon_stat (op, improver, weapon, (signed char *) &(weapon->stats.Cha), 1, "charisma");
747     case IMPROVE_INT:
748     return improve_weapon_stat (op, improver, weapon, (signed char *) &(weapon->stats.Int), 1, "intelligence");
749     case IMPROVE_POW:
750     return improve_weapon_stat (op, improver, weapon, (signed char *) &(weapon->stats.Pow), 1, "power");
751     default:
752     new_draw_info (NDI_UNIQUE, 0, op, "Unknown improvement type.");
753 root 1.22 }
754     LOG (llevError, "improve_weapon: Got to end of function\n");
755 elmex 1.1 return 0;
756     }
757    
758     /**
759     * Handles the applying of improve/prepare/enchant weapon scroll.
760     * Checks a few things (not on a non-magic square, marked weapon, ...),
761     * then calls improve_weapon to do the dirty work.
762     */
763 root 1.22 int
764     check_improve_weapon (object *op, object *tmp)
765 elmex 1.1 {
766 root 1.22 object *otmp;
767 elmex 1.1
768 root 1.22 if (op->type != PLAYER)
769     return 0;
770     if (!QUERY_FLAG (op, FLAG_WIZCAST) && (get_map_flags (op->map, NULL, op->x, op->y, NULL, NULL) & P_NO_MAGIC))
771     {
772     new_draw_info (NDI_UNIQUE, 0, op, "Something blocks the magic of the scroll.");
773 elmex 1.1 return 0;
774     }
775 root 1.22 otmp = find_marked_object (op);
776     if (!otmp)
777     {
778     new_draw_info (NDI_UNIQUE, 0, op, "You need to mark a weapon object.");
779 elmex 1.1 return 0;
780     }
781 root 1.22 if (otmp->type != WEAPON && otmp->type != BOW)
782     {
783     new_draw_info (NDI_UNIQUE, 0, op, "Marked item is not a weapon or bow");
784 elmex 1.1 return 0;
785     }
786 root 1.22 new_draw_info (NDI_UNIQUE, 0, op, "Applied weapon builder.");
787     improve_weapon (op, tmp, otmp);
788     esrv_send_item (op, otmp);
789     return 1;
790 elmex 1.1 }
791    
792     /**
793     * This code deals with the armour improvment scrolls.
794     * Change limits on improvement - let players go up to
795     * +5 no matter what level, but they are limited by item
796     * power.
797     * Try to use same improvement code as in the common/treasure.c
798     * file, so that if you make a +2 full helm, it will be just
799     * the same as one you find in a shop.
800     *
801     * deprecated comment:
802     * this code is by b.t. (thomas@nomad.astro.psu.edu) -
803     * only 'enchantment' of armour is possible - improving
804     * the stats of a player w/ armour as well as a weapon
805     * will probably horribly unbalance the game. Magic enchanting
806     * depends on the level of the character - ie the plus
807     * value (magic) of the armour can never be increased beyond
808     * the level of the character / 10 -- rounding upish, nor may
809     * the armour value of the piece of equipment exceed either
810     * the users level or 90)
811     * Modified by MSW for partial resistance. Only support
812     * changing of physical area right now.
813     */
814 root 1.22 int
815     improve_armour (object *op, object *improver, object *armour)
816 elmex 1.1 {
817 root 1.22 object *tmp;
818 elmex 1.1
819 root 1.22 if (armour->magic >= settings.armor_max_enchant)
820     {
821     new_draw_info (NDI_UNIQUE, 0, op, "This armour can not be enchanted any further.");
822     return 0;
823 elmex 1.1 }
824 root 1.22 /* Dealing with random artifact armor is a lot trickier (in terms of value, weight,
825     * etc), so take the easy way out and don't worry about it.
826     * Note - maybe add scrolls which make the random artifact versions (eg, armour
827     * of gnarg and what not?)
828     */
829     if (armour->title)
830     {
831     new_draw_info (NDI_UNIQUE, 0, op, "This armour will not accept further enchantment.");
832     return 0;
833 elmex 1.1 }
834    
835 root 1.22 /* Split objects if needed. Can't insert tmp until the
836     * end of this function - otherwise it will just re-merge.
837     */
838     if (armour->nrof > 1)
839     tmp = get_split_ob (armour, armour->nrof - 1);
840     else
841     tmp = NULL;
842    
843     armour->magic++;
844    
845     if (!settings.armor_speed_linear)
846     {
847     int base = 100;
848     int pow = 0;
849 elmex 1.1
850 root 1.22 while (pow < armour->magic)
851 elmex 1.1 {
852 root 1.22 base = base - (base * settings.armor_speed_improvement) / 100;
853     pow++;
854 elmex 1.1 }
855    
856 root 1.22 ARMOUR_SPEED (armour) = (ARMOUR_SPEED (&armour->arch->clone) * base) / 100;
857     }
858     else
859     ARMOUR_SPEED (armour) = (ARMOUR_SPEED (&armour->arch->clone) * (100 + armour->magic * settings.armor_speed_improvement)) / 100;
860 elmex 1.1
861 root 1.22 if (!settings.armor_weight_linear)
862     {
863     int base = 100;
864     int pow = 0;
865 elmex 1.1
866 root 1.22 while (pow < armour->magic)
867 elmex 1.1 {
868 root 1.22 base = base - (base * settings.armor_weight_reduction) / 100;
869     pow++;
870 elmex 1.1 }
871    
872 root 1.22 armour->weight = (armour->arch->clone.weight * base) / 100;
873     }
874     else
875     armour->weight = (armour->arch->clone.weight * (100 - armour->magic * settings.armor_weight_reduction)) / 100;
876    
877     if (armour->weight <= 0)
878     {
879     LOG (llevInfo, "Warning: enchanted armours can have negative weight\n.");
880     armour->weight = 1;
881     }
882    
883     armour->item_power = get_power_from_ench (armour->arch->clone.item_power + armour->magic);
884 elmex 1.1
885 root 1.22 if (op->type == PLAYER)
886     {
887     esrv_send_item (op, armour);
888     if (QUERY_FLAG (armour, FLAG_APPLIED))
889 root 1.51 op->update_stats ();
890 elmex 1.1 }
891 root 1.22 decrease_ob (improver);
892     if (tmp)
893     {
894     insert_ob_in_ob (tmp, op);
895     esrv_send_item (op, tmp);
896 elmex 1.1 }
897 root 1.22 return 1;
898 elmex 1.1 }
899    
900    
901     /*
902     * convert_item() returns 1 if anything was converted, 0 if the item was not
903     * what the converter wants, -1 if the converter is broken.
904     */
905     #define CONV_FROM(xyz) xyz->slaying
906     #define CONV_TO(xyz) xyz->other_arch
907     #define CONV_NR(xyz) xyz->stats.sp
908     #define CONV_NEED(xyz) xyz->stats.food
909    
910     /* Takes one items and makes another.
911     * converter is the object that is doing the conversion.
912     * item is the object that triggered the converter - if it is not
913     * what the converter wants, this will not do anything.
914     */
915 root 1.22 int
916     convert_item (object *item, object *converter)
917     {
918     int nr = 0;
919     uint32 price_in;
920    
921     /* We make some assumptions - we assume if it takes money as it type,
922     * it wants some amount. We don't make change (ie, if something costs
923     * 3 gp and player drops a platinum, tough luck)
924     */
925     if (!strcmp (CONV_FROM (converter), "money"))
926     {
927     int cost;
928    
929     if (item->type != MONEY)
930     return 0;
931    
932     nr = (item->nrof * item->value) / CONV_NEED (converter);
933     if (!nr)
934     return 0;
935     cost = nr * CONV_NEED (converter) / item->value;
936     /* take into account rounding errors */
937     if (nr * CONV_NEED (converter) % item->value)
938     cost++;
939     decrease_ob_nr (item, cost);
940 elmex 1.1
941 root 1.22 price_in = cost * item->value;
942     }
943     else
944     {
945     if (item->type == PLAYER || CONV_FROM (converter) != item->arch->name ||
946     (CONV_NEED (converter) && CONV_NEED (converter) > (uint16) item->nrof))
947     return 0;
948 elmex 1.1
949 root 1.22 if (CONV_NEED (converter))
950     {
951     nr = item->nrof / CONV_NEED (converter);
952     decrease_ob_nr (item, nr * CONV_NEED (converter));
953     price_in = nr * CONV_NEED (converter) * item->value;
954     }
955     else
956     {
957     price_in = item->value;
958 root 1.37 item->destroy ();
959 root 1.22 }
960     }
961 root 1.14
962 root 1.22 if (converter->inv != NULL)
963     {
964     object *ob;
965     int i;
966     object *ob_to_copy;
967    
968     /* select random object from inventory to copy */
969     ob_to_copy = converter->inv;
970     for (ob = converter->inv->below, i = 1; ob != NULL; ob = ob->below, i++)
971     {
972     if (rndm (0, i) == 0)
973     {
974     ob_to_copy = ob;
975     }
976 root 1.14 }
977 root 1.22 item = object_create_clone (ob_to_copy);
978     CLEAR_FLAG (item, FLAG_IS_A_TEMPLATE);
979     unflag_inv (item, FLAG_IS_A_TEMPLATE);
980 elmex 1.1 }
981 root 1.22 else
982     {
983     if (converter->other_arch == NULL)
984     {
985     LOG (llevError, "move_creator: Converter doesn't have other arch set: %s (%s, %d, %d)\n",
986 root 1.55 &converter->name, &converter->map->path, converter->x, converter->y);
987 root 1.22 return -1;
988     }
989    
990     item = object_create_arch (converter->other_arch);
991     fix_generated_item (item, converter, 0, 0, GT_MINIMAL);
992     }
993    
994     if (CONV_NR (converter))
995     item->nrof = CONV_NR (converter);
996     if (nr)
997     item->nrof *= nr;
998     if (is_in_shop (converter))
999     SET_FLAG (item, FLAG_UNPAID);
1000     else if (price_in < item->nrof * item->value)
1001     {
1002     LOG (llevDebug, "converter output price higher than input: %s at %s (%d, %d) in value %d, out value %d for %s\n",
1003 root 1.55 &converter->name, &converter->map->path, converter->x, converter->y, price_in, item->nrof * item->value, &item->name);
1004 elmex 1.1
1005     /**
1006     * elmex: we are going to let the game continue, as the mapcreator
1007     * propably had something in mind when doing this
1008     */
1009     }
1010 root 1.22 insert_ob_in_map_at (item, converter->map, converter, 0, converter->x, converter->y);
1011     return 1;
1012 elmex 1.1 }
1013 root 1.22
1014 elmex 1.1 /**
1015     * Handle apply on containers.
1016     * By Eneq(@csd.uu.se).
1017     * Moved to own function and added many features [Tero.Haatanen@lut.fi]
1018     * added the alchemical cauldron to the code -b.t.
1019     */
1020 root 1.22 int
1021     apply_container (object *op, object *sack)
1022 elmex 1.1 {
1023 root 1.68 if (op->type != PLAYER || !op->contr->ns)
1024 root 1.22 return 0; /* This might change */
1025 elmex 1.1
1026 root 1.68 if (!sack || sack->type != CONTAINER)
1027 root 1.22 {
1028 root 1.35 LOG (llevError, "apply_container: %s is not container!\n", sack ? &sack->name : "[nullobject]");
1029 root 1.22 return 0;
1030 elmex 1.1 }
1031 root 1.40
1032     op->contr->last_used = 0;
1033 elmex 1.1
1034 root 1.68 if (sack->env && sack->env != op)
1035 root 1.22 {
1036 root 1.68 new_draw_info (NDI_UNIQUE, 0, op, "You must put it onto the floor or into your inventory first.");
1037     return 1;
1038 elmex 1.1 }
1039    
1040 root 1.68 // already applied == open on ground, or open in inv, or active in inv
1041     if (sack->flag [FLAG_APPLIED])
1042 root 1.22 {
1043 root 1.68 if (op->container == sack)
1044 root 1.22 {
1045 root 1.68 // open on ground or inv, so close
1046     op->close_container ();
1047     return 1;
1048 root 1.22 }
1049 root 1.68 else if (!sack->env)
1050 root 1.22 {
1051 root 1.68 // active, but not ours: some other player has opened it
1052     new_draw_info_format (NDI_UNIQUE, 0, op, "%s is already occupied.", query_name (sack));
1053     return 1;
1054 root 1.14 }
1055 root 1.22
1056 root 1.68 // fall through to opening it (active in inv)
1057 elmex 1.1 }
1058 root 1.68 else if (sack->env)
1059 root 1.22 {
1060 root 1.68 // it is in our env, so activate it, do not open yet
1061     op->close_container ();
1062     sack->flag [FLAG_APPLIED] = 1;
1063     esrv_update_item (UPD_FLAGS, op, sack);
1064 root 1.70 new_draw_info_format (NDI_UNIQUE, 0, op, "You ready %s.", query_name (sack));
1065 root 1.68 return 1;
1066 elmex 1.1 }
1067    
1068 root 1.68 // it's locked?
1069 root 1.22 if (sack->slaying)
1070 root 1.68 {
1071     if (object *tmp = find_key (op, op, sack))
1072     new_draw_info_format (NDI_UNIQUE, 0, op, "You unlock %s with %s.", query_name (sack), query_name (tmp));
1073 root 1.22 else
1074     {
1075     new_draw_info_format (NDI_UNIQUE, 0, op, "You don't have the key to unlock %s.", query_name (sack));
1076 root 1.68 return 1;
1077 root 1.22 }
1078 elmex 1.1 }
1079    
1080 root 1.68 op->open_container (sack);
1081 elmex 1.1
1082 root 1.22 return 1;
1083 elmex 1.1 }
1084    
1085     /**
1086     * Handles dropping things on altar.
1087     * Returns true if sacrifice was accepted.
1088     */
1089 root 1.22 static int
1090     apply_altar (object *altar, object *sacrifice, object *originator)
1091 elmex 1.1 {
1092 root 1.22 /* Only players can make sacrifices on spell casting altars. */
1093     if (altar->inv && (!originator || originator->type != PLAYER))
1094     return 0;
1095    
1096     if (operate_altar (altar, &sacrifice))
1097     {
1098     /* Simple check. Unfortunately, it means you can't cast magic bullet
1099     * with an altar. We call it a Potion - altars are stationary - it
1100     * is up to map designers to use them properly.
1101     */
1102     if (altar->inv && altar->inv->type == SPELL)
1103     {
1104     new_draw_info_format (NDI_BLACK, 0, originator, "The altar casts %s.", &altar->inv->name);
1105     cast_spell (originator, altar, 0, altar->inv, NULL);
1106     /* If it is connected, push the button. Fixes some problems with
1107     * old maps.
1108     */
1109 elmex 1.1
1110     /* push_button (altar);*/
1111 root 1.14 }
1112 root 1.22 else
1113     {
1114     altar->value = 1; /* works only once */
1115     push_button (altar);
1116     }
1117 root 1.26
1118     return !sacrifice;
1119 root 1.22 }
1120     else
1121 root 1.26 return 0;
1122 elmex 1.1 }
1123    
1124     /**
1125     * Handles 'movement' of shop mats.
1126     * Returns 1 if 'op' was destroyed, 0 if not.
1127     * Largely re-written to not use nearly as many gotos, plus
1128     * some of this code just looked plain out of date.
1129     * MSW 2001-08-29
1130     */
1131 root 1.22 int
1132     apply_shop_mat (object *shop_mat, object *op)
1133 elmex 1.1 {
1134 elmex 1.15 int rv = 0;
1135     double opinion;
1136     object *tmp, *next;
1137 elmex 1.1
1138 elmex 1.15 SET_FLAG (op, FLAG_NO_APPLY); /* prevent loops */
1139 elmex 1.1
1140 elmex 1.15 if (op->type != PLAYER)
1141     {
1142     /* Remove all the unpaid objects that may be carried here.
1143     * This could be pets or monsters that are somehow in
1144     * the shop.
1145     */
1146     for (tmp = op->inv; tmp; tmp = next)
1147     {
1148     next = tmp->below;
1149 root 1.25
1150 elmex 1.15 if (QUERY_FLAG (tmp, FLAG_UNPAID))
1151     {
1152     int i = find_free_spot (tmp, op->map, op->x, op->y, 1, 9);
1153 root 1.14
1154 root 1.36 tmp->remove ();
1155 root 1.24
1156 elmex 1.15 if (i == -1)
1157     i = 0;
1158 root 1.24
1159 elmex 1.15 tmp->map = op->map;
1160     tmp->x = op->x + freearr_x[i];
1161     tmp->y = op->y + freearr_y[i];
1162     insert_ob_in_map (tmp, op->map, op, 0);
1163 root 1.14 }
1164     }
1165    
1166 elmex 1.15 /* Don't teleport things like spell effects */
1167     if (QUERY_FLAG (op, FLAG_NO_PICK))
1168     return 0;
1169 root 1.14
1170 elmex 1.15 /* unpaid objects, or non living objects, can't transfer by
1171     * shop mats. Instead, put it on a nearby space.
1172     */
1173     if (QUERY_FLAG (op, FLAG_UNPAID) || !QUERY_FLAG (op, FLAG_ALIVE))
1174     {
1175 root 1.14
1176 elmex 1.15 /* Somebody dropped an unpaid item, just move to an adjacent place. */
1177     int i = find_free_spot (op, op->map, op->x, op->y, 1, 9);
1178 root 1.22
1179 elmex 1.15 if (i != -1)
1180 root 1.24 rv = transfer_ob (op, op->x + freearr_x[i], op->y + freearr_y[i], 0, shop_mat);
1181    
1182 elmex 1.15 return 0;
1183 root 1.14 }
1184 elmex 1.15 /* Removed code that checked for multipart objects - it appears that
1185     * the teleport function should be able to handle this just fine.
1186     */
1187     rv = teleport (shop_mat, SHOP_MAT, op);
1188 elmex 1.1 }
1189 root 1.25 else if (can_pay (op) && get_payment (op))
1190 elmex 1.15 {
1191 root 1.24 /* this is only used for players */
1192 elmex 1.15 rv = teleport (shop_mat, SHOP_MAT, op);
1193    
1194     if (shop_mat->msg)
1195 root 1.24 new_draw_info (NDI_UNIQUE, 0, op, shop_mat->msg);
1196 elmex 1.15 /* This check below is a bit simplistic - generally it should be correct,
1197     * but there is never a guarantee that the bottom space on the map is
1198     * actually the shop floor.
1199     */
1200     else if (!rv && !is_in_shop (op))
1201     {
1202     opinion = shopkeeper_approval (op->map, op);
1203 root 1.24
1204 elmex 1.15 if (opinion > 0.9)
1205 root 1.22 new_draw_info (NDI_UNIQUE, 0, op, "The shopkeeper gives you a friendly wave.");
1206 elmex 1.15 else if (opinion > 0.75)
1207     new_draw_info (NDI_UNIQUE, 0, op, "The shopkeeper waves to you.");
1208     else if (opinion > 0.5)
1209     new_draw_info (NDI_UNIQUE, 0, op, "The shopkeeper ignores you.");
1210     else
1211 root 1.22 new_draw_info (NDI_UNIQUE, 0, op, "The shopkeeper glares at you with contempt.");
1212 root 1.14 }
1213 elmex 1.1 }
1214 elmex 1.15 else
1215     {
1216     /* if we get here, a player tried to leave a shop but was not able
1217     * to afford the items he has. We try to move the player so that
1218     * they are not on the mat anymore
1219     */
1220     int i = find_free_spot (op, op->map, op->x, op->y, 1, 9);
1221 root 1.22
1222 elmex 1.15 if (i == -1)
1223     {
1224     LOG (llevError, "Internal shop-mat problem.\n");
1225     }
1226     else
1227     {
1228 root 1.36 op->remove ();
1229 elmex 1.15 op->x += freearr_x[i];
1230     op->y += freearr_y[i];
1231     rv = insert_ob_in_map (op, op->map, shop_mat, 0) == NULL;
1232 root 1.14 }
1233 elmex 1.1 }
1234 root 1.24
1235 elmex 1.15 CLEAR_FLAG (op, FLAG_NO_APPLY);
1236     return rv;
1237 elmex 1.1 }
1238    
1239     /**
1240     * Handles applying a sign.
1241     */
1242 root 1.22 static void
1243     apply_sign (object *op, object *sign, int autoapply)
1244 elmex 1.1 {
1245 root 1.22 readable_message_type *msgType;
1246     char newbuf[HUGE_BUF];
1247    
1248     if (sign->msg == NULL)
1249     {
1250     new_draw_info (NDI_UNIQUE, 0, op, "Nothing is written on it.");
1251     return;
1252 elmex 1.1 }
1253    
1254 root 1.22 if (sign->stats.food)
1255     {
1256     if (sign->last_eat >= sign->stats.food)
1257     {
1258     if (!sign->move_on)
1259     new_draw_info (NDI_UNIQUE, 0, op, "You cannot read it anymore.");
1260     return;
1261 root 1.14 }
1262 elmex 1.1
1263 root 1.22 if (!QUERY_FLAG (op, FLAG_WIZPASS))
1264     sign->last_eat++;
1265 elmex 1.1 }
1266    
1267 root 1.22 /* Sign or magic mouth? Do we need to see it, or does it talk to us?
1268     * No way to know for sure. The presumption is basically that if
1269     * move_on is zero, it needs to be manually applied (doesn't talk
1270     * to us).
1271     */
1272     if (QUERY_FLAG (op, FLAG_BLIND) && !QUERY_FLAG (op, FLAG_WIZ) && !sign->move_on)
1273     {
1274     new_draw_info (NDI_UNIQUE, 0, op, "You are unable to read while blind.");
1275     return;
1276     }
1277     msgType = get_readable_message_type (sign);
1278     snprintf (newbuf, sizeof (newbuf), "%hhu %s", autoapply ? 1 : 0, &sign->msg);
1279     draw_ext_info (NDI_UNIQUE | NDI_NAVY, 0, op, msgType->message_type, msgType->message_subtype, newbuf, &sign->msg);
1280 elmex 1.1 }
1281    
1282     /**
1283     * 'victim' moves onto 'trap'
1284     * 'victim' leaves 'trap'
1285     * effect is determined by move_on/move_off of trap and move_type of victime.
1286     *
1287     * originator: Player, monster or other object that caused 'victim' to move
1288     * onto 'trap'. Will receive messages caused by this action. May be NULL.
1289     * However, some types of traps require an originator to function.
1290     */
1291 root 1.22 void
1292 elmex 1.46 move_apply (object *trap, object *victim, object *originator)
1293 elmex 1.1 {
1294     static int recursion_depth = 0;
1295    
1296     /* Only exits affect DMs. */
1297 root 1.22 if (QUERY_FLAG (victim, FLAG_WIZPASS) && trap->type != EXIT && trap->type != SIGN)
1298 elmex 1.1 return;
1299    
1300     /* move_apply() is the most likely candidate for causing unwanted and
1301     * possibly unlimited recursion.
1302     */
1303     /* The following was changed because it was causing perfeclty correct
1304     * maps to fail. 1) it's not an error to recurse:
1305     * rune detonates, summoning monster. monster lands on nearby rune.
1306     * nearby rune detonates. This sort of recursion is expected and
1307     * proper. This code was causing needless crashes.
1308     */
1309 root 1.22 if (recursion_depth >= 500)
1310     {
1311     LOG (llevDebug, "WARNING: move_apply(): aborting recursion "
1312     "[trap arch %s, name %s; victim arch %s, name %s]\n", &trap->arch->name, &trap->name, &victim->arch->name, &victim->name);
1313     return;
1314 elmex 1.1 }
1315 root 1.22 recursion_depth++;
1316     if (trap->head)
1317     trap = trap->head;
1318 elmex 1.1
1319 root 1.22 if (INVOKE_OBJECT (MOVE_TRIGGER, trap, ARG_OBJECT (victim), ARG_OBJECT (originator)))
1320     goto leave;
1321 elmex 1.1
1322 root 1.22 switch (trap->type)
1323     {
1324 root 1.23 case PLAYERMOVER:
1325     if (trap->attacktype && (trap->level || victim->type != PLAYER) && !should_director_abort (trap, victim))
1326     {
1327     if (!trap->stats.maxsp)
1328     trap->stats.maxsp = 2;
1329 root 1.14
1330 root 1.23 /* Is this correct? From the docs, it doesn't look like it
1331     * should be divided by trap->speed
1332     */
1333     victim->speed_left = -FABS (trap->stats.maxsp * victim->speed / trap->speed);
1334 root 1.14
1335 root 1.23 /* Just put in some sanity check. I think there is a bug in the
1336     * above with some objects have zero speed, and thus the player
1337     * getting permanently paralyzed.
1338     */
1339     if (victim->speed_left < -50.0)
1340     victim->speed_left = -50.0;
1341     /* LOG(llevDebug, "apply, playermove, player speed_left=%f\n", victim->speed_left); */
1342     }
1343     goto leave;
1344 root 1.14
1345 root 1.23 case SPINNER:
1346     if (victim->direction)
1347     {
1348     victim->direction = absdir (victim->direction - trap->stats.sp);
1349     update_turn_face (victim);
1350     }
1351     goto leave;
1352 root 1.14
1353 root 1.23 case DIRECTOR:
1354     if (victim->direction && !should_director_abort (trap, victim))
1355     {
1356     victim->direction = trap->stats.sp;
1357     update_turn_face (victim);
1358     }
1359     goto leave;
1360 root 1.14
1361 root 1.23 case BUTTON:
1362     case PEDESTAL:
1363     update_button (trap);
1364     goto leave;
1365    
1366     case ALTAR:
1367     /* sacrifice victim on trap */
1368     apply_altar (trap, victim, originator);
1369     goto leave;
1370 root 1.14
1371 root 1.23 case THROWN_OBJ:
1372     if (trap->inv == NULL)
1373 root 1.22 goto leave;
1374 root 1.23 /* fallthrough */
1375 root 1.14
1376 root 1.23 case ARROW:
1377     /* bad bug: monster throw a object, make a step forwards, step on object ,
1378     * trigger this here and get hit by own missile - and will be own enemy.
1379     * Victim then is his own enemy and will start to kill herself (this is
1380     * removed) but we have not synced victim and his missile. To avoid senseless
1381     * action, we avoid hits here
1382     */
1383     if ((QUERY_FLAG (victim, FLAG_ALIVE) && trap->speed) && trap->owner != victim)
1384     hit_with_arrow (trap, victim);
1385     goto leave;
1386 root 1.14
1387 root 1.23 case SPELL_EFFECT:
1388     apply_spell_effect (trap, victim);
1389     goto leave;
1390 root 1.14
1391 root 1.23 case TRAPDOOR:
1392     {
1393     int max, sound_was_played;
1394     object *ab, *ab_next;
1395 root 1.22
1396 root 1.23 if (!trap->value)
1397     {
1398     int tot;
1399 root 1.14
1400 root 1.23 for (ab = trap->above, tot = 0; ab != NULL; ab = ab->above)
1401     if ((ab->move_type && trap->move_on) || ab->move_type == 0)
1402     tot += (ab->nrof ? ab->nrof : 1) * ab->weight + ab->carrying;
1403 root 1.14
1404 root 1.23 if (!(trap->value = (tot > trap->weight) ? 1 : 0))
1405     goto leave;
1406 root 1.22
1407 root 1.23 SET_ANIMATION (trap, trap->value);
1408     update_object (trap, UP_OBJ_FACE);
1409     }
1410 root 1.14
1411 root 1.23 for (ab = trap->above, max = 100, sound_was_played = 0; --max && ab; ab = ab_next)
1412 root 1.22 {
1413 root 1.23 /* need to set this up, since if we do transfer the object,
1414     * ab->above would be bogus
1415     */
1416     ab_next = ab->above;
1417 root 1.14
1418 root 1.23 if ((ab->move_type && trap->move_on) || ab->move_type == 0)
1419 root 1.22 {
1420 root 1.23 if (!sound_was_played)
1421     {
1422     play_sound_map (trap->map, trap->x, trap->y, SOUND_FALL_HOLE);
1423     sound_was_played = 1;
1424     }
1425     new_draw_info (NDI_UNIQUE, 0, ab, "You fall into a trapdoor!");
1426     transfer_ob (ab, (int) EXIT_X (trap), (int) EXIT_Y (trap), 0, ab);
1427 root 1.14 }
1428     }
1429 root 1.22 goto leave;
1430 root 1.23 }
1431 root 1.14
1432    
1433 root 1.23 case CONVERTER:
1434     if (convert_item (victim, trap) < 0)
1435     {
1436     new_draw_info_format (NDI_UNIQUE, 0, originator, "The %s seems to be broken!", query_name (trap));
1437 root 1.63 get_archetype ("burnout")->insert_at (trap, trap);
1438     }
1439 root 1.14
1440 root 1.23 goto leave;
1441 root 1.14
1442 root 1.23 case TRIGGER_BUTTON:
1443     case TRIGGER_PEDESTAL:
1444     case TRIGGER_ALTAR:
1445     check_trigger (trap, victim);
1446     goto leave;
1447    
1448     case DEEP_SWAMP:
1449     walk_on_deep_swamp (trap, victim);
1450     goto leave;
1451    
1452     case CHECK_INV:
1453 elmex 1.46 check_inv (victim, trap);
1454 root 1.23 goto leave;
1455    
1456     case HOLE:
1457     /* Hole not open? */
1458     if (trap->stats.wc > 0)
1459 root 1.22 goto leave;
1460 root 1.14
1461 root 1.23 /* Is this a multipart monster and not the head? If so, return.
1462     * Processing will happen if the head runs into the pit
1463     */
1464     if (victim->head)
1465 root 1.22 goto leave;
1466 root 1.14
1467 root 1.23 play_sound_map (victim->map, victim->x, victim->y, SOUND_FALL_HOLE);
1468     new_draw_info (NDI_UNIQUE, 0, victim, "You fall through the hole!\n");
1469     transfer_ob (victim, EXIT_X (trap), EXIT_Y (trap), 1, victim);
1470     goto leave;
1471 root 1.14
1472 root 1.23 case EXIT:
1473     if (victim->type == PLAYER && EXIT_PATH (trap))
1474     {
1475     /* Basically, don't show exits leading to random maps the
1476     * players output.
1477     */
1478 root 1.57 if (trap->msg && strncmp (EXIT_PATH (trap), "/!", 2))
1479 root 1.23 new_draw_info (NDI_NAVY, 0, victim, trap->msg);
1480 root 1.55
1481     victim->enter_exit (trap);
1482 root 1.23 }
1483     goto leave;
1484 root 1.14
1485 root 1.23 case ENCOUNTER:
1486     /* may be some leftovers on this */
1487     goto leave;
1488    
1489     case SHOP_MAT:
1490     apply_shop_mat (trap, victim);
1491     goto leave;
1492    
1493     /* Drop a certain amount of gold, and have one item identified */
1494     case IDENTIFY_ALTAR:
1495     apply_id_altar (victim, trap, originator);
1496     goto leave;
1497    
1498     case SIGN:
1499     if (victim->type != PLAYER && trap->stats.food > 0)
1500 root 1.24 goto leave; /* monsters musn't apply magic_mouths with counters */
1501 root 1.23
1502     apply_sign (victim, trap, 1);
1503     goto leave;
1504    
1505     case CONTAINER:
1506 root 1.68 apply_container (victim, trap);
1507 root 1.23 goto leave;
1508    
1509     case RUNE:
1510     case TRAP:
1511     if (trap->level && QUERY_FLAG (victim, FLAG_ALIVE))
1512     {
1513     spring_trap (trap, victim);
1514     }
1515     goto leave;
1516 root 1.14
1517 root 1.23 default:
1518     LOG (llevDebug, "name %s, arch %s, type %d with fly/walk on/off not "
1519     "handled in move_apply()\n", &trap->name, &trap->arch->name, trap->type);
1520     goto leave;
1521 elmex 1.1 }
1522    
1523 root 1.22 leave:
1524     recursion_depth--;
1525 elmex 1.1 }
1526    
1527     /**
1528     * Handles reading a regular (ie not containing a spell) book.
1529     */
1530 root 1.22 static void
1531     apply_book (object *op, object *tmp)
1532 elmex 1.1 {
1533 root 1.22 int lev_diff;
1534     object *skill_ob;
1535    
1536     if (QUERY_FLAG (op, FLAG_BLIND) && !QUERY_FLAG (op, FLAG_WIZ))
1537     {
1538     new_draw_info (NDI_UNIQUE, 0, op, "You are unable to read while blind.");
1539     return;
1540     }
1541     if (tmp->msg == NULL)
1542     {
1543     new_draw_info_format (NDI_UNIQUE, 0, op, "You open the %s and find it empty.", &tmp->name);
1544     return;
1545     }
1546 elmex 1.1
1547 root 1.22 /* need a literacy skill to read stuff! */
1548     skill_ob = find_skill_by_name (op, tmp->skill);
1549     if (!skill_ob)
1550     {
1551     new_draw_info (NDI_UNIQUE, 0, op, "You are unable to decipher the strange symbols.");
1552 elmex 1.1 return;
1553     }
1554 root 1.22 lev_diff = tmp->level - (skill_ob->level + 5);
1555     if (!QUERY_FLAG (op, FLAG_WIZ) && lev_diff > 0)
1556     {
1557     if (lev_diff < 2)
1558     new_draw_info (NDI_UNIQUE, 0, op, "This book is just barely beyond your comprehension.");
1559     else if (lev_diff < 3)
1560     new_draw_info (NDI_UNIQUE, 0, op, "This book is slightly beyond your comprehension.");
1561     else if (lev_diff < 5)
1562     new_draw_info (NDI_UNIQUE, 0, op, "This book is beyond your comprehension.");
1563     else if (lev_diff < 8)
1564     new_draw_info (NDI_UNIQUE, 0, op, "This book is quite a bit beyond your comprehension.");
1565     else if (lev_diff < 15)
1566     new_draw_info (NDI_UNIQUE, 0, op, "This book is way beyond your comprehension.");
1567     else
1568     new_draw_info (NDI_UNIQUE, 0, op, "This book is totally beyond your comprehension.");
1569 elmex 1.1 return;
1570     }
1571    
1572 root 1.22 readable_message_type *msgType = get_readable_message_type (tmp);
1573    
1574     draw_ext_info_format (NDI_UNIQUE | NDI_NAVY, 0, op,
1575     msgType->message_type, msgType->message_subtype,
1576 root 1.74 "You open the %s and start reading.\n%s", (char *)"%s\n%s",
1577     long_desc (tmp, op), &tmp->msg);
1578 root 1.22
1579     /* gain xp from reading */
1580     if (!QUERY_FLAG (tmp, FLAG_NO_SKILL_IDENT))
1581     { /* only if not read before */
1582     int exp_gain = calc_skill_exp (op, tmp, skill_ob);
1583    
1584     if (!QUERY_FLAG (tmp, FLAG_IDENTIFIED))
1585     {
1586     /*exp_gain *= 2; because they just identified it too */
1587     SET_FLAG (tmp, FLAG_IDENTIFIED);
1588 root 1.41
1589 root 1.22 /* If in a container, update how it looks */
1590     if (tmp->env)
1591     esrv_update_item (UPD_FLAGS | UPD_NAME, op, tmp);
1592     else
1593 root 1.50 op->contr->ns->floorbox_update ();
1594 root 1.22 }
1595 root 1.41
1596 root 1.22 change_exp (op, exp_gain, skill_ob->skill, 0);
1597     SET_FLAG (tmp, FLAG_NO_SKILL_IDENT); /* so no more xp gained from this book */
1598 elmex 1.1 }
1599     }
1600    
1601     /**
1602     * Handles the applying of a skill scroll, calling learn_skill straight.
1603     * op is the person learning the skill, tmp is the skill scroll object
1604     */
1605 root 1.22 static void
1606     apply_skillscroll (object *op, object *tmp)
1607 elmex 1.1 {
1608 root 1.22 switch ((int) learn_skill (op, tmp))
1609     {
1610 root 1.24 case 0:
1611     new_draw_info (NDI_UNIQUE, 0, op, "You already possess the knowledge ");
1612     new_draw_info_format (NDI_UNIQUE, 0, op, "held within the %s.\n", query_name (tmp));
1613     return;
1614    
1615     case 1:
1616     new_draw_info_format (NDI_UNIQUE, 0, op, "You succeed in learning %s", &tmp->skill);
1617     decrease_ob (tmp);
1618     return;
1619 root 1.14
1620 root 1.24 default:
1621     new_draw_info_format (NDI_UNIQUE, 0, op, "You fail to learn the knowledge of the %s.\n", query_name (tmp));
1622     decrease_ob (tmp);
1623     return;
1624 elmex 1.1 }
1625     }
1626    
1627     /**
1628     * Actually makes op learn spell.
1629     * Informs player of what happens.
1630     */
1631 root 1.22 void
1632     do_learn_spell (object *op, object *spell, int special_prayer)
1633 elmex 1.1 {
1634 root 1.22 object *tmp;
1635 elmex 1.1
1636 root 1.22 if (op->type != PLAYER)
1637     {
1638     LOG (llevError, "BUG: do_learn_spell(): not a player\n");
1639     return;
1640 elmex 1.1 }
1641    
1642 root 1.22 /* Upgrade special prayers to normal prayers */
1643     if ((tmp = check_spell_known (op, spell->name)) != NULL)
1644     {
1645     if (special_prayer && !QUERY_FLAG (tmp, FLAG_STARTEQUIP))
1646     {
1647     LOG (llevError, "BUG: do_learn_spell(): spell already known, but not marked as startequip\n");
1648     return;
1649 elmex 1.1 }
1650 root 1.22 return;
1651 elmex 1.1 }
1652    
1653 root 1.22 play_sound_player_only (op->contr, SOUND_LEARN_SPELL, 0, 0);
1654 root 1.39 tmp = spell->clone ();
1655 root 1.22 insert_ob_in_ob (tmp, op);
1656    
1657     if (special_prayer)
1658 root 1.39 SET_FLAG (tmp, FLAG_STARTEQUIP);
1659 elmex 1.1
1660 root 1.22 esrv_add_spells (op->contr, tmp);
1661 elmex 1.1 }
1662    
1663     /**
1664     * Erases spell from player's inventory.
1665     */
1666 root 1.22 void
1667     do_forget_spell (object *op, const char *spell)
1668 elmex 1.1 {
1669 root 1.22 object *spob;
1670    
1671     if (op->type != PLAYER)
1672     {
1673     LOG (llevError, "BUG: do_forget_spell(): not a player\n");
1674     return;
1675     }
1676     if ((spob = check_spell_known (op, spell)) == NULL)
1677     {
1678     LOG (llevError, "BUG: do_forget_spell(): spell not known\n");
1679     return;
1680     }
1681 elmex 1.1
1682 root 1.22 new_draw_info_format (NDI_UNIQUE | NDI_NAVY, 0, op, "You lose knowledge of %s.", spell);
1683     player_unready_range_ob (op->contr, spob);
1684     esrv_remove_spell (op->contr, spob);
1685 root 1.37 spob->destroy ();
1686 elmex 1.1 }
1687    
1688     /**
1689     * Handles player applying a spellbook.
1690     * Checks whether player has knowledge of required skill, doesn't already know the spell,
1691     * stuff like that. Random learning failure too.
1692     */
1693 root 1.22 static void
1694     apply_spellbook (object *op, object *tmp)
1695 elmex 1.1 {
1696 root 1.22 object *skop, *spell, *spell_skill;
1697    
1698     if (QUERY_FLAG (op, FLAG_BLIND) && !QUERY_FLAG (op, FLAG_WIZ))
1699     {
1700     new_draw_info (NDI_UNIQUE, 0, op, "You are unable to read while blind.");
1701     return;
1702     }
1703    
1704     /* artifact_spellbooks have 'slaying' field point to a spell name,
1705     * instead of having their spell stored in stats.sp. These are
1706     * legacy spellbooks
1707     */
1708 elmex 1.1
1709 root 1.22 if (tmp->slaying != NULL)
1710     {
1711     spell = arch_to_object (find_archetype_by_object_name (tmp->slaying));
1712     if (!spell)
1713     {
1714     new_draw_info_format (NDI_UNIQUE, 0, op, "The book's formula for %s is incomplete", &tmp->slaying);
1715     return;
1716 root 1.14 }
1717 root 1.22 else
1718     insert_ob_in_ob (spell, tmp);
1719     tmp->slaying = NULL;
1720     }
1721    
1722     skop = find_skill_by_name (op, tmp->skill);
1723    
1724     /* need a literacy skill to learn spells. Also, having a literacy level
1725     * lower than the spell will make learning the spell more difficult */
1726     if (!skop)
1727     {
1728     new_draw_info (NDI_UNIQUE, 0, op, "You can't read! Your attempt fails.");
1729     return;
1730     }
1731    
1732     spell = tmp->inv;
1733 root 1.32
1734 root 1.22 if (!spell)
1735     {
1736     LOG (llevError, "apply_spellbook: Book %s has no spell in it!\n", &tmp->name);
1737     new_draw_info (NDI_UNIQUE, 0, op, "The spellbook symbols make no sense.");
1738     return;
1739     }
1740 root 1.31
1741 root 1.34 if (skop->level < int (sqrtf (spell->level) * 1.5f))
1742 root 1.22 {
1743 root 1.73 new_draw_info (NDI_UNIQUE, 0, op, "You are unable to decipher the strange symbols. [Your literacy level is too low]");
1744 root 1.22 return;
1745     }
1746    
1747     new_draw_info_format (NDI_UNIQUE, 0, op, "The spellbook contains the %s level spell %s.", get_levelnumber (spell->level), &spell->name);
1748    
1749     if (!QUERY_FLAG (tmp, FLAG_IDENTIFIED))
1750     {
1751     identify (tmp);
1752 root 1.41
1753 root 1.22 if (tmp->env)
1754     esrv_update_item (UPD_FLAGS | UPD_NAME, op, tmp);
1755     else
1756 root 1.50 op->contr->ns->floorbox_update ();
1757 root 1.22 }
1758    
1759     /* I removed the check for special_prayer_mark here - it didn't make
1760     * a lot of sense - special prayers are not found in spellbooks, and
1761     * if the player doesn't know the spell, doesn't make a lot of sense that
1762     * they would have a special prayer mark.
1763     */
1764     if (check_spell_known (op, spell->name))
1765     {
1766     new_draw_info (NDI_UNIQUE, 0, op, "You already know that spell.\n");
1767     return;
1768 elmex 1.1 }
1769 root 1.22
1770     if (spell->skill)
1771     {
1772     spell_skill = find_skill_by_name (op, spell->skill);
1773 root 1.25
1774 root 1.22 if (!spell_skill)
1775     {
1776 root 1.73 new_draw_info_format (NDI_UNIQUE, 0, op, "You lack the skill %s to use this spell.", &spell->skill);
1777 root 1.22 return;
1778 root 1.14 }
1779 root 1.25
1780 root 1.22 if (spell_skill->level < spell->level)
1781     {
1782     new_draw_info_format (NDI_UNIQUE, 0, op, "You need to be level %d in %s to learn this spell.", spell->level, &spell->skill);
1783     return;
1784 root 1.14 }
1785 elmex 1.1 }
1786    
1787 root 1.22 /* Logic as follows
1788     *
1789     * 1- MU spells use Int to learn, Cleric spells use Wisdom
1790     *
1791     * 2- The learner's skill level in literacy adjusts the chance to learn
1792     * a spell.
1793     *
1794     * 3 -Automatically fail to learn if you read while confused
1795     *
1796     * Overall, chances are the same but a player will find having a high
1797     * literacy rate very useful! -b.t.
1798     */
1799     if (QUERY_FLAG (op, FLAG_CONFUSED))
1800     {
1801     new_draw_info (NDI_UNIQUE, 0, op, "In your confused state you flub the wording of the text!");
1802     scroll_failure (op, 0 - random_roll (0, spell->level, op, PREFER_LOW), MAX (spell->stats.sp, spell->stats.grace));
1803     }
1804     else if (QUERY_FLAG (tmp, FLAG_STARTEQUIP) ||
1805     (random_roll (0, 100, op, PREFER_LOW) - (5 * skop->level)) < learn_spell[spell->stats.grace ? op->stats.Wis : op->stats.Int])
1806     {
1807    
1808     new_draw_info (NDI_UNIQUE, 0, op, "You succeed in learning the spell!");
1809     do_learn_spell (op, spell, 0);
1810    
1811     /* xp gain to literacy for spell learning */
1812     if (!QUERY_FLAG (tmp, FLAG_STARTEQUIP))
1813     change_exp (op, calc_skill_exp (op, tmp, skop), skop->skill, 0);
1814 elmex 1.1 }
1815 root 1.22 else
1816     {
1817     play_sound_player_only (op->contr, SOUND_FUMBLE_SPELL, 0, 0);
1818     new_draw_info (NDI_UNIQUE, 0, op, "You fail to learn the spell.\n");
1819     }
1820 root 1.73
1821 root 1.22 decrease_ob (tmp);
1822 elmex 1.1 }
1823    
1824     /**
1825     * Handles applying a spell scroll.
1826     */
1827 root 1.22 void
1828     apply_scroll (object *op, object *tmp, int dir)
1829 elmex 1.1 {
1830 root 1.22 object *skop;
1831 elmex 1.1
1832 root 1.22 if (QUERY_FLAG (op, FLAG_BLIND) && !QUERY_FLAG (op, FLAG_WIZ))
1833     {
1834     new_draw_info (NDI_UNIQUE, 0, op, "You are unable to read while blind.");
1835     return;
1836 elmex 1.1 }
1837    
1838 root 1.22 if (!tmp->inv || tmp->inv->type != SPELL)
1839     {
1840     new_draw_info (NDI_UNIQUE, 0, op, "The scroll just doesn't make sense!");
1841     return;
1842 elmex 1.1 }
1843    
1844 root 1.22 if (op->type == PLAYER)
1845     {
1846     /* players need a literacy skill to read stuff! */
1847     int exp_gain = 0;
1848 elmex 1.1
1849 root 1.22 /* hard code literacy - tmp->skill points to where the exp
1850     * should go for anything killed by the spell.
1851     */
1852     skop = find_skill_by_name (op, skill_names[SK_LITERACY]);
1853 elmex 1.1
1854 root 1.22 if (!skop)
1855     {
1856     new_draw_info (NDI_UNIQUE, 0, op, "You are unable to decipher the strange symbols.");
1857     return;
1858     }
1859 elmex 1.1
1860 root 1.22 if ((exp_gain = calc_skill_exp (op, tmp, skop)))
1861     change_exp (op, exp_gain, skop->skill, 0);
1862 elmex 1.1 }
1863    
1864 root 1.22 if (!QUERY_FLAG (tmp, FLAG_IDENTIFIED))
1865     identify (tmp);
1866 elmex 1.1
1867 root 1.22 new_draw_info_format (NDI_BLACK, 0, op, "The scroll of %s turns to dust.", &tmp->inv->name);
1868 elmex 1.1
1869    
1870 root 1.22 cast_spell (op, tmp, dir, tmp->inv, NULL);
1871     decrease_ob (tmp);
1872 elmex 1.1 }
1873    
1874     /**
1875     * Applies a treasure object - by default, chest. op
1876     * is the person doing the applying, tmp is the treasure
1877     * chest.
1878     */
1879 root 1.22 static void
1880     apply_treasure (object *op, object *tmp)
1881 elmex 1.1 {
1882 root 1.22 object *treas;
1883    
1884    
1885     /* Nice side effect of new treasure creation method is that the treasure
1886     * for the chest is done when the chest is created, and put into the chest
1887     * inventory. So that when the chest burns up, the items still exist. Also
1888     * prevents people fromt moving chests to more difficult maps to get better
1889     * treasure
1890     */
1891    
1892     treas = tmp->inv;
1893     if (treas == NULL)
1894     {
1895     new_draw_info (NDI_UNIQUE, 0, op, "The chest was empty.");
1896     decrease_ob (tmp);
1897     return;
1898     }
1899     while (tmp->inv)
1900     {
1901     treas = tmp->inv;
1902 elmex 1.1
1903 root 1.36 treas->remove ();
1904 root 1.22 new_draw_info_format (NDI_UNIQUE, 0, op, "You find %s in the chest.", query_name (treas));
1905 elmex 1.1
1906 root 1.22 treas->x = op->x;
1907     treas->y = op->y;
1908     treas = insert_ob_in_map (treas, op->map, op, INS_BELOW_ORIGINATOR);
1909    
1910     if (treas && (treas->type == RUNE || treas->type == TRAP) && treas->level && QUERY_FLAG (op, FLAG_ALIVE))
1911     spring_trap (treas, op);
1912 root 1.37
1913 root 1.22 /* If either player or container was destroyed, no need to do
1914     * further processing. I think this should be enclused with
1915     * spring trap above, as I don't think there is otherwise
1916     * any way for the treasure chest or player to get killed
1917     */
1918 root 1.29 if (op->destroyed () || tmp->destroyed ())
1919 root 1.22 break;
1920 elmex 1.1 }
1921    
1922 root 1.29 if (!tmp->destroyed () && tmp->inv == NULL)
1923 root 1.22 decrease_ob (tmp);
1924 elmex 1.1
1925     }
1926    
1927     /**
1928     * op eats food.
1929     * If player, takes care of messages and dragon special food.
1930     */
1931 root 1.22 static void
1932     apply_food (object *op, object *tmp)
1933 elmex 1.1 {
1934 root 1.22 int capacity_remaining;
1935 elmex 1.1
1936 root 1.22 if (op->type != PLAYER)
1937     op->stats.hp = op->stats.maxhp;
1938     else
1939     {
1940 elmex 1.1 /* check if this is a dragon (player), eating some flesh */
1941 root 1.22 if (tmp->type == FLESH && is_dragon_pl (op) && dragon_eat_flesh (op, tmp))
1942 root 1.14 ;
1943 root 1.22 else
1944     {
1945     /* usual case - no dragon meal: */
1946     if (op->stats.food + tmp->stats.food > 999)
1947     {
1948     if (tmp->type == FOOD || tmp->type == FLESH)
1949     new_draw_info (NDI_UNIQUE, 0, op, "You feel full, but what a waste of food!");
1950     else
1951     new_draw_info (NDI_UNIQUE, 0, op, "Most of the drink goes down your face not your throat!");
1952     }
1953    
1954     if (!QUERY_FLAG (tmp, FLAG_CURSED))
1955     {
1956     char buf[MAX_BUF];
1957    
1958     if (!is_dragon_pl (op))
1959     {
1960     /* eating message for normal players */
1961     if (tmp->type == DRINK)
1962     sprintf (buf, "Ahhh...that %s tasted good.", &tmp->name);
1963     else
1964     sprintf (buf, "The %s tasted %s", &tmp->name, tmp->type == FLESH ? "terrible!" : "good.");
1965     }
1966     else
1967     {
1968     /* eating message for dragon players */
1969     sprintf (buf, "The %s tasted terrible!", &tmp->name);
1970     }
1971    
1972     new_draw_info (NDI_UNIQUE, 0, op, buf);
1973     capacity_remaining = 999 - op->stats.food;
1974     op->stats.food += tmp->stats.food;
1975     if (capacity_remaining < tmp->stats.food)
1976     op->stats.hp += capacity_remaining / 50;
1977     else
1978     op->stats.hp += tmp->stats.food / 50;
1979     if (op->stats.hp > op->stats.maxhp)
1980     op->stats.hp = op->stats.maxhp;
1981     if (op->stats.food > 999)
1982     op->stats.food = 999;
1983     }
1984 root 1.14
1985 root 1.22 /* special food hack -b.t. */
1986     if (tmp->title || QUERY_FLAG (tmp, FLAG_CURSED))
1987     eat_special_food (op, tmp);
1988     }
1989 elmex 1.1 }
1990 root 1.22 handle_apply_yield (tmp);
1991     decrease_ob (tmp);
1992 elmex 1.1 }
1993    
1994     /**
1995     * A dragon is eating some flesh. If the flesh contains resistances,
1996     * there is a chance for the dragon's skin to get improved.
1997     *
1998     * attributes:
1999     * object *op the object (dragon player) eating the flesh
2000     * object *meal the flesh item, getting chewed in dragon's mouth
2001     * return:
2002     * int 1 if eating successful, 0 if it doesn't work
2003     */
2004 root 1.22 int
2005     dragon_eat_flesh (object *op, object *meal)
2006     {
2007     object *skin = NULL; /* pointer to dragon skin force */
2008     object *abil = NULL; /* pointer to dragon ability force */
2009     object *tmp = NULL; /* tmp. object */
2010    
2011 elmex 1.1 char buf[MAX_BUF]; /* tmp. string buffer */
2012     double chance; /* improvement-chance of one resistance type */
2013 root 1.22 double totalchance = 1; /* total chance of gaining one resistance */
2014     double bonus = 0; /* level bonus (improvement is easier at lowlevel) */
2015     double mbonus = 0; /* monster bonus */
2016 elmex 1.1 int atnr_winner[NROFATTACKS]; /* winning candidates for resistance improvement */
2017 root 1.22 int winners = 0; /* number of winners */
2018 elmex 1.1 int i; /* index */
2019 root 1.22
2020 elmex 1.1 /* let's make sure and doublecheck the parameters */
2021 root 1.22 if (meal->type != FLESH || !is_dragon_pl (op))
2022 elmex 1.1 return 0;
2023 root 1.22
2024 elmex 1.1 /* now grab the 'dragon_skin'- and 'dragon_ability'-forces
2025     from the player's inventory */
2026 root 1.60 shstr_cmp dragon_ability_force ("dragon_ability_force");
2027     shstr_cmp dragon_skin_force ("dragon_skin_force");
2028    
2029     for (tmp = op->inv; tmp; tmp = tmp->below)
2030     if (tmp->type == FORCE)
2031     if (tmp->arch->name == dragon_skin_force)
2032     skin = tmp;
2033     else if (tmp->arch->name == dragon_ability_force)
2034     abil = tmp;
2035 root 1.22
2036 elmex 1.1 /* if either skin or ability are missing, this is an old player
2037     which is not to be considered a dragon -> bail out */
2038 root 1.22 if (skin == NULL || abil == NULL)
2039     return 0;
2040    
2041 elmex 1.1 /* now start by filling stomache and health, according to food-value */
2042 root 1.22 if ((999 - op->stats.food) < meal->stats.food)
2043 elmex 1.1 op->stats.hp += (999 - op->stats.food) / 50;
2044     else
2045 root 1.22 op->stats.hp += meal->stats.food / 50;
2046     if (op->stats.hp > op->stats.maxhp)
2047     op->stats.hp = op->stats.maxhp;
2048    
2049     op->stats.food = MIN (999, op->stats.food + meal->stats.food);
2050    
2051     /*LOG(llevDebug, "-> player: %d, flesh: %d\n", op->level, meal->level); */
2052    
2053 elmex 1.1 /* on to the interesting part: chances for adding resistance */
2054 root 1.22 for (i = 0; i < NROFATTACKS; i++)
2055     {
2056     if (meal->resist[i] > 0 && atnr_is_dragon_enabled (i))
2057     {
2058     /* got positive resistance, now calculate improvement chance (0-100) */
2059    
2060     /* this bonus makes resistance increase easier at lower levels */
2061     bonus = (settings.max_level - op->level) * 30. / ((double) settings.max_level);
2062     if (i == abil->stats.exp)
2063     bonus += 5; /* additional bonus for resistance of ability-focus */
2064    
2065     /* monster bonus increases with level, because high-level
2066     flesh is too rare */
2067     mbonus = op->level * 20. / ((double) settings.max_level);
2068    
2069     chance = (((double) MIN (op->level + bonus, meal->level + bonus + mbonus)) * 100. /
2070     ((double) settings.max_level)) - skin->resist[i];
2071    
2072     if (chance >= 0.)
2073     chance += 1.;
2074     else
2075     chance = (chance < -12) ? 0. : 1. / pow (2., -chance);
2076    
2077     /* chance is proportional to amount of resistance (max. 50) */
2078     chance *= ((double) (MIN (meal->resist[i], 50))) / 50.;
2079    
2080     /* doubled chance for resistance of ability-focus */
2081     if (i == abil->stats.exp)
2082     chance = MIN (100., chance * 2.);
2083    
2084     /* now make the throw and save all winners (Don't insert luck bonus here!) */
2085 pippijn 1.71 if (rndm (10000) < (unsigned int) (chance * 100))
2086 root 1.22 {
2087     atnr_winner[winners] = i;
2088     winners++;
2089     }
2090    
2091     if (chance >= 0.01)
2092     totalchance *= 1 - chance / 100;
2093    
2094     /*LOG(llevDebug, " %s: bonus %.1f, chance %.1f\n", attacks[i], bonus, chance); */
2095     }
2096 elmex 1.1 }
2097 root 1.22
2098 elmex 1.1 /* inverse totalchance as until now we have the failure-chance */
2099 root 1.22 totalchance = 100 - totalchance * 100;
2100 elmex 1.1 /* print message according to totalchance */
2101     if (totalchance > 50.)
2102 root 1.22 sprintf (buf, "Hmm! The %s tasted delicious!", &meal->name);
2103 elmex 1.1 else if (totalchance > 10.)
2104 root 1.22 sprintf (buf, "The %s tasted very good.", &meal->name);
2105 elmex 1.1 else if (totalchance > 1.)
2106 root 1.22 sprintf (buf, "The %s tasted good.", &meal->name);
2107 elmex 1.1 else if (totalchance > 0.1)
2108 root 1.22 sprintf (buf, "The %s tasted bland.", &meal->name);
2109 elmex 1.1 else if (totalchance >= 0.01)
2110 root 1.22 sprintf (buf, "The %s had a boring taste.", &meal->name);
2111     else if (meal->last_eat > 0 && atnr_is_dragon_enabled (meal->last_eat))
2112     sprintf (buf, "The %s tasted strange.", &meal->name);
2113     else
2114     sprintf (buf, "The %s had no taste.", &meal->name);
2115     new_draw_info (NDI_UNIQUE, 0, op, buf);
2116    
2117 elmex 1.1 /* now choose a winner if we have any */
2118     i = -1;
2119 root 1.22 if (winners > 0)
2120     i = atnr_winner[RANDOM () % winners];
2121    
2122     if (i >= 0 && i < NROFATTACKS && skin->resist[i] < 95)
2123     {
2124     /* resistance increased! */
2125     skin->resist[i]++;
2126 root 1.51 op->update_stats ();
2127 root 1.22
2128     sprintf (buf, "Your skin is now more resistant to %s!", change_resist_msg[i]);
2129     new_draw_info (NDI_UNIQUE | NDI_RED, 0, op, buf);
2130     }
2131    
2132 elmex 1.1 /* if this flesh contains a new ability focus, we mark it
2133     into the ability_force and it will take effect on next level */
2134 root 1.22 if (meal->last_eat > 0 && atnr_is_dragon_enabled (meal->last_eat) && meal->last_eat != abil->last_eat)
2135     {
2136     abil->last_eat = meal->last_eat; /* write: last_eat <new attnr focus> */
2137    
2138     if (meal->last_eat != abil->stats.exp)
2139     {
2140     sprintf (buf, "Your metabolism prepares to focus on %s!", change_resist_msg[meal->last_eat]);
2141     new_draw_info (NDI_UNIQUE, 0, op, buf);
2142     sprintf (buf, "The change will happen at level %d", abil->level + 1);
2143     new_draw_info (NDI_UNIQUE, 0, op, buf);
2144     }
2145     else
2146     {
2147     sprintf (buf, "Your metabolism will continue to focus on %s.", change_resist_msg[meal->last_eat]);
2148     new_draw_info (NDI_UNIQUE, 0, op, buf);
2149     abil->last_eat = 0;
2150     }
2151 elmex 1.1 }
2152     return 1;
2153     }
2154    
2155     /**
2156     * Handles applying an improve armor scroll.
2157     * Does some sanity checks, then calls improve_armour.
2158     */
2159 root 1.22 static void
2160     apply_armour_improver (object *op, object *tmp)
2161 elmex 1.1 {
2162 root 1.22 object *armor;
2163 elmex 1.1
2164 root 1.22 if (!QUERY_FLAG (op, FLAG_WIZCAST) && (get_map_flags (op->map, NULL, op->x, op->y, NULL, NULL) & P_NO_MAGIC))
2165     {
2166     new_draw_info (NDI_UNIQUE, 0, op, "Something blocks the magic of the scroll.");
2167     return;
2168 elmex 1.1 }
2169 root 1.51
2170 root 1.22 armor = find_marked_object (op);
2171 root 1.51
2172 root 1.22 if (!armor)
2173     {
2174     new_draw_info (NDI_UNIQUE, 0, op, "You need to mark an armor object.");
2175 elmex 1.1 return;
2176     }
2177 root 1.51
2178 root 1.22 if (armor->type != ARMOUR
2179     && armor->type != CLOAK
2180     && armor->type != BOOTS && armor->type != GLOVES && armor->type != BRACERS && armor->type != SHIELD && armor->type != HELMET)
2181 elmex 1.1 {
2182 root 1.22 new_draw_info (NDI_UNIQUE, 0, op, "Your marked item is not armour!\n");
2183     return;
2184 elmex 1.1 }
2185    
2186 root 1.22 new_draw_info (NDI_UNIQUE, 0, op, "Applying armour enchantment.");
2187     improve_armour (op, tmp, armor);
2188 elmex 1.1 }
2189    
2190 root 1.22 extern void
2191     apply_poison (object *op, object *tmp)
2192 elmex 1.1 {
2193 root 1.22 if (op->type == PLAYER)
2194     {
2195     play_sound_player_only (op->contr, SOUND_DRINK_POISON, 0, 0);
2196     new_draw_info (NDI_UNIQUE, 0, op, "Yech! That tasted poisonous!");
2197     strcpy (op->contr->killer, "poisonous booze");
2198 elmex 1.1 }
2199 root 1.22 if (tmp->stats.hp > 0)
2200     {
2201     LOG (llevDebug, "Trying to poison player/monster for %d hp\n", tmp->stats.hp);
2202     hit_player (op, tmp->stats.hp, tmp, AT_POISON, 1);
2203 elmex 1.1 }
2204 root 1.22 op->stats.food -= op->stats.food / 4;
2205     handle_apply_yield (tmp);
2206     decrease_ob (tmp);
2207 elmex 1.1 }
2208    
2209     /**
2210 root 1.55 * This function return true if the exit is not a 2 ways one or it is 2 ways, valid exit.
2211 elmex 1.1 * A valid 2 way exit means:
2212     * -You can come back (there is another exit at the other side)
2213     * -You are
2214 root 1.44 * ° the owner of the exit
2215     * ° or in the same party as the owner
2216 elmex 1.1 *
2217     * Note: a owner in a 2 way exit is saved as the owner's name
2218     * in the field exit->name cause the field exit->owner doesn't
2219     * survive in the swapping (in fact the whole exit doesn't survive).
2220     */
2221 root 1.22 int
2222     is_legal_2ways_exit (object *op, object *exit)
2223     {
2224     if (exit->stats.exp != 1)
2225     return 1; /*This is not a 2 way, so it is legal */
2226 root 1.52
2227 root 1.55 #if 0 //TODO
2228 root 1.22 if (!has_been_loaded (EXIT_PATH (exit)) && exit->race)
2229     return 0; /* This is a reset town portal */
2230 root 1.55 #endif
2231    
2232 root 1.58 maptile *exitmap = maptile::find_sync (EXIT_PATH (exit), exit->map);
2233 root 1.52
2234 root 1.22 if (exitmap)
2235     {
2236 root 1.58 exitmap->load_sync ();
2237    
2238     object *tmp = exitmap->at (EXIT_X (exit), EXIT_Y (exit)).bot;
2239 root 1.52
2240 root 1.22 if (!tmp)
2241     return 0;
2242 root 1.52
2243 root 1.58 for (; tmp; tmp = tmp->above)
2244 root 1.22 {
2245     if (tmp->type != EXIT)
2246     continue; /*Not an exit */
2247 root 1.52
2248 root 1.22 if (!EXIT_PATH (tmp))
2249     continue; /*Not a valid exit */
2250 root 1.52
2251 root 1.22 if ((EXIT_X (tmp) != exit->x) || (EXIT_Y (tmp) != exit->y))
2252     continue; /*Not in the same place */
2253 root 1.52
2254 root 1.66 if (exit->map->path != EXIT_PATH (tmp))
2255 root 1.22 continue; /*Not in the same map */
2256    
2257     /* From here we have found the exit is valid. However we do
2258     * here the check of the exit owner. It is important for the
2259     * town portals to prevent strangers from visiting your appartments
2260     */
2261     if (!exit->race)
2262     return 1; /*No owner, free for all! */
2263 root 1.52
2264 root 1.58 object *exit_owner = 0;
2265 root 1.52
2266     for_all_players (pp)
2267 root 1.22 {
2268     if (!pp->ob)
2269     continue;
2270 root 1.52
2271 root 1.22 if (pp->ob->name != exit->race)
2272     continue;
2273 root 1.52
2274 root 1.22 exit_owner = pp->ob; /*We found a player which correspond to the player name */
2275     break;
2276     }
2277 root 1.52
2278 root 1.22 if (!exit_owner)
2279     return 0; /* No more owner */
2280 root 1.52
2281 root 1.22 if (exit_owner->contr == op->contr)
2282     return 1; /*It is your exit */
2283 root 1.52
2284 root 1.22 if (exit_owner && /*There is a owner */
2285     (op->contr) && /*A player tries to pass */
2286     ((exit_owner->contr->party == NULL) || /*No pass if controller has no party */
2287     (exit_owner->contr->party != op->contr->party))) /* Or not the same as op */
2288     return 0;
2289 root 1.52
2290 root 1.22 return 1;
2291     }
2292     }
2293 root 1.52
2294 root 1.22 return 0;
2295     }
2296 elmex 1.1
2297    
2298     /**
2299     * Main apply handler.
2300     *
2301     * Checks for unpaid items before applying.
2302     *
2303     * Return value:
2304     * 0: player or monster can't apply objects of that type
2305     * 1: has been applied, or there was an error applying the object
2306     * 2: objects of that type can't be applied if not in inventory
2307     *
2308     * op is the object that is causing object to be applied, tmp is the object
2309     * being applied.
2310     *
2311     * aflag is special (always apply/unapply) flags. Nothing is done with
2312     * them in this function - they are passed to apply_special
2313     */
2314    
2315 root 1.22 int
2316     manual_apply (object *op, object *tmp, int aflag)
2317 elmex 1.1 {
2318 root 1.22 if (tmp->head)
2319     tmp = tmp->head;
2320 elmex 1.1
2321 root 1.22 if (QUERY_FLAG (tmp, FLAG_UNPAID) && !QUERY_FLAG (tmp, FLAG_APPLIED))
2322     {
2323     if (op->type == PLAYER)
2324     {
2325     new_draw_info (NDI_UNIQUE, 0, op, "You should pay for it first.");
2326     return 1;
2327     }
2328     else
2329 root 1.51 return 0; /* monsters just skip unpaid items */
2330 elmex 1.1 }
2331    
2332 root 1.22 if (INVOKE_OBJECT (APPLY, tmp, ARG_OBJECT (op)))
2333     return RESULT_INT (0);
2334 root 1.8
2335 root 1.22 switch (tmp->type)
2336     {
2337 root 1.24 case CF_HANDLE:
2338     new_draw_info (NDI_UNIQUE, 0, op, "You turn the handle.");
2339     play_sound_map (op->map, op->x, op->y, SOUND_TURN_HANDLE);
2340     tmp->value = tmp->value ? 0 : 1;
2341     SET_ANIMATION (tmp, tmp->value);
2342     update_object (tmp, UP_OBJ_FACE);
2343     push_button (tmp);
2344     return 1;
2345 root 1.14
2346 root 1.24 case TRIGGER:
2347     if (check_trigger (tmp, op))
2348     {
2349     new_draw_info (NDI_UNIQUE, 0, op, "You turn the handle.");
2350     play_sound_map (tmp->map, tmp->x, tmp->y, SOUND_TURN_HANDLE);
2351     }
2352     else
2353 root 1.57 new_draw_info (NDI_UNIQUE, 0, op, "The handle doesn't move.");
2354    
2355 root 1.24 return 1;
2356 root 1.14
2357 root 1.24 case EXIT:
2358     if (op->type != PLAYER)
2359     return 0;
2360 root 1.57
2361 root 1.24 if (!EXIT_PATH (tmp) || !is_legal_2ways_exit (op, tmp))
2362     {
2363     new_draw_info_format (NDI_UNIQUE, 0, op, "The %s is closed.", query_name (tmp));
2364     }
2365     else
2366     {
2367     /* Don't display messages for random maps. */
2368 root 1.57 if (tmp->msg && strncmp (EXIT_PATH (tmp), "/!", 2))
2369 root 1.24 new_draw_info (NDI_NAVY, 0, op, tmp->msg);
2370 root 1.57
2371 root 1.55 op->enter_exit (tmp);
2372 root 1.24 }
2373     return 1;
2374 root 1.14
2375 root 1.24 case SIGN:
2376     apply_sign (op, tmp, 0);
2377     return 1;
2378 root 1.14
2379 root 1.24 case BOOK:
2380     if (op->type == PLAYER)
2381     {
2382     apply_book (op, tmp);
2383     return 1;
2384     }
2385     else
2386     {
2387     return 0;
2388     }
2389 root 1.14
2390 root 1.24 case SKILLSCROLL:
2391     if (op->type == PLAYER)
2392     {
2393     apply_skillscroll (op, tmp);
2394     return 1;
2395     }
2396     return 0;
2397 root 1.14
2398 root 1.24 case SPELLBOOK:
2399     if (op->type == PLAYER)
2400     {
2401     apply_spellbook (op, tmp);
2402     return 1;
2403     }
2404     return 0;
2405 root 1.14
2406 root 1.24 case SCROLL:
2407     apply_scroll (op, tmp, 0);
2408     return 1;
2409 root 1.14
2410 root 1.24 case POTION:
2411     (void) apply_potion (op, tmp);
2412     return 1;
2413 root 1.14
2414 root 1.24 /* Eneq(@csd.uu.se): Handle apply on containers. */
2415 root 1.68 //TODO: remove, as it is unsed?
2416 root 1.24 case CLOSE_CON:
2417 root 1.68 apply_container (op, tmp->env);
2418 root 1.24 return 1;
2419 root 1.14
2420 root 1.24 case CONTAINER:
2421 root 1.68 apply_container (op, tmp);
2422 root 1.24 return 1;
2423 root 1.14
2424 root 1.24 case TREASURE:
2425     if (op->type == PLAYER)
2426     {
2427     apply_treasure (op, tmp);
2428     return 1;
2429     }
2430     else
2431 root 1.68 return 0;
2432 root 1.14
2433 root 1.24 case WEAPON:
2434     case ARMOUR:
2435     case BOOTS:
2436     case GLOVES:
2437     case AMULET:
2438     case GIRDLE:
2439     case BRACERS:
2440     case SHIELD:
2441     case HELMET:
2442     case RING:
2443     case CLOAK:
2444     case WAND:
2445     case ROD:
2446     case HORN:
2447     case SKILL:
2448     case BOW:
2449     case LAMP:
2450     case BUILDER:
2451     case SKILL_TOOL:
2452     if (tmp->env != op)
2453     return 2; /* not in inventory */
2454     (void) apply_special (op, tmp, aflag);
2455     return 1;
2456 root 1.14
2457 root 1.24 case DRINK:
2458     case FOOD:
2459     case FLESH:
2460     apply_food (op, tmp);
2461     return 1;
2462 root 1.14
2463 root 1.24 case POISON:
2464     apply_poison (op, tmp);
2465     return 1;
2466 root 1.14
2467 root 1.24 case SAVEBED:
2468 root 1.51 return 1;
2469 root 1.14
2470 root 1.24 case ARMOUR_IMPROVER:
2471     if (op->type == PLAYER)
2472     {
2473     apply_armour_improver (op, tmp);
2474     return 1;
2475     }
2476     else
2477 root 1.51 return 0;
2478 root 1.14
2479 root 1.24 case WEAPON_IMPROVER:
2480     (void) check_improve_weapon (op, tmp);
2481     return 1;
2482 root 1.14
2483 root 1.24 case CLOCK:
2484     if (op->type == PLAYER)
2485     {
2486     char buf[MAX_BUF];
2487     timeofday_t tod;
2488 root 1.22
2489 root 1.24 get_tod (&tod);
2490     sprintf (buf, "It is %d minute%s past %d o'clock %s",
2491     tod.minute + 1, ((tod.minute + 1 < 2) ? "" : "s"),
2492     ((tod.hour % 14 == 0) ? 14 : ((tod.hour) % 14)), ((tod.hour >= 14) ? "pm" : "am"));
2493     play_sound_player_only (op->contr, SOUND_CLOCK, 0, 0);
2494     new_draw_info (NDI_UNIQUE, 0, op, buf);
2495     return 1;
2496     }
2497     else
2498     {
2499     return 0;
2500     }
2501 root 1.14
2502 root 1.24 case MENU:
2503     if (op->type == PLAYER)
2504     {
2505 elmex 1.75 shop_listing (tmp, op);
2506 root 1.24 return 1;
2507     }
2508     else
2509     {
2510     return 0;
2511     }
2512 elmex 1.1
2513 root 1.24 case POWER_CRYSTAL:
2514     apply_power_crystal (op, tmp); /* see egoitem.c */
2515     return 1;
2516 root 1.14
2517 root 1.24 case LIGHTER: /* for lighting torches/lanterns/etc */
2518     if (op->type == PLAYER)
2519     {
2520     apply_lighter (op, tmp);
2521     return 1;
2522     }
2523     else
2524     {
2525     return 0;
2526     }
2527 root 1.14
2528 root 1.24 case ITEM_TRANSFORMER:
2529     apply_item_transformer (op, tmp);
2530     return 1;
2531 root 1.14
2532 root 1.24 default:
2533     return 0;
2534 elmex 1.1 }
2535     }
2536    
2537    
2538     /* quiet suppresses the "don't know how to apply" and "you must get it first"
2539     * messages as needed by player_apply_below(). But there can still be
2540     * "but you are floating high above the ground" messages.
2541     *
2542     * Same return value as apply() function.
2543     */
2544 root 1.22 int
2545     player_apply (object *pl, object *op, int aflag, int quiet)
2546 elmex 1.1 {
2547 root 1.22 int tmp;
2548 elmex 1.1
2549 root 1.22 if (op->env == NULL && (pl->move_type & MOVE_FLYING))
2550     {
2551     /* player is flying and applying object not in inventory */
2552     if (!QUERY_FLAG (pl, FLAG_WIZ) && !(op->move_type & MOVE_FLYING))
2553     {
2554     new_draw_info (NDI_UNIQUE, 0, pl, "But you are floating high " "above the ground!");
2555     return 0;
2556 root 1.14 }
2557 elmex 1.1 }
2558    
2559 root 1.22 /* Check for PLAYER to avoid a DM to disappear in a puff of smoke if
2560     * applied.
2561     */
2562     if (op->type != PLAYER && QUERY_FLAG (op, FLAG_WAS_WIZ) && !QUERY_FLAG (pl, FLAG_WAS_WIZ))
2563     {
2564     play_sound_map (pl->map, pl->x, pl->y, SOUND_OB_EVAPORATE);
2565     new_draw_info (NDI_UNIQUE, 0, pl, "The object disappears in a puff " "of smoke!");
2566     new_draw_info (NDI_UNIQUE, 0, pl, "It must have been an illusion.");
2567 root 1.37 op->destroy ();
2568 root 1.22 return 1;
2569 elmex 1.1 }
2570    
2571 root 1.22 pl->contr->last_used = op;
2572 elmex 1.1
2573 root 1.22 tmp = manual_apply (pl, op, aflag);
2574     if (!quiet)
2575     {
2576     if (tmp == 0)
2577     new_draw_info_format (NDI_UNIQUE, 0, pl, "I don't know how to apply the %s.", query_name (op));
2578     else if (tmp == 2)
2579     new_draw_info_format (NDI_UNIQUE, 0, pl, "You must get it first!\n");
2580 elmex 1.1 }
2581 root 1.22 return tmp;
2582 elmex 1.1 }
2583    
2584     /**
2585     * player_apply_below attempts to apply the object 'below' the player.
2586     * If the player has an open container, we use that for below, otherwise
2587     * we use the ground.
2588     */
2589    
2590 root 1.22 void
2591     player_apply_below (object *pl)
2592 elmex 1.1 {
2593 root 1.68 int floors = 0;
2594 root 1.22
2595     /* If using a container, set the starting item to be the top
2596     * item in the container. Otherwise, use the map.
2597 root 1.68 * This is perhaps more complicated. However, I want to make sure that
2598 root 1.22 * we don't use a corrupt pointer for the next object, so we get the
2599     * next object in the stack before applying. This is can only be a
2600     * problem if player_apply() has a bug in that it uses the object but does
2601     * not return a proper value.
2602     */
2603 root 1.68 for (object *next, *tmp = pl->container ? pl->container->inv : pl->below; tmp; tmp = next)
2604 root 1.22 {
2605     next = tmp->below;
2606 root 1.68
2607 root 1.22 if (QUERY_FLAG (tmp, FLAG_IS_FLOOR))
2608     floors++;
2609     else if (floors > 0)
2610     return; /* process only floor objects after first floor object */
2611    
2612     /* If it is visible, player can apply it. If it is applied by
2613     * person moving on it, also activate. Added code to make it
2614     * so that at least one of players movement types be that which
2615     * the item needs.
2616     */
2617     if (!tmp->invisible || (tmp->move_on & pl->move_type))
2618     {
2619     if (player_apply (pl, tmp, 0, 1) == 1)
2620     return;
2621 elmex 1.1 }
2622 root 1.22 if (floors >= 2)
2623     return; /* process at most two floor objects */
2624 elmex 1.1 }
2625     }
2626    
2627     /**
2628     * Unapplies specified item.
2629     * No check done on cursed/damned.
2630     * Break this out of apply_special - this is just done
2631     * to keep the size of apply_special to a more managable size.
2632     */
2633 root 1.22 static int
2634     unapply_special (object *who, object *op, int aflags)
2635 elmex 1.1 {
2636 root 1.22 if (INVOKE_OBJECT (BE_UNREADY, op, ARG_OBJECT (who), ARG_INT (aflags)) || INVOKE_OBJECT (UNREADY, who, ARG_OBJECT (op), ARG_INT (aflags)))
2637     return RESULT_INT (0);
2638 root 1.12
2639 root 1.22 object *tmp2;
2640 elmex 1.1
2641 root 1.22 CLEAR_FLAG (op, FLAG_APPLIED);
2642 root 1.76
2643 root 1.22 switch (op->type)
2644     {
2645 root 1.24 case WEAPON:
2646     new_draw_info_format (NDI_UNIQUE, 0, who, "You unwield %s.", query_name (op));
2647 elmex 1.1
2648 root 1.24 (void) change_abil (who, op);
2649     if (QUERY_FLAG (who, FLAG_READY_WEAPON))
2650     CLEAR_FLAG (who, FLAG_READY_WEAPON);
2651     clear_skill (who);
2652     break;
2653 root 1.14
2654 root 1.24 case SKILL: /* allows objects to impart skills */
2655     case SKILL_TOOL:
2656     if (op != who->chosen_skill)
2657 root 1.76 LOG (llevError, "BUG: apply_special(): applied skill is not a chosen skill\n");
2658    
2659 root 1.24 if (who->type == PLAYER)
2660     {
2661 root 1.76 if (who->contr->ranged_ob == op)
2662 root 1.24 {
2663 root 1.76 who->contr->ranged_skill = 0;
2664     who->contr->ranged_ob = 0;
2665 root 1.24 }
2666 root 1.76
2667     if (!op->invisible)
2668     new_draw_info_format (NDI_UNIQUE, 0, who, "You stop using the %s.", query_name (op));
2669 root 1.24 else
2670 root 1.76 new_draw_info_format (NDI_UNIQUE, 0, who, "You can no longer use the skill: %s.", &op->skill);
2671 root 1.24 }
2672 root 1.76
2673     change_abil (who, op);
2674     who->chosen_skill = 0;
2675 root 1.24 CLEAR_FLAG (who, FLAG_READY_SKILL);
2676     break;
2677 root 1.14
2678 root 1.24 case ARMOUR:
2679     case HELMET:
2680     case SHIELD:
2681     case RING:
2682     case BOOTS:
2683     case GLOVES:
2684     case AMULET:
2685     case GIRDLE:
2686     case BRACERS:
2687     case CLOAK:
2688     new_draw_info_format (NDI_UNIQUE, 0, who, "You unwear %s.", query_name (op));
2689     (void) change_abil (who, op);
2690     break;
2691     case LAMP:
2692     new_draw_info_format (NDI_UNIQUE, 0, who, "You turn off your %s.", &op->name);
2693     tmp2 = arch_to_object (op->other_arch);
2694     tmp2->x = op->x;
2695     tmp2->y = op->y;
2696     tmp2->map = op->map;
2697     tmp2->below = op->below;
2698     tmp2->above = op->above;
2699     tmp2->stats.food = op->stats.food;
2700     CLEAR_FLAG (tmp2, FLAG_APPLIED);
2701 root 1.29
2702 root 1.24 if (QUERY_FLAG (op, FLAG_INV_LOCKED))
2703     SET_FLAG (tmp2, FLAG_INV_LOCKED);
2704 root 1.29
2705 root 1.24 if (who->type == PLAYER)
2706 root 1.29 esrv_del_item (who->contr, op->count);
2707    
2708 root 1.37 op->destroy ();
2709 root 1.24 insert_ob_in_ob (tmp2, who);
2710 root 1.51 who->update_stats ();
2711 root 1.24 if (QUERY_FLAG (op, FLAG_CURSED) || QUERY_FLAG (op, FLAG_DAMNED))
2712     {
2713     if (who->type == PLAYER)
2714     {
2715     new_draw_info (NDI_UNIQUE, 0, who, "Oops, it feels deadly cold!");
2716     SET_FLAG (tmp2, FLAG_KNOWN_CURSED);
2717     }
2718     }
2719     if (who->type == PLAYER)
2720     esrv_send_item (who, tmp2);
2721     return 1; /* otherwise, an attempt to drop causes problems */
2722     break;
2723 root 1.76
2724 root 1.24 case BOW:
2725     case WAND:
2726     case ROD:
2727     case HORN:
2728     clear_skill (who);
2729     if (who->type == PLAYER)
2730     {
2731 root 1.76 new_draw_info_format (NDI_UNIQUE, 0, who, "You unready %s.", query_name (op));
2732    
2733     who->contr->ranged_skill = 0;
2734     who->contr->ranged_ob = 0;
2735 root 1.24 }
2736     else
2737     {
2738     if (op->type == BOW)
2739     CLEAR_FLAG (who, FLAG_READY_BOW);
2740     else
2741     CLEAR_FLAG (who, FLAG_READY_RANGE);
2742     }
2743 root 1.76
2744 root 1.24 break;
2745 elmex 1.1
2746 root 1.24 case BUILDER:
2747 root 1.76 if (who->type == PLAYER)
2748     {
2749     new_draw_info_format (NDI_UNIQUE, 0, who, "You unready %s.", query_name (op));
2750    
2751     who->contr->ranged_skill = 0;
2752     who->contr->ranged_ob = 0;
2753     }
2754 root 1.24 break;
2755 elmex 1.1
2756 root 1.24 default:
2757     new_draw_info_format (NDI_UNIQUE, 0, who, "You unapply %s.", query_name (op));
2758     break;
2759 elmex 1.1 }
2760    
2761 root 1.51 who->update_stats ();
2762 elmex 1.1
2763 root 1.22 if (!(aflags & AP_NO_MERGE))
2764     {
2765     object *tmp;
2766    
2767     tmp = merge_ob (op, NULL);
2768     if (who->type == PLAYER)
2769     {
2770     if (tmp)
2771     { /* it was merged */
2772 root 1.29 esrv_del_item (who->contr, op->count);
2773 root 1.22 op = tmp;
2774 elmex 1.1 }
2775 root 1.29
2776 root 1.22 esrv_send_item (who, op);
2777 root 1.14 }
2778 elmex 1.1 }
2779 root 1.22 return 0;
2780 elmex 1.1 }
2781    
2782     /**
2783     * Returns the object that is using location 'loc'.
2784     * Note that 'start' is the first object to start examing - we
2785     * then go through the below of this. In this way, you can do
2786     * something like:
2787     * tmp = get_item_from_body_location(who->inv, 1);
2788     * if (tmp) tmp1 = get_item_from_body_location(tmp->below, 1);
2789     * to find the second object that may use this location, etc.
2790     * Returns NULL if no match is found.
2791     * loc is the index into the array we are looking for a match.
2792     * don't return invisible objects unless they are skill objects
2793     * invisible other objects that use
2794     * up body locations can be used as restrictions.
2795     */
2796 root 1.22 object *
2797     get_item_from_body_location (object *start, int loc)
2798 elmex 1.1 {
2799 root 1.22 object *tmp;
2800 elmex 1.1
2801 root 1.22 if (!start)
2802     return NULL;
2803 elmex 1.1
2804 root 1.22 for (tmp = start; tmp; tmp = tmp->below)
2805     if (QUERY_FLAG (tmp, FLAG_APPLIED) && tmp->body_info[loc] && (!tmp->invisible || tmp->type == SKILL))
2806     return tmp;
2807 elmex 1.1
2808 root 1.22 return NULL;
2809 elmex 1.1 }
2810    
2811    
2812    
2813     /**
2814     * 'op' wants to apply an object, but can't because of other equipment.
2815     * This should only be called when it is known
2816     * that there are objects to unapply. This makes pretty heavy
2817     * use of get_item_from_body_location. It makes no intelligent choice
2818     * on objects - rather, the first that is matched is used.
2819     * Returns 0 on success, returns 1 if there is some problem.
2820     * if aflags is AP_PRINT, we instead print out waht to unapply
2821     * instead of doing it. This is a lot less code than having
2822     * another function that does just that.
2823     */
2824 root 1.22 int
2825     unapply_for_ob (object *who, object *op, int aflags)
2826 elmex 1.1 {
2827 root 1.22 int i;
2828     object *tmp = NULL, *last;
2829 elmex 1.1
2830 root 1.22 /* If we are applying a shield or weapon, unapply any equipped shield
2831     * or weapons first - only allowed to use one weapon/shield at a time.
2832     */
2833     if (op->type == WEAPON || op->type == SHIELD)
2834     {
2835     for (tmp = who->inv; tmp; tmp = tmp->below)
2836     {
2837     if (QUERY_FLAG (tmp, FLAG_APPLIED) && tmp->type == op->type)
2838     {
2839     if ((aflags & AP_IGNORE_CURSE) || (aflags & AP_PRINT) || (!QUERY_FLAG (tmp, FLAG_CURSED) && !QUERY_FLAG (tmp, FLAG_DAMNED)))
2840     {
2841     if (aflags & AP_PRINT)
2842     new_draw_info (NDI_UNIQUE, 0, who, query_name (tmp));
2843     else
2844     unapply_special (who, tmp, aflags);
2845     }
2846     else
2847     {
2848     /* In this case, we want to try and remove a cursed item.
2849     * While we know it won't work, we want unapply_special to
2850     * at least generate the message.
2851     */
2852     new_draw_info_format (NDI_UNIQUE, 0, who, "No matter how hard you try, you just can't\nremove %s.", query_name (tmp));
2853     return 1;
2854 root 1.14 }
2855 elmex 1.1
2856 root 1.14 }
2857     }
2858 elmex 1.1 }
2859    
2860 root 1.22 for (i = 0; i < NUM_BODY_LOCATIONS; i++)
2861     {
2862     /* this used up a slot that we need to free */
2863     if (op->body_info[i])
2864     {
2865     last = who->inv;
2866 root 1.14
2867 root 1.22 /* We do a while loop - may need to remove several items in order
2868     * to free up enough slots.
2869     */
2870     while ((who->body_used[i] + op->body_info[i]) < 0)
2871     {
2872     tmp = get_item_from_body_location (last, i);
2873     if (!tmp)
2874     {
2875 elmex 1.1 #if 0
2876 root 1.22 /* Not a bug - we'll get this if the player has cursed items
2877     * equipped.
2878     */
2879     LOG (llevError, "Can't find object using location %d (%s) on %s\n", i, body_locations[i].save_name, who->name);
2880 elmex 1.1 #endif
2881 root 1.22 return 1;
2882     }
2883     /* If we are just printing, we don't care about cursed status */
2884     if ((aflags & AP_IGNORE_CURSE) || (aflags & AP_PRINT) || (!(QUERY_FLAG (tmp, FLAG_CURSED) || QUERY_FLAG (tmp, FLAG_DAMNED))))
2885     {
2886     if (aflags & AP_PRINT)
2887     new_draw_info (NDI_UNIQUE, 0, who, query_name (tmp));
2888     else
2889     unapply_special (who, tmp, aflags);
2890 root 1.14 }
2891 root 1.22 else
2892     {
2893     /* Cursed item that we can't unequip - tell the player.
2894     * Note this could be annoying if this is just one of a few,
2895     * so it may not be critical (eg, putting on a ring and you have
2896     * one cursed ring.)
2897     */
2898     new_draw_info_format (NDI_UNIQUE, 0, who, "The %s just won't come off", query_name (tmp));
2899 root 1.14 }
2900 root 1.22 last = tmp->below;
2901 root 1.14 }
2902 root 1.22 /* if we got here, this slot is freed up - otherwise, if it wasn't freed up, the
2903     * return in the !tmp would have kicked in.
2904     */
2905     } /* if op is using this body location */
2906     } /* for body lcoations */
2907     return 0;
2908 elmex 1.1 }
2909    
2910     /**
2911     * Checks to see if 'who' can apply object 'op'.
2912     * Returns 0 if apply can be done without anything special.
2913     * Otherwise returns a bitmask - potentially several of these may be
2914     * set, but largely depends on circumstance - in the future, processing
2915     * may be pruned once we know some status (eg, once CAN_APPLY_NEVER
2916     * is set, do we really are what the other flags may be?)
2917     *
2918     * See include/define.h for detailed description of the meaning of
2919     * these return values.
2920     */
2921 root 1.22 int
2922     can_apply_object (object *who, object *op)
2923 elmex 1.1 {
2924 root 1.22 if (INVOKE_OBJECT (CAN_BE_APPLIED, op, ARG_OBJECT (who)) || INVOKE_OBJECT (CAN_APPLY, who, ARG_OBJECT (op)))
2925     return RESULT_INT (0);
2926    
2927     int i, retval = 0;
2928     object *tmp = NULL, *ws = NULL;
2929    
2930     /* Players have 2 'arm's, so they could in theory equip 2 shields or
2931     * 2 weapons, but we don't want to let them do that. So if they are
2932     * trying to equip a weapon or shield, see if they already have one
2933     * in place and store that way.
2934     */
2935     if (op->type == WEAPON || op->type == SHIELD)
2936     {
2937     for (tmp = who->inv; tmp && !ws; tmp = tmp->below)
2938     {
2939     if (QUERY_FLAG (tmp, FLAG_APPLIED) && tmp->type == op->type)
2940     {
2941     retval = CAN_APPLY_UNAPPLY;
2942     ws = tmp;
2943 root 1.14 }
2944     }
2945 elmex 1.1 }
2946 root 1.14
2947 root 1.22 for (i = 0; i < NUM_BODY_LOCATIONS; i++)
2948     {
2949     if (op->body_info[i])
2950     {
2951     /* Item uses more slots than we have */
2952     if (FABS (op->body_info[i]) > who->body_info[i])
2953     {
2954     /* Could return now for efficiently - rest of info below isn'
2955     * really needed.
2956     */
2957     retval |= CAN_APPLY_NEVER;
2958     }
2959     else if ((who->body_used[i] + op->body_info[i]) < 0)
2960     {
2961     /* in this case, equipping this would use more free spots than
2962     * we have.
2963     */
2964     object *tmp1;
2965    
2966 elmex 1.1
2967 root 1.22 /* if we have an applied weapon/shield, and unapply it would free
2968     * enough slots to equip the new item, then just set this can
2969     * continue. We don't care about the logic below - if you have
2970     * shield equipped and try to equip another shield, there is only
2971     * one choice. However, the check for the number of body locations
2972     * does take into the account cases where what is being applied
2973     * may be two handed for example.
2974     */
2975     if (ws)
2976     {
2977     if ((who->body_used[i] - ws->body_info[i] + op->body_info[i]) >= 0)
2978     {
2979     retval |= CAN_APPLY_UNAPPLY;
2980     continue;
2981     }
2982     }
2983    
2984     tmp1 = get_item_from_body_location (who->inv, i);
2985     if (!tmp1)
2986     {
2987 elmex 1.1 #if 0
2988 root 1.22 /* This is sort of an error, but happens a lot when old players
2989     * join in with more stuff equipped than they are now allowed.
2990     */
2991     LOG (llevError, "Can't find object using location %d on %s\n", i, who->name);
2992 elmex 1.1 #endif
2993 root 1.22 retval |= CAN_APPLY_NEVER;
2994     }
2995     else
2996     {
2997     /* need to unapply something. However, if this something
2998     * is different than we had found before, it means they need
2999     * to apply multiple objects
3000     */
3001     retval |= CAN_APPLY_UNAPPLY;
3002     if (!tmp)
3003     tmp = tmp1;
3004     else if (tmp != tmp1)
3005     {
3006     retval |= CAN_APPLY_UNAPPLY_MULT;
3007 root 1.14 }
3008 root 1.22 /* This object isn't using up all the slots, so there must
3009     * be another. If so, and it the new item doesn't need all
3010     * the slots, the player then has a choice.
3011     */
3012     if (((who->body_used[i] - tmp1->body_info[i]) != who->body_info[i]) && (FABS (op->body_info[i]) < who->body_info[i]))
3013     retval |= CAN_APPLY_UNAPPLY_CHOICE;
3014    
3015     /* Does unequippint 'tmp1' free up enough slots for this to be
3016     * equipped? If not, there must be something else to unapply.
3017     */
3018     if ((who->body_used[i] + op->body_info[i] - tmp1->body_info[i]) < 0)
3019     retval |= CAN_APPLY_UNAPPLY_MULT;
3020    
3021     }
3022     } /* if not enough free slots */
3023     } /* if this object uses location i */
3024     } /* for i -> num_body_locations loop */
3025    
3026     /* Note that we don't check for FLAG_USE_ARMOUR - that should
3027     * really be controlled by use of body locations. We do have
3028     * the weapon/shield checks, and the range checks for monsters,
3029     * because you can't control those just by body location - bows, shields,
3030     * and weapons all use the same slot. Similar for horn/rod/wand - they
3031     * all use the same location.
3032     */
3033     if (op->type == WEAPON && !QUERY_FLAG (who, FLAG_USE_WEAPON))
3034     retval |= CAN_APPLY_RESTRICTION;
3035 root 1.76
3036 root 1.22 if (op->type == SHIELD && !QUERY_FLAG (who, FLAG_USE_SHIELD))
3037     retval |= CAN_APPLY_RESTRICTION;
3038    
3039     if (who->type != PLAYER)
3040     {
3041     if ((op->type == WAND || op->type == HORN || op->type == ROD) && !QUERY_FLAG (who, FLAG_USE_RANGE))
3042 root 1.14 retval |= CAN_APPLY_RESTRICTION;
3043 root 1.22 if (op->type == BOW && !QUERY_FLAG (who, FLAG_USE_BOW))
3044     retval |= CAN_APPLY_RESTRICTION;
3045     if (op->type == RING && !QUERY_FLAG (who, FLAG_USE_RING))
3046     retval |= CAN_APPLY_RESTRICTION;
3047     if (op->type == BOW && !QUERY_FLAG (who, FLAG_USE_BOW))
3048 root 1.14 retval |= CAN_APPLY_RESTRICTION;
3049 elmex 1.1 }
3050 root 1.76
3051 root 1.22 return retval;
3052 elmex 1.1 }
3053    
3054     /**
3055     * who is the object using the object. It can be a monster.
3056     * op is the object they are using. op is an equipment type item,
3057     * eg, one which you put on and keep on for a while, and not something
3058     * like a potion or scroll.
3059     *
3060     * function returns 1 if the action could not be completed, 0 on
3061     * success. However, success is a matter of meaning - if the
3062     * user passes the 'apply' flag to an object already applied,
3063     * nothing is done, and 0 is returned.
3064     *
3065     * aflags is special flags (0 - normal/toggle, AP_APPLY=always apply,
3066     * AP_UNAPPLY=always unapply).
3067     *
3068     * Optional flags:
3069     * AP_NO_MERGE: don't merge an unapplied object with other objects
3070     * AP_IGNORE_CURSE: unapply cursed items
3071     *
3072     * Usage example: apply_special (who, op, AP_UNAPPLY | AP_IGNORE_CURSE)
3073     *
3074     * apply_special() doesn't check for unpaid items.
3075     */
3076 root 1.22 int
3077     apply_special (object *who, object *op, int aflags)
3078 elmex 1.1 {
3079 root 1.22 int basic_flag = aflags & AP_BASIC_FLAGS;
3080     object *tmp, *tmp2, *skop = NULL;
3081     int i;
3082 elmex 1.1
3083 root 1.22 if (who == NULL)
3084     {
3085     LOG (llevError, "apply_special() from object without environment.\n");
3086     return 1;
3087 elmex 1.1 }
3088    
3089 root 1.22 if (op->env != who)
3090     return 1; /* op is not in inventory */
3091 elmex 1.1
3092 root 1.22 /* trying to unequip op */
3093     if (QUERY_FLAG (op, FLAG_APPLIED))
3094     {
3095     /* always apply, so no reason to unapply */
3096     if (basic_flag == AP_APPLY)
3097     return 0;
3098    
3099     if (!(aflags & AP_IGNORE_CURSE) && (QUERY_FLAG (op, FLAG_CURSED) || QUERY_FLAG (op, FLAG_DAMNED)))
3100     {
3101     new_draw_info_format (NDI_UNIQUE, 0, who, "No matter how hard you try, you just can't\nremove %s.", query_name (op));
3102     return 1;
3103 root 1.14 }
3104 root 1.22 return unapply_special (who, op, aflags);
3105 elmex 1.1 }
3106    
3107 root 1.22 if (basic_flag == AP_UNAPPLY)
3108     return 0;
3109 elmex 1.1
3110 root 1.22 i = can_apply_object (who, op);
3111 elmex 1.1
3112 root 1.22 /* Can't just apply this object. Lets see what not and what to do */
3113     if (i)
3114     {
3115     if (i & CAN_APPLY_NEVER)
3116     {
3117     new_draw_info_format (NDI_UNIQUE, 0, who, "You don't have the body to use a %s\n", query_name (op));
3118     return 1;
3119     }
3120     else if (i & CAN_APPLY_RESTRICTION)
3121     {
3122     new_draw_info_format (NDI_UNIQUE, 0, who, "You have a prohibition against using a %s\n", query_name (op));
3123     return 1;
3124     }
3125     if (who->type != PLAYER)
3126     {
3127     /* Some error, so don't try to equip something more */
3128     if (unapply_for_ob (who, op, aflags))
3129 root 1.14 return 1;
3130     }
3131 root 1.22 else
3132     {
3133     if (who->contr->unapply == unapply_never || (i & CAN_APPLY_UNAPPLY_CHOICE && who->contr->unapply == unapply_nochoice))
3134     {
3135 root 1.55 new_draw_info (NDI_UNIQUE, 0, who, "You need to unapply some of the following item(s) or change your applymode:");
3136 root 1.22 unapply_for_ob (who, op, AP_PRINT);
3137     return 1;
3138     }
3139     else if (who->contr->unapply == unapply_always || !(i & CAN_APPLY_UNAPPLY_CHOICE))
3140     {
3141     i = unapply_for_ob (who, op, aflags);
3142     if (i)
3143 root 1.14 return 1;
3144     }
3145     }
3146 elmex 1.1 }
3147 root 1.55
3148 root 1.22 if (op->skill && op->type != SKILL && op->type != SKILL_TOOL)
3149     {
3150     skop = find_skill_by_name (who, op->skill);
3151     if (!skop)
3152     {
3153     new_draw_info_format (NDI_UNIQUE, 0, who, "You need the %s skill to use this item!", &op->skill);
3154     return 1;
3155     }
3156     else
3157 root 1.76 /* While experience will be credited properly, we want to change the
3158     * skill so that the dam and wc get updated
3159     */
3160     change_skill (who, skop, 0);
3161 elmex 1.1 }
3162 root 1.22
3163     if (who->type == PLAYER && op->item_power && (op->item_power + who->contr->item_power) > (settings.item_power_factor * who->level))
3164     {
3165 root 1.72 new_draw_info (NDI_UNIQUE, 0, who,
3166     "Equipping that combined with other items would consume your soul! "
3167     "[use the skills command to check your available item power]");
3168 root 1.22 return 1;
3169 elmex 1.1 }
3170    
3171 root 1.12
3172 root 1.22 /* Ok. We are now at the state where we can apply the new object.
3173     * Note that we don't have the checks for can_use_...
3174     * below - that is already taken care of by can_apply_object.
3175     */
3176    
3177     if (op->nrof > 1)
3178     tmp = get_split_ob (op, op->nrof - 1);
3179     else
3180     tmp = NULL;
3181    
3182     if (INVOKE_OBJECT (BE_READY, op, ARG_OBJECT (who)) || INVOKE_OBJECT (READY, who, ARG_OBJECT (op)))
3183     return RESULT_INT (0);
3184    
3185     switch (op->type)
3186     {
3187 root 1.24 case WEAPON:
3188     if (!check_weapon_power (who, op->last_eat))
3189     {
3190     new_draw_info (NDI_UNIQUE, 0, who, "That weapon is too powerful for you to use.");
3191     new_draw_info (NDI_UNIQUE, 0, who, "It would consume your soul!.");
3192     if (tmp != NULL)
3193     (void) insert_ob_in_ob (tmp, who);
3194     return 1;
3195     }
3196 root 1.65
3197     //TODO: this obviously fails for players using a shiorter prefix
3198     // i.e. "R" can use Ragnarok's swors.
3199 root 1.24 if (op->level && (strncmp (op->name, who->name, strlen (who->name))))
3200     {
3201     /* if the weapon does not have the name as the character, can't use it. */
3202     /* (Ragnarok's sword attempted to be used by Foo: won't work) */
3203     new_draw_info (NDI_UNIQUE, 0, who, "The weapon does not recognize you as its owner.");
3204 root 1.65
3205     if (tmp)
3206     insert_ob_in_ob (tmp, who);
3207    
3208 root 1.24 return 1;
3209     }
3210 root 1.65
3211 root 1.24 SET_FLAG (op, FLAG_APPLIED);
3212 root 1.14
3213 root 1.24 if (skop)
3214     change_skill (who, skop, 1);
3215 root 1.76
3216 root 1.24 if (!QUERY_FLAG (who, FLAG_READY_WEAPON))
3217     SET_FLAG (who, FLAG_READY_WEAPON);
3218 root 1.14
3219 root 1.24 new_draw_info_format (NDI_UNIQUE, 0, who, "You wield %s.", query_name (op));
3220 root 1.14
3221 root 1.76 change_abil (who, op);
3222 root 1.24 break;
3223 root 1.14
3224 root 1.24 case ARMOUR:
3225     case HELMET:
3226     case SHIELD:
3227     case BOOTS:
3228     case GLOVES:
3229     case GIRDLE:
3230     case BRACERS:
3231     case CLOAK:
3232     case RING:
3233     case AMULET:
3234     SET_FLAG (op, FLAG_APPLIED);
3235     new_draw_info_format (NDI_UNIQUE, 0, who, "You wear %s.", query_name (op));
3236 root 1.76 change_abil (who, op);
3237 root 1.24 break;
3238 root 1.76
3239 root 1.24 case LAMP:
3240     if (op->stats.food < 1)
3241     {
3242     new_draw_info_format (NDI_UNIQUE, 0, who, "Your %s is out of" " fuel!", &op->name);
3243     return 1;
3244     }
3245 root 1.76
3246 root 1.24 new_draw_info_format (NDI_UNIQUE, 0, who, "You turn on your %s.", &op->name);
3247     tmp2 = arch_to_object (op->other_arch);
3248     tmp2->stats.food = op->stats.food;
3249     SET_FLAG (tmp2, FLAG_APPLIED);
3250 root 1.76
3251 root 1.24 if (QUERY_FLAG (op, FLAG_INV_LOCKED))
3252     SET_FLAG (tmp2, FLAG_INV_LOCKED);
3253 root 1.76
3254 root 1.24 insert_ob_in_ob (tmp2, who);
3255    
3256     /* Remove the old lantern */
3257     if (who->type == PLAYER)
3258 root 1.29 esrv_del_item (who->contr, op->count);
3259    
3260 root 1.37 op->destroy ();
3261 root 1.22
3262 root 1.24 /* insert the portion that was split off */
3263 root 1.76 if (tmp)
3264 root 1.24 {
3265 root 1.76 insert_ob_in_ob (tmp, who);
3266 root 1.24 if (who->type == PLAYER)
3267     esrv_send_item (who, tmp);
3268     }
3269 root 1.76
3270 root 1.51 who->update_stats ();
3271 root 1.76
3272 root 1.24 if (QUERY_FLAG (op, FLAG_CURSED) || QUERY_FLAG (op, FLAG_DAMNED))
3273     {
3274     if (who->type == PLAYER)
3275     {
3276     new_draw_info (NDI_UNIQUE, 0, who, "Oops, it feels deadly cold!");
3277     SET_FLAG (tmp2, FLAG_KNOWN_CURSED);
3278     }
3279     }
3280 root 1.76
3281 root 1.24 if (who->type == PLAYER)
3282     esrv_send_item (who, tmp2);
3283 root 1.76
3284 root 1.24 return 0;
3285 root 1.14
3286 root 1.24 /* this part is needed for skill-tools */
3287     case SKILL:
3288     case SKILL_TOOL:
3289     if (who->chosen_skill)
3290     {
3291     LOG (llevError, "BUG: apply_special(): can't apply two skills\n");
3292     return 1;
3293     }
3294 root 1.76
3295 root 1.24 if (who->type == PLAYER)
3296     {
3297 root 1.76 who->contr->ranged_skill = who;
3298     who->contr->ranged_ob = op;
3299    
3300 root 1.24 if (!op->invisible)
3301     {
3302     new_draw_info_format (NDI_UNIQUE, 0, who, "You ready %s.", query_name (op));
3303     new_draw_info_format (NDI_UNIQUE, 0, who, "You can now use the skill: %s.", &op->skill);
3304     }
3305     else
3306 root 1.76 new_draw_info_format (NDI_UNIQUE, 0, who, "Readied skill: %s.", op->skill ? &op->skill : &op->name);
3307 root 1.24 }
3308 root 1.76
3309 root 1.24 SET_FLAG (op, FLAG_APPLIED);
3310 root 1.76 change_abil (who, op);
3311 root 1.24 who->chosen_skill = op;
3312     SET_FLAG (who, FLAG_READY_SKILL);
3313     break;
3314 root 1.22
3315 root 1.24 case BOW:
3316     if (!check_weapon_power (who, op->last_eat))
3317     {
3318     new_draw_info (NDI_UNIQUE, 0, who, "That item is too powerful for you to use.");
3319     new_draw_info (NDI_UNIQUE, 0, who, "It would consume your soul!.");
3320 root 1.76
3321     if (tmp)
3322     insert_ob_in_ob (tmp, who);
3323    
3324 root 1.24 return 1;
3325     }
3326 root 1.76
3327 root 1.24 if (op->level && (strncmp (op->name, who->name, strlen (who->name))))
3328     {
3329     new_draw_info (NDI_UNIQUE, 0, who, "The weapon does not recognize you as its owner.");
3330     if (tmp != NULL)
3331 root 1.76 insert_ob_in_ob (tmp, who);
3332    
3333 root 1.24 return 1;
3334     }
3335 root 1.76
3336     /*FALLTHROUGH*/
3337     case WAND:
3338 root 1.24 case ROD:
3339     case HORN:
3340     /* check for skill, alter player status */
3341     SET_FLAG (op, FLAG_APPLIED);
3342     if (skop)
3343     change_skill (who, skop, 0);
3344 root 1.22
3345 root 1.24 if (who->type == PLAYER)
3346     {
3347 root 1.76 new_draw_info_format (NDI_UNIQUE, 0, who, "You ready %s.", query_name (op));
3348    
3349 root 1.24 if (op->type == BOW)
3350     {
3351 root 1.76 change_abil (who, op);
3352 root 1.24 new_draw_info_format (NDI_UNIQUE, 0, who,
3353     "You will now fire %s with %s.", op->race ? &op->race : "nothing", query_name (op));
3354     }
3355 root 1.76
3356     who->contr->ranged_skill = find_skill_by_name (who, op->skill);//TODO
3357     who->contr->ranged_ob = op;
3358 root 1.24 }
3359     else
3360     {
3361     if (op->type == BOW)
3362     SET_FLAG (who, FLAG_READY_BOW);
3363     else
3364     SET_FLAG (who, FLAG_READY_RANGE);
3365     }
3366 root 1.76
3367 root 1.24 break;
3368 elmex 1.1
3369 root 1.24 case BUILDER:
3370 root 1.76 if (who->type == PLAYER)
3371     {
3372     if (who->contr->ranged_ob && who->contr->ranged_ob->type == BUILDER)
3373     unapply_special (who, who->contr->ranged_ob, 0);
3374    
3375     new_draw_info_format (NDI_UNIQUE, 0, who, "You ready your %s.", query_name (op));
3376    
3377     who->contr->ranged_skill = who;
3378     who->contr->ranged_ob = op;
3379     }
3380 root 1.24 break;
3381 elmex 1.1
3382 root 1.24 default:
3383     new_draw_info_format (NDI_UNIQUE, 0, who, "You apply %s.", query_name (op));
3384 root 1.22 } /* end of switch op->type */
3385    
3386     SET_FLAG (op, FLAG_APPLIED);
3387 elmex 1.1
3388 root 1.22 if (tmp != NULL)
3389     tmp = insert_ob_in_ob (tmp, who);
3390 elmex 1.1
3391 root 1.51 who->update_stats ();
3392 elmex 1.1
3393 root 1.22 /* We exclude spell casting objects. The fire code will set the
3394     * been applied flag when they are used - until that point,
3395     * you don't know anything about them.
3396     */
3397     if (who->type == PLAYER && op->type != WAND && op->type != HORN && op->type != ROD)
3398     SET_FLAG (op, FLAG_BEEN_APPLIED);
3399    
3400     if (QUERY_FLAG (op, FLAG_CURSED) || QUERY_FLAG (op, FLAG_DAMNED))
3401     {
3402     if (who->type == PLAYER)
3403     {
3404     new_draw_info (NDI_UNIQUE, 0, who, "Oops, it feels deadly cold!");
3405     SET_FLAG (op, FLAG_KNOWN_CURSED);
3406     }
3407     }
3408 root 1.76
3409 root 1.22 if (who->type == PLAYER)
3410     {
3411     /* if multiple objects were applied, update both slots */
3412     if (tmp)
3413     esrv_send_item (who, tmp);
3414 root 1.76
3415 root 1.22 esrv_send_item (who, op);
3416 elmex 1.1 }
3417 root 1.76
3418 root 1.22 return 0;
3419 elmex 1.1 }
3420    
3421 root 1.22 int
3422     monster_apply_special (object *who, object *op, int aflags)
3423 elmex 1.1 {
3424 root 1.22 if (QUERY_FLAG (op, FLAG_UNPAID) && !QUERY_FLAG (op, FLAG_APPLIED))
3425 elmex 1.1 return 1;
3426     return apply_special (who, op, aflags);
3427     }
3428    
3429     /**
3430     * Map was just loaded, handle op's initialisation.
3431     *
3432     * Generates shop floor's item, and treasures.
3433     */
3434 root 1.22 int
3435     auto_apply (object *op)
3436     {
3437     object *tmp = NULL, *tmp2;
3438     int i;
3439 elmex 1.1
3440 root 1.22 switch (op->type)
3441     {
3442 root 1.24 case SHOP_FLOOR:
3443 root 1.42 if (!op->has_random_items ())
3444 root 1.24 return 0;
3445 root 1.38
3446 root 1.24 do
3447     {
3448     i = 10; /* let's give it 10 tries */
3449     while ((tmp = generate_treasure (op->randomitems,
3450     op->stats.exp ? (int) op->stats.exp : MAX (op->map->difficulty, 5))) == NULL && --i);
3451     if (tmp == NULL)
3452     return 0;
3453     if (QUERY_FLAG (tmp, FLAG_CURSED) || QUERY_FLAG (tmp, FLAG_DAMNED))
3454     {
3455 root 1.37 tmp->destroy ();
3456 root 1.24 tmp = NULL;
3457     }
3458     }
3459     while (!tmp);
3460 root 1.38
3461 root 1.24 tmp->x = op->x;
3462     tmp->y = op->y;
3463     SET_FLAG (tmp, FLAG_UNPAID);
3464     insert_ob_in_map (tmp, op->map, NULL, 0);
3465     CLEAR_FLAG (op, FLAG_AUTO_APPLY);
3466     identify (tmp);
3467     break;
3468 root 1.14
3469 root 1.24 case TREASURE:
3470     if (QUERY_FLAG (op, FLAG_IS_A_TEMPLATE))
3471     return 0;
3472 root 1.37
3473 root 1.67 while (op->stats.hp-- > 0)
3474 root 1.24 create_treasure (op->randomitems, op, op->map ? GT_ENVIRONMENT : 0,
3475     op->stats.exp ? (int) op->stats.exp : op->map == NULL ? 14 : op->map->difficulty, 0);
3476    
3477     /* If we generated an object and put it in this object inventory,
3478     * move it to the parent object as the current object is about
3479     * to disappear. An example of this item is the random_* stuff
3480     * that is put inside other objects.
3481     */
3482     for (tmp = op->inv; tmp; tmp = tmp2)
3483     {
3484     tmp2 = tmp->below;
3485 root 1.36 tmp->remove ();
3486 root 1.37
3487 root 1.24 if (op->env)
3488     insert_ob_in_ob (tmp, op->env);
3489     else
3490 root 1.37 tmp->destroy ();
3491 root 1.24 }
3492 root 1.37
3493     op->destroy ();
3494 root 1.24 break;
3495 elmex 1.1 }
3496 root 1.22 return tmp ? 1 : 0;
3497 elmex 1.1 }
3498    
3499     /**
3500 root 1.68 * fix_auto_apply goes through the entire map every time a map
3501     * is loaded or swapped in and performs special actions for
3502 elmex 1.1 * certain objects (most initialization of chests and creation of
3503     * treasures and stuff). Calls auto_apply if appropriate.
3504     */
3505 root 1.20 void
3506 root 1.55 maptile::fix_auto_apply ()
3507 root 1.20 {
3508 root 1.55 if (!spaces)
3509 root 1.20 return;
3510    
3511 root 1.55 for (mapspace *ms = spaces + size (); ms-- > spaces; )
3512     for (object *tmp = ms->bot; tmp; )
3513     {
3514     object *above = tmp->above;
3515 root 1.20
3516 root 1.55 if (tmp->inv)
3517     {
3518     object *invtmp, *invnext;
3519 elmex 1.1
3520 root 1.55 for (invtmp = tmp->inv; invtmp != NULL; invtmp = invnext)
3521     {
3522     invnext = invtmp->below;
3523 root 1.14
3524 root 1.55 if (QUERY_FLAG (invtmp, FLAG_AUTO_APPLY))
3525     auto_apply (invtmp);
3526     else if (invtmp->type == TREASURE && invtmp->has_random_items ())
3527     {
3528     while ((invtmp->stats.hp--) > 0)
3529     create_treasure (invtmp->randomitems, invtmp, 0, difficulty, 0);
3530    
3531     invtmp->randomitems = NULL;
3532     }
3533     else if (invtmp && invtmp->arch
3534     && invtmp->type != TREASURE && invtmp->type != SPELL && invtmp->type != CLASS && invtmp->has_random_items ())
3535     {
3536     create_treasure (invtmp->randomitems, invtmp, 0, difficulty, 0);
3537     /* Need to clear this so that we never try to create
3538     * treasure again for this object
3539     */
3540     invtmp->randomitems = NULL;
3541     }
3542     }
3543     /* This is really temporary - the code at the bottom will
3544     * also set randomitems to null. The problem is there are bunches
3545     * of maps/players already out there with items that have spells
3546     * which haven't had the randomitems set to null yet.
3547     * MSW 2004-05-13
3548     *
3549     * And if it's a spellbook, it's better to set randomitems to NULL too,
3550     * else you get two spells in the book ^_-
3551     * Ryo 2004-08-16
3552     */
3553     if (tmp->type == WAND || tmp->type == ROD || tmp->type == SCROLL
3554     || tmp->type == HORN || tmp->type == FIREWALL || tmp->type == POTION || tmp->type == ALTAR || tmp->type == SPELLBOOK)
3555     tmp->randomitems = NULL;
3556 root 1.14
3557 root 1.55 }
3558 root 1.20
3559 root 1.55 if (QUERY_FLAG (tmp, FLAG_AUTO_APPLY))
3560     auto_apply (tmp);
3561     else if ((tmp->type == TREASURE || (tmp->type == CONTAINER)) && tmp->has_random_items ())
3562     {
3563     while ((tmp->stats.hp--) > 0)
3564     create_treasure (tmp->randomitems, tmp, 0, difficulty, 0);
3565     tmp->randomitems = NULL;
3566     }
3567     else if (tmp->type == TIMED_GATE)
3568     {
3569     object *head = tmp->head != NULL ? tmp->head : tmp;
3570    
3571     if (QUERY_FLAG (head, FLAG_IS_LINKED))
3572     tmp->set_speed (0);
3573     }
3574     /* This function can be called everytime a map is loaded, even when
3575     * swapping back in. As such, we don't want to create the treasure
3576     * over and ove again, so after we generate the treasure, blank out
3577     * randomitems so if it is swapped in again, it won't make anything.
3578     * This is a problem for the above objects, because they have counters
3579     * which say how many times to make the treasure.
3580     */
3581     else if (tmp && tmp->arch && tmp->type != PLAYER
3582     && tmp->type != TREASURE && tmp->type != SPELL
3583     && tmp->type != PLAYER_CHANGER && tmp->type != CLASS && tmp->has_random_items ())
3584     {
3585     create_treasure (tmp->randomitems, tmp, GT_APPLY, difficulty, 0);
3586     tmp->randomitems = NULL;
3587     }
3588 root 1.68 // close all containers
3589     else if (tmp->type == CONTAINER)
3590     tmp->flag [FLAG_APPLIED] = 0;
3591 root 1.22
3592 root 1.55 tmp = above;
3593     }
3594 elmex 1.1
3595 root 1.55 for (mapspace *ms = spaces + size (); ms-- > spaces; )
3596     for (object *tmp = ms->bot; tmp; tmp = tmp->above)
3597     if (tmp->above && (tmp->type == TRIGGER_BUTTON || tmp->type == TRIGGER_PEDESTAL))
3598     check_trigger (tmp, tmp->above);
3599 elmex 1.1 }
3600    
3601     /**
3602     * Handles player eating food that temporarily changes status (resistances, stats).
3603     * This used to call cast_change_attr(), but
3604     * that doesn't work with the new spell code. Since we know what
3605     * the food changes, just grab a force and use that instead.
3606     */
3607    
3608 root 1.22 void
3609     eat_special_food (object *who, object *food)
3610     {
3611     object *force;
3612     int i, did_one = 0;
3613     sint8 k;
3614    
3615     force = get_archetype (FORCE_NAME);
3616    
3617     for (i = 0; i < NUM_STATS; i++)
3618     {
3619     k = get_attr_value (&food->stats, i);
3620     if (k)
3621     {
3622     set_attr_value (&force->stats, i, k);
3623     did_one = 1;
3624 root 1.14 }
3625 elmex 1.1 }
3626    
3627 root 1.22 /* check if we can protect the eater */
3628     for (i = 0; i < NROFATTACKS; i++)
3629     {
3630     if (food->resist[i] > 0)
3631     {
3632     force->resist[i] = food->resist[i] / 2;
3633     did_one = 1;
3634     }
3635     }
3636 elmex 1.47
3637 root 1.22 if (did_one)
3638     {
3639 root 1.54 force->set_speed (0.1);
3640 root 1.22 /* bigger morsel of food = longer effect time */
3641 elmex 1.47 force->duration = food->stats.food / 5;
3642 root 1.22 SET_FLAG (force, FLAG_APPLIED);
3643     change_abil (who, force);
3644     insert_ob_in_ob (force, who);
3645     }
3646     else
3647 root 1.37 force->destroy ();
3648 root 1.22
3649     /* check for hp, sp change */
3650     if (food->stats.hp != 0)
3651     {
3652     if (QUERY_FLAG (food, FLAG_CURSED))
3653     {
3654 root 1.64 assign (who->contr->killer, food->name);
3655 root 1.22 hit_player (who, food->stats.hp, food, AT_POISON, 1);
3656     new_draw_info (NDI_UNIQUE, 0, who, "Eck!...that was poisonous!");
3657     }
3658     else
3659     {
3660     if (food->stats.hp > 0)
3661     new_draw_info (NDI_UNIQUE, 0, who, "You begin to feel better.");
3662     else
3663     new_draw_info (NDI_UNIQUE, 0, who, "Eck!...that was poisonous!");
3664     who->stats.hp += food->stats.hp;
3665     }
3666     }
3667     if (food->stats.sp != 0)
3668     {
3669     if (QUERY_FLAG (food, FLAG_CURSED))
3670     {
3671     new_draw_info (NDI_UNIQUE, 0, who, "You are drained of mana!");
3672     who->stats.sp -= food->stats.sp;
3673     if (who->stats.sp < 0)
3674     who->stats.sp = 0;
3675     }
3676     else
3677     {
3678     new_draw_info (NDI_UNIQUE, 0, who, "You feel a rush of magical energy!");
3679     who->stats.sp += food->stats.sp;
3680     /* place limit on max sp from food? */
3681     }
3682 elmex 1.1 }
3683 root 1.51 who->update_stats ();
3684 elmex 1.1 }
3685    
3686     /**
3687     * Designed primarily to light torches/lanterns/etc.
3688     * Also burns up burnable material too. First object in the inventory is
3689     * the selected object to "burn". -b.t.
3690     */
3691 root 1.22 void
3692     apply_lighter (object *who, object *lighter)
3693     {
3694     object *item;
3695     int is_player_env = 0;
3696    
3697     item = find_marked_object (who);
3698     if (item)
3699     {
3700     if (lighter->last_eat && lighter->stats.food)
3701     { /* lighter gets used up */
3702     /* Split multiple lighters if they're being used up. Otherwise *
3703     * one charge from each would be used up. --DAMN */
3704     if (lighter->nrof > 1)
3705     {
3706 root 1.39 object *oneLighter = lighter->clone ();
3707 root 1.14
3708 root 1.22 lighter->nrof -= 1;
3709     oneLighter->nrof = 1;
3710     oneLighter->stats.food--;
3711     esrv_send_item (who, lighter);
3712     oneLighter = insert_ob_in_ob (oneLighter, who);
3713     esrv_send_item (who, oneLighter);
3714     }
3715     else
3716 root 1.29 lighter->stats.food--;
3717 root 1.22 }
3718     else if (lighter->last_eat)
3719     { /* no charges left in lighter */
3720     new_draw_info_format (NDI_UNIQUE, 0, who, "You attempt to light the %s with a used up %s.", &item->name, &lighter->name);
3721     return;
3722     }
3723 root 1.48
3724 root 1.22 /* Perhaps we should split what we are trying to light on fire?
3725     * I can't see many times when you would want to light multiple
3726     * objects at once.
3727     */
3728 root 1.48
3729     if (who == item->in_player ())
3730 root 1.22 is_player_env = 1;
3731    
3732     save_throw_object (item, AT_FIRE, who);
3733 root 1.48
3734 root 1.49 if (item->destroyed ())
3735 root 1.22 {
3736 root 1.48 new_draw_info_format (NDI_UNIQUE, 0, who, "You light the %s with the %s.", &item->name, &lighter->name);
3737 root 1.22 /* Need to update the player so that the players glow radius
3738     * gets changed.
3739     */
3740     if (is_player_env)
3741 root 1.51 who->update_stats ();
3742 root 1.22 }
3743     else
3744 root 1.29 new_draw_info_format (NDI_UNIQUE, 0, who, "You attempt to light the %s with the %s and fail.", &item->name, &lighter->name);
3745 root 1.22 }
3746     else /* nothing to light */
3747     new_draw_info (NDI_UNIQUE, 0, who, "You need to mark a lightable object.");
3748 elmex 1.1
3749     }
3750    
3751     /**
3752     * op made some mistake with a scroll, this takes care of punishment.
3753     * scroll_failure()- hacked directly from spell_failure
3754     */
3755 root 1.22 void
3756     scroll_failure (object *op, int failure, int power)
3757 elmex 1.1 {
3758 root 1.22 if (abs (failure / 4) > power)
3759     power = abs (failure / 4); /* set minimum effect */
3760 elmex 1.1
3761 root 1.22 if (failure <= -1 && failure > -15)
3762     { /* wonder */
3763     object *tmp;
3764    
3765     new_draw_info (NDI_UNIQUE, 0, op, "Your spell warps!.");
3766     tmp = get_archetype (SPELL_WONDER);
3767     cast_wonder (op, op, 0, tmp);
3768 root 1.37 tmp->destroy ();
3769 root 1.22 }
3770     else if (failure <= -15 && failure > -35)
3771     { /* drain mana */
3772     new_draw_info (NDI_UNIQUE, 0, op, "Your mana is drained!.");
3773     op->stats.sp -= random_roll (0, power - 1, op, PREFER_LOW);
3774     if (op->stats.sp < 0)
3775     op->stats.sp = 0;
3776     }
3777     else if (settings.spell_failure_effects == TRUE)
3778     {
3779     if (failure <= -35 && failure > -60)
3780     { /* confusion */
3781     new_draw_info (NDI_UNIQUE, 0, op, "The magic recoils on you!");
3782     confuse_player (op, op, power);
3783     }
3784     else if (failure <= -60 && failure > -70)
3785     { /* paralysis */
3786     new_draw_info (NDI_UNIQUE, 0, op, "The magic recoils and paralyzes " "you!");
3787     paralyze_player (op, op, power);
3788     }
3789     else if (failure <= -70 && failure > -80)
3790     { /* blind */
3791     new_draw_info (NDI_UNIQUE, 0, op, "The magic recoils on you!");
3792     blind_player (op, op, power);
3793     }
3794     else if (failure <= -80)
3795     { /* blast the immediate area */
3796     object *tmp;
3797    
3798     tmp = get_archetype (LOOSE_MANA);
3799     cast_magic_storm (op, tmp, power);
3800     new_draw_info (NDI_UNIQUE, 0, op, "You unlease uncontrolled mana!");
3801 root 1.37 tmp->destroy ();
3802 root 1.14 }
3803 elmex 1.1 }
3804     }
3805    
3806 root 1.22 void
3807     apply_changes_to_player (object *pl, object *change)
3808     {
3809     int excess_stat = 0; /* if the stat goes over the maximum
3810     for the race, put the excess stat some
3811     where else. */
3812 elmex 1.1
3813 root 1.22 switch (change->type)
3814     {
3815 root 1.24 case CLASS:
3816     {
3817     living *stats = &(pl->contr->orig_stats);
3818     living *ns = &(change->stats);
3819     object *walk;
3820     int flag_change_face = 1;
3821    
3822     /* the following code assigns stats up to the stat max
3823     * for the race, and if the stat max is exceeded,
3824     * tries to randomly reassign the excess stat
3825     */
3826     int i, j;
3827 root 1.22
3828 root 1.24 for (i = 0; i < NUM_STATS; i++)
3829     {
3830     sint8 stat = get_attr_value (stats, i);
3831     int race_bonus = get_attr_value (&(pl->arch->clone.stats), i);
3832 root 1.22
3833 root 1.24 stat += get_attr_value (ns, i);
3834     if (stat > 20 + race_bonus)
3835     {
3836     excess_stat++;
3837     stat = 20 + race_bonus;
3838     }
3839     set_attr_value (stats, i, stat);
3840     }
3841 elmex 1.1
3842 root 1.24 for (j = 0; excess_stat > 0 && j < 100; j++)
3843     { /* try 100 times to assign excess stats */
3844     int i = rndm (0, 6);
3845     int stat = get_attr_value (stats, i);
3846     int race_bonus = get_attr_value (&(pl->arch->clone.stats), i);
3847    
3848     if (i == CHA)
3849     continue; /* exclude cha from this */
3850     if (stat < 20 + race_bonus)
3851     {
3852     change_attr_value (stats, i, 1);
3853     excess_stat--;
3854     }
3855     }
3856 root 1.14
3857 root 1.24 /* insert the randomitems from the change's treasurelist into
3858     * the player ref: player.c
3859     */
3860     if (change->randomitems != NULL)
3861     give_initial_items (pl, change->randomitems);
3862 root 1.14
3863    
3864 root 1.24 /* set up the face, for some races. */
3865 root 1.14
3866 root 1.24 /* first, look for the force object banning
3867     * changing the face. Certain races never change face with class.
3868     */
3869     for (walk = pl->inv; walk != NULL; walk = walk->below)
3870     if (!strcmp (walk->name, "NOCLASSFACECHANGE"))
3871     flag_change_face = 0;
3872 root 1.14
3873 root 1.24 if (flag_change_face)
3874     {
3875     pl->animation_id = GET_ANIM_ID (change);
3876     pl->face = change->face;
3877 root 1.14
3878 root 1.24 if (QUERY_FLAG (change, FLAG_ANIMATE))
3879     SET_FLAG (pl, FLAG_ANIMATE);
3880     else
3881     CLEAR_FLAG (pl, FLAG_ANIMATE);
3882     }
3883 root 1.14
3884 root 1.24 /* check the special case of can't use weapons */
3885     /*if(QUERY_FLAG(change,FLAG_USE_WEAPON)) CLEAR_FLAG(pl,FLAG_USE_WEAPON); */
3886     if (!strcmp (change->name, "monk"))
3887     CLEAR_FLAG (pl, FLAG_USE_WEAPON);
3888 root 1.14
3889 root 1.24 break;
3890     }
3891 elmex 1.1 }
3892     }
3893    
3894     /**
3895     * This handles items of type 'transformer'.
3896     * Basically those items, used with a marked item, transform both items into something
3897     * else.
3898     * "Transformer" item has food decreased by 1, removed if 0 (0 at start means illimited)..
3899     * Change information is contained in the 'slaying' field of the marked item.
3900     * The format is as follow: transformer:[number ]yield[;transformer:...].
3901     * This way an item can be transformed in many things, and/or many objects.
3902     * The 'slaying' field for transformer is used as verb for the action.
3903     */
3904 root 1.22 void
3905     apply_item_transformer (object *pl, object *transformer)
3906     {
3907     object *marked;
3908     object *new_item;
3909     char *find;
3910     char *separator;
3911     int yield;
3912     char got[MAX_BUF];
3913     int len;
3914    
3915     if (!pl || !transformer)
3916     return;
3917     marked = find_marked_object (pl);
3918     if (!marked)
3919 elmex 1.1 {
3920 root 1.22 new_draw_info_format (NDI_UNIQUE, 0, pl, "Use the %s with what item?", query_name (transformer));
3921     return;
3922     }
3923     if (!marked->slaying)
3924     {
3925     new_draw_info_format (NDI_UNIQUE, 0, pl, "You can't use the %s with your %s!", query_name (transformer), query_name (marked));
3926     return;
3927     }
3928     /* check whether they are compatible or not */
3929     find = strstr (marked->slaying, transformer->arch->name);
3930     if (!find || (*(find + strlen (transformer->arch->name)) != ':'))
3931     {
3932     new_draw_info_format (NDI_UNIQUE, 0, pl, "You can't use the %s with your %s!", query_name (transformer), query_name (marked));
3933     return;
3934     }
3935     find += strlen (transformer->arch->name) + 1;
3936     /* Item can be used, now find how many and what it yields */
3937     if (isdigit (*(find)))
3938     {
3939     yield = atoi (find);
3940     if (yield < 1)
3941 elmex 1.1 {
3942 root 1.22 LOG (llevDebug, "apply_item_transformer: item %s has slaying-yield %d.", query_base_name (marked, 0), yield);
3943     yield = 1;
3944 elmex 1.1 }
3945 root 1.22 }
3946     else
3947     yield = 1;
3948 elmex 1.1
3949 root 1.22 while (isdigit (*find))
3950     find++;
3951     while (*find == ' ')
3952     find++;
3953     memset (got, 0, MAX_BUF);
3954     if ((separator = strchr (find, ';')) != NULL)
3955     {
3956     len = separator - find;
3957     }
3958     else
3959     {
3960     len = strlen (find);
3961     }
3962     if (len > MAX_BUF - 1)
3963     len = MAX_BUF - 1;
3964     strcpy (got, find);
3965     got[len] = '\0';
3966    
3967     /* Now create new item, remove used ones when required. */
3968     new_item = get_archetype (got);
3969     if (!new_item)
3970     {
3971     new_draw_info_format (NDI_UNIQUE, 0, pl, "This %s is strange, better to not use it.", query_base_name (marked, 0));
3972     return;
3973 elmex 1.1 }
3974 root 1.29
3975 root 1.22 new_item->nrof = yield;
3976     new_draw_info_format (NDI_UNIQUE, 0, pl, "You %s the %s.", &transformer->slaying, query_base_name (marked, 0));
3977     insert_ob_in_ob (new_item, pl);
3978     esrv_send_inventory (pl, pl);
3979     /* Eat up one item */
3980     decrease_ob_nr (marked, 1);
3981     /* Eat one transformer if needed */
3982     if (transformer->stats.food)
3983     if (--transformer->stats.food == 0)
3984     decrease_ob_nr (transformer, 1);
3985     }