ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/apply.C
Revision: 1.111
Committed: Sun Jul 1 05:00:19 2007 UTC (16 years, 11 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.110: +10 -11 lines
Log Message:
- upgrade crossfire trt to the GPL version 3 (hopefully correctly).
- add a single file covered by the GNU Affero General Public License
  (which is not yet released, so I used the current draft, which is
  legally a bit wavy, but its likely better than nothing as it expresses
  direct intent by the authors, and we can upgrade as soon as it has been
  released).
  * this should ensure availability of source code for the server at least
    and hopefully also archetypes and maps even when modified versions
    are not being distributed, in accordance of section 13 of the agplv3.

File Contents

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