ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/apply.C
Revision: 1.27
Committed: Thu Sep 14 21:16:12 2006 UTC (17 years, 8 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.26: +2 -2 lines
Log Message:
cleanup

File Contents

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