ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_effect.C
Revision: 1.70
Committed: Mon Aug 27 05:10:51 2007 UTC (16 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.69: +5 -4 lines
Log Message:
fix cure disease giving exp for the wrong skill

File Contents

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