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

File Contents

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