ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_effect.C
Revision: 1.123
Committed: Sun Apr 4 04:10:47 2010 UTC (14 years, 1 month ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.122: +1 -1 lines
Log Message:
tuning

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