ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_effect.C
Revision: 1.51
Committed: Sat May 12 18:14:48 2007 UTC (17 years ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.50: +13 -22 lines
Log Message:
- unrelated change, replace get_attr_value/set_attr_value by a nicer to use
  stat member function. should really replace the struct values by an array.

File Contents

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