ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/apply.C
Revision: 1.99
Committed: Thu May 17 00:33:29 2007 UTC (17 years, 1 month ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.98: +3 -19 lines
Log Message:
- do not require an item for the use magic item skill.
  thats because it is often used for "misc" objects such as scrolls,
  which do not get applied as ranged weapons. not requiring an item
  is not likely to be a big deal anyways.

File Contents

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