ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_effect.C
Revision: 1.62
Committed: Sun Jul 1 05:00:20 2007 UTC (16 years, 10 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.61: +10 -11 lines
Log Message:
- upgrade crossfire trt to the GPL version 3 (hopefully correctly).
- add a single file covered by the GNU Affero General Public License
  (which is not yet released, so I used the current draft, which is
  legally a bit wavy, but its likely better than nothing as it expresses
  direct intent by the authors, and we can upgrade as soon as it has been
  released).
  * this should ensure availability of source code for the server at least
    and hopefully also archetypes and maps even when modified versions
    are not being distributed, in accordance of section 13 of the agplv3.

File Contents

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