ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_effect.C
Revision: 1.94
Committed: Thu Jan 1 15:43:35 2009 UTC (15 years, 4 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.93: +3 -3 lines
Log Message:
eradictae strstr when contains is meant

File Contents

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