ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_effect.c
Revision: 1.1.1.2 (vendor branch)
Committed: Wed Feb 22 18:03:26 2006 UTC (18 years, 3 months ago) by elmex
Content type: text/plain
Branch: UPSTREAM
CVS Tags: UPSTREAM_2006_03_15, UPSTREAM_2006_02_22
Changes since 1.1.1.1: +10 -9 lines
Log Message:
cvs -z7 -d:ext:elmex@cvs.schmorp.de:/schmorpforge import cf.schmorp.de UPSTREAM UPSTREAM_2006_02_22

File Contents

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