ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/apply.C
Revision: 1.25
Committed: Mon Sep 11 23:33:30 2006 UTC (17 years, 8 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.24: +5 -4 lines
Log Message:
- temporarily disabled shstr garbage collection
- use sint64 instead of uint64 in shop code
- implement fully recursive item iterator for object
- add some utility functions

File Contents

# User Rev Content
1 root 1.22
2 elmex 1.1 /*
3     * static char *rcsid_apply_c =
4 root 1.25 * "$Id: apply.C,v 1.24 2006-09-11 20:26:41 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 elmex 1.4 if ((at = find_archetype (ARCH_DEPLETION)) == NULL)
238     {
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     return sacrifice == NULL;
1321     }
1322     else
1323     {
1324     return 0;
1325 elmex 1.1 }
1326     }
1327    
1328     /**
1329     * Handles 'movement' of shop mats.
1330     * Returns 1 if 'op' was destroyed, 0 if not.
1331     * Largely re-written to not use nearly as many gotos, plus
1332     * some of this code just looked plain out of date.
1333     * MSW 2001-08-29
1334     */
1335 root 1.22 int
1336     apply_shop_mat (object *shop_mat, object *op)
1337 elmex 1.1 {
1338 elmex 1.15 int rv = 0;
1339     double opinion;
1340     object *tmp, *next;
1341 elmex 1.1
1342 elmex 1.15 SET_FLAG (op, FLAG_NO_APPLY); /* prevent loops */
1343 elmex 1.1
1344 elmex 1.15 if (op->type != PLAYER)
1345     {
1346     /* Remove all the unpaid objects that may be carried here.
1347     * This could be pets or monsters that are somehow in
1348     * the shop.
1349     */
1350     for (tmp = op->inv; tmp; tmp = next)
1351     {
1352     next = tmp->below;
1353 root 1.25
1354 elmex 1.15 if (QUERY_FLAG (tmp, FLAG_UNPAID))
1355     {
1356     int i = find_free_spot (tmp, op->map, op->x, op->y, 1, 9);
1357 root 1.14
1358 elmex 1.15 remove_ob (tmp);
1359 root 1.24
1360 elmex 1.15 if (i == -1)
1361     i = 0;
1362 root 1.24
1363 elmex 1.15 tmp->map = op->map;
1364     tmp->x = op->x + freearr_x[i];
1365     tmp->y = op->y + freearr_y[i];
1366     insert_ob_in_map (tmp, op->map, op, 0);
1367 root 1.14 }
1368     }
1369    
1370 elmex 1.15 /* Don't teleport things like spell effects */
1371     if (QUERY_FLAG (op, FLAG_NO_PICK))
1372     return 0;
1373 root 1.14
1374 elmex 1.15 /* unpaid objects, or non living objects, can't transfer by
1375     * shop mats. Instead, put it on a nearby space.
1376     */
1377     if (QUERY_FLAG (op, FLAG_UNPAID) || !QUERY_FLAG (op, FLAG_ALIVE))
1378     {
1379 root 1.14
1380 elmex 1.15 /* Somebody dropped an unpaid item, just move to an adjacent place. */
1381     int i = find_free_spot (op, op->map, op->x, op->y, 1, 9);
1382 root 1.22
1383 elmex 1.15 if (i != -1)
1384 root 1.24 rv = transfer_ob (op, op->x + freearr_x[i], op->y + freearr_y[i], 0, shop_mat);
1385    
1386 elmex 1.15 return 0;
1387 root 1.14 }
1388 elmex 1.15 /* Removed code that checked for multipart objects - it appears that
1389     * the teleport function should be able to handle this just fine.
1390     */
1391     rv = teleport (shop_mat, SHOP_MAT, op);
1392 elmex 1.1 }
1393 root 1.25 else if (can_pay (op) && get_payment (op))
1394 elmex 1.15 {
1395 root 1.24 /* this is only used for players */
1396 elmex 1.15 rv = teleport (shop_mat, SHOP_MAT, op);
1397    
1398     if (shop_mat->msg)
1399 root 1.24 new_draw_info (NDI_UNIQUE, 0, op, shop_mat->msg);
1400 elmex 1.15 /* This check below is a bit simplistic - generally it should be correct,
1401     * but there is never a guarantee that the bottom space on the map is
1402     * actually the shop floor.
1403     */
1404     else if (!rv && !is_in_shop (op))
1405     {
1406     opinion = shopkeeper_approval (op->map, op);
1407 root 1.24
1408 elmex 1.15 if (opinion > 0.9)
1409 root 1.22 new_draw_info (NDI_UNIQUE, 0, op, "The shopkeeper gives you a friendly wave.");
1410 elmex 1.15 else if (opinion > 0.75)
1411     new_draw_info (NDI_UNIQUE, 0, op, "The shopkeeper waves to you.");
1412     else if (opinion > 0.5)
1413     new_draw_info (NDI_UNIQUE, 0, op, "The shopkeeper ignores you.");
1414     else
1415 root 1.22 new_draw_info (NDI_UNIQUE, 0, op, "The shopkeeper glares at you with contempt.");
1416 root 1.14 }
1417 elmex 1.1 }
1418 elmex 1.15 else
1419     {
1420     /* if we get here, a player tried to leave a shop but was not able
1421     * to afford the items he has. We try to move the player so that
1422     * they are not on the mat anymore
1423     */
1424     int i = find_free_spot (op, op->map, op->x, op->y, 1, 9);
1425 root 1.22
1426 elmex 1.15 if (i == -1)
1427     {
1428     LOG (llevError, "Internal shop-mat problem.\n");
1429     }
1430     else
1431     {
1432     remove_ob (op);
1433     op->x += freearr_x[i];
1434     op->y += freearr_y[i];
1435     rv = insert_ob_in_map (op, op->map, shop_mat, 0) == NULL;
1436 root 1.14 }
1437 elmex 1.1 }
1438 root 1.24
1439 elmex 1.15 CLEAR_FLAG (op, FLAG_NO_APPLY);
1440     return rv;
1441 elmex 1.1 }
1442    
1443     /**
1444     * Handles applying a sign.
1445     */
1446 root 1.22 static void
1447     apply_sign (object *op, object *sign, int autoapply)
1448 elmex 1.1 {
1449 root 1.22 readable_message_type *msgType;
1450     char newbuf[HUGE_BUF];
1451    
1452     if (sign->msg == NULL)
1453     {
1454     new_draw_info (NDI_UNIQUE, 0, op, "Nothing is written on it.");
1455     return;
1456 elmex 1.1 }
1457    
1458 root 1.22 if (sign->stats.food)
1459     {
1460     if (sign->last_eat >= sign->stats.food)
1461     {
1462     if (!sign->move_on)
1463     new_draw_info (NDI_UNIQUE, 0, op, "You cannot read it anymore.");
1464     return;
1465 root 1.14 }
1466 elmex 1.1
1467 root 1.22 if (!QUERY_FLAG (op, FLAG_WIZPASS))
1468     sign->last_eat++;
1469 elmex 1.1 }
1470    
1471 root 1.22 /* Sign or magic mouth? Do we need to see it, or does it talk to us?
1472     * No way to know for sure. The presumption is basically that if
1473     * move_on is zero, it needs to be manually applied (doesn't talk
1474     * to us).
1475     */
1476     if (QUERY_FLAG (op, FLAG_BLIND) && !QUERY_FLAG (op, FLAG_WIZ) && !sign->move_on)
1477     {
1478     new_draw_info (NDI_UNIQUE, 0, op, "You are unable to read while blind.");
1479     return;
1480     }
1481     msgType = get_readable_message_type (sign);
1482     snprintf (newbuf, sizeof (newbuf), "%hhu %s", autoapply ? 1 : 0, &sign->msg);
1483     draw_ext_info (NDI_UNIQUE | NDI_NAVY, 0, op, msgType->message_type, msgType->message_subtype, newbuf, &sign->msg);
1484 elmex 1.1 }
1485    
1486     /**
1487     * 'victim' moves onto 'trap'
1488     * 'victim' leaves 'trap'
1489     * effect is determined by move_on/move_off of trap and move_type of victime.
1490     *
1491     * originator: Player, monster or other object that caused 'victim' to move
1492     * onto 'trap'. Will receive messages caused by this action. May be NULL.
1493     * However, some types of traps require an originator to function.
1494     */
1495 root 1.22 void
1496     move_apply (object *trap, object *victim, object *originator)
1497 elmex 1.1 {
1498     static int recursion_depth = 0;
1499    
1500     /* Only exits affect DMs. */
1501 root 1.22 if (QUERY_FLAG (victim, FLAG_WIZPASS) && trap->type != EXIT && trap->type != SIGN)
1502 elmex 1.1 return;
1503    
1504     /* move_apply() is the most likely candidate for causing unwanted and
1505     * possibly unlimited recursion.
1506     */
1507     /* The following was changed because it was causing perfeclty correct
1508     * maps to fail. 1) it's not an error to recurse:
1509     * rune detonates, summoning monster. monster lands on nearby rune.
1510     * nearby rune detonates. This sort of recursion is expected and
1511     * proper. This code was causing needless crashes.
1512     */
1513 root 1.22 if (recursion_depth >= 500)
1514     {
1515     LOG (llevDebug, "WARNING: move_apply(): aborting recursion "
1516     "[trap arch %s, name %s; victim arch %s, name %s]\n", &trap->arch->name, &trap->name, &victim->arch->name, &victim->name);
1517     return;
1518 elmex 1.1 }
1519 root 1.22 recursion_depth++;
1520     if (trap->head)
1521     trap = trap->head;
1522 elmex 1.1
1523 root 1.22 if (INVOKE_OBJECT (MOVE_TRIGGER, trap, ARG_OBJECT (victim), ARG_OBJECT (originator)))
1524     goto leave;
1525 elmex 1.1
1526 root 1.22 switch (trap->type)
1527     {
1528 root 1.23 case PLAYERMOVER:
1529     if (trap->attacktype && (trap->level || victim->type != PLAYER) && !should_director_abort (trap, victim))
1530     {
1531     if (!trap->stats.maxsp)
1532     trap->stats.maxsp = 2;
1533 root 1.14
1534 root 1.23 /* Is this correct? From the docs, it doesn't look like it
1535     * should be divided by trap->speed
1536     */
1537     victim->speed_left = -FABS (trap->stats.maxsp * victim->speed / trap->speed);
1538 root 1.14
1539 root 1.23 /* Just put in some sanity check. I think there is a bug in the
1540     * above with some objects have zero speed, and thus the player
1541     * getting permanently paralyzed.
1542     */
1543     if (victim->speed_left < -50.0)
1544     victim->speed_left = -50.0;
1545     /* LOG(llevDebug, "apply, playermove, player speed_left=%f\n", victim->speed_left); */
1546     }
1547     goto leave;
1548 root 1.14
1549 root 1.23 case SPINNER:
1550     if (victim->direction)
1551     {
1552     victim->direction = absdir (victim->direction - trap->stats.sp);
1553     update_turn_face (victim);
1554     }
1555     goto leave;
1556 root 1.14
1557 root 1.23 case DIRECTOR:
1558     if (victim->direction && !should_director_abort (trap, victim))
1559     {
1560     victim->direction = trap->stats.sp;
1561     update_turn_face (victim);
1562     }
1563     goto leave;
1564 root 1.14
1565 root 1.23 case BUTTON:
1566     case PEDESTAL:
1567     update_button (trap);
1568     goto leave;
1569    
1570     case ALTAR:
1571     /* sacrifice victim on trap */
1572     apply_altar (trap, victim, originator);
1573     goto leave;
1574 root 1.14
1575 root 1.23 case THROWN_OBJ:
1576     if (trap->inv == NULL)
1577 root 1.22 goto leave;
1578 root 1.23 /* fallthrough */
1579 root 1.14
1580 root 1.23 case ARROW:
1581     /* bad bug: monster throw a object, make a step forwards, step on object ,
1582     * trigger this here and get hit by own missile - and will be own enemy.
1583     * Victim then is his own enemy and will start to kill herself (this is
1584     * removed) but we have not synced victim and his missile. To avoid senseless
1585     * action, we avoid hits here
1586     */
1587     if ((QUERY_FLAG (victim, FLAG_ALIVE) && trap->speed) && trap->owner != victim)
1588     hit_with_arrow (trap, victim);
1589     goto leave;
1590 root 1.14
1591 root 1.23 case SPELL_EFFECT:
1592     apply_spell_effect (trap, victim);
1593     goto leave;
1594 root 1.14
1595 root 1.23 case TRAPDOOR:
1596     {
1597     int max, sound_was_played;
1598     object *ab, *ab_next;
1599 root 1.22
1600 root 1.23 if (!trap->value)
1601     {
1602     int tot;
1603 root 1.14
1604 root 1.23 for (ab = trap->above, tot = 0; ab != NULL; ab = ab->above)
1605     if ((ab->move_type && trap->move_on) || ab->move_type == 0)
1606     tot += (ab->nrof ? ab->nrof : 1) * ab->weight + ab->carrying;
1607 root 1.14
1608 root 1.23 if (!(trap->value = (tot > trap->weight) ? 1 : 0))
1609     goto leave;
1610 root 1.22
1611 root 1.23 SET_ANIMATION (trap, trap->value);
1612     update_object (trap, UP_OBJ_FACE);
1613     }
1614 root 1.14
1615 root 1.23 for (ab = trap->above, max = 100, sound_was_played = 0; --max && ab; ab = ab_next)
1616 root 1.22 {
1617 root 1.23 /* need to set this up, since if we do transfer the object,
1618     * ab->above would be bogus
1619     */
1620     ab_next = ab->above;
1621 root 1.14
1622 root 1.23 if ((ab->move_type && trap->move_on) || ab->move_type == 0)
1623 root 1.22 {
1624 root 1.23 if (!sound_was_played)
1625     {
1626     play_sound_map (trap->map, trap->x, trap->y, SOUND_FALL_HOLE);
1627     sound_was_played = 1;
1628     }
1629     new_draw_info (NDI_UNIQUE, 0, ab, "You fall into a trapdoor!");
1630     transfer_ob (ab, (int) EXIT_X (trap), (int) EXIT_Y (trap), 0, ab);
1631 root 1.14 }
1632     }
1633 root 1.22 goto leave;
1634 root 1.23 }
1635 root 1.14
1636    
1637 root 1.23 case CONVERTER:
1638     if (convert_item (victim, trap) < 0)
1639     {
1640     object *op;
1641 root 1.14
1642 root 1.23 new_draw_info_format (NDI_UNIQUE, 0, originator, "The %s seems to be broken!", query_name (trap));
1643 root 1.14
1644 root 1.23 op = get_archetype ("burnout");
1645     if (op != NULL)
1646     {
1647     op->x = trap->x;
1648     op->y = trap->y;
1649     insert_ob_in_map (op, trap->map, trap, 0);
1650     }
1651     }
1652     goto leave;
1653 root 1.14
1654 root 1.23 case TRIGGER_BUTTON:
1655     case TRIGGER_PEDESTAL:
1656     case TRIGGER_ALTAR:
1657     check_trigger (trap, victim);
1658     goto leave;
1659    
1660     case DEEP_SWAMP:
1661     walk_on_deep_swamp (trap, victim);
1662     goto leave;
1663    
1664     case CHECK_INV:
1665     check_inv (victim, trap);
1666     goto leave;
1667    
1668     case HOLE:
1669     /* Hole not open? */
1670     if (trap->stats.wc > 0)
1671 root 1.22 goto leave;
1672 root 1.14
1673 root 1.23 /* Is this a multipart monster and not the head? If so, return.
1674     * Processing will happen if the head runs into the pit
1675     */
1676     if (victim->head)
1677 root 1.22 goto leave;
1678 root 1.14
1679 root 1.23 play_sound_map (victim->map, victim->x, victim->y, SOUND_FALL_HOLE);
1680     new_draw_info (NDI_UNIQUE, 0, victim, "You fall through the hole!\n");
1681     transfer_ob (victim, EXIT_X (trap), EXIT_Y (trap), 1, victim);
1682     goto leave;
1683 root 1.14
1684 root 1.23 case EXIT:
1685     if (victim->type == PLAYER && EXIT_PATH (trap))
1686     {
1687     /* Basically, don't show exits leading to random maps the
1688     * players output.
1689     */
1690     if (trap->msg && strncmp (EXIT_PATH (trap), "/!", 2) && strncmp (EXIT_PATH (trap), "/random/", 8))
1691     new_draw_info (NDI_NAVY, 0, victim, trap->msg);
1692     enter_exit (victim, trap);
1693     }
1694     goto leave;
1695 root 1.14
1696 root 1.23 case ENCOUNTER:
1697     /* may be some leftovers on this */
1698     goto leave;
1699    
1700     case SHOP_MAT:
1701     apply_shop_mat (trap, victim);
1702     goto leave;
1703    
1704     /* Drop a certain amount of gold, and have one item identified */
1705     case IDENTIFY_ALTAR:
1706     apply_id_altar (victim, trap, originator);
1707     goto leave;
1708    
1709     case SIGN:
1710     if (victim->type != PLAYER && trap->stats.food > 0)
1711 root 1.24 goto leave; /* monsters musn't apply magic_mouths with counters */
1712 root 1.23
1713     apply_sign (victim, trap, 1);
1714     goto leave;
1715    
1716     case CONTAINER:
1717     if (victim->type == PLAYER)
1718     (void) esrv_apply_container (victim, trap);
1719     else
1720     (void) apply_container (victim, trap);
1721     goto leave;
1722    
1723     case RUNE:
1724     case TRAP:
1725     if (trap->level && QUERY_FLAG (victim, FLAG_ALIVE))
1726     {
1727     spring_trap (trap, victim);
1728     }
1729     goto leave;
1730 root 1.14
1731 root 1.23 default:
1732     LOG (llevDebug, "name %s, arch %s, type %d with fly/walk on/off not "
1733     "handled in move_apply()\n", &trap->name, &trap->arch->name, trap->type);
1734     goto leave;
1735 elmex 1.1 }
1736    
1737 root 1.22 leave:
1738     recursion_depth--;
1739 elmex 1.1 }
1740    
1741     /**
1742     * Handles reading a regular (ie not containing a spell) book.
1743     */
1744 root 1.22 static void
1745     apply_book (object *op, object *tmp)
1746 elmex 1.1 {
1747 root 1.22 int lev_diff;
1748     object *skill_ob;
1749    
1750     if (QUERY_FLAG (op, FLAG_BLIND) && !QUERY_FLAG (op, FLAG_WIZ))
1751     {
1752     new_draw_info (NDI_UNIQUE, 0, op, "You are unable to read while blind.");
1753     return;
1754     }
1755     if (tmp->msg == NULL)
1756     {
1757     new_draw_info_format (NDI_UNIQUE, 0, op, "You open the %s and find it empty.", &tmp->name);
1758     return;
1759     }
1760 elmex 1.1
1761 root 1.22 /* need a literacy skill to read stuff! */
1762     skill_ob = find_skill_by_name (op, tmp->skill);
1763     if (!skill_ob)
1764     {
1765     new_draw_info (NDI_UNIQUE, 0, op, "You are unable to decipher the strange symbols.");
1766 elmex 1.1 return;
1767     }
1768 root 1.22 lev_diff = tmp->level - (skill_ob->level + 5);
1769     if (!QUERY_FLAG (op, FLAG_WIZ) && lev_diff > 0)
1770     {
1771     if (lev_diff < 2)
1772     new_draw_info (NDI_UNIQUE, 0, op, "This book is just barely beyond your comprehension.");
1773     else if (lev_diff < 3)
1774     new_draw_info (NDI_UNIQUE, 0, op, "This book is slightly beyond your comprehension.");
1775     else if (lev_diff < 5)
1776     new_draw_info (NDI_UNIQUE, 0, op, "This book is beyond your comprehension.");
1777     else if (lev_diff < 8)
1778     new_draw_info (NDI_UNIQUE, 0, op, "This book is quite a bit beyond your comprehension.");
1779     else if (lev_diff < 15)
1780     new_draw_info (NDI_UNIQUE, 0, op, "This book is way beyond your comprehension.");
1781     else
1782     new_draw_info (NDI_UNIQUE, 0, op, "This book is totally beyond your comprehension.");
1783 elmex 1.1 return;
1784     }
1785    
1786 root 1.22 readable_message_type *msgType = get_readable_message_type (tmp);
1787    
1788     draw_ext_info_format (NDI_UNIQUE | NDI_NAVY, 0, op,
1789     msgType->message_type, msgType->message_subtype,
1790     "You open the %s and start reading.\n%s", "%s\n%s", long_desc (tmp, op), &tmp->msg);
1791    
1792     /* gain xp from reading */
1793     if (!QUERY_FLAG (tmp, FLAG_NO_SKILL_IDENT))
1794     { /* only if not read before */
1795     int exp_gain = calc_skill_exp (op, tmp, skill_ob);
1796    
1797     if (!QUERY_FLAG (tmp, FLAG_IDENTIFIED))
1798     {
1799     /*exp_gain *= 2; because they just identified it too */
1800     SET_FLAG (tmp, FLAG_IDENTIFIED);
1801     /* If in a container, update how it looks */
1802     if (tmp->env)
1803     esrv_update_item (UPD_FLAGS | UPD_NAME, op, tmp);
1804     else
1805     op->contr->socket.update_look = 1;
1806     }
1807     change_exp (op, exp_gain, skill_ob->skill, 0);
1808     SET_FLAG (tmp, FLAG_NO_SKILL_IDENT); /* so no more xp gained from this book */
1809 elmex 1.1 }
1810     }
1811    
1812     /**
1813     * Handles the applying of a skill scroll, calling learn_skill straight.
1814     * op is the person learning the skill, tmp is the skill scroll object
1815     */
1816 root 1.22 static void
1817     apply_skillscroll (object *op, object *tmp)
1818 elmex 1.1 {
1819 root 1.22 switch ((int) learn_skill (op, tmp))
1820     {
1821 root 1.24 case 0:
1822     new_draw_info (NDI_UNIQUE, 0, op, "You already possess the knowledge ");
1823     new_draw_info_format (NDI_UNIQUE, 0, op, "held within the %s.\n", query_name (tmp));
1824     return;
1825    
1826     case 1:
1827     new_draw_info_format (NDI_UNIQUE, 0, op, "You succeed in learning %s", &tmp->skill);
1828     decrease_ob (tmp);
1829     return;
1830 root 1.14
1831 root 1.24 default:
1832     new_draw_info_format (NDI_UNIQUE, 0, op, "You fail to learn the knowledge of the %s.\n", query_name (tmp));
1833     decrease_ob (tmp);
1834     return;
1835 elmex 1.1 }
1836     }
1837    
1838     /**
1839     * Actually makes op learn spell.
1840     * Informs player of what happens.
1841     */
1842 root 1.22 void
1843     do_learn_spell (object *op, object *spell, int special_prayer)
1844 elmex 1.1 {
1845 root 1.22 object *tmp;
1846 elmex 1.1
1847 root 1.22 if (op->type != PLAYER)
1848     {
1849     LOG (llevError, "BUG: do_learn_spell(): not a player\n");
1850     return;
1851 elmex 1.1 }
1852    
1853 root 1.22 /* Upgrade special prayers to normal prayers */
1854     if ((tmp = check_spell_known (op, spell->name)) != NULL)
1855     {
1856     if (special_prayer && !QUERY_FLAG (tmp, FLAG_STARTEQUIP))
1857     {
1858     LOG (llevError, "BUG: do_learn_spell(): spell already known, but not marked as startequip\n");
1859     return;
1860 elmex 1.1 }
1861 root 1.22 return;
1862 elmex 1.1 }
1863    
1864 root 1.22 play_sound_player_only (op->contr, SOUND_LEARN_SPELL, 0, 0);
1865     tmp = get_object ();
1866     copy_object (spell, tmp);
1867     insert_ob_in_ob (tmp, op);
1868    
1869     if (special_prayer)
1870     {
1871     SET_FLAG (tmp, FLAG_STARTEQUIP);
1872 elmex 1.1 }
1873    
1874 root 1.22 esrv_add_spells (op->contr, tmp);
1875 elmex 1.1 }
1876    
1877     /**
1878     * Erases spell from player's inventory.
1879     */
1880 root 1.22 void
1881     do_forget_spell (object *op, const char *spell)
1882 elmex 1.1 {
1883 root 1.22 object *spob;
1884    
1885     if (op->type != PLAYER)
1886     {
1887     LOG (llevError, "BUG: do_forget_spell(): not a player\n");
1888     return;
1889     }
1890     if ((spob = check_spell_known (op, spell)) == NULL)
1891     {
1892     LOG (llevError, "BUG: do_forget_spell(): spell not known\n");
1893     return;
1894     }
1895 elmex 1.1
1896 root 1.22 new_draw_info_format (NDI_UNIQUE | NDI_NAVY, 0, op, "You lose knowledge of %s.", spell);
1897     player_unready_range_ob (op->contr, spob);
1898     esrv_remove_spell (op->contr, spob);
1899     remove_ob (spob);
1900     free_object (spob);
1901 elmex 1.1 }
1902    
1903     /**
1904     * Handles player applying a spellbook.
1905     * Checks whether player has knowledge of required skill, doesn't already know the spell,
1906     * stuff like that. Random learning failure too.
1907     */
1908 root 1.22 static void
1909     apply_spellbook (object *op, object *tmp)
1910 elmex 1.1 {
1911 root 1.22 object *skop, *spell, *spell_skill;
1912    
1913     if (QUERY_FLAG (op, FLAG_BLIND) && !QUERY_FLAG (op, FLAG_WIZ))
1914     {
1915     new_draw_info (NDI_UNIQUE, 0, op, "You are unable to read while blind.");
1916     return;
1917     }
1918    
1919     /* artifact_spellbooks have 'slaying' field point to a spell name,
1920     * instead of having their spell stored in stats.sp. These are
1921     * legacy spellbooks
1922     */
1923 elmex 1.1
1924 root 1.22 if (tmp->slaying != NULL)
1925     {
1926     spell = arch_to_object (find_archetype_by_object_name (tmp->slaying));
1927     if (!spell)
1928     {
1929     new_draw_info_format (NDI_UNIQUE, 0, op, "The book's formula for %s is incomplete", &tmp->slaying);
1930     return;
1931 root 1.14 }
1932 root 1.22 else
1933     insert_ob_in_ob (spell, tmp);
1934     tmp->slaying = NULL;
1935     }
1936    
1937     skop = find_skill_by_name (op, tmp->skill);
1938    
1939     /* need a literacy skill to learn spells. Also, having a literacy level
1940     * lower than the spell will make learning the spell more difficult */
1941     if (!skop)
1942     {
1943     new_draw_info (NDI_UNIQUE, 0, op, "You can't read! Your attempt fails.");
1944     return;
1945     }
1946    
1947     spell = tmp->inv;
1948     if (!spell)
1949     {
1950     LOG (llevError, "apply_spellbook: Book %s has no spell in it!\n", &tmp->name);
1951     new_draw_info (NDI_UNIQUE, 0, op, "The spellbook symbols make no sense.");
1952     return;
1953     }
1954     if (spell->level > (skop->level + 10))
1955     {
1956     new_draw_info (NDI_UNIQUE, 0, op, "You are unable to decipher the strange symbols.");
1957     return;
1958     }
1959    
1960     new_draw_info_format (NDI_UNIQUE, 0, op, "The spellbook contains the %s level spell %s.", get_levelnumber (spell->level), &spell->name);
1961    
1962     if (!QUERY_FLAG (tmp, FLAG_IDENTIFIED))
1963     {
1964     identify (tmp);
1965     if (tmp->env)
1966     esrv_update_item (UPD_FLAGS | UPD_NAME, op, tmp);
1967     else
1968     op->contr->socket.update_look = 1;
1969     }
1970    
1971     /* I removed the check for special_prayer_mark here - it didn't make
1972     * a lot of sense - special prayers are not found in spellbooks, and
1973     * if the player doesn't know the spell, doesn't make a lot of sense that
1974     * they would have a special prayer mark.
1975     */
1976     if (check_spell_known (op, spell->name))
1977     {
1978     new_draw_info (NDI_UNIQUE, 0, op, "You already know that spell.\n");
1979     return;
1980 elmex 1.1 }
1981 root 1.22
1982     if (spell->skill)
1983     {
1984     spell_skill = find_skill_by_name (op, spell->skill);
1985 root 1.25
1986 root 1.22 if (!spell_skill)
1987     {
1988     new_draw_info_format (NDI_UNIQUE, 0, op, "You lack the skill %s to use this spell", &spell->skill);
1989     return;
1990 root 1.14 }
1991 root 1.25
1992 root 1.22 if (spell_skill->level < spell->level)
1993     {
1994     new_draw_info_format (NDI_UNIQUE, 0, op, "You need to be level %d in %s to learn this spell.", spell->level, &spell->skill);
1995     return;
1996 root 1.14 }
1997 elmex 1.1 }
1998    
1999 root 1.22 /* Logic as follows
2000     *
2001     * 1- MU spells use Int to learn, Cleric spells use Wisdom
2002     *
2003     * 2- The learner's skill level in literacy adjusts the chance to learn
2004     * a spell.
2005     *
2006     * 3 -Automatically fail to learn if you read while confused
2007     *
2008     * Overall, chances are the same but a player will find having a high
2009     * literacy rate very useful! -b.t.
2010     */
2011     if (QUERY_FLAG (op, FLAG_CONFUSED))
2012     {
2013     new_draw_info (NDI_UNIQUE, 0, op, "In your confused state you flub the wording of the text!");
2014     scroll_failure (op, 0 - random_roll (0, spell->level, op, PREFER_LOW), MAX (spell->stats.sp, spell->stats.grace));
2015     }
2016     else if (QUERY_FLAG (tmp, FLAG_STARTEQUIP) ||
2017     (random_roll (0, 100, op, PREFER_LOW) - (5 * skop->level)) < learn_spell[spell->stats.grace ? op->stats.Wis : op->stats.Int])
2018     {
2019    
2020     new_draw_info (NDI_UNIQUE, 0, op, "You succeed in learning the spell!");
2021     do_learn_spell (op, spell, 0);
2022    
2023     /* xp gain to literacy for spell learning */
2024     if (!QUERY_FLAG (tmp, FLAG_STARTEQUIP))
2025     change_exp (op, calc_skill_exp (op, tmp, skop), skop->skill, 0);
2026 elmex 1.1 }
2027 root 1.22 else
2028     {
2029     play_sound_player_only (op->contr, SOUND_FUMBLE_SPELL, 0, 0);
2030     new_draw_info (NDI_UNIQUE, 0, op, "You fail to learn the spell.\n");
2031     }
2032     decrease_ob (tmp);
2033 elmex 1.1 }
2034    
2035     /**
2036     * Handles applying a spell scroll.
2037     */
2038 root 1.22 void
2039     apply_scroll (object *op, object *tmp, int dir)
2040 elmex 1.1 {
2041 root 1.22 object *skop;
2042 elmex 1.1
2043 root 1.22 if (QUERY_FLAG (op, FLAG_BLIND) && !QUERY_FLAG (op, FLAG_WIZ))
2044     {
2045     new_draw_info (NDI_UNIQUE, 0, op, "You are unable to read while blind.");
2046     return;
2047 elmex 1.1 }
2048    
2049 root 1.22 if (!tmp->inv || tmp->inv->type != SPELL)
2050     {
2051     new_draw_info (NDI_UNIQUE, 0, op, "The scroll just doesn't make sense!");
2052     return;
2053 elmex 1.1 }
2054    
2055 root 1.22 if (op->type == PLAYER)
2056     {
2057     /* players need a literacy skill to read stuff! */
2058     int exp_gain = 0;
2059 elmex 1.1
2060 root 1.22 /* hard code literacy - tmp->skill points to where the exp
2061     * should go for anything killed by the spell.
2062     */
2063     skop = find_skill_by_name (op, skill_names[SK_LITERACY]);
2064 elmex 1.1
2065 root 1.22 if (!skop)
2066     {
2067     new_draw_info (NDI_UNIQUE, 0, op, "You are unable to decipher the strange symbols.");
2068     return;
2069     }
2070 elmex 1.1
2071 root 1.22 if ((exp_gain = calc_skill_exp (op, tmp, skop)))
2072     change_exp (op, exp_gain, skop->skill, 0);
2073 elmex 1.1 }
2074    
2075 root 1.22 if (!QUERY_FLAG (tmp, FLAG_IDENTIFIED))
2076     identify (tmp);
2077 elmex 1.1
2078 root 1.22 new_draw_info_format (NDI_BLACK, 0, op, "The scroll of %s turns to dust.", &tmp->inv->name);
2079 elmex 1.1
2080    
2081 root 1.22 cast_spell (op, tmp, dir, tmp->inv, NULL);
2082     decrease_ob (tmp);
2083 elmex 1.1 }
2084    
2085     /**
2086     * Applies a treasure object - by default, chest. op
2087     * is the person doing the applying, tmp is the treasure
2088     * chest.
2089     */
2090 root 1.22 static void
2091     apply_treasure (object *op, object *tmp)
2092 elmex 1.1 {
2093 root 1.22 object *treas;
2094     tag_t tmp_tag = tmp->count, op_tag = op->count;
2095    
2096    
2097     /* Nice side effect of new treasure creation method is that the treasure
2098     * for the chest is done when the chest is created, and put into the chest
2099     * inventory. So that when the chest burns up, the items still exist. Also
2100     * prevents people fromt moving chests to more difficult maps to get better
2101     * treasure
2102     */
2103    
2104     treas = tmp->inv;
2105     if (treas == NULL)
2106     {
2107     new_draw_info (NDI_UNIQUE, 0, op, "The chest was empty.");
2108     decrease_ob (tmp);
2109     return;
2110     }
2111     while (tmp->inv)
2112     {
2113     treas = tmp->inv;
2114 elmex 1.1
2115 root 1.22 remove_ob (treas);
2116     new_draw_info_format (NDI_UNIQUE, 0, op, "You find %s in the chest.", query_name (treas));
2117 elmex 1.1
2118 root 1.22 treas->x = op->x;
2119     treas->y = op->y;
2120     treas = insert_ob_in_map (treas, op->map, op, INS_BELOW_ORIGINATOR);
2121    
2122     if (treas && (treas->type == RUNE || treas->type == TRAP) && treas->level && QUERY_FLAG (op, FLAG_ALIVE))
2123     spring_trap (treas, op);
2124     /* If either player or container was destroyed, no need to do
2125     * further processing. I think this should be enclused with
2126     * spring trap above, as I don't think there is otherwise
2127     * any way for the treasure chest or player to get killed
2128     */
2129     if (was_destroyed (op, op_tag) || was_destroyed (tmp, tmp_tag))
2130     break;
2131 elmex 1.1 }
2132    
2133 root 1.22 if (!was_destroyed (tmp, tmp_tag) && tmp->inv == NULL)
2134     decrease_ob (tmp);
2135 elmex 1.1
2136     }
2137    
2138     /**
2139     * op eats food.
2140     * If player, takes care of messages and dragon special food.
2141     */
2142 root 1.22 static void
2143     apply_food (object *op, object *tmp)
2144 elmex 1.1 {
2145 root 1.22 int capacity_remaining;
2146 elmex 1.1
2147 root 1.22 if (op->type != PLAYER)
2148     op->stats.hp = op->stats.maxhp;
2149     else
2150     {
2151 elmex 1.1 /* check if this is a dragon (player), eating some flesh */
2152 root 1.22 if (tmp->type == FLESH && is_dragon_pl (op) && dragon_eat_flesh (op, tmp))
2153 root 1.14 ;
2154 root 1.22 else
2155     {
2156     /* usual case - no dragon meal: */
2157     if (op->stats.food + tmp->stats.food > 999)
2158     {
2159     if (tmp->type == FOOD || tmp->type == FLESH)
2160     new_draw_info (NDI_UNIQUE, 0, op, "You feel full, but what a waste of food!");
2161     else
2162     new_draw_info (NDI_UNIQUE, 0, op, "Most of the drink goes down your face not your throat!");
2163     }
2164    
2165     if (!QUERY_FLAG (tmp, FLAG_CURSED))
2166     {
2167     char buf[MAX_BUF];
2168    
2169     if (!is_dragon_pl (op))
2170     {
2171     /* eating message for normal players */
2172     if (tmp->type == DRINK)
2173     sprintf (buf, "Ahhh...that %s tasted good.", &tmp->name);
2174     else
2175     sprintf (buf, "The %s tasted %s", &tmp->name, tmp->type == FLESH ? "terrible!" : "good.");
2176     }
2177     else
2178     {
2179     /* eating message for dragon players */
2180     sprintf (buf, "The %s tasted terrible!", &tmp->name);
2181     }
2182    
2183     new_draw_info (NDI_UNIQUE, 0, op, buf);
2184     capacity_remaining = 999 - op->stats.food;
2185     op->stats.food += tmp->stats.food;
2186     if (capacity_remaining < tmp->stats.food)
2187     op->stats.hp += capacity_remaining / 50;
2188     else
2189     op->stats.hp += tmp->stats.food / 50;
2190     if (op->stats.hp > op->stats.maxhp)
2191     op->stats.hp = op->stats.maxhp;
2192     if (op->stats.food > 999)
2193     op->stats.food = 999;
2194     }
2195 root 1.14
2196 root 1.22 /* special food hack -b.t. */
2197     if (tmp->title || QUERY_FLAG (tmp, FLAG_CURSED))
2198     eat_special_food (op, tmp);
2199     }
2200 elmex 1.1 }
2201 root 1.22 handle_apply_yield (tmp);
2202     decrease_ob (tmp);
2203 elmex 1.1 }
2204    
2205     /**
2206     * A dragon is eating some flesh. If the flesh contains resistances,
2207     * there is a chance for the dragon's skin to get improved.
2208     *
2209     * attributes:
2210     * object *op the object (dragon player) eating the flesh
2211     * object *meal the flesh item, getting chewed in dragon's mouth
2212     * return:
2213     * int 1 if eating successful, 0 if it doesn't work
2214     */
2215 root 1.22 int
2216     dragon_eat_flesh (object *op, object *meal)
2217     {
2218     object *skin = NULL; /* pointer to dragon skin force */
2219     object *abil = NULL; /* pointer to dragon ability force */
2220     object *tmp = NULL; /* tmp. object */
2221    
2222 elmex 1.1 char buf[MAX_BUF]; /* tmp. string buffer */
2223     double chance; /* improvement-chance of one resistance type */
2224 root 1.22 double totalchance = 1; /* total chance of gaining one resistance */
2225     double bonus = 0; /* level bonus (improvement is easier at lowlevel) */
2226     double mbonus = 0; /* monster bonus */
2227 elmex 1.1 int atnr_winner[NROFATTACKS]; /* winning candidates for resistance improvement */
2228 root 1.22 int winners = 0; /* number of winners */
2229 elmex 1.1 int i; /* index */
2230 root 1.22
2231 elmex 1.1 /* let's make sure and doublecheck the parameters */
2232 root 1.22 if (meal->type != FLESH || !is_dragon_pl (op))
2233 elmex 1.1 return 0;
2234 root 1.22
2235 elmex 1.1 /* now grab the 'dragon_skin'- and 'dragon_ability'-forces
2236     from the player's inventory */
2237 root 1.22 for (tmp = op->inv; tmp != NULL; tmp = tmp->below)
2238     {
2239     if (tmp->type == FORCE)
2240     {
2241     if (strcmp (tmp->arch->name, "dragon_skin_force") == 0)
2242     skin = tmp;
2243     else if (strcmp (tmp->arch->name, "dragon_ability_force") == 0)
2244     abil = tmp;
2245     }
2246 elmex 1.1 }
2247 root 1.22
2248 elmex 1.1 /* if either skin or ability are missing, this is an old player
2249     which is not to be considered a dragon -> bail out */
2250 root 1.22 if (skin == NULL || abil == NULL)
2251     return 0;
2252    
2253 elmex 1.1 /* now start by filling stomache and health, according to food-value */
2254 root 1.22 if ((999 - op->stats.food) < meal->stats.food)
2255 elmex 1.1 op->stats.hp += (999 - op->stats.food) / 50;
2256     else
2257 root 1.22 op->stats.hp += meal->stats.food / 50;
2258     if (op->stats.hp > op->stats.maxhp)
2259     op->stats.hp = op->stats.maxhp;
2260    
2261     op->stats.food = MIN (999, op->stats.food + meal->stats.food);
2262    
2263     /*LOG(llevDebug, "-> player: %d, flesh: %d\n", op->level, meal->level); */
2264    
2265 elmex 1.1 /* on to the interesting part: chances for adding resistance */
2266 root 1.22 for (i = 0; i < NROFATTACKS; i++)
2267     {
2268     if (meal->resist[i] > 0 && atnr_is_dragon_enabled (i))
2269     {
2270     /* got positive resistance, now calculate improvement chance (0-100) */
2271    
2272     /* this bonus makes resistance increase easier at lower levels */
2273     bonus = (settings.max_level - op->level) * 30. / ((double) settings.max_level);
2274     if (i == abil->stats.exp)
2275     bonus += 5; /* additional bonus for resistance of ability-focus */
2276    
2277     /* monster bonus increases with level, because high-level
2278     flesh is too rare */
2279     mbonus = op->level * 20. / ((double) settings.max_level);
2280    
2281     chance = (((double) MIN (op->level + bonus, meal->level + bonus + mbonus)) * 100. /
2282     ((double) settings.max_level)) - skin->resist[i];
2283    
2284     if (chance >= 0.)
2285     chance += 1.;
2286     else
2287     chance = (chance < -12) ? 0. : 1. / pow (2., -chance);
2288    
2289     /* chance is proportional to amount of resistance (max. 50) */
2290     chance *= ((double) (MIN (meal->resist[i], 50))) / 50.;
2291    
2292     /* doubled chance for resistance of ability-focus */
2293     if (i == abil->stats.exp)
2294     chance = MIN (100., chance * 2.);
2295    
2296     /* now make the throw and save all winners (Don't insert luck bonus here!) */
2297     if (RANDOM () % 10000 < (int) (chance * 100))
2298     {
2299     atnr_winner[winners] = i;
2300     winners++;
2301     }
2302    
2303     if (chance >= 0.01)
2304     totalchance *= 1 - chance / 100;
2305    
2306     /*LOG(llevDebug, " %s: bonus %.1f, chance %.1f\n", attacks[i], bonus, chance); */
2307     }
2308 elmex 1.1 }
2309 root 1.22
2310 elmex 1.1 /* inverse totalchance as until now we have the failure-chance */
2311 root 1.22 totalchance = 100 - totalchance * 100;
2312 elmex 1.1 /* print message according to totalchance */
2313     if (totalchance > 50.)
2314 root 1.22 sprintf (buf, "Hmm! The %s tasted delicious!", &meal->name);
2315 elmex 1.1 else if (totalchance > 10.)
2316 root 1.22 sprintf (buf, "The %s tasted very good.", &meal->name);
2317 elmex 1.1 else if (totalchance > 1.)
2318 root 1.22 sprintf (buf, "The %s tasted good.", &meal->name);
2319 elmex 1.1 else if (totalchance > 0.1)
2320 root 1.22 sprintf (buf, "The %s tasted bland.", &meal->name);
2321 elmex 1.1 else if (totalchance >= 0.01)
2322 root 1.22 sprintf (buf, "The %s had a boring taste.", &meal->name);
2323     else if (meal->last_eat > 0 && atnr_is_dragon_enabled (meal->last_eat))
2324     sprintf (buf, "The %s tasted strange.", &meal->name);
2325     else
2326     sprintf (buf, "The %s had no taste.", &meal->name);
2327     new_draw_info (NDI_UNIQUE, 0, op, buf);
2328    
2329 elmex 1.1 /* now choose a winner if we have any */
2330     i = -1;
2331 root 1.22 if (winners > 0)
2332     i = atnr_winner[RANDOM () % winners];
2333    
2334     if (i >= 0 && i < NROFATTACKS && skin->resist[i] < 95)
2335     {
2336     /* resistance increased! */
2337     skin->resist[i]++;
2338     fix_player (op);
2339    
2340     sprintf (buf, "Your skin is now more resistant to %s!", change_resist_msg[i]);
2341     new_draw_info (NDI_UNIQUE | NDI_RED, 0, op, buf);
2342     }
2343    
2344 elmex 1.1 /* if this flesh contains a new ability focus, we mark it
2345     into the ability_force and it will take effect on next level */
2346 root 1.22 if (meal->last_eat > 0 && atnr_is_dragon_enabled (meal->last_eat) && meal->last_eat != abil->last_eat)
2347     {
2348     abil->last_eat = meal->last_eat; /* write: last_eat <new attnr focus> */
2349    
2350     if (meal->last_eat != abil->stats.exp)
2351     {
2352     sprintf (buf, "Your metabolism prepares to focus on %s!", change_resist_msg[meal->last_eat]);
2353     new_draw_info (NDI_UNIQUE, 0, op, buf);
2354     sprintf (buf, "The change will happen at level %d", abil->level + 1);
2355     new_draw_info (NDI_UNIQUE, 0, op, buf);
2356     }
2357     else
2358     {
2359     sprintf (buf, "Your metabolism will continue to focus on %s.", change_resist_msg[meal->last_eat]);
2360     new_draw_info (NDI_UNIQUE, 0, op, buf);
2361     abil->last_eat = 0;
2362     }
2363 elmex 1.1 }
2364     return 1;
2365     }
2366    
2367 root 1.22 static void
2368     apply_savebed (object *pl)
2369 elmex 1.1 {
2370     #ifndef COZY_SERVER
2371 root 1.22 if (!pl->contr->name_changed || !pl->stats.exp)
2372     {
2373     new_draw_info (NDI_UNIQUE, 0, pl, "You don't deserve to save your character yet.");
2374 elmex 1.1 return;
2375     }
2376     #endif
2377 root 1.22 INVOKE_PLAYER (LOGOUT, pl->contr);
2378     /* Need to call terminate_all_pets() before we remove the player ob */
2379     terminate_all_pets (pl);
2380     remove_ob (pl);
2381     pl->direction = 0;
2382     new_draw_info_format (NDI_UNIQUE | NDI_ALL | NDI_DK_ORANGE, 5, pl, "%s leaves the game.", &pl->name);
2383    
2384     /* update respawn position */
2385     strcpy (pl->contr->savebed_map, pl->map->path);
2386     pl->contr->bed_x = pl->x;
2387     pl->contr->bed_y = pl->y;
2388    
2389     strcpy (pl->contr->killer, "left");
2390     check_score (pl); /* Always check score */
2391     (void) save_player (pl, 0);
2392     pl->map->players--;
2393     #if MAP_MAXTIMEOUT
2394     MAP_SWAP_TIME (pl->map) = MAP_TIMEOUT (pl->map);
2395 elmex 1.1 #endif
2396 root 1.22 play_again (pl);
2397     pl->speed = 0;
2398     update_ob_speed (pl);
2399 elmex 1.1 }
2400    
2401     /**
2402     * Handles applying an improve armor scroll.
2403     * Does some sanity checks, then calls improve_armour.
2404     */
2405 root 1.22 static void
2406     apply_armour_improver (object *op, object *tmp)
2407 elmex 1.1 {
2408 root 1.22 object *armor;
2409 elmex 1.1
2410 root 1.22 if (!QUERY_FLAG (op, FLAG_WIZCAST) && (get_map_flags (op->map, NULL, op->x, op->y, NULL, NULL) & P_NO_MAGIC))
2411     {
2412     new_draw_info (NDI_UNIQUE, 0, op, "Something blocks the magic of the scroll.");
2413     return;
2414 elmex 1.1 }
2415 root 1.22 armor = find_marked_object (op);
2416     if (!armor)
2417     {
2418     new_draw_info (NDI_UNIQUE, 0, op, "You need to mark an armor object.");
2419 elmex 1.1 return;
2420     }
2421 root 1.22 if (armor->type != ARMOUR
2422     && armor->type != CLOAK
2423     && armor->type != BOOTS && armor->type != GLOVES && armor->type != BRACERS && armor->type != SHIELD && armor->type != HELMET)
2424 elmex 1.1 {
2425 root 1.22 new_draw_info (NDI_UNIQUE, 0, op, "Your marked item is not armour!\n");
2426     return;
2427 elmex 1.1 }
2428    
2429 root 1.22 new_draw_info (NDI_UNIQUE, 0, op, "Applying armour enchantment.");
2430     improve_armour (op, tmp, armor);
2431 elmex 1.1 }
2432    
2433    
2434 root 1.22 extern void
2435     apply_poison (object *op, object *tmp)
2436 elmex 1.1 {
2437 root 1.22 if (op->type == PLAYER)
2438     {
2439     play_sound_player_only (op->contr, SOUND_DRINK_POISON, 0, 0);
2440     new_draw_info (NDI_UNIQUE, 0, op, "Yech! That tasted poisonous!");
2441     strcpy (op->contr->killer, "poisonous booze");
2442 elmex 1.1 }
2443 root 1.22 if (tmp->stats.hp > 0)
2444     {
2445     LOG (llevDebug, "Trying to poison player/monster for %d hp\n", tmp->stats.hp);
2446     hit_player (op, tmp->stats.hp, tmp, AT_POISON, 1);
2447 elmex 1.1 }
2448 root 1.22 op->stats.food -= op->stats.food / 4;
2449     handle_apply_yield (tmp);
2450     decrease_ob (tmp);
2451 elmex 1.1 }
2452    
2453     /**
2454     * This fonction return true if the exit is not a 2 ways one or it is 2 ways, valid exit.
2455     * A valid 2 way exit means:
2456     * -You can come back (there is another exit at the other side)
2457     * -You are
2458     * ° the owner of the exit
2459     * ° or in the same party as the owner
2460     *
2461     * Note: a owner in a 2 way exit is saved as the owner's name
2462     * in the field exit->name cause the field exit->owner doesn't
2463     * survive in the swapping (in fact the whole exit doesn't survive).
2464     */
2465 root 1.22 int
2466     is_legal_2ways_exit (object *op, object *exit)
2467     {
2468     object *tmp;
2469     object *exit_owner;
2470     player *pp;
2471     mapstruct *exitmap;
2472    
2473     if (exit->stats.exp != 1)
2474     return 1; /*This is not a 2 way, so it is legal */
2475     if (!has_been_loaded (EXIT_PATH (exit)) && exit->race)
2476     return 0; /* This is a reset town portal */
2477     /* To know if an exit has a correspondant, we look at
2478     * all the exits in destination and try to find one with same path as
2479     * the current exit's position */
2480     if (!strncmp (EXIT_PATH (exit), settings.localdir, strlen (settings.localdir)))
2481     exitmap = ready_map_name (EXIT_PATH (exit), MAP_PLAYER_UNIQUE);
2482     else
2483     exitmap = ready_map_name (EXIT_PATH (exit), 0);
2484     if (exitmap)
2485     {
2486     tmp = get_map_ob (exitmap, EXIT_X (exit), EXIT_Y (exit));
2487     if (!tmp)
2488     return 0;
2489     for ((tmp = get_map_ob (exitmap, EXIT_X (exit), EXIT_Y (exit))); tmp; tmp = tmp->above)
2490     {
2491     if (tmp->type != EXIT)
2492     continue; /*Not an exit */
2493     if (!EXIT_PATH (tmp))
2494     continue; /*Not a valid exit */
2495     if ((EXIT_X (tmp) != exit->x) || (EXIT_Y (tmp) != exit->y))
2496     continue; /*Not in the same place */
2497     if (strcmp (exit->map->path, EXIT_PATH (tmp)) != 0)
2498     continue; /*Not in the same map */
2499    
2500     /* From here we have found the exit is valid. However we do
2501     * here the check of the exit owner. It is important for the
2502     * town portals to prevent strangers from visiting your appartments
2503     */
2504     if (!exit->race)
2505     return 1; /*No owner, free for all! */
2506     exit_owner = NULL;
2507     for (pp = first_player; pp; pp = pp->next)
2508     {
2509     if (!pp->ob)
2510     continue;
2511     if (pp->ob->name != exit->race)
2512     continue;
2513     exit_owner = pp->ob; /*We found a player which correspond to the player name */
2514     break;
2515     }
2516     if (!exit_owner)
2517     return 0; /* No more owner */
2518     if (exit_owner->contr == op->contr)
2519     return 1; /*It is your exit */
2520     if (exit_owner && /*There is a owner */
2521     (op->contr) && /*A player tries to pass */
2522     ((exit_owner->contr->party == NULL) || /*No pass if controller has no party */
2523     (exit_owner->contr->party != op->contr->party))) /* Or not the same as op */
2524     return 0;
2525     return 1;
2526     }
2527     }
2528     return 0;
2529     }
2530 elmex 1.1
2531    
2532     /**
2533     * Main apply handler.
2534     *
2535     * Checks for unpaid items before applying.
2536     *
2537     * Return value:
2538     * 0: player or monster can't apply objects of that type
2539     * 1: has been applied, or there was an error applying the object
2540     * 2: objects of that type can't be applied if not in inventory
2541     *
2542     * op is the object that is causing object to be applied, tmp is the object
2543     * being applied.
2544     *
2545     * aflag is special (always apply/unapply) flags. Nothing is done with
2546     * them in this function - they are passed to apply_special
2547     */
2548    
2549 root 1.22 int
2550     manual_apply (object *op, object *tmp, int aflag)
2551 elmex 1.1 {
2552 root 1.22 if (tmp->head)
2553     tmp = tmp->head;
2554 elmex 1.1
2555 root 1.22 if (QUERY_FLAG (tmp, FLAG_UNPAID) && !QUERY_FLAG (tmp, FLAG_APPLIED))
2556     {
2557     if (op->type == PLAYER)
2558     {
2559     new_draw_info (NDI_UNIQUE, 0, op, "You should pay for it first.");
2560     return 1;
2561     }
2562     else
2563     {
2564     return 0; /* monsters just skip unpaid items */
2565 root 1.14 }
2566 elmex 1.1 }
2567    
2568 root 1.22 if (INVOKE_OBJECT (APPLY, tmp, ARG_OBJECT (op)))
2569     return RESULT_INT (0);
2570 root 1.8
2571 root 1.22 switch (tmp->type)
2572     {
2573 elmex 1.1
2574 root 1.24 case CF_HANDLE:
2575     new_draw_info (NDI_UNIQUE, 0, op, "You turn the handle.");
2576     play_sound_map (op->map, op->x, op->y, SOUND_TURN_HANDLE);
2577     tmp->value = tmp->value ? 0 : 1;
2578     SET_ANIMATION (tmp, tmp->value);
2579     update_object (tmp, UP_OBJ_FACE);
2580     push_button (tmp);
2581     return 1;
2582 root 1.14
2583 root 1.24 case TRIGGER:
2584     if (check_trigger (tmp, op))
2585     {
2586     new_draw_info (NDI_UNIQUE, 0, op, "You turn the handle.");
2587     play_sound_map (tmp->map, tmp->x, tmp->y, SOUND_TURN_HANDLE);
2588     }
2589     else
2590     {
2591     new_draw_info (NDI_UNIQUE, 0, op, "The handle doesn't move.");
2592     }
2593     return 1;
2594 root 1.14
2595 root 1.24 case EXIT:
2596     if (op->type != PLAYER)
2597     return 0;
2598     if (!EXIT_PATH (tmp) || !is_legal_2ways_exit (op, tmp))
2599     {
2600     new_draw_info_format (NDI_UNIQUE, 0, op, "The %s is closed.", query_name (tmp));
2601     }
2602     else
2603     {
2604     /* Don't display messages for random maps. */
2605     if (tmp->msg && strncmp (EXIT_PATH (tmp), "/!", 2) && strncmp (EXIT_PATH (tmp), "/random/", 8))
2606     new_draw_info (NDI_NAVY, 0, op, tmp->msg);
2607     enter_exit (op, tmp);
2608     }
2609     return 1;
2610 root 1.14
2611 root 1.24 case SIGN:
2612     apply_sign (op, tmp, 0);
2613     return 1;
2614 root 1.14
2615 root 1.24 case BOOK:
2616     if (op->type == PLAYER)
2617     {
2618     apply_book (op, tmp);
2619     return 1;
2620     }
2621     else
2622     {
2623     return 0;
2624     }
2625 root 1.14
2626 root 1.24 case SKILLSCROLL:
2627     if (op->type == PLAYER)
2628     {
2629     apply_skillscroll (op, tmp);
2630     return 1;
2631     }
2632     return 0;
2633 root 1.14
2634 root 1.24 case SPELLBOOK:
2635     if (op->type == PLAYER)
2636     {
2637     apply_spellbook (op, tmp);
2638     return 1;
2639     }
2640     return 0;
2641 root 1.14
2642 root 1.24 case SCROLL:
2643     apply_scroll (op, tmp, 0);
2644     return 1;
2645 root 1.14
2646 root 1.24 case POTION:
2647     (void) apply_potion (op, tmp);
2648     return 1;
2649 root 1.14
2650 root 1.24 /* Eneq(@csd.uu.se): Handle apply on containers. */
2651     case CLOSE_CON:
2652     if (op->type == PLAYER)
2653     (void) esrv_apply_container (op, tmp->env);
2654     else
2655     (void) apply_container (op, tmp->env);
2656     return 1;
2657 root 1.14
2658 root 1.24 case CONTAINER:
2659     if (op->type == PLAYER)
2660     (void) esrv_apply_container (op, tmp);
2661     else
2662     (void) apply_container (op, tmp);
2663     return 1;
2664 root 1.14
2665 root 1.24 case TREASURE:
2666     if (op->type == PLAYER)
2667     {
2668     apply_treasure (op, tmp);
2669     return 1;
2670     }
2671     else
2672     {
2673     return 0;
2674     }
2675 root 1.14
2676 root 1.24 case WEAPON:
2677     case ARMOUR:
2678     case BOOTS:
2679     case GLOVES:
2680     case AMULET:
2681     case GIRDLE:
2682     case BRACERS:
2683     case SHIELD:
2684     case HELMET:
2685     case RING:
2686     case CLOAK:
2687     case WAND:
2688     case ROD:
2689     case HORN:
2690     case SKILL:
2691     case BOW:
2692     case LAMP:
2693     case BUILDER:
2694     case SKILL_TOOL:
2695     if (tmp->env != op)
2696     return 2; /* not in inventory */
2697     (void) apply_special (op, tmp, aflag);
2698     return 1;
2699 root 1.14
2700 root 1.24 case DRINK:
2701     case FOOD:
2702     case FLESH:
2703     apply_food (op, tmp);
2704     return 1;
2705 root 1.14
2706 root 1.24 case POISON:
2707     apply_poison (op, tmp);
2708     return 1;
2709 root 1.14
2710 root 1.24 case SAVEBED:
2711     if (op->type == PLAYER)
2712     {
2713     apply_savebed (op);
2714     return 1;
2715     }
2716     else
2717     {
2718     return 0;
2719     }
2720 root 1.14
2721 root 1.24 case ARMOUR_IMPROVER:
2722     if (op->type == PLAYER)
2723     {
2724     apply_armour_improver (op, tmp);
2725     return 1;
2726     }
2727     else
2728     {
2729     return 0;
2730     }
2731 root 1.14
2732 root 1.24 case WEAPON_IMPROVER:
2733     (void) check_improve_weapon (op, tmp);
2734     return 1;
2735 root 1.14
2736 root 1.24 case CLOCK:
2737     if (op->type == PLAYER)
2738     {
2739     char buf[MAX_BUF];
2740     timeofday_t tod;
2741 root 1.22
2742 root 1.24 get_tod (&tod);
2743     sprintf (buf, "It is %d minute%s past %d o'clock %s",
2744     tod.minute + 1, ((tod.minute + 1 < 2) ? "" : "s"),
2745     ((tod.hour % 14 == 0) ? 14 : ((tod.hour) % 14)), ((tod.hour >= 14) ? "pm" : "am"));
2746     play_sound_player_only (op->contr, SOUND_CLOCK, 0, 0);
2747     new_draw_info (NDI_UNIQUE, 0, op, buf);
2748     return 1;
2749     }
2750     else
2751     {
2752     return 0;
2753     }
2754 root 1.14
2755 root 1.24 case MENU:
2756     if (op->type == PLAYER)
2757     {
2758     shop_listing (op);
2759     return 1;
2760     }
2761     else
2762     {
2763     return 0;
2764     }
2765 elmex 1.1
2766 root 1.24 case POWER_CRYSTAL:
2767     apply_power_crystal (op, tmp); /* see egoitem.c */
2768     return 1;
2769 root 1.14
2770 root 1.24 case LIGHTER: /* for lighting torches/lanterns/etc */
2771     if (op->type == PLAYER)
2772     {
2773     apply_lighter (op, tmp);
2774     return 1;
2775     }
2776     else
2777     {
2778     return 0;
2779     }
2780 root 1.14
2781 root 1.24 case ITEM_TRANSFORMER:
2782     apply_item_transformer (op, tmp);
2783     return 1;
2784 root 1.14
2785 root 1.24 default:
2786     return 0;
2787 elmex 1.1 }
2788     }
2789    
2790    
2791     /* quiet suppresses the "don't know how to apply" and "you must get it first"
2792     * messages as needed by player_apply_below(). But there can still be
2793     * "but you are floating high above the ground" messages.
2794     *
2795     * Same return value as apply() function.
2796     */
2797 root 1.22 int
2798     player_apply (object *pl, object *op, int aflag, int quiet)
2799 elmex 1.1 {
2800 root 1.22 int tmp;
2801 elmex 1.1
2802 root 1.22 if (op->env == NULL && (pl->move_type & MOVE_FLYING))
2803     {
2804     /* player is flying and applying object not in inventory */
2805     if (!QUERY_FLAG (pl, FLAG_WIZ) && !(op->move_type & MOVE_FLYING))
2806     {
2807     new_draw_info (NDI_UNIQUE, 0, pl, "But you are floating high " "above the ground!");
2808     return 0;
2809 root 1.14 }
2810 elmex 1.1 }
2811    
2812 root 1.22 /* Check for PLAYER to avoid a DM to disappear in a puff of smoke if
2813     * applied.
2814     */
2815     if (op->type != PLAYER && QUERY_FLAG (op, FLAG_WAS_WIZ) && !QUERY_FLAG (pl, FLAG_WAS_WIZ))
2816     {
2817     play_sound_map (pl->map, pl->x, pl->y, SOUND_OB_EVAPORATE);
2818     new_draw_info (NDI_UNIQUE, 0, pl, "The object disappears in a puff " "of smoke!");
2819     new_draw_info (NDI_UNIQUE, 0, pl, "It must have been an illusion.");
2820     remove_ob (op);
2821     free_object (op);
2822     return 1;
2823 elmex 1.1 }
2824    
2825 root 1.22 pl->contr->last_used = op;
2826     pl->contr->last_used_id = op->count;
2827 elmex 1.1
2828 root 1.22 tmp = manual_apply (pl, op, aflag);
2829     if (!quiet)
2830     {
2831     if (tmp == 0)
2832     new_draw_info_format (NDI_UNIQUE, 0, pl, "I don't know how to apply the %s.", query_name (op));
2833     else if (tmp == 2)
2834     new_draw_info_format (NDI_UNIQUE, 0, pl, "You must get it first!\n");
2835 elmex 1.1 }
2836 root 1.22 return tmp;
2837 elmex 1.1 }
2838    
2839     /**
2840     * player_apply_below attempts to apply the object 'below' the player.
2841     * If the player has an open container, we use that for below, otherwise
2842     * we use the ground.
2843     */
2844    
2845 root 1.22 void
2846     player_apply_below (object *pl)
2847 elmex 1.1 {
2848 root 1.22 object *tmp, *next;
2849     int floors;
2850    
2851     /* If using a container, set the starting item to be the top
2852     * item in the container. Otherwise, use the map.
2853     */
2854     tmp = (pl->container != NULL) ? pl->container->inv : pl->below;
2855 elmex 1.1
2856 root 1.22 /* This is perhaps more complicated. However, I want to make sure that
2857     * we don't use a corrupt pointer for the next object, so we get the
2858     * next object in the stack before applying. This is can only be a
2859     * problem if player_apply() has a bug in that it uses the object but does
2860     * not return a proper value.
2861     */
2862     for (floors = 0; tmp != NULL; tmp = next)
2863     {
2864     next = tmp->below;
2865     if (QUERY_FLAG (tmp, FLAG_IS_FLOOR))
2866     floors++;
2867     else if (floors > 0)
2868     return; /* process only floor objects after first floor object */
2869    
2870     /* If it is visible, player can apply it. If it is applied by
2871     * person moving on it, also activate. Added code to make it
2872     * so that at least one of players movement types be that which
2873     * the item needs.
2874     */
2875     if (!tmp->invisible || (tmp->move_on & pl->move_type))
2876     {
2877     if (player_apply (pl, tmp, 0, 1) == 1)
2878     return;
2879 elmex 1.1 }
2880 root 1.22 if (floors >= 2)
2881     return; /* process at most two floor objects */
2882 elmex 1.1 }
2883     }
2884    
2885     /**
2886     * Unapplies specified item.
2887     * No check done on cursed/damned.
2888     * Break this out of apply_special - this is just done
2889     * to keep the size of apply_special to a more managable size.
2890     */
2891 root 1.22 static int
2892     unapply_special (object *who, object *op, int aflags)
2893 elmex 1.1 {
2894 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)))
2895     return RESULT_INT (0);
2896 root 1.12
2897 root 1.22 object *tmp2;
2898 elmex 1.1
2899 root 1.22 CLEAR_FLAG (op, FLAG_APPLIED);
2900     switch (op->type)
2901     {
2902 root 1.24 case WEAPON:
2903     new_draw_info_format (NDI_UNIQUE, 0, who, "You unwield %s.", query_name (op));
2904 elmex 1.1
2905 root 1.24 (void) change_abil (who, op);
2906     if (QUERY_FLAG (who, FLAG_READY_WEAPON))
2907     CLEAR_FLAG (who, FLAG_READY_WEAPON);
2908     clear_skill (who);
2909     break;
2910 root 1.14
2911 root 1.24 case SKILL: /* allows objects to impart skills */
2912     case SKILL_TOOL:
2913     if (op != who->chosen_skill)
2914     {
2915     LOG (llevError, "BUG: apply_special(): applied skill is not a chosen skill\n");
2916     }
2917     if (who->type == PLAYER)
2918     {
2919     if (who->contr->shoottype == range_skill)
2920     who->contr->shoottype = range_none;
2921     if (!op->invisible)
2922     {
2923     new_draw_info_format (NDI_UNIQUE, 0, who, "You stop using the %s.", query_name (op));
2924     }
2925     else
2926     {
2927     new_draw_info_format (NDI_UNIQUE, 0, who, "You can no longer use the skill: %s.", &op->skill);
2928     }
2929     }
2930     (void) change_abil (who, op);
2931     who->chosen_skill = NULL;
2932     CLEAR_FLAG (who, FLAG_READY_SKILL);
2933     break;
2934 root 1.14
2935 root 1.24 case ARMOUR:
2936     case HELMET:
2937     case SHIELD:
2938     case RING:
2939     case BOOTS:
2940     case GLOVES:
2941     case AMULET:
2942     case GIRDLE:
2943     case BRACERS:
2944     case CLOAK:
2945     new_draw_info_format (NDI_UNIQUE, 0, who, "You unwear %s.", query_name (op));
2946     (void) change_abil (who, op);
2947     break;
2948     case LAMP:
2949     new_draw_info_format (NDI_UNIQUE, 0, who, "You turn off your %s.", &op->name);
2950     tmp2 = arch_to_object (op->other_arch);
2951     tmp2->x = op->x;
2952     tmp2->y = op->y;
2953     tmp2->map = op->map;
2954     tmp2->below = op->below;
2955     tmp2->above = op->above;
2956     tmp2->stats.food = op->stats.food;
2957     CLEAR_FLAG (tmp2, FLAG_APPLIED);
2958     if (QUERY_FLAG (op, FLAG_INV_LOCKED))
2959     SET_FLAG (tmp2, FLAG_INV_LOCKED);
2960     if (who->type == PLAYER)
2961     esrv_del_item (who->contr, (tag_t) op->count);
2962     remove_ob (op);
2963     free_object (op);
2964     insert_ob_in_ob (tmp2, who);
2965     fix_player (who);
2966     if (QUERY_FLAG (op, FLAG_CURSED) || QUERY_FLAG (op, FLAG_DAMNED))
2967     {
2968     if (who->type == PLAYER)
2969     {
2970     new_draw_info (NDI_UNIQUE, 0, who, "Oops, it feels deadly cold!");
2971     SET_FLAG (tmp2, FLAG_KNOWN_CURSED);
2972     }
2973     }
2974     if (who->type == PLAYER)
2975     esrv_send_item (who, tmp2);
2976     return 1; /* otherwise, an attempt to drop causes problems */
2977     break;
2978     case BOW:
2979     case WAND:
2980     case ROD:
2981     case HORN:
2982     clear_skill (who);
2983     new_draw_info_format (NDI_UNIQUE, 0, who, "You unready %s.", query_name (op));
2984     if (who->type == PLAYER)
2985     {
2986     who->contr->shoottype = range_none;
2987     }
2988     else
2989     {
2990     if (op->type == BOW)
2991     CLEAR_FLAG (who, FLAG_READY_BOW);
2992     else
2993     CLEAR_FLAG (who, FLAG_READY_RANGE);
2994     }
2995     break;
2996 elmex 1.1
2997 root 1.24 case BUILDER:
2998     new_draw_info_format (NDI_UNIQUE, 0, who, "You unready %s.", query_name (op));
2999     who->contr->shoottype = range_none;
3000     who->contr->ranges[range_builder] = NULL;
3001     break;
3002 elmex 1.1
3003 root 1.24 default:
3004     new_draw_info_format (NDI_UNIQUE, 0, who, "You unapply %s.", query_name (op));
3005     break;
3006 elmex 1.1 }
3007    
3008 root 1.22 fix_player (who);
3009 elmex 1.1
3010 root 1.22 if (!(aflags & AP_NO_MERGE))
3011     {
3012     object *tmp;
3013    
3014     tag_t del_tag = op->count;
3015 elmex 1.1
3016 root 1.22 tmp = merge_ob (op, NULL);
3017     if (who->type == PLAYER)
3018     {
3019     if (tmp)
3020     { /* it was merged */
3021     esrv_del_item (who->contr, del_tag);
3022     op = tmp;
3023 elmex 1.1 }
3024 root 1.22 esrv_send_item (who, op);
3025 root 1.14 }
3026 elmex 1.1 }
3027 root 1.22 return 0;
3028 elmex 1.1 }
3029    
3030     /**
3031     * Returns the object that is using location 'loc'.
3032     * Note that 'start' is the first object to start examing - we
3033     * then go through the below of this. In this way, you can do
3034     * something like:
3035     * tmp = get_item_from_body_location(who->inv, 1);
3036     * if (tmp) tmp1 = get_item_from_body_location(tmp->below, 1);
3037     * to find the second object that may use this location, etc.
3038     * Returns NULL if no match is found.
3039     * loc is the index into the array we are looking for a match.
3040     * don't return invisible objects unless they are skill objects
3041     * invisible other objects that use
3042     * up body locations can be used as restrictions.
3043     */
3044 root 1.22 object *
3045     get_item_from_body_location (object *start, int loc)
3046 elmex 1.1 {
3047 root 1.22 object *tmp;
3048 elmex 1.1
3049 root 1.22 if (!start)
3050     return NULL;
3051 elmex 1.1
3052 root 1.22 for (tmp = start; tmp; tmp = tmp->below)
3053     if (QUERY_FLAG (tmp, FLAG_APPLIED) && tmp->body_info[loc] && (!tmp->invisible || tmp->type == SKILL))
3054     return tmp;
3055 elmex 1.1
3056 root 1.22 return NULL;
3057 elmex 1.1 }
3058    
3059    
3060    
3061     /**
3062     * 'op' wants to apply an object, but can't because of other equipment.
3063     * This should only be called when it is known
3064     * that there are objects to unapply. This makes pretty heavy
3065     * use of get_item_from_body_location. It makes no intelligent choice
3066     * on objects - rather, the first that is matched is used.
3067     * Returns 0 on success, returns 1 if there is some problem.
3068     * if aflags is AP_PRINT, we instead print out waht to unapply
3069     * instead of doing it. This is a lot less code than having
3070     * another function that does just that.
3071     */
3072 root 1.22 int
3073     unapply_for_ob (object *who, object *op, int aflags)
3074 elmex 1.1 {
3075 root 1.22 int i;
3076     object *tmp = NULL, *last;
3077 elmex 1.1
3078 root 1.22 /* If we are applying a shield or weapon, unapply any equipped shield
3079     * or weapons first - only allowed to use one weapon/shield at a time.
3080     */
3081     if (op->type == WEAPON || op->type == SHIELD)
3082     {
3083     for (tmp = who->inv; tmp; tmp = tmp->below)
3084     {
3085     if (QUERY_FLAG (tmp, FLAG_APPLIED) && tmp->type == op->type)
3086     {
3087     if ((aflags & AP_IGNORE_CURSE) || (aflags & AP_PRINT) || (!QUERY_FLAG (tmp, FLAG_CURSED) && !QUERY_FLAG (tmp, FLAG_DAMNED)))
3088     {
3089     if (aflags & AP_PRINT)
3090     new_draw_info (NDI_UNIQUE, 0, who, query_name (tmp));
3091     else
3092     unapply_special (who, tmp, aflags);
3093     }
3094     else
3095     {
3096     /* In this case, we want to try and remove a cursed item.
3097     * While we know it won't work, we want unapply_special to
3098     * at least generate the message.
3099     */
3100     new_draw_info_format (NDI_UNIQUE, 0, who, "No matter how hard you try, you just can't\nremove %s.", query_name (tmp));
3101     return 1;
3102 root 1.14 }
3103 elmex 1.1
3104 root 1.14 }
3105     }
3106 elmex 1.1 }
3107    
3108 root 1.22 for (i = 0; i < NUM_BODY_LOCATIONS; i++)
3109     {
3110     /* this used up a slot that we need to free */
3111     if (op->body_info[i])
3112     {
3113     last = who->inv;
3114 root 1.14
3115 root 1.22 /* We do a while loop - may need to remove several items in order
3116     * to free up enough slots.
3117     */
3118     while ((who->body_used[i] + op->body_info[i]) < 0)
3119     {
3120     tmp = get_item_from_body_location (last, i);
3121     if (!tmp)
3122     {
3123 elmex 1.1 #if 0
3124 root 1.22 /* Not a bug - we'll get this if the player has cursed items
3125     * equipped.
3126     */
3127     LOG (llevError, "Can't find object using location %d (%s) on %s\n", i, body_locations[i].save_name, who->name);
3128 elmex 1.1 #endif
3129 root 1.22 return 1;
3130     }
3131     /* If we are just printing, we don't care about cursed status */
3132     if ((aflags & AP_IGNORE_CURSE) || (aflags & AP_PRINT) || (!(QUERY_FLAG (tmp, FLAG_CURSED) || QUERY_FLAG (tmp, FLAG_DAMNED))))
3133     {
3134     if (aflags & AP_PRINT)
3135     new_draw_info (NDI_UNIQUE, 0, who, query_name (tmp));
3136     else
3137     unapply_special (who, tmp, aflags);
3138 root 1.14 }
3139 root 1.22 else
3140     {
3141     /* Cursed item that we can't unequip - tell the player.
3142     * Note this could be annoying if this is just one of a few,
3143     * so it may not be critical (eg, putting on a ring and you have
3144     * one cursed ring.)
3145     */
3146     new_draw_info_format (NDI_UNIQUE, 0, who, "The %s just won't come off", query_name (tmp));
3147 root 1.14 }
3148 root 1.22 last = tmp->below;
3149 root 1.14 }
3150 root 1.22 /* if we got here, this slot is freed up - otherwise, if it wasn't freed up, the
3151     * return in the !tmp would have kicked in.
3152     */
3153     } /* if op is using this body location */
3154     } /* for body lcoations */
3155     return 0;
3156 elmex 1.1 }
3157    
3158     /**
3159     * Checks to see if 'who' can apply object 'op'.
3160     * Returns 0 if apply can be done without anything special.
3161     * Otherwise returns a bitmask - potentially several of these may be
3162     * set, but largely depends on circumstance - in the future, processing
3163     * may be pruned once we know some status (eg, once CAN_APPLY_NEVER
3164     * is set, do we really are what the other flags may be?)
3165     *
3166     * See include/define.h for detailed description of the meaning of
3167     * these return values.
3168     */
3169 root 1.22 int
3170     can_apply_object (object *who, object *op)
3171 elmex 1.1 {
3172 root 1.22 if (INVOKE_OBJECT (CAN_BE_APPLIED, op, ARG_OBJECT (who)) || INVOKE_OBJECT (CAN_APPLY, who, ARG_OBJECT (op)))
3173     return RESULT_INT (0);
3174    
3175     int i, retval = 0;
3176     object *tmp = NULL, *ws = NULL;
3177    
3178     /* Players have 2 'arm's, so they could in theory equip 2 shields or
3179     * 2 weapons, but we don't want to let them do that. So if they are
3180     * trying to equip a weapon or shield, see if they already have one
3181     * in place and store that way.
3182     */
3183     if (op->type == WEAPON || op->type == SHIELD)
3184     {
3185     for (tmp = who->inv; tmp && !ws; tmp = tmp->below)
3186     {
3187     if (QUERY_FLAG (tmp, FLAG_APPLIED) && tmp->type == op->type)
3188     {
3189     retval = CAN_APPLY_UNAPPLY;
3190     ws = tmp;
3191 root 1.14 }
3192     }
3193 elmex 1.1 }
3194 root 1.14
3195    
3196 root 1.22 for (i = 0; i < NUM_BODY_LOCATIONS; i++)
3197     {
3198     if (op->body_info[i])
3199     {
3200     /* Item uses more slots than we have */
3201     if (FABS (op->body_info[i]) > who->body_info[i])
3202     {
3203     /* Could return now for efficiently - rest of info below isn'
3204     * really needed.
3205     */
3206     retval |= CAN_APPLY_NEVER;
3207     }
3208     else if ((who->body_used[i] + op->body_info[i]) < 0)
3209     {
3210     /* in this case, equipping this would use more free spots than
3211     * we have.
3212     */
3213     object *tmp1;
3214    
3215 elmex 1.1
3216 root 1.22 /* if we have an applied weapon/shield, and unapply it would free
3217     * enough slots to equip the new item, then just set this can
3218     * continue. We don't care about the logic below - if you have
3219     * shield equipped and try to equip another shield, there is only
3220     * one choice. However, the check for the number of body locations
3221     * does take into the account cases where what is being applied
3222     * may be two handed for example.
3223     */
3224     if (ws)
3225     {
3226     if ((who->body_used[i] - ws->body_info[i] + op->body_info[i]) >= 0)
3227     {
3228     retval |= CAN_APPLY_UNAPPLY;
3229     continue;
3230     }
3231     }
3232    
3233     tmp1 = get_item_from_body_location (who->inv, i);
3234     if (!tmp1)
3235     {
3236 elmex 1.1 #if 0
3237 root 1.22 /* This is sort of an error, but happens a lot when old players
3238     * join in with more stuff equipped than they are now allowed.
3239     */
3240     LOG (llevError, "Can't find object using location %d on %s\n", i, who->name);
3241 elmex 1.1 #endif
3242 root 1.22 retval |= CAN_APPLY_NEVER;
3243     }
3244     else
3245     {
3246     /* need to unapply something. However, if this something
3247     * is different than we had found before, it means they need
3248     * to apply multiple objects
3249     */
3250     retval |= CAN_APPLY_UNAPPLY;
3251     if (!tmp)
3252     tmp = tmp1;
3253     else if (tmp != tmp1)
3254     {
3255     retval |= CAN_APPLY_UNAPPLY_MULT;
3256 root 1.14 }
3257 root 1.22 /* This object isn't using up all the slots, so there must
3258     * be another. If so, and it the new item doesn't need all
3259     * the slots, the player then has a choice.
3260     */
3261     if (((who->body_used[i] - tmp1->body_info[i]) != who->body_info[i]) && (FABS (op->body_info[i]) < who->body_info[i]))
3262     retval |= CAN_APPLY_UNAPPLY_CHOICE;
3263    
3264     /* Does unequippint 'tmp1' free up enough slots for this to be
3265     * equipped? If not, there must be something else to unapply.
3266     */
3267     if ((who->body_used[i] + op->body_info[i] - tmp1->body_info[i]) < 0)
3268     retval |= CAN_APPLY_UNAPPLY_MULT;
3269    
3270     }
3271     } /* if not enough free slots */
3272     } /* if this object uses location i */
3273     } /* for i -> num_body_locations loop */
3274    
3275     /* Note that we don't check for FLAG_USE_ARMOUR - that should
3276     * really be controlled by use of body locations. We do have
3277     * the weapon/shield checks, and the range checks for monsters,
3278     * because you can't control those just by body location - bows, shields,
3279     * and weapons all use the same slot. Similar for horn/rod/wand - they
3280     * all use the same location.
3281     */
3282     if (op->type == WEAPON && !QUERY_FLAG (who, FLAG_USE_WEAPON))
3283     retval |= CAN_APPLY_RESTRICTION;
3284     if (op->type == SHIELD && !QUERY_FLAG (who, FLAG_USE_SHIELD))
3285     retval |= CAN_APPLY_RESTRICTION;
3286    
3287    
3288     if (who->type != PLAYER)
3289     {
3290     if ((op->type == WAND || op->type == HORN || op->type == ROD) && !QUERY_FLAG (who, FLAG_USE_RANGE))
3291 root 1.14 retval |= CAN_APPLY_RESTRICTION;
3292 root 1.22 if (op->type == BOW && !QUERY_FLAG (who, FLAG_USE_BOW))
3293     retval |= CAN_APPLY_RESTRICTION;
3294     if (op->type == RING && !QUERY_FLAG (who, FLAG_USE_RING))
3295     retval |= CAN_APPLY_RESTRICTION;
3296     if (op->type == BOW && !QUERY_FLAG (who, FLAG_USE_BOW))
3297 root 1.14 retval |= CAN_APPLY_RESTRICTION;
3298 elmex 1.1 }
3299 root 1.22 return retval;
3300 elmex 1.1 }
3301    
3302 root 1.22
3303 elmex 1.1
3304     /**
3305     * who is the object using the object. It can be a monster.
3306     * op is the object they are using. op is an equipment type item,
3307     * eg, one which you put on and keep on for a while, and not something
3308     * like a potion or scroll.
3309     *
3310     * function returns 1 if the action could not be completed, 0 on
3311     * success. However, success is a matter of meaning - if the
3312     * user passes the 'apply' flag to an object already applied,
3313     * nothing is done, and 0 is returned.
3314     *
3315     * aflags is special flags (0 - normal/toggle, AP_APPLY=always apply,
3316     * AP_UNAPPLY=always unapply).
3317     *
3318     * Optional flags:
3319     * AP_NO_MERGE: don't merge an unapplied object with other objects
3320     * AP_IGNORE_CURSE: unapply cursed items
3321     *
3322     * Usage example: apply_special (who, op, AP_UNAPPLY | AP_IGNORE_CURSE)
3323     *
3324     * apply_special() doesn't check for unpaid items.
3325     */
3326 root 1.22 int
3327     apply_special (object *who, object *op, int aflags)
3328 elmex 1.1 {
3329 root 1.22 int basic_flag = aflags & AP_BASIC_FLAGS;
3330     object *tmp, *tmp2, *skop = NULL;
3331     int i;
3332 elmex 1.1
3333 root 1.22 if (who == NULL)
3334     {
3335     LOG (llevError, "apply_special() from object without environment.\n");
3336     return 1;
3337 elmex 1.1 }
3338    
3339 root 1.22 if (op->env != who)
3340     return 1; /* op is not in inventory */
3341 elmex 1.1
3342 root 1.22 /* trying to unequip op */
3343     if (QUERY_FLAG (op, FLAG_APPLIED))
3344     {
3345     /* always apply, so no reason to unapply */
3346     if (basic_flag == AP_APPLY)
3347     return 0;
3348    
3349     if (!(aflags & AP_IGNORE_CURSE) && (QUERY_FLAG (op, FLAG_CURSED) || QUERY_FLAG (op, FLAG_DAMNED)))
3350     {
3351     new_draw_info_format (NDI_UNIQUE, 0, who, "No matter how hard you try, you just can't\nremove %s.", query_name (op));
3352     return 1;
3353 root 1.14 }
3354 root 1.22 return unapply_special (who, op, aflags);
3355 elmex 1.1 }
3356    
3357 root 1.22 if (basic_flag == AP_UNAPPLY)
3358     return 0;
3359 elmex 1.1
3360 root 1.22 i = can_apply_object (who, op);
3361 elmex 1.1
3362 root 1.22 /* Can't just apply this object. Lets see what not and what to do */
3363     if (i)
3364     {
3365     if (i & CAN_APPLY_NEVER)
3366     {
3367     new_draw_info_format (NDI_UNIQUE, 0, who, "You don't have the body to use a %s\n", query_name (op));
3368     return 1;
3369     }
3370     else if (i & CAN_APPLY_RESTRICTION)
3371     {
3372     new_draw_info_format (NDI_UNIQUE, 0, who, "You have a prohibition against using a %s\n", query_name (op));
3373     return 1;
3374     }
3375     if (who->type != PLAYER)
3376     {
3377     /* Some error, so don't try to equip something more */
3378     if (unapply_for_ob (who, op, aflags))
3379 root 1.14 return 1;
3380     }
3381 root 1.22 else
3382     {
3383     if (who->contr->unapply == unapply_never || (i & CAN_APPLY_UNAPPLY_CHOICE && who->contr->unapply == unapply_nochoice))
3384     {
3385     new_draw_info (NDI_UNIQUE, 0, who, "You need to unapply some item(s):");
3386     unapply_for_ob (who, op, AP_PRINT);
3387     return 1;
3388     }
3389     else if (who->contr->unapply == unapply_always || !(i & CAN_APPLY_UNAPPLY_CHOICE))
3390     {
3391     i = unapply_for_ob (who, op, aflags);
3392     if (i)
3393 root 1.14 return 1;
3394     }
3395     }
3396 elmex 1.1 }
3397 root 1.22 if (op->skill && op->type != SKILL && op->type != SKILL_TOOL)
3398     {
3399     skop = find_skill_by_name (who, op->skill);
3400     if (!skop)
3401     {
3402     new_draw_info_format (NDI_UNIQUE, 0, who, "You need the %s skill to use this item!", &op->skill);
3403     return 1;
3404     }
3405     else
3406     {
3407     /* While experience will be credited properly, we want to change the
3408     * skill so that the dam and wc get updated
3409     */
3410     change_skill (who, skop, 0);
3411 root 1.14 }
3412 elmex 1.1 }
3413 root 1.22
3414     if (who->type == PLAYER && op->item_power && (op->item_power + who->contr->item_power) > (settings.item_power_factor * who->level))
3415     {
3416     new_draw_info (NDI_UNIQUE, 0, who, "Equipping that combined with other items would consume your soul!");
3417     return 1;
3418 elmex 1.1 }
3419    
3420 root 1.12
3421 root 1.22 /* Ok. We are now at the state where we can apply the new object.
3422     * Note that we don't have the checks for can_use_...
3423     * below - that is already taken care of by can_apply_object.
3424     */
3425    
3426    
3427     if (op->nrof > 1)
3428     tmp = get_split_ob (op, op->nrof - 1);
3429     else
3430     tmp = NULL;
3431    
3432     if (INVOKE_OBJECT (BE_READY, op, ARG_OBJECT (who)) || INVOKE_OBJECT (READY, who, ARG_OBJECT (op)))
3433     return RESULT_INT (0);
3434    
3435     switch (op->type)
3436     {
3437 root 1.24 case WEAPON:
3438     if (!check_weapon_power (who, op->last_eat))
3439     {
3440     new_draw_info (NDI_UNIQUE, 0, who, "That weapon is too powerful for you to use.");
3441     new_draw_info (NDI_UNIQUE, 0, who, "It would consume your soul!.");
3442     if (tmp != NULL)
3443     (void) insert_ob_in_ob (tmp, who);
3444     return 1;
3445     }
3446     if (op->level && (strncmp (op->name, who->name, strlen (who->name))))
3447     {
3448     /* if the weapon does not have the name as the character, can't use it. */
3449     /* (Ragnarok's sword attempted to be used by Foo: won't work) */
3450     new_draw_info (NDI_UNIQUE, 0, who, "The weapon does not recognize you as its owner.");
3451     if (tmp != NULL)
3452     (void) insert_ob_in_ob (tmp, who);
3453     return 1;
3454     }
3455     SET_FLAG (op, FLAG_APPLIED);
3456 root 1.14
3457 root 1.24 if (skop)
3458     change_skill (who, skop, 1);
3459     if (!QUERY_FLAG (who, FLAG_READY_WEAPON))
3460     SET_FLAG (who, FLAG_READY_WEAPON);
3461 root 1.14
3462 root 1.24 new_draw_info_format (NDI_UNIQUE, 0, who, "You wield %s.", query_name (op));
3463 root 1.14
3464 root 1.24 (void) change_abil (who, op);
3465     break;
3466 root 1.14
3467 root 1.24 case ARMOUR:
3468     case HELMET:
3469     case SHIELD:
3470     case BOOTS:
3471     case GLOVES:
3472     case GIRDLE:
3473     case BRACERS:
3474     case CLOAK:
3475     case RING:
3476     case AMULET:
3477     SET_FLAG (op, FLAG_APPLIED);
3478     new_draw_info_format (NDI_UNIQUE, 0, who, "You wear %s.", query_name (op));
3479     (void) change_abil (who, op);
3480     break;
3481     case LAMP:
3482     if (op->stats.food < 1)
3483     {
3484     new_draw_info_format (NDI_UNIQUE, 0, who, "Your %s is out of" " fuel!", &op->name);
3485     return 1;
3486     }
3487     new_draw_info_format (NDI_UNIQUE, 0, who, "You turn on your %s.", &op->name);
3488     tmp2 = arch_to_object (op->other_arch);
3489     tmp2->stats.food = op->stats.food;
3490     SET_FLAG (tmp2, FLAG_APPLIED);
3491     if (QUERY_FLAG (op, FLAG_INV_LOCKED))
3492     SET_FLAG (tmp2, FLAG_INV_LOCKED);
3493     insert_ob_in_ob (tmp2, who);
3494    
3495     /* Remove the old lantern */
3496     if (who->type == PLAYER)
3497     esrv_del_item (who->contr, (tag_t) op->count);
3498     remove_ob (op);
3499     free_object (op);
3500 root 1.22
3501 root 1.24 /* insert the portion that was split off */
3502     if (tmp != NULL)
3503     {
3504     (void) insert_ob_in_ob (tmp, who);
3505     if (who->type == PLAYER)
3506     esrv_send_item (who, tmp);
3507     }
3508     fix_player (who);
3509     if (QUERY_FLAG (op, FLAG_CURSED) || QUERY_FLAG (op, FLAG_DAMNED))
3510     {
3511     if (who->type == PLAYER)
3512     {
3513     new_draw_info (NDI_UNIQUE, 0, who, "Oops, it feels deadly cold!");
3514     SET_FLAG (tmp2, FLAG_KNOWN_CURSED);
3515     }
3516     }
3517     if (who->type == PLAYER)
3518     esrv_send_item (who, tmp2);
3519     return 0;
3520     break;
3521 root 1.14
3522 root 1.24 /* this part is needed for skill-tools */
3523     case SKILL:
3524     case SKILL_TOOL:
3525     if (who->chosen_skill)
3526     {
3527     LOG (llevError, "BUG: apply_special(): can't apply two skills\n");
3528     return 1;
3529     }
3530     if (who->type == PLAYER)
3531     {
3532     who->contr->shoottype = range_skill;
3533     who->contr->ranges[range_skill] = op;
3534     if (!op->invisible)
3535     {
3536     new_draw_info_format (NDI_UNIQUE, 0, who, "You ready %s.", query_name (op));
3537     new_draw_info_format (NDI_UNIQUE, 0, who, "You can now use the skill: %s.", &op->skill);
3538     }
3539     else
3540     {
3541     new_draw_info_format (NDI_UNIQUE, 0, who, "Readied skill: %s.", op->skill ? &op->skill : &op->name);
3542     }
3543     }
3544     SET_FLAG (op, FLAG_APPLIED);
3545     (void) change_abil (who, op);
3546     who->chosen_skill = op;
3547     SET_FLAG (who, FLAG_READY_SKILL);
3548     break;
3549 root 1.22
3550 root 1.24 case BOW:
3551     if (!check_weapon_power (who, op->last_eat))
3552     {
3553     new_draw_info (NDI_UNIQUE, 0, who, "That item is too powerful for you to use.");
3554     new_draw_info (NDI_UNIQUE, 0, who, "It would consume your soul!.");
3555     if (tmp != NULL)
3556     (void) insert_ob_in_ob (tmp, who);
3557     return 1;
3558     }
3559     if (op->level && (strncmp (op->name, who->name, strlen (who->name))))
3560     {
3561     new_draw_info (NDI_UNIQUE, 0, who, "The weapon does not recognize you as its owner.");
3562     if (tmp != NULL)
3563     (void) insert_ob_in_ob (tmp, who);
3564     return 1;
3565     }
3566     /*FALLTHROUGH*/ case WAND:
3567     case ROD:
3568     case HORN:
3569     /* check for skill, alter player status */
3570     SET_FLAG (op, FLAG_APPLIED);
3571     if (skop)
3572     change_skill (who, skop, 0);
3573     new_draw_info_format (NDI_UNIQUE, 0, who, "You ready %s.", query_name (op));
3574 root 1.22
3575 root 1.24 if (who->type == PLAYER)
3576     {
3577     if (op->type == BOW)
3578     {
3579     (void) change_abil (who, op);
3580     new_draw_info_format (NDI_UNIQUE, 0, who,
3581     "You will now fire %s with %s.", op->race ? &op->race : "nothing", query_name (op));
3582     who->contr->shoottype = range_bow;
3583     }
3584     else
3585     {
3586     who->contr->shoottype = range_misc;
3587     }
3588     }
3589     else
3590     {
3591     if (op->type == BOW)
3592     SET_FLAG (who, FLAG_READY_BOW);
3593     else
3594     SET_FLAG (who, FLAG_READY_RANGE);
3595     }
3596     break;
3597 elmex 1.1
3598 root 1.24 case BUILDER:
3599     if (who->contr->ranges[range_builder])
3600     unapply_special (who, who->contr->ranges[range_builder], 0);
3601     who->contr->shoottype = range_builder;
3602     who->contr->ranges[range_builder] = op;
3603     new_draw_info_format (NDI_UNIQUE, 0, who, "You ready your %s.", query_name (op));
3604     break;
3605 elmex 1.1
3606 root 1.24 default:
3607     new_draw_info_format (NDI_UNIQUE, 0, who, "You apply %s.", query_name (op));
3608 root 1.22 } /* end of switch op->type */
3609    
3610     SET_FLAG (op, FLAG_APPLIED);
3611 elmex 1.1
3612 root 1.22 if (tmp != NULL)
3613     tmp = insert_ob_in_ob (tmp, who);
3614 elmex 1.1
3615 root 1.22 fix_player (who);
3616 elmex 1.1
3617 root 1.22 /* We exclude spell casting objects. The fire code will set the
3618     * been applied flag when they are used - until that point,
3619     * you don't know anything about them.
3620     */
3621     if (who->type == PLAYER && op->type != WAND && op->type != HORN && op->type != ROD)
3622     SET_FLAG (op, FLAG_BEEN_APPLIED);
3623    
3624     if (QUERY_FLAG (op, FLAG_CURSED) || QUERY_FLAG (op, FLAG_DAMNED))
3625     {
3626     if (who->type == PLAYER)
3627     {
3628     new_draw_info (NDI_UNIQUE, 0, who, "Oops, it feels deadly cold!");
3629     SET_FLAG (op, FLAG_KNOWN_CURSED);
3630     }
3631     }
3632     if (who->type == PLAYER)
3633     {
3634     /* if multiple objects were applied, update both slots */
3635     if (tmp)
3636     esrv_send_item (who, tmp);
3637     esrv_send_item (who, op);
3638 elmex 1.1 }
3639 root 1.22 return 0;
3640 elmex 1.1 }
3641    
3642    
3643 root 1.22 int
3644     monster_apply_special (object *who, object *op, int aflags)
3645 elmex 1.1 {
3646 root 1.22 if (QUERY_FLAG (op, FLAG_UNPAID) && !QUERY_FLAG (op, FLAG_APPLIED))
3647 elmex 1.1 return 1;
3648     return apply_special (who, op, aflags);
3649     }
3650    
3651     /**
3652     * Map was just loaded, handle op's initialisation.
3653     *
3654     * Generates shop floor's item, and treasures.
3655     */
3656 root 1.22 int
3657     auto_apply (object *op)
3658     {
3659     object *tmp = NULL, *tmp2;
3660     int i;
3661 elmex 1.1
3662 root 1.22 switch (op->type)
3663     {
3664 root 1.24 case SHOP_FLOOR:
3665     if (!HAS_RANDOM_ITEMS (op))
3666     return 0;
3667     do
3668     {
3669     i = 10; /* let's give it 10 tries */
3670     while ((tmp = generate_treasure (op->randomitems,
3671     op->stats.exp ? (int) op->stats.exp : MAX (op->map->difficulty, 5))) == NULL && --i);
3672     if (tmp == NULL)
3673     return 0;
3674     if (QUERY_FLAG (tmp, FLAG_CURSED) || QUERY_FLAG (tmp, FLAG_DAMNED))
3675     {
3676     free_object (tmp);
3677     tmp = NULL;
3678     }
3679     }
3680     while (!tmp);
3681     tmp->x = op->x;
3682     tmp->y = op->y;
3683     SET_FLAG (tmp, FLAG_UNPAID);
3684     insert_ob_in_map (tmp, op->map, NULL, 0);
3685     CLEAR_FLAG (op, FLAG_AUTO_APPLY);
3686     identify (tmp);
3687     break;
3688 root 1.14
3689 root 1.24 case TREASURE:
3690     if (QUERY_FLAG (op, FLAG_IS_A_TEMPLATE))
3691     return 0;
3692     while ((op->stats.hp--) > 0)
3693     create_treasure (op->randomitems, op, op->map ? GT_ENVIRONMENT : 0,
3694     op->stats.exp ? (int) op->stats.exp : op->map == NULL ? 14 : op->map->difficulty, 0);
3695    
3696     /* If we generated an object and put it in this object inventory,
3697     * move it to the parent object as the current object is about
3698     * to disappear. An example of this item is the random_* stuff
3699     * that is put inside other objects.
3700     */
3701     for (tmp = op->inv; tmp; tmp = tmp2)
3702     {
3703     tmp2 = tmp->below;
3704     remove_ob (tmp);
3705     if (op->env)
3706     insert_ob_in_ob (tmp, op->env);
3707     else
3708     free_object (tmp);
3709     }
3710     remove_ob (op);
3711     free_object (op);
3712     break;
3713 elmex 1.1 }
3714 root 1.22 return tmp ? 1 : 0;
3715 elmex 1.1 }
3716    
3717     /**
3718     * fix_auto_apply goes through the entire map (only the first time
3719     * when an original map is loaded) and performs special actions for
3720     * certain objects (most initialization of chests and creation of
3721     * treasures and stuff). Calls auto_apply if appropriate.
3722     */
3723 root 1.20 void
3724 root 1.22 fix_auto_apply (mapstruct *m)
3725 root 1.20 {
3726     object *tmp, *above = NULL;
3727     int x, y;
3728    
3729     if (m == NULL)
3730     return;
3731    
3732     for (x = 0; x < MAP_WIDTH (m); x++)
3733     for (y = 0; y < MAP_HEIGHT (m); y++)
3734     for (tmp = get_map_ob (m, x, y); tmp != NULL; tmp = above)
3735     {
3736     above = tmp->above;
3737    
3738     if (tmp->inv)
3739     {
3740     object *invtmp, *invnext;
3741 elmex 1.1
3742 root 1.20 for (invtmp = tmp->inv; invtmp != NULL; invtmp = invnext)
3743     {
3744     invnext = invtmp->below;
3745 root 1.14
3746 root 1.20 if (QUERY_FLAG (invtmp, FLAG_AUTO_APPLY))
3747     auto_apply (invtmp);
3748     else if (invtmp->type == TREASURE && HAS_RANDOM_ITEMS (invtmp))
3749     {
3750     while ((invtmp->stats.hp--) > 0)
3751     create_treasure (invtmp->randomitems, invtmp, 0, m->difficulty, 0);
3752 root 1.14
3753 root 1.20 invtmp->randomitems = NULL;
3754     }
3755     else if (invtmp && invtmp->arch
3756 root 1.22 && invtmp->type != TREASURE && invtmp->type != SPELL && invtmp->type != CLASS && HAS_RANDOM_ITEMS (invtmp))
3757 root 1.20 {
3758 root 1.22 create_treasure (invtmp->randomitems, invtmp, 0, m->difficulty, 0);
3759 root 1.20 /* Need to clear this so that we never try to create
3760     * treasure again for this object
3761     */
3762     invtmp->randomitems = NULL;
3763 root 1.14 }
3764     }
3765 root 1.20 /* This is really temporary - the code at the bottom will
3766     * also set randomitems to null. The problem is there are bunches
3767     * of maps/players already out there with items that have spells
3768     * which haven't had the randomitems set to null yet.
3769     * MSW 2004-05-13
3770     *
3771     * And if it's a spellbook, it's better to set randomitems to NULL too,
3772     * else you get two spells in the book ^_-
3773     * Ryo 2004-08-16
3774     */
3775     if (tmp->type == WAND || tmp->type == ROD || tmp->type == SCROLL
3776 root 1.22 || tmp->type == HORN || tmp->type == FIREWALL || tmp->type == POTION || tmp->type == ALTAR || tmp->type == SPELLBOOK)
3777 root 1.20 tmp->randomitems = NULL;
3778    
3779     }
3780    
3781     if (QUERY_FLAG (tmp, FLAG_AUTO_APPLY))
3782     auto_apply (tmp);
3783 root 1.22 else if ((tmp->type == TREASURE || (tmp->type == CONTAINER)) && HAS_RANDOM_ITEMS (tmp))
3784 root 1.20 {
3785     while ((tmp->stats.hp--) > 0)
3786     create_treasure (tmp->randomitems, tmp, 0, m->difficulty, 0);
3787     tmp->randomitems = NULL;
3788     }
3789     else if (tmp->type == TIMED_GATE)
3790     {
3791     object *head = tmp->head != NULL ? tmp->head : tmp;
3792 root 1.22
3793 root 1.20 if (QUERY_FLAG (head, FLAG_IS_LINKED))
3794     {
3795     tmp->speed = 0;
3796     update_ob_speed (tmp);
3797 root 1.14 }
3798     }
3799 root 1.20 /* This function can be called everytime a map is loaded, even when
3800     * swapping back in. As such, we don't want to create the treasure
3801     * over and ove again, so after we generate the treasure, blank out
3802     * randomitems so if it is swapped in again, it won't make anything.
3803     * This is a problem for the above objects, because they have counters
3804     * which say how many times to make the treasure.
3805     */
3806     else if (tmp && tmp->arch && tmp->type != PLAYER
3807     && tmp->type != TREASURE && tmp->type != SPELL
3808 root 1.22 && tmp->type != PLAYER_CHANGER && tmp->type != CLASS && HAS_RANDOM_ITEMS (tmp))
3809 root 1.20 {
3810 root 1.22 create_treasure (tmp->randomitems, tmp, GT_APPLY, m->difficulty, 0);
3811 root 1.20 tmp->randomitems = NULL;
3812     }
3813     }
3814 elmex 1.1
3815 root 1.20 for (x = 0; x < MAP_WIDTH (m); x++)
3816     for (y = 0; y < MAP_HEIGHT (m); y++)
3817     for (tmp = get_map_ob (m, x, y); tmp != NULL; tmp = tmp->above)
3818 root 1.22 if (tmp->above && (tmp->type == TRIGGER_BUTTON || tmp->type == TRIGGER_PEDESTAL))
3819 root 1.20 check_trigger (tmp, tmp->above);
3820 elmex 1.1 }
3821    
3822     /**
3823     * Handles player eating food that temporarily changes status (resistances, stats).
3824     * This used to call cast_change_attr(), but
3825     * that doesn't work with the new spell code. Since we know what
3826     * the food changes, just grab a force and use that instead.
3827     */
3828    
3829 root 1.22 void
3830     eat_special_food (object *who, object *food)
3831     {
3832     object *force;
3833     int i, did_one = 0;
3834     sint8 k;
3835    
3836     force = get_archetype (FORCE_NAME);
3837    
3838     for (i = 0; i < NUM_STATS; i++)
3839     {
3840     k = get_attr_value (&food->stats, i);
3841     if (k)
3842     {
3843     set_attr_value (&force->stats, i, k);
3844     did_one = 1;
3845 root 1.14 }
3846 elmex 1.1 }
3847    
3848 root 1.22 /* check if we can protect the eater */
3849     for (i = 0; i < NROFATTACKS; i++)
3850     {
3851     if (food->resist[i] > 0)
3852     {
3853     force->resist[i] = food->resist[i] / 2;
3854     did_one = 1;
3855     }
3856     }
3857     if (did_one)
3858     {
3859     force->speed = 0.1;
3860     update_ob_speed (force);
3861     /* bigger morsel of food = longer effect time */
3862     force->stats.food = food->stats.food / 5;
3863     SET_FLAG (force, FLAG_IS_USED_UP);
3864     SET_FLAG (force, FLAG_APPLIED);
3865     change_abil (who, force);
3866     insert_ob_in_ob (force, who);
3867     }
3868     else
3869     {
3870     free_object (force);
3871     }
3872    
3873     /* check for hp, sp change */
3874     if (food->stats.hp != 0)
3875     {
3876     if (QUERY_FLAG (food, FLAG_CURSED))
3877     {
3878     strcpy (who->contr->killer, food->name);
3879     hit_player (who, food->stats.hp, food, AT_POISON, 1);
3880     new_draw_info (NDI_UNIQUE, 0, who, "Eck!...that was poisonous!");
3881     }
3882     else
3883     {
3884     if (food->stats.hp > 0)
3885     new_draw_info (NDI_UNIQUE, 0, who, "You begin to feel better.");
3886     else
3887     new_draw_info (NDI_UNIQUE, 0, who, "Eck!...that was poisonous!");
3888     who->stats.hp += food->stats.hp;
3889     }
3890     }
3891     if (food->stats.sp != 0)
3892     {
3893     if (QUERY_FLAG (food, FLAG_CURSED))
3894     {
3895     new_draw_info (NDI_UNIQUE, 0, who, "You are drained of mana!");
3896     who->stats.sp -= food->stats.sp;
3897     if (who->stats.sp < 0)
3898     who->stats.sp = 0;
3899     }
3900     else
3901     {
3902     new_draw_info (NDI_UNIQUE, 0, who, "You feel a rush of magical energy!");
3903     who->stats.sp += food->stats.sp;
3904     /* place limit on max sp from food? */
3905     }
3906 elmex 1.1 }
3907 root 1.22 fix_player (who);
3908 elmex 1.1 }
3909    
3910    
3911     /**
3912     * Designed primarily to light torches/lanterns/etc.
3913     * Also burns up burnable material too. First object in the inventory is
3914     * the selected object to "burn". -b.t.
3915     */
3916    
3917 root 1.22 void
3918     apply_lighter (object *who, object *lighter)
3919     {
3920     object *item;
3921     int is_player_env = 0;
3922     uint32 nrof;
3923     tag_t count;
3924     char item_name[MAX_BUF];
3925    
3926     item = find_marked_object (who);
3927     if (item)
3928     {
3929     if (lighter->last_eat && lighter->stats.food)
3930     { /* lighter gets used up */
3931     /* Split multiple lighters if they're being used up. Otherwise *
3932     * one charge from each would be used up. --DAMN */
3933     if (lighter->nrof > 1)
3934     {
3935     object *oneLighter = get_object ();
3936 root 1.14
3937 root 1.22 copy_object (lighter, oneLighter);
3938     lighter->nrof -= 1;
3939     oneLighter->nrof = 1;
3940     oneLighter->stats.food--;
3941     esrv_send_item (who, lighter);
3942     oneLighter = insert_ob_in_ob (oneLighter, who);
3943     esrv_send_item (who, oneLighter);
3944     }
3945     else
3946     {
3947     lighter->stats.food--;
3948     }
3949 root 1.14
3950 root 1.22 }
3951     else if (lighter->last_eat)
3952     { /* no charges left in lighter */
3953     new_draw_info_format (NDI_UNIQUE, 0, who, "You attempt to light the %s with a used up %s.", &item->name, &lighter->name);
3954     return;
3955     }
3956     /* Perhaps we should split what we are trying to light on fire?
3957     * I can't see many times when you would want to light multiple
3958     * objects at once.
3959     */
3960     nrof = item->nrof;
3961     count = item->count;
3962     /* If the item is destroyed, we don't have a valid pointer to the
3963     * name object, so make a copy so the message we print out makes
3964     * some sense.
3965     */
3966     strcpy (item_name, item->name);
3967     if (who == is_player_inv (item))
3968     is_player_env = 1;
3969    
3970     save_throw_object (item, AT_FIRE, who);
3971     /* Change to check count and not freed, since the object pointer
3972     * may have gotten recycled
3973     */
3974     if ((nrof != item->nrof) || (count != item->count))
3975     {
3976     new_draw_info_format (NDI_UNIQUE, 0, who, "You light the %s with the %s.", &item_name, &lighter->name);
3977     /* Need to update the player so that the players glow radius
3978     * gets changed.
3979     */
3980     if (is_player_env)
3981     fix_player (who);
3982     }
3983     else
3984     {
3985     new_draw_info_format (NDI_UNIQUE, 0, who, "You attempt to light the %s with the %s and fail.", &item->name, &lighter->name);
3986 root 1.14 }
3987 elmex 1.1
3988 root 1.22 }
3989     else /* nothing to light */
3990     new_draw_info (NDI_UNIQUE, 0, who, "You need to mark a lightable object.");
3991 elmex 1.1
3992     }
3993    
3994     /**
3995     * op made some mistake with a scroll, this takes care of punishment.
3996     * scroll_failure()- hacked directly from spell_failure
3997     */
3998 root 1.22 void
3999     scroll_failure (object *op, int failure, int power)
4000 elmex 1.1 {
4001 root 1.22 if (abs (failure / 4) > power)
4002     power = abs (failure / 4); /* set minimum effect */
4003 elmex 1.1
4004 root 1.22 if (failure <= -1 && failure > -15)
4005     { /* wonder */
4006     object *tmp;
4007    
4008     new_draw_info (NDI_UNIQUE, 0, op, "Your spell warps!.");
4009     tmp = get_archetype (SPELL_WONDER);
4010     cast_wonder (op, op, 0, tmp);
4011     free_object (tmp);
4012     }
4013     else if (failure <= -15 && failure > -35)
4014     { /* drain mana */
4015     new_draw_info (NDI_UNIQUE, 0, op, "Your mana is drained!.");
4016     op->stats.sp -= random_roll (0, power - 1, op, PREFER_LOW);
4017     if (op->stats.sp < 0)
4018     op->stats.sp = 0;
4019     }
4020     else if (settings.spell_failure_effects == TRUE)
4021     {
4022     if (failure <= -35 && failure > -60)
4023     { /* confusion */
4024     new_draw_info (NDI_UNIQUE, 0, op, "The magic recoils on you!");
4025     confuse_player (op, op, power);
4026     }
4027     else if (failure <= -60 && failure > -70)
4028     { /* paralysis */
4029     new_draw_info (NDI_UNIQUE, 0, op, "The magic recoils and paralyzes " "you!");
4030     paralyze_player (op, op, power);
4031     }
4032     else if (failure <= -70 && failure > -80)
4033     { /* blind */
4034     new_draw_info (NDI_UNIQUE, 0, op, "The magic recoils on you!");
4035     blind_player (op, op, power);
4036     }
4037     else if (failure <= -80)
4038     { /* blast the immediate area */
4039     object *tmp;
4040    
4041     tmp = get_archetype (LOOSE_MANA);
4042     cast_magic_storm (op, tmp, power);
4043     new_draw_info (NDI_UNIQUE, 0, op, "You unlease uncontrolled mana!");
4044     free_object (tmp);
4045 root 1.14 }
4046 elmex 1.1 }
4047     }
4048    
4049 root 1.22 void
4050     apply_changes_to_player (object *pl, object *change)
4051     {
4052     int excess_stat = 0; /* if the stat goes over the maximum
4053     for the race, put the excess stat some
4054     where else. */
4055 elmex 1.1
4056 root 1.22 switch (change->type)
4057     {
4058 root 1.24 case CLASS:
4059     {
4060     living *stats = &(pl->contr->orig_stats);
4061     living *ns = &(change->stats);
4062     object *walk;
4063     int flag_change_face = 1;
4064    
4065     /* the following code assigns stats up to the stat max
4066     * for the race, and if the stat max is exceeded,
4067     * tries to randomly reassign the excess stat
4068     */
4069     int i, j;
4070 root 1.22
4071 root 1.24 for (i = 0; i < NUM_STATS; i++)
4072     {
4073     sint8 stat = get_attr_value (stats, i);
4074     int race_bonus = get_attr_value (&(pl->arch->clone.stats), i);
4075 root 1.22
4076 root 1.24 stat += get_attr_value (ns, i);
4077     if (stat > 20 + race_bonus)
4078     {
4079     excess_stat++;
4080     stat = 20 + race_bonus;
4081     }
4082     set_attr_value (stats, i, stat);
4083     }
4084 elmex 1.1
4085 root 1.24 for (j = 0; excess_stat > 0 && j < 100; j++)
4086     { /* try 100 times to assign excess stats */
4087     int i = rndm (0, 6);
4088     int stat = get_attr_value (stats, i);
4089     int race_bonus = get_attr_value (&(pl->arch->clone.stats), i);
4090    
4091     if (i == CHA)
4092     continue; /* exclude cha from this */
4093     if (stat < 20 + race_bonus)
4094     {
4095     change_attr_value (stats, i, 1);
4096     excess_stat--;
4097     }
4098     }
4099 root 1.14
4100 root 1.24 /* insert the randomitems from the change's treasurelist into
4101     * the player ref: player.c
4102     */
4103     if (change->randomitems != NULL)
4104     give_initial_items (pl, change->randomitems);
4105 root 1.14
4106    
4107 root 1.24 /* set up the face, for some races. */
4108 root 1.14
4109 root 1.24 /* first, look for the force object banning
4110     * changing the face. Certain races never change face with class.
4111     */
4112     for (walk = pl->inv; walk != NULL; walk = walk->below)
4113     if (!strcmp (walk->name, "NOCLASSFACECHANGE"))
4114     flag_change_face = 0;
4115 root 1.14
4116 root 1.24 if (flag_change_face)
4117     {
4118     pl->animation_id = GET_ANIM_ID (change);
4119     pl->face = change->face;
4120 root 1.14
4121 root 1.24 if (QUERY_FLAG (change, FLAG_ANIMATE))
4122     SET_FLAG (pl, FLAG_ANIMATE);
4123     else
4124     CLEAR_FLAG (pl, FLAG_ANIMATE);
4125     }
4126 root 1.14
4127 root 1.24 /* check the special case of can't use weapons */
4128     /*if(QUERY_FLAG(change,FLAG_USE_WEAPON)) CLEAR_FLAG(pl,FLAG_USE_WEAPON); */
4129     if (!strcmp (change->name, "monk"))
4130     CLEAR_FLAG (pl, FLAG_USE_WEAPON);
4131 root 1.14
4132 root 1.24 break;
4133     }
4134 elmex 1.1 }
4135     }
4136    
4137     /**
4138     * This handles items of type 'transformer'.
4139     * Basically those items, used with a marked item, transform both items into something
4140     * else.
4141     * "Transformer" item has food decreased by 1, removed if 0 (0 at start means illimited)..
4142     * Change information is contained in the 'slaying' field of the marked item.
4143     * The format is as follow: transformer:[number ]yield[;transformer:...].
4144     * This way an item can be transformed in many things, and/or many objects.
4145     * The 'slaying' field for transformer is used as verb for the action.
4146     */
4147 root 1.22 void
4148     apply_item_transformer (object *pl, object *transformer)
4149     {
4150     object *marked;
4151     object *new_item;
4152     char *find;
4153     char *separator;
4154     int yield;
4155     char got[MAX_BUF];
4156     int len;
4157    
4158     if (!pl || !transformer)
4159     return;
4160     marked = find_marked_object (pl);
4161     if (!marked)
4162 elmex 1.1 {
4163 root 1.22 new_draw_info_format (NDI_UNIQUE, 0, pl, "Use the %s with what item?", query_name (transformer));
4164     return;
4165     }
4166     if (!marked->slaying)
4167     {
4168     new_draw_info_format (NDI_UNIQUE, 0, pl, "You can't use the %s with your %s!", query_name (transformer), query_name (marked));
4169     return;
4170     }
4171     /* check whether they are compatible or not */
4172     find = strstr (marked->slaying, transformer->arch->name);
4173     if (!find || (*(find + strlen (transformer->arch->name)) != ':'))
4174     {
4175     new_draw_info_format (NDI_UNIQUE, 0, pl, "You can't use the %s with your %s!", query_name (transformer), query_name (marked));
4176     return;
4177     }
4178     find += strlen (transformer->arch->name) + 1;
4179     /* Item can be used, now find how many and what it yields */
4180     if (isdigit (*(find)))
4181     {
4182     yield = atoi (find);
4183     if (yield < 1)
4184 elmex 1.1 {
4185 root 1.22 LOG (llevDebug, "apply_item_transformer: item %s has slaying-yield %d.", query_base_name (marked, 0), yield);
4186     yield = 1;
4187 elmex 1.1 }
4188 root 1.22 }
4189     else
4190     yield = 1;
4191 elmex 1.1
4192 root 1.22 while (isdigit (*find))
4193     find++;
4194     while (*find == ' ')
4195     find++;
4196     memset (got, 0, MAX_BUF);
4197     if ((separator = strchr (find, ';')) != NULL)
4198     {
4199     len = separator - find;
4200     }
4201     else
4202     {
4203     len = strlen (find);
4204     }
4205     if (len > MAX_BUF - 1)
4206     len = MAX_BUF - 1;
4207     strcpy (got, find);
4208     got[len] = '\0';
4209    
4210     /* Now create new item, remove used ones when required. */
4211     new_item = get_archetype (got);
4212     if (!new_item)
4213     {
4214     new_draw_info_format (NDI_UNIQUE, 0, pl, "This %s is strange, better to not use it.", query_base_name (marked, 0));
4215     return;
4216 elmex 1.1 }
4217 root 1.22 new_item->nrof = yield;
4218     new_draw_info_format (NDI_UNIQUE, 0, pl, "You %s the %s.", &transformer->slaying, query_base_name (marked, 0));
4219     insert_ob_in_ob (new_item, pl);
4220     esrv_send_inventory (pl, pl);
4221     /* Eat up one item */
4222     decrease_ob_nr (marked, 1);
4223     /* Eat one transformer if needed */
4224     if (transformer->stats.food)
4225     if (--transformer->stats.food == 0)
4226     decrease_ob_nr (transformer, 1);
4227     }