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

File Contents

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