ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_effect.C
Revision: 1.16
Committed: Tue Dec 12 20:53:03 2006 UTC (17 years, 5 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.15: +34 -34 lines
Log Message:
replace some function- by method-calls

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