ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_effect.C
Revision: 1.73
Committed: Sat Sep 1 08:03:46 2007 UTC (16 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-2_2
Changes since 1.72: +17 -19 lines
Log Message:
first round of infobox and c++-level channels

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 (©) 2002,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 <global.h>
25 #include <object.h>
26 #include <living.h>
27 #include <sproto.h>
28 #include <spells.h>
29 #include <sounds.h>
30
31 /* cast_magic_storm: This is really used mostly for spell
32 * fumbles at the like. tmp is the object to propogate.
33 * op is what is casting this.
34 */
35 void
36 cast_magic_storm (object *op, object *tmp, int lvl)
37 {
38 if (!tmp)
39 return; /* error */
40
41 tmp->level = op->level;
42 tmp->range += lvl / 5; /* increase the area of destruction */
43 tmp->duration += lvl / 5;
44
45 /* Put a cap on duration for this - if the player fails in their
46 * apartment, don't want it to go on so long that it kills them
47 * multiple times. Also, damge already increases with level,
48 * so don't really need to increase the duration as much either.
49 */
50 if (tmp->duration >= 40)
51 tmp->duration = 40;
52
53 tmp->stats.dam = lvl; /* nasty recoils! */
54 tmp->stats.maxhp = tmp->count; /* tract single parent */
55
56 tmp->insert_at (op, op);
57 }
58
59 int
60 recharge (object *op, object *caster, object *spell_ob)
61 {
62 object *wand, *tmp;
63 int ncharges;
64
65 wand = find_marked_object (op);
66 if (wand == NULL || wand->type != WAND)
67 {
68 new_draw_info (NDI_UNIQUE, 0, op, "You need to mark the wand you want to recharge.");
69 return 0;
70 }
71 if (!(random_roll (0, 3, op, PREFER_HIGH)))
72 {
73 new_draw_info_format (NDI_UNIQUE, 0, op, "The %s vibrates violently, then explodes!", query_name (wand));
74 op->play_sound (sound_find ("ob_explode"));
75 esrv_del_item (op->contr, wand->count);
76 wand->destroy ();
77 tmp = get_archetype ("fireball");
78 tmp->stats.dam = (spell_ob->stats.dam + SP_level_dam_adjust (caster, spell_ob)) / 10;
79
80 if (!tmp->stats.dam)
81 tmp->stats.dam = 1;
82
83 tmp->stats.hp = tmp->stats.dam / 2;
84
85 if (tmp->stats.hp < 2)
86 tmp->stats.hp = 2;
87
88 tmp->insert_at (op);
89 return 1;
90 }
91
92 ncharges = (spell_ob->stats.dam + SP_level_dam_adjust (caster, spell_ob));
93
94 if (wand->inv && wand->inv->level)
95 ncharges /= wand->inv->level;
96 else
97 {
98 new_draw_info_format (NDI_UNIQUE, 0, op, "Your %s is broken.", query_name (wand));
99 return 0;
100 }
101
102 if (!ncharges)
103 ncharges = 1;
104
105 wand->stats.food += ncharges;
106 new_draw_info_format (NDI_UNIQUE, 0, op, "The %s glows with power.", query_name (wand));
107
108 if (wand->arch && QUERY_FLAG (wand->arch, FLAG_ANIMATE))
109 {
110 SET_FLAG (wand, FLAG_ANIMATE);
111 wand->set_speed (wand->arch->speed);
112 }
113
114 return 1;
115 }
116
117 /* Create a missile (nonmagic - magic +4). Will either create bolts or arrows
118 * based on whether a crossbow or bow is equiped. If neither, it defaults to
119 * arrows.
120 * Sets the plus based on the casters level. It is also settable with the
121 * invoke command. If the caster attempts to create missiles with too
122 * great a plus, the default is used.
123 * The # of arrows created also goes up with level, so if a 30th level mage
124 * wants LOTS of arrows, and doesn't care what the plus is he could
125 * create nonnmagic arrows, or even -1, etc...
126 */
127 int
128 cast_create_missile (object *op, object *caster, object *spell, int dir, const char *stringarg)
129 {
130 int missile_plus = 0, bonus_plus = 0;
131 const char *missile_name;
132 object *tmp, *missile;
133
134 missile_name = "arrow";
135
136 for (tmp = op->inv; tmp != NULL; tmp = tmp->below)
137 if (tmp->type == BOW && QUERY_FLAG (tmp, FLAG_APPLIED))
138 missile_name = tmp->race;
139
140 missile_plus = spell->stats.dam + SP_level_dam_adjust (caster, spell);
141
142 if (archetype::find (missile_name) == NULL)
143 {
144 LOG (llevDebug, "Cast create_missile: could not find archetype %s\n", missile_name);
145 return 0;
146 }
147
148 missile = get_archetype (missile_name);
149
150 if (stringarg)
151 {
152 /* If it starts with a letter, presume it is a description */
153 if (isalpha (*stringarg))
154 {
155 artifact *al = find_artifactlist (missile->type)->items;
156
157 for (; al; al = al->next)
158 if (!strcasecmp (al->item->name, stringarg))
159 break;
160
161 if (!al)
162 {
163 missile->destroy ();
164 new_draw_info_format (NDI_UNIQUE, 0, op, "No such object %ss of %s", missile_name, stringarg);
165 return 0;
166 }
167
168 if (al->item->slaying)
169 {
170 missile->destroy ();
171 new_draw_info_format (NDI_UNIQUE, 0, op, "You are not allowed to create %ss of %s", missile_name, stringarg);
172 return 0;
173 }
174
175 give_artifact_abilities (missile, al->item);
176 /* These special arrows cost something extra. Don't have them also be magical -
177 * otherwise, in most cases, not enough will be created. I don't want to get into
178 * the parsing of having to do both plus and type.
179 */
180 bonus_plus = 1 + (al->item->value / 5);
181 missile_plus = 0;
182 }
183 else if (atoi (stringarg) < missile_plus)
184 missile_plus = atoi (stringarg);
185 }
186
187 if (missile_plus > 4)
188 missile_plus = 4;
189 else if (missile_plus < -4)
190 missile_plus = -4;
191
192 missile->nrof = spell->duration + SP_level_duration_adjust (caster, spell);
193 missile->nrof -= 3 * (missile_plus + bonus_plus);
194
195 if (missile->nrof < 1)
196 missile->nrof = 1;
197
198 missile->magic = missile_plus;
199 /* Can't get any money for these objects */
200 missile->value = 0;
201
202 SET_FLAG (missile, FLAG_IDENTIFIED);
203
204 if (!cast_create_obj (op, caster, missile, dir) && op->type == PLAYER && !missile->destroyed ())
205 pick_up (op, missile);
206
207 return 1;
208 }
209
210
211 /* allows the choice of what sort of food object to make.
212 * If stringarg is NULL, it will create food dependent on level --PeterM*/
213 int
214 cast_create_food (object *op, object *caster, object *spell_ob, int dir, const char *stringarg)
215 {
216 int food_value;
217 archetype *at = NULL;
218 object *new_op;
219
220 food_value = spell_ob->stats.food + +50 * SP_level_duration_adjust (caster, spell_ob);
221
222 if (stringarg)
223 {
224 at = find_archetype_by_object_type_name (FOOD, stringarg);
225 if (at == NULL)
226 at = find_archetype_by_object_type_name (DRINK, stringarg);
227 if (at == NULL || at->stats.food > food_value)
228 stringarg = NULL;
229 }
230
231 if (!stringarg)
232 {
233 archetype *at_tmp;
234
235 /* We try to find the archetype with the maximum food value.
236 * This removes the dependancy of hard coded food values in this
237 * function, and addition of new food types is automatically added.
238 * We don't use flesh types because the weight values of those need
239 * to be altered from the donor.
240 */
241
242 /* We assume the food items don't have multiple parts */
243 for_all_archetypes (at_tmp)
244 {
245 if (at_tmp->type == FOOD || at_tmp->type == DRINK)
246 {
247 /* Basically, if the food value is something that is creatable
248 * under the limits of the spell and it is higher than
249 * the item we have now, take it instead.
250 */
251 if (at_tmp->stats.food <= food_value
252 && (!at
253 || at_tmp->stats.food > at->stats.food
254 || (at_tmp->stats.food == at->stats.food
255 && at_tmp->weight < at->weight)))
256 at = at_tmp;
257 }
258 }
259 }
260
261 /* Pretty unlikely (there are some very low food items), but you never
262 * know
263 */
264 if (!at)
265 {
266 new_draw_info (NDI_UNIQUE, 0, op, "You don't have enough experience to create any food.");
267 return 0;
268 }
269
270 food_value /= at->stats.food;
271 new_op = arch_to_object (at);
272 new_op->nrof = food_value;
273
274 new_op->value = 0;
275 if (new_op->nrof < 1)
276 new_op->nrof = 1;
277
278 cast_create_obj (op, caster, new_op, dir);
279 return 1;
280 }
281
282 int
283 probe (object *op, object *caster, object *spell_ob, int dir)
284 {
285 int r, mflags, maxrange;
286 object *tmp;
287 maptile *m;
288
289
290 if (!dir)
291 {
292 examine_monster (op, op);
293 return 1;
294 }
295
296 maxrange = spell_ob->range + SP_level_range_adjust (caster, spell_ob);
297 for (r = 1; r < maxrange; r++)
298 {
299 sint16 x = op->x + r * freearr_x[dir], y = op->y + r * freearr_y[dir];
300
301 m = op->map;
302 mflags = get_map_flags (m, &m, x, y, &x, &y);
303
304 if (mflags & P_OUT_OF_MAP)
305 break;
306
307 if (!QUERY_FLAG (op, FLAG_WIZCAST) && (mflags & P_NO_MAGIC))
308 {
309 new_draw_info (NDI_UNIQUE, 0, op, "Something blocks your magic.");
310 return 0;
311 }
312 if (mflags & P_IS_ALIVE)
313 {
314 for (tmp = GET_MAP_OB (m, x, y); tmp != NULL; tmp = tmp->above)
315 if (QUERY_FLAG (tmp, FLAG_ALIVE) && (tmp->type == PLAYER || QUERY_FLAG (tmp, FLAG_MONSTER)))
316 {
317 new_draw_info (NDI_UNIQUE, 0, op, "You detect something.");
318 if (tmp->head != NULL)
319 tmp = tmp->head;
320 examine_monster (op, tmp);
321 return 1;
322 }
323 }
324 }
325
326 new_draw_info (NDI_UNIQUE, 0, op, "You detect nothing.");
327 return 1;
328 }
329
330 /* This checks to see if 'pl' is invisible to 'mon'.
331 * does race check, undead check, etc
332 * Returns TRUE if mon can't see pl, false
333 * otherwise. This doesn't check range, walls, etc. It
334 * only checks the racial adjustments, and in fact that
335 * pl is invisible.
336 */
337 int
338 makes_invisible_to (object *pl, object *mon)
339 {
340 if (!pl->invisible)
341 return 0;
342
343 if (pl->type == PLAYER)
344 {
345 /* If race isn't set, then invisible unless it is undead */
346 if (!pl->contr->invis_race)
347 {
348 if (QUERY_FLAG (mon, FLAG_UNDEAD))
349 return 0;
350
351 return 1;
352 }
353
354 /* invis_race is set if we get here */
355 if (!strcmp (pl->contr->invis_race, "undead") && is_true_undead (mon))
356 return 1;
357
358 /* No race, can't be invisible to it */
359 if (!mon->race)
360 return 0;
361
362 if (strstr (mon->race, pl->contr->invis_race))
363 return 1;
364
365 /* Nothing matched above, return 0 */
366 return 0;
367 }
368 else
369 {
370 /* monsters are invisible to everything */
371 return 1;
372 }
373 }
374
375 /* Makes the player or character invisible.
376 * Note the spells to 'stack', but perhaps in odd ways.
377 * the duration for all is cumulative.
378 * In terms of invis undead/normal invis, it is the last one cast that
379 * will determine if you are invisible to undead or normal monsters.
380 * For improved invis, if you cast it with a one of the others, you
381 * lose the improved part of it, and the above statement about undead/
382 * normal applies.
383 */
384 int
385 cast_invisible (object *op, object *caster, object *spell_ob)
386 {
387 if (op->invisible > 1000)
388 {
389 new_draw_info (NDI_UNIQUE, 0, op, "You can not extend the duration of your invisibility any further");
390 return 0;
391 }
392
393 /* Remove the switch with 90% duplicate code - just handle the differences with
394 * and if statement or two.
395 */
396 op->invisible += spell_ob->duration + SP_level_duration_adjust (caster, spell_ob);
397 /* max duration */
398 if (op->invisible > 1000)
399 op->invisible = 1000;
400
401 if (op->type == PLAYER)
402 {
403 op->contr->invis_race = spell_ob->race;
404
405 if (QUERY_FLAG (spell_ob, FLAG_MAKE_INVIS))
406 op->contr->tmp_invis = 0;
407 else
408 op->contr->tmp_invis = 1;
409
410 op->contr->hidden = 0;
411 }
412
413 if (makes_invisible_to (op, op))
414 new_draw_info (NDI_UNIQUE, 0, op, "You can't see your hands!");
415 else
416 new_draw_info (NDI_UNIQUE, 0, op, "You feel more transparent!");
417
418 update_object (op, UP_OBJ_CHANGE);
419
420 /* Only search the active objects - only these should actually do
421 * harm to the player.
422 */
423 for_all_actives (tmp)
424 if (tmp->enemy == op)
425 tmp->enemy = 0;
426
427 return 1;
428 }
429
430 /* earth to dust spell. Basically destroys earthwalls in the area.
431 */
432 int
433 cast_earth_to_dust (object *op, object *caster, object *spell_ob)
434 {
435 object *tmp, *next;
436 int range, i, j, mflags;
437 sint16 sx, sy;
438 maptile *m;
439
440 if (op->type != PLAYER)
441 return 0;
442
443 range = spell_ob->range + SP_level_range_adjust (caster, spell_ob);
444
445 for (i = -range; i <= range; i++)
446 for (j = -range; j <= range; j++)
447 {
448 sx = op->x + i;
449 sy = op->y + j;
450 m = op->map;
451 mflags = get_map_flags (m, &m, sx, sy, &sx, &sy);
452
453 if (mflags & P_OUT_OF_MAP)
454 continue;
455
456 // earth to dust tears down everything that can be teared down
457 for (tmp = GET_MAP_OB (m, sx, sy); tmp != NULL; tmp = next)
458 {
459 next = tmp->above;
460 if (QUERY_FLAG (tmp, FLAG_TEAR_DOWN))
461 hit_player (tmp, 9998, op, AT_PHYSICAL, 0);
462 }
463 }
464
465 return 1;
466 }
467
468 void
469 execute_word_of_recall (object *op)
470 {
471 if (object *pl = op->in_player ())
472 {
473 if (pl->ms ().flags () & P_NO_CLERIC && !QUERY_FLAG (pl, FLAG_WIZCAST))
474 new_draw_info (NDI_UNIQUE, 0, pl, "You feel something fizzle inside you.");
475 else
476 {
477 // remove first so we do not call update_stats
478 op->remove ();
479 pl->enter_exit (op);
480 }
481 }
482
483 op->destroy ();
484 }
485
486 /* Word of recall causes the player to return 'home'.
487 * we put a force into the player object, so that there is a
488 * time delay effect.
489 */
490 int
491 cast_word_of_recall (object *op, object *caster, object *spell_ob)
492 {
493 object *dummy;
494 int time;
495
496 if (op->type != PLAYER)
497 return 0;
498
499 if (find_obj_by_type_subtype (op, SPELL_EFFECT, SP_WORD_OF_RECALL))
500 {
501 new_draw_info (NDI_UNIQUE, 0, op, "You feel a force starting to build up inside you.");
502 return 1;
503 }
504
505 dummy = get_archetype (FORCE_NAME);
506 if (dummy == NULL)
507 {
508 new_draw_info (NDI_UNIQUE, 0, op, "Oops, program error!");
509 LOG (llevError, "cast_word_of_recall: get_archetype(force) failed!\n");
510 return 0;
511 }
512
513 time = spell_ob->duration - SP_level_duration_adjust (caster, spell_ob);
514 if (time < 1)
515 time = 1;
516
517 /* value of speed really doesn't make much difference, as long as it is
518 * positive. Lower value may be useful so that the problem doesn't
519 * do anything really odd if it say a -1000 or something.
520 */
521 dummy->set_speed (0.002);
522 dummy->speed_left = -dummy->speed * time;
523 dummy->type = SPELL_EFFECT;
524 dummy->subtype = SP_WORD_OF_RECALL;
525
526 /* If we could take advantage of enter_player_savebed() here, it would be
527 * nice, but until the map load fails, we can't.
528 */
529 EXIT_PATH (dummy) = op->contr->savebed_map;
530 EXIT_X (dummy) = op->contr->bed_x;
531 EXIT_Y (dummy) = op->contr->bed_y;
532
533 op->insert (dummy);
534
535 new_draw_info (NDI_UNIQUE, 0, op, "You feel a force starting to build up inside you.");
536
537 return 1;
538 }
539
540 /* cast_wonder
541 * wonder is really just a spell that will likely cast another
542 * spell.
543 */
544 int
545 cast_wonder (object *op, object *caster, int dir, object *spell_ob)
546 {
547 object *newspell;
548
549 if (!rndm (0, 3))
550 return cast_cone (op, caster, dir, spell_ob);
551
552 if (spell_ob->randomitems)
553 {
554 newspell = generate_treasure (spell_ob->randomitems, caster->level);
555 if (!newspell)
556 {
557 LOG (llevError, "cast_wonder: Unable to get a spell!\n");
558 return 0;
559 }
560 if (newspell->type != SPELL)
561 {
562 LOG (llevError, "cast_wonder: spell returned is not a spell (%d, %s)!\n", &newspell->type, &newspell->name);
563 return 0;
564 }
565 /* Prevent inifinit recursion */
566 if (newspell->subtype == SP_WONDER)
567 {
568 LOG (llevError, "cast_wonder: spell returned is another wonder spell!\n");
569 return 0;
570 }
571 return cast_spell (op, caster, dir, newspell, NULL);
572 }
573 return 1;
574 }
575
576 int
577 perceive_self (object *op)
578 {
579 const char *cp = describe_item (op, op);
580 archetype *at = archetype::find (ARCH_DEPLETION);
581
582 dynbuf_text buf;
583
584 if (player *pl = op->contr)
585 if (object *race = archetype::find (op->race))
586 buf << "You are a " << (pl->gender ? "female" : "male") << " " << &race->name << ".\n";
587
588 if (object *god = find_god (determine_god (op)))
589 buf << "You worship " << &god->name << ".\n";
590 else
591 buf << "You worship no god.\n";
592
593 object *tmp = present_arch_in_ob (at, op);
594
595 if (*cp == '\0' && tmp == NULL)
596 buf << "You feel very mundane. ";
597 else
598 {
599 buf << "You have: " << cp << ".\n";
600
601 if (tmp)
602 for (int i = 0; i < NUM_STATS; i++)
603 if (tmp->stats.stat (i) < 0)
604 buf.printf ("Your %s is depleted by %d.\n", statname[i], -tmp->stats.stat (i));
605 }
606
607 if (is_dragon_pl (op))
608 /* now grab the 'dragon_ability'-force from the player's inventory */
609 for (tmp = op->inv; tmp; tmp = tmp->below)
610 {
611 if (tmp->type == FORCE && tmp->arch->archname == shstr_dragon_ability_force)
612 {
613 if (tmp->stats.exp == 0)
614 buf << "Your metabolism isn't focused on anything.\n";
615 else
616 buf << "Your metabolism is focused on " << change_resist_msg[tmp->stats.exp] << ".\n";
617
618 break;
619 }
620 }
621
622 buf << '\0'; // zero-terminate
623
624 new_draw_info (NDI_UNIQUE, 0, op, buf.linearise ());
625
626 return 1;
627 }
628
629 /* This creates magic walls. Really, it can create most any object,
630 * within some reason.
631 */
632 int
633 magic_wall (object *op, object *caster, int dir, object *spell_ob)
634 {
635 object *tmp;
636 int i, posblocked, negblocked, maxrange;
637 sint16 x, y;
638 maptile *m;
639 const char *name;
640 archetype *at;
641
642 if (!dir)
643 {
644 dir = op->facing;
645 x = op->x;
646 y = op->y;
647 }
648 else
649 {
650 x = op->x + freearr_x[dir];
651 y = op->y + freearr_y[dir];
652 }
653
654 m = op->map;
655
656 if ((spell_ob->move_block || x != op->x || y != op->y) &&
657 (get_map_flags (m, &m, x, y, &x, &y) & (P_OUT_OF_MAP | P_IS_ALIVE) ||
658 ((spell_ob->move_block & GET_MAP_MOVE_BLOCK (m, x, y)) == spell_ob->move_block)))
659 {
660 new_draw_info (NDI_UNIQUE, 0, op, "Something is in the way.");
661 return 0;
662 }
663
664 if (spell_ob->other_arch)
665 tmp = arch_to_object (spell_ob->other_arch);
666 else if (spell_ob->race)
667 {
668 char buf1[MAX_BUF];
669
670 sprintf (buf1, spell_ob->race, dir);
671 at = archetype::find (buf1);
672 if (!at)
673 {
674 LOG (llevError, "summon_wall: Unable to find archetype %s\n", buf1);
675 new_draw_info (NDI_UNIQUE, 0, op, "This spell is broken.");
676 return 0;
677 }
678
679 tmp = arch_to_object (at);
680 }
681 else
682 {
683 LOG (llevError, "magic_wall: spell %s lacks other_arch\n", &spell_ob->name);
684 return 0;
685 }
686
687 if (tmp->type == SPELL_EFFECT)
688 {
689 tmp->attacktype = spell_ob->attacktype;
690 tmp->duration = spell_ob->duration + SP_level_duration_adjust (caster, spell_ob);
691 tmp->stats.dam = spell_ob->stats.dam + SP_level_dam_adjust (caster, spell_ob);
692 tmp->range = 0;
693 }
694 else if (QUERY_FLAG (tmp, FLAG_ALIVE))
695 {
696 tmp->stats.hp = spell_ob->duration + SP_level_duration_adjust (caster, spell_ob);
697 tmp->stats.maxhp = tmp->stats.hp;
698 }
699
700 if (QUERY_FLAG (spell_ob, FLAG_IS_USED_UP) || QUERY_FLAG (tmp, FLAG_IS_USED_UP))
701 {
702 tmp->stats.food = spell_ob->duration + SP_level_duration_adjust (caster, spell_ob);
703 SET_FLAG (tmp, FLAG_IS_USED_UP);
704 }
705
706 if (QUERY_FLAG (spell_ob, FLAG_TEAR_DOWN))
707 {
708 tmp->stats.hp = spell_ob->stats.dam + SP_level_dam_adjust (caster, spell_ob);
709 tmp->stats.maxhp = tmp->stats.hp;
710 SET_FLAG (tmp, FLAG_TEAR_DOWN);
711 SET_FLAG (tmp, FLAG_ALIVE);
712 }
713
714 /* This can't really hurt - if the object doesn't kill anything,
715 * these fields just won't be used. Do not set the owner for
716 * earthwalls, though, so they survive restarts.
717 */
718 if (tmp->type != EARTHWALL) //TODO
719 tmp->set_owner (op);
720
721 set_spell_skill (op, caster, spell_ob, tmp);
722 tmp->level = caster_level (caster, spell_ob) / 2;
723
724 name = tmp->name;
725 if (!(tmp = m->insert (tmp, x, y, op)))
726 {
727 new_draw_info_format (NDI_UNIQUE, 0, op, "Something destroys your %s", name);
728 return 0;
729 }
730
731 /* If this is a spellcasting wall, need to insert the spell object */
732 if (tmp->other_arch && tmp->other_arch->type == SPELL)
733 insert_ob_in_ob (arch_to_object (tmp->other_arch), tmp);
734
735 /* This code causes the wall to extend some distance in
736 * each direction, or until an obstruction is encountered.
737 * posblocked and negblocked help determine how far the
738 * created wall can extend, it won't go extend through
739 * blocked spaces.
740 */
741 maxrange = spell_ob->range + SP_level_range_adjust (caster, spell_ob);
742 posblocked = 0;
743 negblocked = 0;
744
745 for (i = 1; i <= maxrange; i++)
746 {
747 int dir2;
748
749 dir2 = (dir < 4) ? (dir + 2) : dir - 2;
750
751 x = tmp->x + i * freearr_x[dir2];
752 y = tmp->y + i * freearr_y[dir2];
753 m = tmp->map;
754
755 if (!(get_map_flags (m, &m, x, y, &x, &y) & (P_OUT_OF_MAP | P_IS_ALIVE)) &&
756 ((spell_ob->move_block & GET_MAP_MOVE_BLOCK (m, x, y)) != spell_ob->move_block) && !posblocked)
757 {
758 object *tmp2 = tmp->clone ();
759 m->insert (tmp2, x, y, op);
760
761 /* If this is a spellcasting wall, need to insert the spell object */
762 if (tmp2->other_arch && tmp2->other_arch->type == SPELL)
763 tmp2->insert (arch_to_object (tmp2->other_arch));
764
765 }
766 else
767 posblocked = 1;
768
769 x = tmp->x - i * freearr_x[dir2];
770 y = tmp->y - i * freearr_y[dir2];
771 m = tmp->map;
772
773 if (!(get_map_flags (m, &m, x, y, &x, &y) & (P_OUT_OF_MAP | P_IS_ALIVE)) &&
774 ((spell_ob->move_block & GET_MAP_MOVE_BLOCK (m, x, y)) != spell_ob->move_block) && !negblocked)
775 {
776 object *tmp2 = tmp->clone ();
777 m->insert (tmp2, x, y, op);
778
779 if (tmp2->other_arch && tmp2->other_arch->type == SPELL)
780 tmp2->insert (arch_to_object (tmp2->other_arch));
781 }
782 else
783 negblocked = 1;
784 }
785
786 if (QUERY_FLAG (tmp, FLAG_BLOCKSVIEW))
787 update_all_los (op->map, op->x, op->y);
788
789 return 1;
790 }
791
792 int
793 dimension_door (object *op, object *caster, object *spob, int dir)
794 {
795 uint32 dist, maxdist;
796 int mflags;
797 maptile *m;
798 sint16 sx, sy;
799
800 if (op->type != PLAYER)
801 return 0;
802
803 if (!dir)
804 {
805 new_draw_info (NDI_UNIQUE, 0, op, "In what direction?");
806 return 0;
807 }
808
809 /* Given the new outdoor maps, can't let players dimension door for
810 * ever, so put limits in.
811 */
812 maxdist = spob->range + SP_level_range_adjust (caster, spob);
813
814 if (op->contr->count)
815 {
816 if (op->contr->count > maxdist)
817 {
818 new_draw_info (NDI_UNIQUE, 0, op, "You can't dimension door that far!");
819 return 0;
820 }
821
822 for (dist = 0; dist < op->contr->count; dist++)
823 {
824 mflags = get_map_flags (op->map, &m, op->x + freearr_x[dir] * (dist + 1), op->y + freearr_y[dir] * (dist + 1), &sx, &sy);
825
826 if (mflags & (P_NO_MAGIC | P_OUT_OF_MAP))
827 break;
828
829 if ((mflags & P_BLOCKSVIEW) && OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, sx, sy)))
830 break;
831 }
832
833 if (dist < op->contr->count)
834 {
835 new_draw_info (NDI_UNIQUE, 0, op, "Something blocks the magic of the spell.\n");
836 op->contr->count = 0;
837 return 0;
838 }
839
840 op->contr->count = 0;
841
842 /* Remove code that puts player on random space on maps. IMO,
843 * a lot of maps probably have areas the player should not get to,
844 * but may not be marked as NO_MAGIC (as they may be bounded
845 * by such squares). Also, there are probably treasure rooms and
846 * lots of other maps that protect areas with no magic, but the
847 * areas themselves don't contain no magic spaces.
848 */
849 /* This call here is really just to normalize the coordinates */
850 mflags = get_map_flags (op->map, &m, op->x + freearr_x[dir] * dist, op->y + freearr_y[dir] * dist, &sx, &sy);
851 if (mflags & P_IS_ALIVE || OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, sx, sy)))
852 {
853 new_draw_info (NDI_UNIQUE, 0, op, "You cast your spell, but nothing happens.\n");
854 return 1; /* Maybe the penalty should be more severe... */
855 }
856 }
857 else
858 {
859 /* Player didn't specify a distance, so lets see how far
860 * we can move the player. Don't know why this stopped on
861 * spaces that blocked the players view.
862 */
863
864 for (dist = 0; dist < maxdist; dist++)
865 {
866 mflags = get_map_flags (op->map, &m, op->x + freearr_x[dir] * (dist + 1), op->y + freearr_y[dir] * (dist + 1), &sx, &sy);
867
868 if (mflags & (P_NO_MAGIC | P_OUT_OF_MAP))
869 break;
870
871 if ((mflags & P_BLOCKSVIEW) && OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, sx, sy)))
872 break;
873
874 }
875
876 /* If the destination is blocked, keep backing up until we
877 * find a place for the player.
878 */
879 for (; dist > 0; dist--)
880 {
881 if (get_map_flags (op->map, &m, op->x + freearr_x[dir] * dist, op->y + freearr_y[dir] * dist,
882 &sx, &sy) & (P_OUT_OF_MAP | P_IS_ALIVE))
883 continue;
884
885
886 if (!OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, sx, sy)))
887 break;
888
889 }
890 if (!dist)
891 {
892 new_draw_info (NDI_UNIQUE, 0, op, "Your spell failed!\n");
893 return 0;
894 }
895 }
896
897 /* Actually move the player now */
898 if (!(op = op->map->insert (op, op->x + freearr_x[dir] * dist, op->y + freearr_y[dir] * dist, op)))
899 return 1;
900
901 op->speed_left = -FABS (op->speed) * 5; /* Freeze them for a short while */
902 return 1;
903 }
904
905 /* cast_heal: Heals something.
906 * op is the caster.
907 * dir is the direction he is casting it in.
908 * spell is the spell object.
909 */
910 int
911 cast_heal (object *op, object *caster, object *spell, int dir)
912 {
913 object *tmp;
914 archetype *at;
915 object *poison;
916 int heal = 0, success = 0;
917
918 tmp = find_target_for_friendly_spell (op, dir);
919
920 if (!tmp)
921 return 0;
922
923 /* Figure out how many hp this spell might cure.
924 * could be zero if this spell heals effects, not damage.
925 */
926 heal = spell->stats.dam;
927 if (spell->stats.hp)
928 heal += random_roll (spell->stats.hp, 6, op, PREFER_HIGH) + spell->stats.hp;
929
930 if (heal)
931 {
932 if (tmp->stats.hp >= tmp->stats.maxhp)
933 new_draw_info (NDI_UNIQUE, 0, tmp, "You are already fully healed.");
934 else
935 {
936 /* See how many points we actually heal. Instead of messages
937 * based on type of spell, we instead do messages based
938 * on amount of damage healed.
939 */
940 if (heal > tmp->stats.maxhp - tmp->stats.hp)
941 heal = tmp->stats.maxhp - tmp->stats.hp;
942
943 tmp->stats.hp += heal;
944
945 if (tmp->stats.hp >= tmp->stats.maxhp)
946 new_draw_info (NDI_UNIQUE, 0, tmp, "You feel just fine!");
947 else if (heal > 50)
948 new_draw_info (NDI_UNIQUE, 0, tmp, "Your wounds close!");
949 else if (heal > 25)
950 new_draw_info (NDI_UNIQUE, 0, tmp, "Your wounds mostly close.");
951 else if (heal > 10)
952 new_draw_info (NDI_UNIQUE, 0, tmp, "Your wounds start to fade.");
953 else
954 new_draw_info (NDI_UNIQUE, 0, tmp, "Your wounds start to close.");
955
956 success = 1;
957 }
958 }
959
960 if (spell->attacktype & AT_DISEASE)
961 if (cure_disease (tmp, op, spell))
962 success = 1;
963
964 if (spell->attacktype & AT_POISON)
965 {
966 at = archetype::find ("poisoning");
967 poison = present_arch_in_ob (at, tmp);
968 if (poison)
969 {
970 success = 1;
971 new_draw_info (NDI_UNIQUE, 0, tmp, "Your body feels cleansed");
972 poison->stats.food = 1;
973 }
974 }
975
976 if (spell->attacktype & AT_CONFUSION)
977 {
978 poison = present_in_ob_by_name (FORCE, "confusion", tmp);
979 if (poison)
980 {
981 success = 1;
982 new_draw_info (NDI_UNIQUE, 0, tmp, "Your mind feels clearer");
983 poison->duration = 1;
984 }
985 }
986
987 if (spell->attacktype & AT_BLIND)
988 {
989 at = archetype::find ("blindness");
990 poison = present_arch_in_ob (at, tmp);
991 if (poison)
992 {
993 success = 1;
994 new_draw_info (NDI_UNIQUE, 0, tmp, "Your vision begins to return.");
995 poison->stats.food = 1;
996 }
997 }
998
999 if (spell->last_sp && tmp->stats.sp < tmp->stats.maxsp)
1000 {
1001 tmp->stats.sp += spell->last_sp;
1002 if (tmp->stats.sp > tmp->stats.maxsp)
1003 tmp->stats.sp = tmp->stats.maxsp;
1004 success = 1;
1005 new_draw_info (NDI_UNIQUE, 0, tmp, "Magical energy surges through your body!");
1006 }
1007
1008 if (spell->last_grace && tmp->stats.grace < tmp->stats.maxgrace)
1009 {
1010 tmp->stats.grace += spell->last_grace;
1011 if (tmp->stats.grace > tmp->stats.maxgrace)
1012 tmp->stats.grace = tmp->stats.maxgrace;
1013 success = 1;
1014 new_draw_info (NDI_UNIQUE, 0, tmp, "You feel redeemed with your god!");
1015 }
1016
1017 if (spell->stats.food && tmp->stats.food < 999)
1018 {
1019 tmp->stats.food += spell->stats.food;
1020
1021 if (tmp->stats.food > 999)
1022 tmp->stats.food = 999;
1023
1024 success = 1;
1025 /* We could do something a bit better like the messages for healing above */
1026 new_draw_info (NDI_UNIQUE, 0, tmp, "You feel your belly fill with food");
1027 }
1028
1029 return success;
1030 }
1031
1032 /* This is used for the spells that gain stats. There are no spells
1033 * right now that icnrease wis/int/pow on a temp basis, so no
1034 * good comments for those.
1035 */
1036 static const char *const no_gain_msgs[NUM_STATS] = {
1037 "You grow no stronger.",
1038 "You grow no more agile.",
1039 "You don't feel any healthier.",
1040 "You didn't grow any more intelligent.",
1041 "You do not feel any wiser.",
1042 "You don't feel any more powerful."
1043 "You are no easier to look at.",
1044 };
1045
1046 int
1047 cast_change_ability (object *op, object *caster, object *spell_ob, int dir, int silent)
1048 {
1049 object *force = NULL;
1050 int i;
1051
1052 /* if dir = 99 op defaults to tmp, eat_special_food() requires this. */
1053 object *tmp = dir
1054 ? find_target_for_friendly_spell (op, dir)
1055 : op;
1056
1057 if (!tmp)
1058 return 0;
1059
1060 /* If we've already got a force of this type, don't add a new one. */
1061 for (object *tmp2 = tmp->inv; tmp2; tmp2 = tmp2->below)
1062 {
1063 if (tmp2->type == FORCE && tmp2->subtype == FORCE_CHANGE_ABILITY)
1064 {
1065 if (tmp2->name == spell_ob->name)
1066 {
1067 force = tmp2; /* the old effect will be "refreshed" */
1068 break;
1069 }
1070 else if (spell_ob->race && spell_ob->race == tmp2->name)
1071 {
1072 if (!silent)
1073 new_draw_info_format (NDI_UNIQUE, 0, op, "You can not cast %s while %s is in effect", &spell_ob->name, &tmp2->name_pl);
1074 return 0;
1075 }
1076 }
1077 }
1078 if (force == NULL)
1079 {
1080 force = get_archetype (FORCE_NAME);
1081 force->subtype = FORCE_CHANGE_ABILITY;
1082 if (spell_ob->race)
1083 force->name = spell_ob->race;
1084 else
1085 force->name = spell_ob->name;
1086 force->name_pl = spell_ob->name;
1087 new_draw_info (NDI_UNIQUE, 0, op, "You create an aura of magical force.");
1088
1089 }
1090 else
1091 {
1092 int duration;
1093
1094 duration = spell_ob->duration + SP_level_duration_adjust (caster, spell_ob) * 50;
1095 if (duration > force->duration)
1096 {
1097 force->duration = duration;
1098 new_draw_info (NDI_UNIQUE, 0, op, "You recast the spell while in effect.");
1099 }
1100 else
1101 {
1102 new_draw_info (NDI_UNIQUE, 0, op, "Recasting the spell had no effect.");
1103 }
1104
1105 return 1;
1106 }
1107
1108 force->duration = spell_ob->duration + SP_level_duration_adjust (caster, spell_ob) * 50;
1109 force->speed = 1.0;
1110 force->speed_left = -1.0;
1111 SET_FLAG (force, FLAG_APPLIED);
1112
1113 /* Now start processing the effects. First, protections */
1114 for (i = 0; i < NROFATTACKS; i++)
1115 {
1116 if (spell_ob->resist[i])
1117 {
1118 force->resist[i] = spell_ob->resist[i] + SP_level_dam_adjust (caster, spell_ob);
1119 if (force->resist[i] > 100)
1120 force->resist[i] = 100;
1121 }
1122 }
1123
1124 if (spell_ob->stats.hp)
1125 force->stats.hp = spell_ob->stats.hp + SP_level_dam_adjust (caster, spell_ob);
1126
1127 if (tmp->type == PLAYER)
1128 {
1129 /* Stat adjustment spells */
1130 for (i = 0; i < NUM_STATS; i++)
1131 {
1132 if (sint8 stat = spell_ob->stats.stat (i))
1133 {
1134 sint8 sm = 0;
1135 for (sint8 k = 0; k < stat; k++)
1136 sm += rndm (1, 3);
1137
1138 if (tmp->stats.stat (i) + sm > 15 + 5 * stat)
1139 sm = max (0, (15 + 5 * stat) - tmp->stats.stat (i));
1140
1141 force->stats.stat (i) = sm;
1142
1143 if (!sm)
1144 new_draw_info (NDI_UNIQUE, 0, op, no_gain_msgs[i]);
1145 }
1146 }
1147 }
1148
1149 force->move_type = spell_ob->move_type;
1150
1151 if (QUERY_FLAG (spell_ob, FLAG_SEE_IN_DARK))
1152 SET_FLAG (force, FLAG_SEE_IN_DARK);
1153
1154 if (QUERY_FLAG (spell_ob, FLAG_XRAYS))
1155 SET_FLAG (force, FLAG_XRAYS);
1156
1157 /* Haste/bonus speed */
1158 if (spell_ob->stats.exp)
1159 {
1160 if (op->speed > 0.5f)
1161 force->stats.exp = (sint64) ((float) spell_ob->stats.exp / (op->speed + 0.5f));
1162 else
1163 force->stats.exp = spell_ob->stats.exp;
1164 }
1165
1166 force->stats.wc = spell_ob->stats.wc;
1167 force->stats.ac = spell_ob->stats.ac;
1168 force->attacktype = spell_ob->attacktype;
1169
1170 insert_ob_in_ob (force, tmp);
1171 change_abil (tmp, force); /* Mostly to display any messages */
1172 tmp->update_stats ();
1173
1174 return 1;
1175 }
1176
1177 /* This used to be part of cast_change_ability, but it really didn't make
1178 * a lot of sense, since most of the values it derives are from the god
1179 * of the caster.
1180 */
1181 int
1182 cast_bless (object *op, object *caster, object *spell_ob, int dir)
1183 {
1184 int i;
1185 object *god = find_god (determine_god (op)), *tmp2, *force = NULL, *tmp;
1186
1187 /* if dir = 99 op defaults to tmp, eat_special_food() requires this. */
1188 if (dir != 0)
1189 {
1190 tmp = find_target_for_friendly_spell (op, dir);
1191 }
1192 else
1193 {
1194 tmp = op;
1195 }
1196
1197 /* If we've already got a force of this type, don't add a new one. */
1198 for (tmp2 = tmp->inv; tmp2 != NULL; tmp2 = tmp2->below)
1199 {
1200 if (tmp2->type == FORCE && tmp2->subtype == FORCE_CHANGE_ABILITY)
1201 {
1202 if (tmp2->name == spell_ob->name)
1203 {
1204 force = tmp2; /* the old effect will be "refreshed" */
1205 break;
1206 }
1207 else if (spell_ob->race && spell_ob->race == tmp2->name)
1208 {
1209 new_draw_info_format (NDI_UNIQUE, 0, op, "You can not cast %s while %s is in effect", &spell_ob->name, &tmp2->name_pl);
1210 return 0;
1211 }
1212 }
1213 }
1214 if (force == NULL)
1215 {
1216 force = get_archetype (FORCE_NAME);
1217 force->subtype = FORCE_CHANGE_ABILITY;
1218 if (spell_ob->race)
1219 force->name = spell_ob->race;
1220 else
1221 force->name = spell_ob->name;
1222 force->name_pl = spell_ob->name;
1223 new_draw_info (NDI_UNIQUE, 0, op, "You create an aura of magical force.");
1224 }
1225 else
1226 {
1227 int duration;
1228
1229 duration = spell_ob->duration + SP_level_duration_adjust (caster, spell_ob) * 50;
1230 if (duration > force->duration)
1231 {
1232 force->duration = duration;
1233 new_draw_info (NDI_UNIQUE, 0, op, "You recast the spell while in effect.");
1234 }
1235 else
1236 {
1237 new_draw_info (NDI_UNIQUE, 0, op, "Recasting the spell had no effect.");
1238 }
1239 return 0;
1240 }
1241 force->duration = spell_ob->duration + SP_level_duration_adjust (caster, spell_ob) * 50;
1242 force->speed = 1.0;
1243 force->speed_left = -1.0;
1244 SET_FLAG (force, FLAG_APPLIED);
1245
1246 if (!god)
1247 {
1248 new_draw_info (NDI_UNIQUE, 0, op, "Your blessing seems empty.");
1249 }
1250 else
1251 {
1252 /* Only give out good benefits, and put a max on it */
1253 for (i = 0; i < NROFATTACKS; i++)
1254 {
1255 if (god->resist[i] > 0)
1256 {
1257 force->resist[i] = MIN (god->resist[i], spell_ob->resist[ATNR_GODPOWER]);
1258 }
1259 }
1260 force->path_attuned |= god->path_attuned;
1261
1262 if (spell_ob->attacktype)
1263 force->slaying = god->slaying;
1264
1265 if (tmp != op)
1266 {
1267 new_draw_info_format (NDI_UNIQUE, 0, op, "You bless %s.", &tmp->name);
1268 new_draw_info_format (NDI_UNIQUE, 0, tmp, "%s blessed you.", &op->name);
1269 }
1270 else
1271 {
1272 new_draw_info_format (NDI_UNIQUE, 0, tmp, "You are blessed by %s!", &god->name);
1273 }
1274
1275 }
1276 force->stats.wc = spell_ob->stats.wc;
1277 force->stats.ac = spell_ob->stats.ac;
1278
1279 change_abil (tmp, force); /* Mostly to display any messages */
1280 insert_ob_in_ob (force, tmp);
1281 tmp->update_stats ();
1282 return 1;
1283 }
1284
1285 /* Alchemy code by Mark Wedel
1286 *
1287 * This code adds a new spell, called alchemy. Alchemy will turn
1288 * objects to pyrite ("false gold"), henceforth called gold nuggets.
1289 *
1290 * The value of the gold nuggets being about 90% of that of the item
1291 * itself. It uses the value of the object before charisma adjustments,
1292 * because the nuggets themselves will be will be adjusted by charisma
1293 * when sold.
1294 *
1295 * There is also a chance (1:30) that you will get nothing at all
1296 * for the object. There is also a maximum weight that will be
1297 * alchemised.
1298 */
1299 static void
1300 alchemy_object (object *obj, uint64 &total_value, int &total_weight)
1301 {
1302 uint64 value = query_cost (obj, NULL, F_TRUE);
1303
1304 /* Give third price when we alchemy money (This should hopefully
1305 * make it so that it isn't worth it to alchemy money, sell
1306 * the nuggets, alchemy the gold from that, etc.
1307 * Otherwise, give 9 silver on the gold for other objects,
1308 * so that it would still be more affordable to haul
1309 * the stuff back to town.
1310 */
1311 if (QUERY_FLAG (obj, FLAG_UNPAID))
1312 value = 0;
1313 else if (obj->type == MONEY || obj->type == GEM)
1314 value /= 3;
1315 else
1316 value = value * 9 / 10;
1317
1318 if (obj->value > 0 && rndm (0, 29))
1319 total_value += value;
1320
1321 total_weight += obj->total_weight ();
1322
1323 obj->destroy ();
1324 }
1325
1326 int
1327 alchemy (object *op, object *caster, object *spell_ob)
1328 {
1329 if (op->type != PLAYER)
1330 return 0;
1331
1332 archetype *nugget[3];
1333
1334 nugget[0] = archetype::find ("pyrite3");
1335 nugget[1] = archetype::find ("pyrite2");
1336 nugget[2] = archetype::find ("pyrite");
1337
1338 /* Put a maximum weight of items that can be alchemised. Limits the power
1339 * some, and also prevents people from alchemising every table/chair/clock
1340 * in sight
1341 */
1342 int duration = spell_ob->duration + SP_level_duration_adjust (caster, spell_ob);
1343 int weight_max = duration * 1000;
1344 uint64 value_max = duration * 1000;
1345
1346 int weight = 0;
1347
1348 for (int y = op->y - 1; y <= op->y + 1; y++)
1349 {
1350 for (int x = op->x - 1; x <= op->x + 1; x++)
1351 {
1352 uint64 value = 0;
1353
1354 sint16 nx = x;
1355 sint16 ny = y;
1356
1357 maptile *mp = op->map;
1358
1359 int mflags = get_map_flags (mp, &mp, nx, ny, &nx, &ny);
1360
1361 if (mflags & (P_OUT_OF_MAP | P_NO_MAGIC))
1362 continue;
1363
1364 /* Treat alchemy a little differently - most spell effects
1365 * use fly as the movement type - for alchemy, consider it
1366 * ground level effect.
1367 */
1368 if (GET_MAP_MOVE_BLOCK (mp, nx, ny) & MOVE_WALK)
1369 continue;
1370
1371 for (object *next, *tmp = mp->at (nx, ny).bot; tmp; tmp = next)
1372 {
1373 next = tmp->above;
1374
1375 if (tmp->weight > 0 && !QUERY_FLAG (tmp, FLAG_NO_PICK) &&
1376 !QUERY_FLAG (tmp, FLAG_ALIVE) && !QUERY_FLAG (tmp, FLAG_IS_CAULDRON))
1377 {
1378 if (tmp->inv)
1379 {
1380 object *next1, *tmp1;
1381
1382 for (tmp1 = tmp->inv; tmp1; tmp1 = next1)
1383 {
1384 next1 = tmp1->below;
1385 if (tmp1->weight > 0 && !QUERY_FLAG (tmp1, FLAG_NO_PICK) &&
1386 !QUERY_FLAG (tmp1, FLAG_ALIVE) && !QUERY_FLAG (tmp1, FLAG_IS_CAULDRON))
1387 alchemy_object (tmp1, value, weight);
1388 }
1389 }
1390
1391 alchemy_object (tmp, value, weight);
1392
1393 if (weight > weight_max)
1394 break;
1395 }
1396 }
1397
1398 value -= rndm (value >> 4);
1399 value = min (value, value_max);
1400
1401 for (int i = 0; i < sizeof (nugget) / sizeof (nugget [0]); ++i)
1402 if (int nrof = value / nugget [i]->value)
1403 {
1404 value -= nrof * nugget[i]->value;
1405
1406 object *tmp = arch_to_object (nugget[i]);
1407 tmp->nrof = nrof;
1408 tmp->flag [FLAG_IDENTIFIED] = true;
1409 op->map->insert (tmp, x, y, op, 0);
1410 }
1411
1412 if (weight > weight_max)
1413 goto bailout;
1414 }
1415 }
1416
1417 bailout:
1418 return 1;
1419 }
1420
1421
1422 /* This function removes the cursed/damned status on equipped
1423 * items.
1424 */
1425 int
1426 remove_curse (object *op, object *caster, object *spell)
1427 {
1428 object *tmp;
1429 int success = 0, was_one = 0;
1430
1431 for (tmp = op->inv; tmp; tmp = tmp->below)
1432 if (QUERY_FLAG (tmp, FLAG_APPLIED) &&
1433 ((QUERY_FLAG (tmp, FLAG_CURSED) && QUERY_FLAG (spell, FLAG_CURSED)) ||
1434 (QUERY_FLAG (tmp, FLAG_DAMNED) && QUERY_FLAG (spell, FLAG_DAMNED))))
1435 {
1436 was_one++;
1437 if (tmp->level <= caster_level (caster, spell))
1438 {
1439 success++;
1440 if (QUERY_FLAG (spell, FLAG_DAMNED))
1441 CLEAR_FLAG (tmp, FLAG_DAMNED);
1442
1443 CLEAR_FLAG (tmp, FLAG_CURSED);
1444 CLEAR_FLAG (tmp, FLAG_KNOWN_CURSED);
1445 tmp->value = 0; /* Still can't sell it */
1446 if (op->type == PLAYER)
1447 esrv_send_item (op, tmp);
1448 }
1449 }
1450
1451 if (op->type == PLAYER)
1452 {
1453 if (success)
1454 new_draw_info (NDI_UNIQUE, 0, op, "You feel like some of your items are looser now.");
1455 else
1456 {
1457 if (was_one)
1458 new_draw_info (NDI_UNIQUE, 0, op, "You failed to remove the curse.");
1459 else
1460 new_draw_info (NDI_UNIQUE, 0, op, "You are not using any cursed items.");
1461 }
1462 }
1463
1464 return success;
1465 }
1466
1467 /* Identifies objects in the players inventory/on the ground */
1468 int
1469 cast_identify (object *op, object *caster, object *spell)
1470 {
1471 dynbuf_text buf;
1472 object *tmp;
1473
1474 int num_ident = spell->stats.dam + SP_level_dam_adjust (caster, spell);
1475
1476 if (num_ident < 1)
1477 num_ident = 1;
1478
1479 for (tmp = op->inv; tmp; tmp = tmp->below)
1480 {
1481 if (!QUERY_FLAG (tmp, FLAG_IDENTIFIED) && !tmp->invisible && need_identify (tmp))
1482 {
1483 identify (tmp);
1484
1485 if (op->type == PLAYER)
1486 {
1487 buf.printf ("You identified: %s.\n\n", long_desc (tmp, op));
1488
1489 if (tmp->msg)
1490 buf << "The item has a story:\n\n" << tmp->msg << "\n\n";
1491 }
1492
1493 num_ident--;
1494 if (!num_ident)
1495 break;
1496 }
1497 }
1498
1499 /* If all the power of the spell has been used up, don't go and identify
1500 * stuff on the floor. Only identify stuff on the floor if the spell
1501 * was not fully used.
1502 */
1503 if (num_ident)
1504 {
1505 for (tmp = GET_MAP_OB (op->map, op->x, op->y); tmp; tmp = tmp->above)
1506 if (!QUERY_FLAG (tmp, FLAG_IDENTIFIED) && !tmp->invisible && need_identify (tmp))
1507 {
1508 identify (tmp);
1509
1510 if (op->type == PLAYER)
1511 {
1512 buf.printf ("On the ground you identified: %s.\n\n", long_desc (tmp, op));
1513
1514 if (tmp->msg)
1515 buf << "The item has a story:\n\n" << tmp->msg << "\n\n";
1516
1517 esrv_send_item (op, tmp);
1518 }
1519
1520 num_ident--;
1521 if (!num_ident)
1522 break;
1523 }
1524 }
1525
1526 if (buf.empty ())
1527 {
1528 op->failmsg ("You can't reach anything unidentified.");
1529 return 0;
1530 }
1531 else
1532 {
1533 if (op->contr)
1534 op->contr->infobox (MSG_CHANNEL ("identify"), buf);
1535
1536 spell_effect (spell, op->x, op->y, op->map, op);
1537 return 1;
1538 }
1539 }
1540
1541 int
1542 cast_detection (object *op, object *caster, object *spell, object *skill)
1543 {
1544 object *tmp, *last, *god, *detect;
1545 int done_one, range, mflags, floor, level;
1546 sint16 x, y, nx, ny;
1547 maptile *m;
1548
1549 /* We precompute some values here so that we don't have to keep
1550 * doing it over and over again.
1551 */
1552 god = find_god (determine_god (op));
1553 level = caster_level (caster, spell);
1554 range = spell->range + SP_level_range_adjust (caster, spell);
1555
1556 if (!skill)
1557 skill = caster;
1558
1559 for (x = op->x - range; x <= op->x + range; x++)
1560 for (y = op->y - range; y <= op->y + range; y++)
1561 {
1562 m = op->map;
1563 mflags = get_map_flags (m, &m, x, y, &nx, &ny);
1564 if (mflags & P_OUT_OF_MAP)
1565 continue;
1566
1567 /* For most of the detections, we only detect objects above the
1568 * floor. But this is not true for show invisible.
1569 * Basically, we just go and find the top object and work
1570 * down - that is easier than working up.
1571 */
1572
1573 for (last = NULL, tmp = GET_MAP_OB (m, nx, ny); tmp; tmp = tmp->above)
1574 last = tmp;
1575
1576 /* Shouldn't happen, but if there are no objects on a space, this
1577 * would happen.
1578 */
1579 if (!last)
1580 continue;
1581
1582 done_one = 0;
1583 floor = 0;
1584 detect = NULL;
1585 for (tmp = last; tmp; tmp = tmp->below)
1586 {
1587 /* show invisible */
1588 if (QUERY_FLAG (spell, FLAG_MAKE_INVIS) &&
1589 /* Might there be other objects that we can make visible? */
1590 (tmp->invisible && (QUERY_FLAG (tmp, FLAG_MONSTER) ||
1591 (tmp->type == PLAYER && !QUERY_FLAG (tmp, FLAG_WIZ)) ||
1592 tmp->type == CF_HANDLE ||
1593 tmp->type == TRAPDOOR || tmp->type == EXIT || tmp->type == HOLE ||
1594 tmp->type == BUTTON || tmp->type == TELEPORTER ||
1595 tmp->type == GATE || tmp->type == LOCKED_DOOR ||
1596 tmp->type == WEAPON || tmp->type == ALTAR || tmp->type == SIGN ||
1597 tmp->type == TRIGGER_PEDESTAL || tmp->type == SPECIAL_KEY ||
1598 tmp->type == TREASURE || tmp->type == BOOK || tmp->type == HOLY_ALTAR)))
1599 {
1600 if (random_roll (0, skill->level - 1, op, PREFER_HIGH) > level / 4)
1601 {
1602 tmp->invisible = 0;
1603 done_one = 1;
1604 }
1605 }
1606
1607 if (QUERY_FLAG (tmp, FLAG_IS_FLOOR))
1608 floor = 1;
1609
1610 /* All detections below this point don't descend beneath the floor,
1611 * so just continue on. We could be clever and look at the type of
1612 * detection to completely break out if we don't care about objects beneath
1613 * the floor, but once we get to the floor, not likely a very big issue anyways.
1614 */
1615 if (floor)
1616 continue;
1617
1618 /* I had thought about making detect magic and detect curse
1619 * show the flash the magic item like it does for detect monster.
1620 * however, if the object is within sight, this would then make it
1621 * difficult to see what object is magical/cursed, so the
1622 * effect wouldn't be as apparant.
1623 */
1624
1625 /* detect magic */
1626 if (QUERY_FLAG (spell, FLAG_KNOWN_MAGICAL) &&
1627 !QUERY_FLAG (tmp, FLAG_KNOWN_MAGICAL) && !QUERY_FLAG (tmp, FLAG_IDENTIFIED) && is_magical (tmp))
1628 {
1629 SET_FLAG (tmp, FLAG_KNOWN_MAGICAL);
1630 /* make runes more visibile */
1631 if (tmp->type == RUNE && tmp->attacktype & AT_MAGIC)
1632 tmp->stats.Cha /= 4;
1633 done_one = 1;
1634 }
1635 /* detect monster */
1636 if (QUERY_FLAG (spell, FLAG_MONSTER) && (QUERY_FLAG (tmp, FLAG_MONSTER) || tmp->type == PLAYER))
1637 {
1638 done_one = 2;
1639 if (!detect)
1640 detect = tmp;
1641 }
1642 /* Basically, if race is set in the spell, then the creatures race must
1643 * match that. if the spell race is set to GOD, then the gods opposing
1644 * race must match.
1645 */
1646 if (spell->race && QUERY_FLAG (tmp, FLAG_MONSTER) && tmp->race &&
1647 ((!strcmp (spell->race, "GOD") && god && god->slaying && strstr (god->slaying, tmp->race)) ||
1648 (strstr (spell->race, tmp->race))))
1649 {
1650 done_one = 2;
1651 if (!detect)
1652 detect = tmp;
1653 }
1654 if (QUERY_FLAG (spell, FLAG_KNOWN_CURSED) && !QUERY_FLAG (tmp, FLAG_KNOWN_CURSED) &&
1655 (QUERY_FLAG (tmp, FLAG_CURSED) || QUERY_FLAG (tmp, FLAG_DAMNED)))
1656 {
1657 SET_FLAG (tmp, FLAG_KNOWN_CURSED);
1658 done_one = 1;
1659 }
1660 } /* for stack of objects on this space */
1661
1662 /* Code here puts an effect of the spell on the space, so you can see
1663 * where the magic is.
1664 */
1665 if (done_one)
1666 {
1667 object *detect_ob = arch_to_object (spell->other_arch);
1668
1669 /* if this is set, we want to copy the face */
1670 if (done_one == 2 && detect)
1671 {
1672 detect_ob->face = detect->face;
1673 detect_ob->animation_id = detect->animation_id;
1674 detect_ob->anim_speed = detect->anim_speed;
1675 detect_ob->last_anim = 0;
1676 /* by default, the detect_ob is already animated */
1677 if (!QUERY_FLAG (detect, FLAG_ANIMATE))
1678 CLEAR_FLAG (detect_ob, FLAG_ANIMATE);
1679 }
1680
1681 m->insert (detect_ob, nx, ny, op);
1682 }
1683 } /* for processing the surrounding spaces */
1684
1685
1686 /* Now process objects in the players inventory if detect curse or magic */
1687 if (QUERY_FLAG (spell, FLAG_KNOWN_CURSED) || QUERY_FLAG (spell, FLAG_KNOWN_MAGICAL))
1688 {
1689 done_one = 0;
1690 for (tmp = op->inv; tmp; tmp = tmp->below)
1691 {
1692 if (!tmp->invisible && !QUERY_FLAG (tmp, FLAG_IDENTIFIED))
1693 {
1694 if (QUERY_FLAG (spell, FLAG_KNOWN_MAGICAL) && is_magical (tmp) && !QUERY_FLAG (tmp, FLAG_KNOWN_MAGICAL))
1695 {
1696 SET_FLAG (tmp, FLAG_KNOWN_MAGICAL);
1697 if (op->type == PLAYER)
1698 esrv_send_item (op, tmp);
1699 }
1700 if (QUERY_FLAG (spell, FLAG_KNOWN_CURSED) && !QUERY_FLAG (tmp, FLAG_KNOWN_CURSED) &&
1701 (QUERY_FLAG (tmp, FLAG_CURSED) || QUERY_FLAG (tmp, FLAG_DAMNED)))
1702 {
1703 SET_FLAG (tmp, FLAG_KNOWN_CURSED);
1704 if (op->type == PLAYER)
1705 esrv_send_item (op, tmp);
1706 }
1707 } /* if item is not identified */
1708 } /* for the players inventory */
1709 } /* if detect magic/curse and object is a player */
1710 return 1;
1711 }
1712
1713
1714 /**
1715 * Checks if victim has overcharged mana. caster_level is the caster's (skill)
1716 * level whos spell did cause the overcharge.
1717 */
1718 static void
1719 charge_mana_effect (object *victim, int caster_level)
1720 {
1721
1722 /* Prevent explosions for objects without mana. Without this check, doors
1723 * will explode, too.
1724 */
1725 if (victim->stats.maxsp <= 0)
1726 return;
1727
1728 new_draw_info (NDI_UNIQUE, 0, victim, "You feel energy course through you.");
1729
1730 if (victim->stats.sp >= victim->stats.maxsp * 2)
1731 {
1732 object *tmp;
1733
1734 new_draw_info (NDI_UNIQUE, 0, victim, "Your head explodes!");
1735
1736 /* Explodes a fireball centered at player */
1737 tmp = get_archetype (EXPLODING_FIREBALL);
1738 tmp->dam_modifier = random_roll (1, caster_level, victim, PREFER_LOW) / 5 + 1;
1739 tmp->stats.maxhp = random_roll (1, caster_level, victim, PREFER_LOW) / 10 + 2;
1740
1741 tmp->insert_at (victim);
1742 victim->stats.sp = 2 * victim->stats.maxsp;
1743 }
1744 else if (victim->stats.sp >= victim->stats.maxsp * 1.88)
1745 new_draw_info (NDI_UNIQUE, NDI_ORANGE, victim, "You feel like your head is going to explode.");
1746 else if (victim->stats.sp >= victim->stats.maxsp * 1.66)
1747 new_draw_info (NDI_UNIQUE, 0, victim, "You get a splitting headache!");
1748 else if (victim->stats.sp >= victim->stats.maxsp * 1.5)
1749 {
1750 new_draw_info (NDI_UNIQUE, 0, victim, "Chaos fills your world.");
1751 confuse_player (victim, victim, 99);
1752 }
1753 else if (victim->stats.sp >= victim->stats.maxsp * 1.25)
1754 new_draw_info (NDI_UNIQUE, 0, victim, "You start hearing voices.");
1755 }
1756
1757 /* cast_transfer
1758 * This spell transfers sp from the player to another person.
1759 * We let the target go above their normal maximum SP.
1760 */
1761
1762 int
1763 cast_transfer (object *op, object *caster, object *spell, int dir)
1764 {
1765 object *plyr = NULL;
1766 sint16 x, y;
1767 maptile *m;
1768 int mflags;
1769
1770 m = op->map;
1771 x = op->x + freearr_x[dir];
1772 y = op->y + freearr_y[dir];
1773
1774 mflags = get_map_flags (m, &m, x, y, &x, &y);
1775
1776 if (!(mflags & P_OUT_OF_MAP) && mflags & P_IS_ALIVE)
1777 {
1778 for (plyr = GET_MAP_OB (m, x, y); plyr != NULL; plyr = plyr->above)
1779 if (plyr != op && QUERY_FLAG (plyr, FLAG_ALIVE))
1780 break;
1781 }
1782
1783
1784 /* If we did not find a player in the specified direction, transfer
1785 * to anyone on top of us. This is used for the rune of transference mostly.
1786 */
1787 if (plyr == NULL)
1788 for (plyr = GET_MAP_OB (op->map, op->x, op->y); plyr != NULL; plyr = plyr->above)
1789 if (plyr != op && QUERY_FLAG (plyr, FLAG_ALIVE))
1790 break;
1791
1792 if (!plyr)
1793 {
1794 new_draw_info (NDI_BLACK, 0, op, "There is no one there.");
1795 return 0;
1796 }
1797 /* give sp */
1798 if (spell->stats.dam > 0)
1799 {
1800 plyr->stats.sp += spell->stats.dam + SP_level_dam_adjust (caster, spell);
1801 charge_mana_effect (plyr, caster_level (caster, spell));
1802 return 1;
1803 }
1804 /* suck sp away. Can't suck sp from yourself */
1805 else if (op != plyr)
1806 {
1807 /* old dragin magic used floats. easier to just use ints and divide by 100 */
1808
1809 int rate = -spell->stats.dam + SP_level_dam_adjust (caster, spell), sucked;
1810
1811 if (rate > 95)
1812 rate = 95;
1813
1814 sucked = (plyr->stats.sp * rate) / 100;
1815 plyr->stats.sp -= sucked;
1816 if (QUERY_FLAG (op, FLAG_ALIVE))
1817 {
1818 /* Player doesn't get full credit */
1819 sucked = (sucked * rate) / 100;
1820 op->stats.sp += sucked;
1821 if (sucked > 0)
1822 {
1823 charge_mana_effect (op, caster_level (caster, spell));
1824 }
1825 }
1826 return 1;
1827 }
1828 return 0;
1829 }
1830
1831
1832 /* counterspell: nullifies spell effects.
1833 * op is the counterspell object, dir is the direction
1834 * it was cast in.
1835 * Basically, if the object has a magic attacktype,
1836 * this may nullify it.
1837 */
1838 void
1839 counterspell (object *op, int dir)
1840 {
1841 object *tmp, *head, *next;
1842 int mflags;
1843 maptile *m;
1844 sint16 sx, sy;
1845
1846 sx = op->x + freearr_x[dir];
1847 sy = op->y + freearr_y[dir];
1848 m = op->map;
1849 mflags = get_map_flags (m, &m, sx, sy, &sx, &sy);
1850 if (mflags & P_OUT_OF_MAP)
1851 return;
1852
1853 for (tmp = GET_MAP_OB (m, sx, sy); tmp != NULL; tmp = next)
1854 {
1855 next = tmp->above;
1856
1857 /* Need to look at the head object - otherwise, if tmp
1858 * points to a monster, we don't have all the necessary
1859 * info for it.
1860 */
1861 if (tmp->head)
1862 head = tmp->head;
1863 else
1864 head = tmp;
1865
1866 /* don't attack our own spells */
1867 if (tmp->owner && tmp->owner == op->owner)
1868 continue;
1869
1870 /* Basically, if the object is magical and not counterspell,
1871 * we will more or less remove the object. Don't counterspell
1872 * monsters either.
1873 */
1874
1875 if (head->attacktype & AT_MAGIC
1876 && !(head->attacktype & AT_COUNTERSPELL)
1877 && !QUERY_FLAG (head, FLAG_MONSTER)
1878 && (op->level > head->level))
1879 head->destroy ();
1880 else
1881 switch (head->type)
1882 {
1883 case SPELL_EFFECT:
1884 // XXX: Don't affect floor spelleffects. See also XXX comment
1885 // about sanctuary in spell_util.C
1886 if (QUERY_FLAG (tmp, FLAG_IS_FLOOR))
1887 continue;
1888
1889 if (op->level > head->level)
1890 head->destroy ();
1891
1892 break;
1893
1894 /* I really don't get this rune code that much - that
1895 * random chance seems really low.
1896 */
1897 case RUNE:
1898 if (rndm (0, 149) == 0)
1899 {
1900 head->stats.hp--; /* weaken the rune */
1901 if (!head->stats.hp)
1902 head->destroy ();
1903 }
1904 break;
1905 }
1906 }
1907 }
1908
1909
1910
1911 /* cast_consecrate() - a spell to make an altar your god's */
1912 int
1913 cast_consecrate (object *op, object *caster, object *spell)
1914 {
1915 char buf[MAX_BUF];
1916
1917 object *tmp, *god = find_god (determine_god (op));
1918
1919 if (!god)
1920 {
1921 new_draw_info (NDI_UNIQUE, 0, op, "You can't consecrate anything if you don't worship a god!");
1922 return 0;
1923 }
1924
1925 for (tmp = op->below; tmp; tmp = tmp->below)
1926 {
1927 if (QUERY_FLAG (tmp, FLAG_IS_FLOOR))
1928 break;
1929 if (tmp->type == HOLY_ALTAR)
1930 {
1931
1932 if (tmp->level > caster_level (caster, spell))
1933 {
1934 new_draw_info_format (NDI_UNIQUE, 0, op, "You are not powerful enough to reconsecrate the %s", &tmp->name);
1935 return 0;
1936 }
1937 else
1938 {
1939 /* If we got here, we are consecrating an altar */
1940 sprintf (buf, "Altar of %s", &god->name);
1941 tmp->name = buf;
1942 tmp->level = caster_level (caster, spell);
1943 tmp->other_arch = god->arch;
1944 if (op->type == PLAYER)
1945 esrv_update_item (UPD_NAME, op, tmp);
1946 new_draw_info_format (NDI_UNIQUE, 0, op, "You consecrated the altar to %s!", &god->name);
1947 return 1;
1948 }
1949 }
1950 }
1951 new_draw_info (NDI_UNIQUE, 0, op, "You are not standing over an altar!");
1952 return 0;
1953 }
1954
1955 /* animate_weapon -
1956 * Generalization of staff_to_snake. Makes a golem out of the caster's weapon.
1957 * The golem is based on the archetype specified, modified by the caster's level
1958 * and the attributes of the weapon. The weapon is inserted in the golem's
1959 * inventory so that it falls to the ground when the golem dies.
1960 * This code was very odd - code early on would only let players use the spell,
1961 * yet the code wass full of player checks. I've presumed that the code
1962 * that only let players use it was correct, and removed all the other
1963 * player checks. MSW 2003-01-06
1964 */
1965 int
1966 animate_weapon (object *op, object *caster, object *spell, int dir)
1967 {
1968 object *weapon, *tmp;
1969 char buf[MAX_BUF];
1970 int a, i;
1971 sint16 x, y;
1972 maptile *m;
1973
1974 if (!spell->other_arch)
1975 {
1976 new_draw_info (NDI_UNIQUE, 0, op, "Oops, program error!");
1977 LOG (llevError, "animate_weapon failed: spell %s missing other_arch!\n", &spell->name);
1978 return 0;
1979 }
1980 /* exit if it's not a player using this spell. */
1981 if (op->type != PLAYER)
1982 return 0;
1983
1984 /* if player already has a golem, abort */
1985 if (object *golem = op->contr->golem)
1986 {
1987 control_golem (golem, dir);
1988 return 0;
1989 }
1990
1991 /* if no direction specified, pick one */
1992 if (!dir)
1993 dir = find_free_spot (NULL, op->map, op->x, op->y, 1, 9);
1994
1995 m = op->map;
1996 x = op->x + freearr_x[dir];
1997 y = op->y + freearr_y[dir];
1998
1999 /* if there's no place to put the golem, abort */
2000 if ((dir == -1) || (get_map_flags (m, &m, x, y, &x, &y) & P_OUT_OF_MAP) ||
2001 ((spell->other_arch->move_type & GET_MAP_MOVE_BLOCK (m, x, y)) == spell->other_arch->move_type))
2002 {
2003 new_draw_info (NDI_UNIQUE, 0, op, "There is something in the way.");
2004 return 0;
2005 }
2006
2007 /* Use the weapon marked by the player. */
2008 weapon = find_marked_object (op);
2009
2010 if (!weapon)
2011 {
2012 new_draw_info (NDI_BLACK, 0, op, "You must mark a weapon to use with this spell!");
2013 return 0;
2014 }
2015 if (spell->race && strcmp (weapon->arch->archname, spell->race))
2016 {
2017 new_draw_info (NDI_UNIQUE, 0, op, "The spell fails to transform your weapon.");
2018 return 0;
2019 }
2020 if (weapon->type != WEAPON)
2021 {
2022 new_draw_info (NDI_UNIQUE, 0, op, "You need to wield a weapon to animate it.");
2023 return 0;
2024 }
2025 if (QUERY_FLAG (weapon, FLAG_APPLIED))
2026 {
2027 new_draw_info_format (NDI_BLACK, 0, op, "You need to unequip %s before using it in this spell", query_name (weapon));
2028 return 0;
2029 }
2030
2031 if (weapon->nrof > 1)
2032 {
2033 tmp = get_split_ob (weapon, 1);
2034 esrv_send_item (op, weapon);
2035 weapon = tmp;
2036 }
2037
2038 /* create the golem object */
2039 tmp = arch_to_object (spell->other_arch);
2040
2041 /* if animated by a player, give the player control of the golem */
2042 CLEAR_FLAG (tmp, FLAG_MONSTER);
2043 tmp->stats.exp = 0;
2044 add_friendly_object (tmp);
2045 tmp->type = GOLEM;
2046 tmp->set_owner (op);
2047 op->contr->golem = tmp;
2048 set_spell_skill (op, caster, spell, tmp);
2049
2050 /* Give the weapon to the golem now. A bit of a hack to check the
2051 * removed flag - it should only be set if get_split_object was
2052 * used above.
2053 */
2054 if (!QUERY_FLAG (weapon, FLAG_REMOVED))
2055 weapon->remove ();
2056
2057 insert_ob_in_ob (weapon, tmp);
2058 esrv_send_item (op, weapon);
2059 /* To do everything necessary to let a golem use the weapon is a pain,
2060 * so instead, just set it as equipped (otherwise, we need to update
2061 * body_info, skills, etc)
2062 */
2063 SET_FLAG (tmp, FLAG_USE_WEAPON);
2064 SET_FLAG (weapon, FLAG_APPLIED);
2065 tmp->update_stats ();
2066
2067 /* There used to be 'odd' code that basically seemed to take the absolute
2068 * value of the weapon->magic an use that. IMO, that doesn't make sense -
2069 * if you're using a crappy weapon, it shouldn't be as good.
2070 */
2071
2072 /* modify weapon's animated wc */
2073 tmp->stats.wc = tmp->stats.wc - SP_level_range_adjust (caster, spell) - 5 * weapon->stats.Dex - 2 * weapon->stats.Str - weapon->magic;
2074 if (tmp->stats.wc < -127)
2075 tmp->stats.wc = -127;
2076
2077 /* Modify hit points for weapon */
2078 tmp->stats.maxhp = tmp->stats.maxhp + spell->duration +
2079 SP_level_duration_adjust (caster, spell) + +8 * weapon->magic + 12 * weapon->stats.Con;
2080 if (tmp->stats.maxhp < 0)
2081 tmp->stats.maxhp = 10;
2082 tmp->stats.hp = tmp->stats.maxhp;
2083
2084 /* Modify weapon's damage */
2085 tmp->stats.dam = spell->stats.dam + SP_level_dam_adjust (caster, spell) + weapon->stats.dam + weapon->magic + 5 * weapon->stats.Str;
2086 if (tmp->stats.dam < 0)
2087 tmp->stats.dam = 127;
2088
2089
2090 /* attacktype */
2091 if (!tmp->attacktype)
2092 tmp->attacktype = AT_PHYSICAL;
2093
2094 if (materialtype_t *mt = name_to_material (op->materialname))
2095 {
2096 for (i = 0; i < NROFATTACKS; i++)
2097 tmp->resist[i] = 50 - (mt->save[i] * 5);
2098 a = mt->save[0];
2099 }
2100 else
2101 {
2102 for (i = 0; i < NROFATTACKS; i++)
2103 tmp->resist[i] = 5;
2104 a = 10;
2105 }
2106
2107 /* Set weapon's immunity */
2108 tmp->resist[ATNR_CONFUSION] = 100;
2109 tmp->resist[ATNR_POISON] = 100;
2110 tmp->resist[ATNR_SLOW] = 100;
2111 tmp->resist[ATNR_PARALYZE] = 100;
2112 tmp->resist[ATNR_TURN_UNDEAD] = 100;
2113 tmp->resist[ATNR_FEAR] = 100;
2114 tmp->resist[ATNR_DEPLETE] = 100;
2115 tmp->resist[ATNR_DEATH] = 100;
2116 tmp->resist[ATNR_BLIND] = 100;
2117
2118 /* Improve weapon's armour value according to best save vs. physical of its material */
2119
2120 if (a > 14)
2121 a = 14;
2122
2123 tmp->resist[ATNR_PHYSICAL] = 100 - (int) ((100.0 - (float) tmp->resist[ATNR_PHYSICAL]) / (30.0 - 2.0 * a));
2124
2125 /* Determine golem's speed */
2126 tmp->set_speed (min (3.33, 0.4 + 0.1 * SP_level_range_adjust (caster, spell)));
2127
2128 if (!spell->race)
2129 {
2130 sprintf (buf, "animated %s", &weapon->name);
2131 tmp->name = buf;
2132
2133 tmp->face = weapon->face;
2134 tmp->animation_id = weapon->animation_id;
2135 tmp->anim_speed = weapon->anim_speed;
2136 tmp->last_anim = weapon->last_anim;
2137 tmp->state = weapon->state;
2138 tmp->flag [FLAG_ANIMATE] = weapon->flag [FLAG_ANIMATE];
2139 }
2140
2141 /* make experience increase in proportion to the strength of the summoned creature. */
2142 tmp->stats.exp *= 1 + (MAX (spell->stats.maxgrace, spell->stats.sp) / caster_level (caster, spell));
2143
2144 tmp->speed_left = -1;
2145 tmp->direction = dir;
2146
2147 m->insert (tmp, x, y, op);
2148 return 1;
2149 }
2150
2151 /* cast_daylight() - changes the map darkness level *lower* */
2152
2153 /* cast_change_map_lightlevel: Was cast_daylight/nightfall.
2154 * This changes the light level for the entire map.
2155 */
2156
2157 int
2158 cast_change_map_lightlevel (object *op, object *caster, object *spell)
2159 {
2160 int success;
2161
2162 if (!op->map)
2163 return 0; /* shouldnt happen */
2164
2165 success = op->map->change_map_light (spell->stats.dam);
2166
2167 if (!success)
2168 {
2169 if (spell->stats.dam < 0)
2170 new_draw_info (NDI_UNIQUE, 0, op, "It can be no brighter here.");
2171 else
2172 new_draw_info (NDI_UNIQUE, 0, op, "It can be no darker here.");
2173 }
2174 return success;
2175 }
2176
2177 /* create an aura spell object and put it in the player's inventory.
2178 * as usual, op is player, caster is the object casting the spell,
2179 * spell is the spell object itself.
2180 */
2181 int
2182 create_aura (object *op, object *caster, object *spell)
2183 {
2184 int refresh = 0;
2185 object *new_aura;
2186
2187 new_aura = present_arch_in_ob (spell->other_arch, op);
2188 if (new_aura)
2189 refresh = 1;
2190 else
2191 new_aura = arch_to_object (spell->other_arch);
2192
2193 new_aura->duration = spell->duration + 10 * SP_level_duration_adjust (caster, spell);
2194
2195 new_aura->stats.dam = spell->stats.dam + SP_level_dam_adjust (caster, spell);
2196
2197 set_spell_skill (op, caster, spell, new_aura);
2198 new_aura->attacktype = spell->attacktype;
2199
2200 new_aura->level = caster_level (caster, spell);
2201
2202 if (refresh)
2203 new_draw_info (NDI_UNIQUE, 0, op, "You recast the spell while in effect.");
2204 else
2205 new_draw_info (NDI_UNIQUE, 0, op, "You create an aura of magical force.");
2206
2207 insert_ob_in_ob (new_aura, op);
2208 new_aura->set_owner (op);
2209
2210 return 1;
2211 }
2212
2213 /* move aura function. An aura is a part of someone's inventory,
2214 * which he carries with him, but which acts on the map immediately
2215 * around him.
2216 * Aura parameters:
2217 * duration: duration counter.
2218 * attacktype: aura's attacktype
2219 * other_arch: archetype to drop where we attack
2220 */
2221 void
2222 move_aura (object *aura)
2223 {
2224 /* auras belong in inventories */
2225 object *env = aura->env;
2226 object *owner = aura->owner;
2227
2228 /* no matter what we've gotta remove the aura...
2229 * we'll put it back if its time isn't up.
2230 */
2231 aura->remove ();
2232
2233 /* exit if we're out of gas */
2234 if (aura->duration-- < 0)
2235 {
2236 aura->destroy ();
2237 return;
2238 }
2239
2240 /* auras only exist in inventories */
2241 if (!env || !env->map)
2242 {
2243 aura->destroy ();
2244 return;
2245 }
2246
2247 /* we need to jump out of the inventory for a bit
2248 * in order to hit the map conveniently.
2249 */
2250 aura->insert_at (env, aura);
2251
2252 for (int i = 1; i < 9; i++)
2253 {
2254 mapxy pos (env);
2255 pos.move (i);
2256
2257 /* Consider the movement type of the person with the aura as
2258 * movement type of the aura. Eg, if the player is flying, the aura
2259 * is flying also, if player is walking, it is on the ground, etc.
2260 */
2261 if (pos.normalise () && !(OB_TYPE_MOVE_BLOCK (env, pos->move_block)))
2262 {
2263 hit_map (aura, i, aura->attacktype, 0);
2264
2265 if (aura->other_arch)
2266 pos.insert (arch_to_object (aura->other_arch), aura);
2267 }
2268 }
2269
2270 /* put the aura back in the player's inventory */
2271 env->insert (aura);
2272 aura->set_owner (owner);
2273 }
2274
2275 /* moves the peacemaker spell.
2276 * op is the piece object.
2277 */
2278 void
2279 move_peacemaker (object *op)
2280 {
2281 object *tmp;
2282
2283 for (tmp = GET_MAP_OB (op->map, op->x, op->y); tmp != NULL; tmp = tmp->above)
2284 {
2285 int atk_lev, def_lev;
2286 object *victim = tmp;
2287
2288 if (tmp->head)
2289 victim = tmp->head;
2290 if (!QUERY_FLAG (victim, FLAG_MONSTER))
2291 continue;
2292 if (QUERY_FLAG (victim, FLAG_UNAGGRESSIVE))
2293 continue;
2294 if (victim->stats.exp == 0)
2295 continue;
2296
2297 def_lev = MAX (1, victim->level);
2298 atk_lev = MAX (1, op->level);
2299
2300 if (rndm (0, atk_lev - 1) > def_lev)
2301 {
2302 /* make this sucker peaceful. */
2303
2304 change_exp (op->owner, victim->stats.exp, op->skill, 0);
2305 victim->stats.exp = 0;
2306 #if 0
2307 /* No idea why these were all set to zero - if something
2308 * makes this creature agressive, he should still do damage.
2309 */
2310 victim->stats.dam = 0;
2311 victim->stats.sp = 0;
2312 victim->stats.grace = 0;
2313 victim->stats.Pow = 0;
2314 #endif
2315 victim->attack_movement = RANDO2;
2316 SET_FLAG (victim, FLAG_UNAGGRESSIVE);
2317 SET_FLAG (victim, FLAG_RUN_AWAY);
2318 SET_FLAG (victim, FLAG_RANDOM_MOVE);
2319 CLEAR_FLAG (victim, FLAG_MONSTER);
2320 if (victim->name)
2321 {
2322 new_draw_info_format (NDI_UNIQUE, 0, op->owner, "%s no longer feels like fighting.", &victim->name);
2323 }
2324 }
2325 }
2326 }
2327
2328
2329 /* This writes a rune that contains the appropriate message.
2330 * There really isn't any adjustments we make.
2331 */
2332
2333 int
2334 write_mark (object *op, object *spell, const char *msg)
2335 {
2336 char rune[HUGE_BUF];
2337 object *tmp;
2338
2339 if (!msg || msg[0] == 0)
2340 {
2341 new_draw_info (NDI_UNIQUE, 0, op, "Write what?");
2342 return 0;
2343 }
2344
2345 if (strcasestr_local (msg, "endmsg"))
2346 {
2347 new_draw_info (NDI_UNIQUE, 0, op, "Trying to cheat are we?");
2348 LOG (llevInfo, "write_rune: player %s tried to write bogus rune %s\n", &op->name, msg);
2349 return 0;
2350 }
2351 if (!spell->other_arch)
2352 return 0;
2353 tmp = arch_to_object (spell->other_arch);
2354
2355 snprintf (rune, sizeof (rune), "%s\n", msg);
2356
2357 tmp->race = op->name; /*Save the owner of the rune */
2358 tmp->msg = rune;
2359
2360 tmp->insert_at (op, op, INS_BELOW_ORIGINATOR);
2361 return 1;
2362 }