ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_effect.C
Revision: 1.31
Committed: Thu Jan 4 16:19:32 2007 UTC (17 years, 5 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.30: +27 -22 lines
Log Message:
- word of recall activated the player indirectly
- implement maptile->xy_find and xy_load
- separate find and load, even on C level
- generate map_leave/enter and map_change events even for tiled map changes
  (experimental)
- implement mainloop freezeing by start/stop, not skipping ticks
- no map updates when player !active

File Contents

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