ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/apply.C
Revision: 1.76
Committed: Mon Apr 30 04:25:30 2007 UTC (17 years, 1 month ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.75: +82 -55 lines
Log Message:
This is the first rough cut of the skill use system (use the STABLE tag).

Details will likely change, and combat skills do not work very well, but
it works quite well.

Players no longer have a shoottype or range slots, instead, each player
has these members:

   combat_skill/combat_ob  the currently selected skill (and weapon)
                           for direct attacks.
   ranged_skill/ranged_ob  the currently selected ranged skill (and
                           bow/spell/item)
   golem                   the currently-controlled golem, if any.

File Contents

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