ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_effect.C
Revision: 1.135
Committed: Fri Jul 2 19:58:19 2010 UTC (13 years, 11 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.134: +1 -1 lines
Log Message:
*** empty log message ***

File Contents

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