ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_effect.c
Revision: 1.8
Committed: Fri May 12 13:32:35 2006 UTC (18 years, 1 month ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.7: +9 -14 lines
Log Message:
fix earth to dust range and ignore move block - tera down flag decides

File Contents

# User Rev Content
1 root 1.1 /*
2     * static char *rcsid_spell_effect_c =
3 root 1.2 * "$Id$";
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 root 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 root 1.7 object *tmp, *next;
685 root 1.1 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 root 1.8 for(i= -range;i<=range;i++)
695     for(j= -range;j<=range;j++) {
696 root 1.1 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 root 1.8 // earth to dust tears down everything that can be teared down
704     for (tmp = get_map_ob(m, sx, sy); tmp != NULL; tmp = next)
705     {
706     next = tmp->above;
707     if (QUERY_FLAG (tmp, FLAG_TEAR_DOWN))
708     hit_player (tmp, 9998, op, AT_PHYSICAL, 0);
709     }
710 root 1.1 }
711     return 1;
712     }
713    
714    
715     void execute_word_of_recall(object *op) {
716     object *wor=op;
717     while(op!=NULL && op->type!=PLAYER)
718     op=op->env;
719    
720     if(op!=NULL && op->map) {
721     if ((get_map_flags(op->map, NULL, op->x, op->y, NULL, NULL) & P_NO_CLERIC) && (!QUERY_FLAG(op,FLAG_WIZCAST)))
722     new_draw_info(NDI_UNIQUE, 0,op,"You feel something fizzle inside you.");
723     else
724     enter_exit(op,wor);
725     }
726     remove_ob(wor);
727     free_object(wor);
728     }
729    
730     /* Word of recall causes the player to return 'home'.
731     * we put a force into the player object, so that there is a
732     * time delay effect.
733     */
734     int cast_word_of_recall(object *op, object *caster, object *spell_ob) {
735     object *dummy;
736     int time;
737    
738     if(op->type!=PLAYER)
739     return 0;
740    
741     if (find_obj_by_type_subtype(op,SPELL_EFFECT, SP_WORD_OF_RECALL))
742     {
743     new_draw_info(NDI_UNIQUE, 0, op, "You feel a force starting to build up inside you." );
744     return 1;
745     }
746    
747     dummy=get_archetype(FORCE_NAME);
748     if(dummy == NULL){
749     new_draw_info(NDI_UNIQUE, 0,op,"Oops, program error!");
750     LOG(llevError,"cast_word_of_recall: get_archetype(force) failed!\n");
751     return 0;
752     }
753     time = spell_ob->duration - SP_level_duration_adjust(caster, spell_ob);
754     if (time <1 ) time=1;
755    
756     /* value of speed really doesn't make much difference, as long as it is
757     * positive. Lower value may be useful so that the problem doesn't
758     * do anything really odd if it say a -1000 or something.
759     */
760     dummy->speed = 0.002;
761     update_ob_speed(dummy);
762     dummy->speed_left = -dummy->speed * time;
763     dummy->type=SPELL_EFFECT;
764     dummy->subtype = SP_WORD_OF_RECALL;
765    
766     /* If we could take advantage of enter_player_savebed() here, it would be
767     * nice, but until the map load fails, we can't.
768     */
769     EXIT_PATH(dummy) = add_string(op->contr->savebed_map);
770     EXIT_X(dummy) = op->contr->bed_x;
771     EXIT_Y(dummy) = op->contr->bed_y;
772    
773     (void) insert_ob_in_ob(dummy,op);
774     new_draw_info(NDI_UNIQUE, 0,op,"You feel a force starting to build up inside you.");
775     return 1;
776     }
777    
778     /* cast_wonder
779     * wonder is really just a spell that will likely cast another
780     * spell.
781     */
782     int cast_wonder(object *op, object *caster, int dir, object *spell_ob) {
783     object *newspell;
784    
785     if(!rndm(0, 3))
786     return cast_cone(op,caster,dir, spell_ob);
787    
788     if (spell_ob->randomitems) {
789     newspell = generate_treasure(spell_ob->randomitems, caster->level);
790     if (!newspell) {
791     LOG(llevError,"cast_wonder: Unable to get a spell!\n");
792     return 0;
793     }
794     if (newspell->type != SPELL) {
795     LOG(llevError,"cast_wonder: spell returned is not a spell (%d, %s)!\n",
796     newspell->type, newspell->name);
797     return 0;
798     }
799     /* Prevent inifinit recursion */
800     if (newspell->subtype == SP_WONDER) {
801     LOG(llevError,"cast_wonder: spell returned is another wonder spell!\n");
802     return 0;
803     }
804     return cast_spell(op,caster,dir,newspell, NULL);
805     }
806     return 1;
807     }
808    
809    
810     int perceive_self(object *op) {
811     char *cp=describe_item(op, op), buf[MAX_BUF];
812     archetype *at=find_archetype(ARCH_DEPLETION);
813     object *tmp;
814     int i;
815    
816     tmp=find_god(determine_god(op));
817     if (tmp)
818     new_draw_info_format(NDI_UNIQUE, 0, op, "You worship %s", tmp->name);
819     else
820     new_draw_info(NDI_UNIQUE, 0,op,"You worship no god");
821    
822     tmp=present_arch_in_ob(at,op);
823    
824     if(*cp=='\0' && tmp==NULL)
825     new_draw_info(NDI_UNIQUE, 0,op,"You feel very mundane");
826     else {
827     new_draw_info(NDI_UNIQUE, 0,op,"You have:");
828     new_draw_info(NDI_UNIQUE, 0,op,cp);
829     if (tmp!=NULL) {
830     for (i=0; i<NUM_STATS; i++) {
831     if (get_attr_value(&tmp->stats, i)<0) {
832     new_draw_info_format(NDI_UNIQUE, 0,op,
833     "Your %s is depleted by %d", statname[i],
834     -(get_attr_value(&tmp->stats,i)));
835     }
836     }
837     }
838     }
839    
840     if (is_dragon_pl(op)) {
841     /* now grab the 'dragon_ability'-force from the player's inventory */
842     for (tmp = op->inv; tmp != NULL; tmp = tmp->below) {
843     if (tmp->type == FORCE && !strcmp(tmp->arch->name, "dragon_ability_force")) {
844     if(tmp->stats.exp == 0) {
845     sprintf(buf, "Your metabolism isn't focused on anything.");
846     } else {
847     sprintf(buf, "Your metabolism is focused on %s.", change_resist_msg[tmp->stats.exp]);
848     }
849     new_draw_info(NDI_UNIQUE, 0,op, buf);
850     break;
851     }
852     }
853     }
854     return 1;
855     }
856    
857     /* int cast_create_town_portal (object *op, object *caster, int dir)
858     *
859     * This function cast the spell of town portal for op
860     *
861     * The spell operates in two passes. During the first one a place
862     * is marked as a destination for the portal. During the second one,
863     * 2 portals are created, one in the position the player cast it and
864     * one in the destination place. The portal are synchronized and 2 forces
865     * are inserted in the player to destruct the portal next time player
866     * creates a new portal pair.
867     * This spell has a side effect that it allows people to meet each other
868     * in a permanent, private, appartements by making a town portal from it
869     * to the town or another public place. So, check if the map is unique and if
870     * so return an error
871     *
872     * Code by Tchize (david.delbecq@usa.net)
873     */
874     int cast_create_town_portal (object *op, object *caster, object *spell, int dir)
875     {
876     object *dummy, *force, *old_force, *tmp;
877     archetype *perm_portal;
878     char portal_name [1024], portal_message [1024];
879     sint16 exitx, exity;
880     mapstruct *exitmap;
881     int op_level;
882    
883    
884     /* Check to see if the map the player is currently on is a per player unique
885     * map. This can be determined in that per player unique maps have the
886     * full pathname listed.
887     */
888 pippijn 1.4 if (!strncmp(op->map->path, settings.localdir, strlen(settings.localdir)) &&
889     settings.create_home_portals != TRUE )
890     {
891     new_draw_info(NDI_UNIQUE | NDI_NAVY, 0,op,"You can't cast that here.\n");
892     return 0;
893 root 1.1 }
894    
895     /* The first thing to do is to check if we have a marked destination
896     * dummy is used to make a check inventory for the force
897     */
898     dummy=arch_to_object(spell->other_arch);
899     if(dummy == NULL){
900     new_draw_info(NDI_UNIQUE, 0,op,"Oops, program error!");
901     LOG(llevError,"get_object failed (force in cast_create_town_portal for %s!\n",op->name);
902     return 0;
903     }
904     force=check_inv_recursive (op,dummy);
905    
906     if (force==NULL) {
907     /* Here we know there is no destination marked up.
908     * We have 2 things to do:
909     * 1. Mark the destination in the player inventory.
910     * 2. Let the player know it worked.
911     */
912     free_string (dummy->name);
913     dummy->name = add_string (op->map->path);
914     EXIT_X(dummy)= op->x;
915     EXIT_Y(dummy)= op->y;
916     insert_ob_in_ob (dummy,op);
917     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.");
918     return 1;
919     }
920     free_object (dummy);
921    
922     /* Here we know where the town portal should go to
923     * We should kill any existing portal associated with the player.
924     * Than we should create the 2 portals.
925     * For each of them, we need:
926     * - To create the portal with the name of the player+destination map
927     * - set the owner of the town portal
928     * - To mark the position of the portal in the player's inventory
929     * for easier destruction.
930     *
931     * The mark works has follow:
932     * slaying: Existing town portal
933     * hp, sp : x & y of the associated portal
934     * name : name of the portal
935     * race : map the portal is in
936     */
937    
938     /* First step: killing existing town portals */
939     dummy=get_archetype(spell->race);
940     if(dummy == NULL){
941     new_draw_info(NDI_UNIQUE, 0,op,"Oops, program error!");
942     LOG(llevError,"get_object failed (force) in cast_create_town_portal for %s!\n",op->name);
943     return 0;
944     }
945     perm_portal = find_archetype (spell->slaying);
946    
947     /* To kill a town portal, we go trough the player's inventory,
948     * for each marked portal in player's inventory,
949     * -We try load the associated map (if impossible, consider the portal destructed)
950     * -We find any portal in the specified location.
951     * If it has the good name, we destruct it.
952     * -We destruct the force indicating that portal.
953     */
954     while ( (old_force=check_inv_recursive (op,dummy))) {
955     exitx=EXIT_X(old_force);
956     exity=EXIT_Y(old_force);
957     LOG (llevDebug,"Trying to kill a portal in %s (%d,%d)\n",old_force->race,exitx,exity);
958    
959     if (!strncmp(old_force->race, settings.localdir, strlen(settings.localdir)))
960     exitmap = ready_map_name(old_force->race, MAP_PLAYER_UNIQUE);
961     else exitmap = ready_map_name(old_force->race, 0);
962    
963     if (exitmap) {
964     tmp=present_arch (perm_portal,exitmap,exitx,exity);
965     while (tmp) {
966     if (tmp->name == old_force->name) {
967     remove_ob (tmp);
968     free_object (tmp);
969     break;
970     } else {
971     tmp = tmp->above;
972     }
973     }
974     }
975     remove_ob (old_force);
976     free_object (old_force);
977     LOG (llevDebug,"\n");
978     }
979     free_object (dummy);
980    
981     /* Creating the portals.
982     * The very first thing to do is to ensure
983     * access to the destination map.
984     * If we can't, don't fizzle. Simply warn player.
985     * This ensure player pays his mana for the spell
986     * because HE is responsible of forgotting.
987     * 'force' is the destination of the town portal, which we got
988     * from the players inventory above.
989     */
990    
991     /* Ensure exit map is loaded*/
992     if (!strncmp(force->name, settings.localdir, strlen(settings.localdir)))
993     exitmap = ready_map_name(force->name, MAP_PLAYER_UNIQUE);
994     else
995     exitmap = ready_map_name(force->name, 0);
996    
997     /* If we were unable to load (ex. random map deleted), warn player*/
998     if (exitmap==NULL) {
999     new_draw_info(NDI_UNIQUE | NDI_NAVY, 0,op,"Something strange happens.\nYou can't remember where to go!?");
1000     remove_ob(force);
1001     free_object(force);
1002     return 1;
1003     }
1004    
1005     op_level = caster_level(caster, spell);
1006     if (op_level<15)
1007     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);
1008     else if (op_level<30)
1009     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);
1010     else if (op_level<60)
1011     snprintf (portal_message,1024,"\nA shining door opens in the air in front of you,\nshowing you the path to another place.\n");
1012     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);
1013    
1014     /* Create a portal in front of player
1015     * dummy contain the portal and
1016     * force contain the track to kill it later
1017     */
1018    
1019     snprintf (portal_name,1024,"%s's portal to %s",op->name,force->name);
1020     dummy=get_archetype(spell->slaying); /*The portal*/
1021     if(dummy == NULL) {
1022     new_draw_info(NDI_UNIQUE, 0,op,"Oops, program error!");
1023     LOG(llevError,"get_object failed (perm_magic_portal) in cast_create_town_portal for %s!\n",op->name);
1024     return 0;
1025     }
1026     EXIT_PATH(dummy) = add_string (force->name);
1027     EXIT_X(dummy)=EXIT_X(force);
1028     EXIT_Y(dummy)=EXIT_Y(force);
1029     FREE_AND_COPY(dummy->name, portal_name);
1030     FREE_AND_COPY(dummy->name_pl, portal_name);
1031     dummy->msg=add_string (portal_message);
1032     dummy->race=add_string (op->name); /*Save the owner of the portal*/
1033     cast_create_obj (op, caster, dummy, 0);
1034    
1035     /* Now we need to to create a town portal marker inside the player
1036     * object, so on future castings, we can know that he has an active
1037     * town portal.
1038     */
1039     tmp=get_archetype(spell->race);
1040     if(tmp == NULL){
1041     new_draw_info(NDI_UNIQUE, 0,op,"Oops, program error!");
1042     LOG(llevError,"get_object failed (force) in cast_create_town_portal for %s!\n",op->name);
1043     return 0;
1044     }
1045     tmp->race=add_string (op->map->path);
1046     FREE_AND_COPY(tmp->name, portal_name);
1047     EXIT_X(tmp)=dummy->x;
1048     EXIT_Y(tmp)=dummy->y;
1049     insert_ob_in_ob (tmp,op);
1050    
1051     /* Create a portal in the destination map
1052     * dummy contain the portal and
1053     * force the track to kill it later
1054     * the 'force' variable still contains the 'reminder' of
1055     * where this portal goes to.
1056     */
1057     snprintf (portal_name,1024,"%s's portal to %s",op->name,op->map->path);
1058     dummy=get_archetype (spell->slaying); /*The portal*/
1059     if(dummy == NULL) {
1060     new_draw_info(NDI_UNIQUE, 0,op,"Oops, program error!");
1061     LOG(llevError,"get_object failed (perm_magic_portal) in cast_create_town_portal for %s!\n",op->name);
1062     return 0;
1063     }
1064     EXIT_PATH(dummy) = add_string (op->map->path);
1065     EXIT_X(dummy)=op->x;
1066     EXIT_Y(dummy)=op->y;
1067     FREE_AND_COPY(dummy->name, portal_name);
1068     FREE_AND_COPY(dummy->name_pl, portal_name);
1069     dummy->msg=add_string (portal_message);
1070     dummy->x=EXIT_X(force);
1071     dummy->y=EXIT_Y(force);
1072     dummy->race=add_string (op->name); /*Save the owner of the portal*/
1073     insert_ob_in_map(dummy,exitmap,op,0);
1074    
1075     /* Now we create another town portal marker that
1076     * points back to the one we just made
1077     */
1078     tmp=get_archetype(spell->race);
1079     if(tmp == NULL){
1080     new_draw_info(NDI_UNIQUE, 0,op,"Oops, program error!");
1081     LOG(llevError,"get_object failed (force) in cast_create_town_portal for %s!\n",op->name);
1082     return 0;
1083     }
1084     tmp->race=add_string(force->name);
1085     FREE_AND_COPY(tmp->name, portal_name);
1086     EXIT_X(tmp)=dummy->x;
1087     EXIT_Y(tmp)=dummy->y;
1088     insert_ob_in_ob (tmp,op);
1089    
1090     /* Describe the player what happened
1091     */
1092     new_draw_info(NDI_UNIQUE | NDI_NAVY, 0,op,"You see air moving and showing you the way home.");
1093     remove_ob(force); /* Delete the force inside the player*/
1094     free_object(force);
1095     return 1;
1096     }
1097    
1098    
1099     /* This creates magic walls. Really, it can create most any object,
1100     * within some reason.
1101     */
1102    
1103     int magic_wall(object *op,object *caster,int dir,object *spell_ob) {
1104     object *tmp, *tmp2;
1105     int i,posblocked,negblocked, maxrange;
1106     sint16 x, y;
1107     mapstruct *m;
1108     const char *name;
1109     archetype *at;
1110    
1111     if(!dir) {
1112     dir=op->facing;
1113     x = op->x;
1114     y = op->y;
1115     } else {
1116     x = op->x+freearr_x[dir];
1117     y = op->y+freearr_y[dir];
1118     }
1119     m = op->map;
1120    
1121     if ((spell_ob->move_block || x != op->x || y != op->y) &&
1122     (get_map_flags(m, &m, x, y, &x, &y) & (P_OUT_OF_MAP|P_IS_ALIVE) ||
1123     ((spell_ob->move_block & GET_MAP_MOVE_BLOCK(m, x, y)) == spell_ob->move_block))) {
1124     new_draw_info(NDI_UNIQUE, 0,op,"Something is in the way.");
1125     return 0;
1126     }
1127     if (spell_ob->other_arch) {
1128     tmp = arch_to_object(spell_ob->other_arch);
1129     } else if (spell_ob->race) {
1130     char buf1[MAX_BUF];
1131    
1132     sprintf(buf1,spell_ob->race,dir);
1133     at = find_archetype(buf1);
1134     if (!at) {
1135     LOG(llevError, "summon_wall: Unable to find archetype %s\n", buf1);
1136     new_draw_info(NDI_UNIQUE, 0,op,"This spell is broken.");
1137     return 0;
1138     }
1139     tmp = arch_to_object(at);
1140     } else {
1141     LOG(llevError,"magic_wall: spell %s lacks other_arch\n",
1142     spell_ob->name);
1143     return 0;
1144     }
1145    
1146     if (tmp->type == SPELL_EFFECT) {
1147     tmp->attacktype = spell_ob->attacktype;
1148     tmp->duration = spell_ob->duration +
1149     SP_level_duration_adjust(caster, spell_ob);
1150     tmp->stats.dam = spell_ob->stats.dam +
1151     SP_level_dam_adjust(caster, spell_ob);
1152     tmp->range = 0;
1153     } else if (QUERY_FLAG(tmp, FLAG_ALIVE)) {
1154     tmp->stats.hp = spell_ob->duration +
1155     SP_level_duration_adjust(caster, spell_ob);
1156     tmp->stats.maxhp = tmp->stats.hp;
1157     set_owner(tmp,op);
1158     set_spell_skill(op, caster, spell_ob, tmp);
1159     }
1160     if (QUERY_FLAG(spell_ob, FLAG_IS_USED_UP) || QUERY_FLAG(tmp, FLAG_IS_USED_UP)) {
1161     tmp->stats.food = spell_ob->duration +
1162     SP_level_duration_adjust(caster, spell_ob);
1163     SET_FLAG(tmp, FLAG_IS_USED_UP);
1164     }
1165     if (QUERY_FLAG(spell_ob, FLAG_TEAR_DOWN)) {
1166     tmp->stats.hp = spell_ob->stats.dam + SP_level_dam_adjust(caster, spell_ob);
1167     tmp->stats.maxhp = tmp->stats.hp;
1168     SET_FLAG(tmp, FLAG_TEAR_DOWN);
1169     SET_FLAG(tmp, FLAG_ALIVE);
1170     }
1171    
1172     /* This can't really hurt - if the object doesn't kill anything,
1173     * these fields just won't be used.
1174     */
1175     set_owner(tmp,op);
1176     set_spell_skill(op, caster, spell_ob, tmp);
1177     tmp->x = x;
1178     tmp->y = y;
1179     tmp->level = caster_level(caster, spell_ob) / 2;
1180    
1181     name = tmp->name;
1182     if ((tmp = insert_ob_in_map (tmp, m, op,0)) == NULL) {
1183     new_draw_info_format(NDI_UNIQUE, 0,op,"Something destroys your %s", name);
1184     return 0;
1185     }
1186     /* If this is a spellcasting wall, need to insert the spell object */
1187     if (tmp->other_arch && tmp->other_arch->clone.type == SPELL)
1188     insert_ob_in_ob(arch_to_object(tmp->other_arch), tmp);
1189    
1190     /* This code causes the wall to extend some distance in
1191     * each direction, or until an obstruction is encountered.
1192     * posblocked and negblocked help determine how far the
1193     * created wall can extend, it won't go extend through
1194     * blocked spaces.
1195     */
1196     maxrange = spell_ob->range + SP_level_range_adjust(caster, spell_ob);
1197     posblocked=0;
1198     negblocked=0;
1199    
1200     for(i=1; i<=maxrange; i++) {
1201     int dir2;
1202    
1203     dir2 = (dir<4)?(dir+2):dir-2;
1204    
1205     x = tmp->x+i*freearr_x[dir2];
1206     y = tmp->y+i*freearr_y[dir2];
1207     m = tmp->map;
1208    
1209     if(!(get_map_flags(m, &m, x, y, &x, &y) & (P_OUT_OF_MAP|P_IS_ALIVE)) &&
1210     ((spell_ob->move_block & GET_MAP_MOVE_BLOCK(m, x, y)) != spell_ob->move_block) &&
1211     !posblocked) {
1212     tmp2 = get_object();
1213     copy_object(tmp,tmp2);
1214     tmp2->x = x;
1215     tmp2->y = y;
1216     insert_ob_in_map(tmp2,m,op,0);
1217     /* If this is a spellcasting wall, need to insert the spell object */
1218     if (tmp2->other_arch && tmp2->other_arch->clone.type == SPELL)
1219     insert_ob_in_ob(arch_to_object(tmp2->other_arch), tmp2);
1220    
1221     } else posblocked=1;
1222    
1223     x = tmp->x-i*freearr_x[dir2];
1224     y = tmp->y-i*freearr_y[dir2];
1225     m = tmp->map;
1226    
1227     if(!(get_map_flags(m, &m, x, y, &x, &y) & (P_OUT_OF_MAP|P_IS_ALIVE)) &&
1228     ((spell_ob->move_block & GET_MAP_MOVE_BLOCK(m, x, y)) != spell_ob->move_block) &&
1229     !negblocked) {
1230     tmp2 = get_object();
1231     copy_object(tmp,tmp2);
1232     tmp2->x = x;
1233     tmp2->y = y;
1234     insert_ob_in_map(tmp2,m,op,0);
1235     if (tmp2->other_arch && tmp2->other_arch->clone.type == SPELL)
1236     insert_ob_in_ob(arch_to_object(tmp2->other_arch), tmp2);
1237     } else negblocked=1;
1238     }
1239    
1240     if(QUERY_FLAG(tmp, FLAG_BLOCKSVIEW))
1241     update_all_los(op->map, op->x, op->y);
1242    
1243     return 1;
1244     }
1245    
1246     int dimension_door(object *op,object *caster, object *spob, int dir) {
1247     uint32 dist, maxdist;
1248     int mflags;
1249     mapstruct *m;
1250     sint16 sx, sy;
1251    
1252     if(op->type!=PLAYER)
1253     return 0;
1254    
1255     if(!dir) {
1256     new_draw_info(NDI_UNIQUE, 0,op,"In what direction?");
1257     return 0;
1258     }
1259    
1260     /* Given the new outdoor maps, can't let players dimension door for
1261     * ever, so put limits in.
1262     */
1263     maxdist = spob->range +
1264     SP_level_range_adjust(caster, spob);
1265    
1266     if(op->contr->count) {
1267     if (op->contr->count > maxdist) {
1268     new_draw_info(NDI_UNIQUE, 0, op, "You can't dimension door that far!");
1269     return 0;
1270     }
1271    
1272     for(dist=0;dist<op->contr->count; dist++) {
1273     mflags = get_map_flags(op->map, &m,
1274     op->x+freearr_x[dir]*(dist+1), op->y+freearr_y[dir]*(dist+1),
1275     &sx, &sy);
1276    
1277     if (mflags & (P_NO_MAGIC | P_OUT_OF_MAP)) break;
1278    
1279     if ((mflags & P_BLOCKSVIEW) &&
1280     OB_TYPE_MOVE_BLOCK(op, GET_MAP_MOVE_BLOCK(m, sx, sy))) break;
1281     }
1282    
1283     if(dist<op->contr->count) {
1284     new_draw_info(NDI_UNIQUE, 0,op,"Something blocks the magic of the spell.\n");
1285     op->contr->count=0;
1286     return 0;
1287     }
1288     op->contr->count=0;
1289    
1290     /* Remove code that puts player on random space on maps. IMO,
1291     * a lot of maps probably have areas the player should not get to,
1292     * but may not be marked as NO_MAGIC (as they may be bounded
1293     * by such squares). Also, there are probably treasure rooms and
1294     * lots of other maps that protect areas with no magic, but the
1295     * areas themselves don't contain no magic spaces.
1296     */
1297     /* This call here is really just to normalize the coordinates */
1298 root 1.2 mflags = get_map_flags(op->map, &m,op->x+freearr_x[dir]*dist, op->y+freearr_y[dir]*dist,
1299 root 1.1 &sx, &sy);
1300 root 1.2 if (mflags&P_IS_ALIVE || OB_TYPE_MOVE_BLOCK(op, GET_MAP_MOVE_BLOCK(m, sx, sy))) {
1301 root 1.1 new_draw_info(NDI_UNIQUE, 0,op,"You cast your spell, but nothing happens.\n");
1302     return 1; /* Maybe the penalty should be more severe... */
1303     }
1304     } else {
1305     /* Player didn't specify a distance, so lets see how far
1306     * we can move the player. Don't know why this stopped on
1307     * spaces that blocked the players view.
1308     */
1309    
1310     for(dist=0; dist < maxdist; dist++) {
1311     mflags = get_map_flags(op->map, &m,
1312     op->x+freearr_x[dir] * (dist+1),
1313     op->y+freearr_y[dir] * (dist+1),
1314     &sx, &sy);
1315    
1316     if (mflags & (P_NO_MAGIC | P_OUT_OF_MAP)) break;
1317    
1318     if ((mflags & P_BLOCKSVIEW) &&
1319     OB_TYPE_MOVE_BLOCK(op, GET_MAP_MOVE_BLOCK(m, sx, sy))) break;
1320    
1321     }
1322    
1323     /* If the destination is blocked, keep backing up until we
1324     * find a place for the player.
1325     */
1326     for(;dist>0; dist--) {
1327     if (get_map_flags(op->map, &m,op->x+freearr_x[dir]*dist, op->y+freearr_y[dir]*dist,
1328 root 1.2 &sx, &sy) & (P_OUT_OF_MAP|P_IS_ALIVE)) continue;
1329 root 1.1
1330    
1331     if (!OB_TYPE_MOVE_BLOCK(op, GET_MAP_MOVE_BLOCK(m, sx, sy))) break;
1332    
1333     }
1334     if(!dist) {
1335     new_draw_info(NDI_UNIQUE, 0,op,"Your spell failed!\n");
1336     return 0;
1337     }
1338     }
1339    
1340     /* Actually move the player now */
1341     remove_ob(op);
1342     op->x+=freearr_x[dir]*dist;
1343     op->y+=freearr_y[dir]*dist;
1344     if ((op = insert_ob_in_map(op,op->map,op,0)) == NULL)
1345     return 1;
1346    
1347     if (op->type == PLAYER)
1348     MapNewmapCmd(op->contr);
1349     op->speed_left= -FABS(op->speed)*5; /* Freeze them for a short while */
1350     return 1;
1351     }
1352    
1353    
1354     /* cast_heal: Heals something.
1355     * op is the caster.
1356     * dir is the direction he is casting it in.
1357     * spell is the spell object.
1358     */
1359     int cast_heal(object *op,object *caster, object *spell, int dir) {
1360     object *tmp;
1361     archetype *at;
1362     object *poison;
1363     int heal = 0, success = 0;
1364    
1365     tmp = find_target_for_friendly_spell(op,dir);
1366    
1367     if (tmp==NULL) return 0;
1368    
1369     /* Figure out how many hp this spell might cure.
1370     * could be zero if this spell heals effects, not damage.
1371     */
1372     heal = spell->stats.dam;
1373     if (spell->stats.hp)
1374     heal += random_roll(spell->stats.hp, 6, op, PREFER_HIGH) +
1375     spell->stats.hp;
1376    
1377     if (heal) {
1378     if (tmp->stats.hp >= tmp->stats.maxhp) {
1379     new_draw_info(NDI_UNIQUE, 0,tmp, "You are already fully healed.");
1380     }
1381     else {
1382     /* See how many points we actually heal. Instead of messages
1383     * based on type of spell, we instead do messages based
1384     * on amount of damage healed.
1385     */
1386     if (heal > (tmp->stats.maxhp - tmp->stats.hp))
1387     heal = tmp->stats.maxhp - tmp->stats.hp;
1388     tmp->stats.hp += heal;
1389    
1390     if (tmp->stats.hp >= tmp->stats.maxhp) {
1391     new_draw_info(NDI_UNIQUE, 0,tmp, "You feel just fine!");
1392     } else if (heal > 50) {
1393     new_draw_info(NDI_UNIQUE, 0,tmp, "Your wounds close!");
1394     } else if (heal > 25) {
1395     new_draw_info(NDI_UNIQUE, 0,tmp, "Your wounds mostly close.");
1396     } else if (heal > 10) {
1397     new_draw_info(NDI_UNIQUE, 0,tmp, "Your wounds start to fade.");
1398     } else {
1399     new_draw_info(NDI_UNIQUE, 0,tmp, "Your wounds start to close.");
1400     }
1401     success=1;
1402     }
1403     }
1404     if (spell->attacktype & AT_DISEASE)
1405     if (cure_disease (tmp, op))
1406     success = 1;
1407    
1408     if (spell->attacktype & AT_POISON) {
1409     at = find_archetype("poisoning");
1410     poison=present_arch_in_ob(at,tmp);
1411     if (poison) {
1412     success = 1;
1413     new_draw_info(NDI_UNIQUE, 0,tmp, "Your body feels cleansed");
1414     poison->stats.food = 1;
1415     }
1416     }
1417     if (spell->attacktype & AT_CONFUSION) {
1418     poison=present_in_ob_by_name(FORCE,"confusion", tmp);
1419     if (poison) {
1420     success = 1;
1421     new_draw_info(NDI_UNIQUE, 0,tmp, "Your mind feels clearer");
1422     poison->duration = 1;
1423     }
1424     }
1425     if (spell->attacktype & AT_BLIND) {
1426     at=find_archetype("blindness");
1427     poison=present_arch_in_ob(at,tmp);
1428     if (poison) {
1429     success = 1;
1430     new_draw_info(NDI_UNIQUE, 0,tmp,"Your vision begins to return.");
1431     poison->stats.food = 1;
1432     }
1433     }
1434     if (spell->last_sp && tmp->stats.sp < tmp->stats.maxsp) {
1435     tmp->stats.sp += spell->last_sp;
1436     if (tmp->stats.sp > tmp->stats.maxsp) tmp->stats.sp = tmp->stats.maxsp;
1437     success = 1;
1438 pippijn 1.3 new_draw_info(NDI_UNIQUE, 0,tmp,"Magical energy surges through your body!");
1439 root 1.1 }
1440     if (spell->last_grace && tmp->stats.grace < tmp->stats.maxgrace) {
1441     tmp->stats.grace += spell->last_grace;
1442     if (tmp->stats.grace > tmp->stats.maxgrace) tmp->stats.grace = tmp->stats.maxgrace;
1443     success = 1;
1444 pippijn 1.3 new_draw_info(NDI_UNIQUE, 0,tmp,"You feel redeemed with your god!");
1445 root 1.1 }
1446     if (spell->stats.food && tmp->stats.food < 999) {
1447     tmp->stats.food += spell->stats.food;
1448     if (tmp->stats.food > 999) tmp->stats.food=999;
1449     success = 1;
1450     /* We could do something a bit better like the messages for healing above */
1451     new_draw_info(NDI_UNIQUE, 0,tmp,"You feel your belly fill with food");
1452     }
1453     return success;
1454     }
1455    
1456    
1457     /* This is used for the spells that gain stats. There are no spells
1458     * right now that icnrease wis/int/pow on a temp basis, so no
1459     * good comments for those.
1460     */
1461 root 1.2 static const char* const no_gain_msgs[NUM_STATS] = {
1462 root 1.1 "You grow no stronger.",
1463     "You grow no more agile.",
1464     "You don't feel any healthier.",
1465     "no wis",
1466     "You are no easier to look at.",
1467     "no int",
1468     "no pow"
1469     };
1470    
1471     int cast_change_ability(object *op,object *caster,object *spell_ob, int dir, int silent) {
1472     object *tmp, *tmp2=NULL;
1473     object *force=NULL;
1474     int i;
1475    
1476     /* if dir = 99 op defaults to tmp, eat_special_food() requires this. */
1477     if(dir!=0) {
1478     tmp=find_target_for_friendly_spell(op,dir);
1479     } else {
1480     tmp = op;
1481     }
1482    
1483     if(tmp==NULL) return 0;
1484    
1485     /* If we've already got a force of this type, don't add a new one. */
1486     for(tmp2=tmp->inv; tmp2!=NULL; tmp2=tmp2->below) {
1487     if (tmp2->type==FORCE && tmp2->subtype == FORCE_CHANGE_ABILITY) {
1488     if (tmp2->name == spell_ob->name) {
1489     force=tmp2; /* the old effect will be "refreshed" */
1490     break;
1491     }
1492     else if (spell_ob->race && spell_ob->race == tmp2->name) {
1493     if ( !silent )
1494     new_draw_info_format(NDI_UNIQUE, 0, op,
1495     "You can not cast %s while %s is in effect",
1496     spell_ob->name, tmp2->name_pl);
1497     return 0;
1498     }
1499     }
1500     }
1501     if(force==NULL) {
1502     force=get_archetype(FORCE_NAME);
1503     force->subtype = FORCE_CHANGE_ABILITY;
1504     free_string(force->name);
1505     if (spell_ob->race)
1506     force->name = add_refcount(spell_ob->race);
1507     else
1508     force->name = add_refcount(spell_ob->name);
1509     free_string(force->name_pl);
1510     force->name_pl = add_refcount(spell_ob->name);
1511    
1512     } else {
1513     int duration;
1514    
1515     duration = spell_ob->duration + SP_level_duration_adjust(caster, spell_ob) * 50;
1516     if (duration > force->duration) {
1517     force->duration = duration;
1518     new_draw_info(NDI_UNIQUE, 0, op, "You recast the spell while in effect.");
1519     } else {
1520     new_draw_info(NDI_UNIQUE, 0, op, "Recasting the spell had no effect.");
1521     }
1522     return 1;
1523     }
1524     force->duration = spell_ob->duration + SP_level_duration_adjust(caster, spell_ob) * 50;
1525     force->speed = 1.0;
1526     force->speed_left = -1.0;
1527     SET_FLAG(force, FLAG_APPLIED);
1528    
1529     /* Now start processing the effects. First, protections */
1530     for (i=0; i < NROFATTACKS; i++) {
1531     if (spell_ob->resist[i]) {
1532     force->resist[i] = spell_ob->resist[i] + SP_level_dam_adjust(caster, spell_ob);
1533     if (force->resist[i] > 100) force->resist[i] = 100;
1534     }
1535     }
1536     if (spell_ob->stats.hp)
1537     force->stats.hp = spell_ob->stats.hp + SP_level_dam_adjust(caster,spell_ob);
1538    
1539     if (tmp->type == PLAYER) {
1540     /* Stat adjustment spells */
1541     for (i=0; i < NUM_STATS; i++) {
1542     sint8 stat = get_attr_value(&spell_ob->stats, i), k, sm;
1543     if (stat) {
1544     sm=0;
1545     for (k=0; k<stat; k++)
1546     sm += rndm(1, 3);
1547    
1548     if ((get_attr_value(&tmp->stats, i) + sm) > (15 + 5 * stat)) {
1549     sm = (15 + 5 * stat) - get_attr_value(&tmp->stats, i);
1550     if (sm<0) sm = 0;
1551     }
1552     set_attr_value(&force->stats, i, sm);
1553     if (!sm)
1554     new_draw_info(NDI_UNIQUE, 0,op,no_gain_msgs[i]);
1555     }
1556     }
1557     }
1558    
1559     force->move_type = spell_ob->move_type;
1560    
1561     if (QUERY_FLAG(spell_ob, FLAG_SEE_IN_DARK))
1562     SET_FLAG(force, FLAG_SEE_IN_DARK);
1563    
1564     if (QUERY_FLAG(spell_ob, FLAG_XRAYS))
1565     SET_FLAG(force, FLAG_XRAYS);
1566    
1567     /* Haste/bonus speed */
1568     if (spell_ob->stats.exp) {
1569     if (op->speed > 0.5) force->stats.exp = (float) spell_ob->stats.exp / (op->speed + 0.5);
1570     else
1571     force->stats.exp = spell_ob->stats.exp;
1572     }
1573    
1574     force->stats.wc = spell_ob->stats.wc;
1575     force->stats.ac = spell_ob->stats.ac;
1576     force->attacktype = spell_ob->attacktype;
1577    
1578     insert_ob_in_ob(force,tmp);
1579     change_abil(tmp,force); /* Mostly to display any messages */
1580     fix_player(tmp);
1581     return 1;
1582     }
1583    
1584     /* This used to be part of cast_change_ability, but it really didn't make
1585     * a lot of sense, since most of the values it derives are from the god
1586     * of the caster.
1587     */
1588    
1589     int cast_bless(object *op,object *caster,object *spell_ob, int dir) {
1590     int i;
1591     object *god = find_god(determine_god(op)), *tmp2, *force=NULL, *tmp;
1592    
1593     /* if dir = 99 op defaults to tmp, eat_special_food() requires this. */
1594     if(dir!=0) {
1595     tmp=find_target_for_friendly_spell(op,dir);
1596     } else {
1597     tmp = op;
1598     }
1599    
1600     /* If we've already got a force of this type, don't add a new one. */
1601     for(tmp2=tmp->inv; tmp2!=NULL; tmp2=tmp2->below) {
1602     if (tmp2->type==FORCE && tmp2->subtype == FORCE_CHANGE_ABILITY) {
1603     if (tmp2->name == spell_ob->name) {
1604     force=tmp2; /* the old effect will be "refreshed" */
1605     break;
1606     }
1607     else if (spell_ob->race && spell_ob->race == tmp2->name) {
1608     new_draw_info_format(NDI_UNIQUE, 0, op,
1609     "You can not cast %s while %s is in effect",
1610     spell_ob->name, tmp2->name_pl);
1611     return 0;
1612     }
1613     }
1614     }
1615     if(force==NULL) {
1616     force=get_archetype(FORCE_NAME);
1617     force->subtype = FORCE_CHANGE_ABILITY;
1618     free_string(force->name);
1619     if (spell_ob->race)
1620     force->name = add_refcount(spell_ob->race);
1621     else
1622     force->name = add_refcount(spell_ob->name);
1623     free_string(force->name_pl);
1624     force->name_pl = add_refcount(spell_ob->name);
1625     } else {
1626     int duration;
1627    
1628     duration = spell_ob->duration + SP_level_duration_adjust(caster, spell_ob) * 50;
1629     if (duration > force->duration) {
1630     force->duration = duration;
1631     new_draw_info(NDI_UNIQUE, 0, op, "You recast the spell while in effect.");
1632     } else {
1633     new_draw_info(NDI_UNIQUE, 0, op, "Recasting the spell had no effect.");
1634     }
1635     return 0;
1636     }
1637     force->duration = spell_ob->duration + SP_level_duration_adjust(caster, spell_ob) * 50;
1638     force->speed = 1.0;
1639     force->speed_left = -1.0;
1640     SET_FLAG(force, FLAG_APPLIED);
1641    
1642     if(!god) {
1643     new_draw_info(NDI_UNIQUE, 0,op,"Your blessing seems empty.");
1644     } else {
1645     /* Only give out good benefits, and put a max on it */
1646     for (i=0; i<NROFATTACKS; i++) {
1647     if (god->resist[i]>0) {
1648     force->resist[i] = MIN(god->resist[i], spell_ob->resist[ATNR_GODPOWER]);
1649     }
1650     }
1651     force->path_attuned|=god->path_attuned;
1652     if (spell_ob->attacktype) {
1653     force->attacktype|=god->attacktype | AT_PHYSICAL;
1654     if(god->slaying) force->slaying = add_string(god->slaying);
1655     }
1656     if (tmp != op) {
1657     new_draw_info_format(NDI_UNIQUE, 0, op, "You bless %s.", tmp->name);
1658     new_draw_info_format(NDI_UNIQUE, 0, tmp, "%s blessed you.", op->name);
1659     } else {
1660     new_draw_info_format(NDI_UNIQUE, 0,tmp,
1661     "You are blessed by %s!",god->name);
1662     }
1663    
1664     }
1665     force->stats.wc = spell_ob->stats.wc;
1666     force->stats.ac = spell_ob->stats.ac;
1667    
1668     change_abil(tmp,force); /* Mostly to display any messages */
1669     insert_ob_in_ob(force,tmp);
1670     fix_player(tmp);
1671     return 1;
1672     }
1673    
1674    
1675    
1676     /* Alchemy code by Mark Wedel
1677     *
1678     * This code adds a new spell, called alchemy. Alchemy will turn
1679     * objects to gold nuggets, the value of the gold nuggets being
1680     * about 90% of that of the item itself. It uses the value of the
1681     * object before charisma adjustments, because the nuggets themselves
1682     * will be will be adjusted by charisma when sold.
1683     *
1684     * Large nuggets are worth 25 gp each (base). You will always get
1685     * the maximum number of large nuggets you could get.
1686     * Small nuggets are worth 1 gp each (base). You will get from 0
1687     * to the max amount of small nuggets as you could get.
1688     *
1689     * For example, if an item is worth 110 gold, you will get
1690     * 4 large nuggets, and from 0-10 small nuggets.
1691     *
1692     * There is also a chance (1:30) that you will get nothing at all
1693     * for the object. There is also a maximum weight that will be
1694     * alchemied.
1695     */
1696    
1697     /* I didn't feel like passing these as arguements to the
1698     * two functions that need them. Real values are put in them
1699     * when the spell is cast, and these are freed when the spell
1700     * is finished.
1701     */
1702     static object *small, *large;
1703    
1704     static void alchemy_object(object *obj, int *small_nuggets,
1705     int *large_nuggets, int *weight)
1706     {
1707     uint64 value=query_cost(obj, NULL, F_TRUE);
1708    
1709     /* Give third price when we alchemy money (This should hopefully
1710     * make it so that it isn't worth it to alchemy money, sell
1711     * the nuggets, alchemy the gold from that, etc.
1712     * Otherwise, give 9 silver on the gold for other objects,
1713     * so that it would still be more affordable to haul
1714     * the stuff back to town.
1715     */
1716    
1717     if (QUERY_FLAG(obj, FLAG_UNPAID))
1718     value=0;
1719     else if (obj->type==MONEY || obj->type==GEM)
1720     value /=3;
1721     else
1722     value = (value*9)/10;
1723    
1724 root 1.2 value /= 4; // fix by GHJ, don't understand, pcg
1725    
1726 root 1.1 if ((obj->value>0) && rndm(0, 29)) {
1727     int count;
1728    
1729     count = value / large->value;
1730     *large_nuggets += count;
1731     value -= (uint64)count * (uint64)large->value;
1732     count = value / small->value;
1733     *small_nuggets += count;
1734     }
1735    
1736     /* Turn 25 small nuggets into 1 large nugget. If the value
1737     * of large nuggets is not evenly divisable by the small nugget
1738     * value, take off an extra small_nugget (Assuming small_nuggets!=0)
1739     */
1740     if (*small_nuggets * small->value >= large->value) {
1741     (*large_nuggets)++;
1742     *small_nuggets -= large->value / small->value;
1743     if (*small_nuggets && large->value % small->value)
1744     (*small_nuggets)--;
1745     }
1746     weight += obj->weight;
1747     remove_ob(obj);
1748     free_object(obj);
1749     }
1750    
1751     static void update_map(object *op, mapstruct *m, int small_nuggets, int large_nuggets,
1752     int x, int y)
1753     {
1754     object *tmp;
1755     int flag=0;
1756    
1757     /* Put any nuggets below the player, but we can only pass this
1758     * flag if we are on the same space as the player
1759     */
1760     if (x == op->x && y == op->y && op->map == m) flag = INS_BELOW_ORIGINATOR;
1761    
1762     if (small_nuggets) {
1763     tmp = get_object();
1764     copy_object(small, tmp);
1765     tmp-> nrof = small_nuggets;
1766     tmp->x = x;
1767     tmp->y = y;
1768     insert_ob_in_map(tmp, m, op, flag);
1769     }
1770     if (large_nuggets) {
1771     tmp = get_object();
1772     copy_object(large, tmp);
1773     tmp-> nrof = large_nuggets;
1774     tmp->x = x;
1775     tmp->y = y;
1776     insert_ob_in_map(tmp, m, op, flag);
1777     }
1778     }
1779    
1780     int alchemy(object *op, object *caster, object *spell_ob)
1781     {
1782     int x,y,weight=0,weight_max,large_nuggets,small_nuggets, mflags;
1783     sint16 nx, ny;
1784     object *next,*tmp;
1785     mapstruct *mp;
1786    
1787     if(op->type!=PLAYER)
1788     return 0;
1789    
1790     /* Put a maximum weight of items that can be alchemied. Limits the power
1791     * some, and also prevents people from alcheming every table/chair/clock
1792     * in sight
1793     */
1794     weight_max = spell_ob->duration + +SP_level_duration_adjust(caster,spell_ob);
1795     weight_max *= 1000;
1796     small=get_archetype("smallnugget"),
1797     large=get_archetype("largenugget");
1798    
1799     for(y= op->y-1;y<=op->y+1;y++) {
1800     for(x= op->x-1;x<=op->x+1;x++) {
1801     nx = x;
1802     ny = y;
1803    
1804     mp = op->map;
1805    
1806     mflags = get_map_flags(mp, &mp, nx, ny, &nx, &ny);
1807    
1808     if(mflags & (P_OUT_OF_MAP | P_NO_MAGIC))
1809     continue;
1810    
1811     /* Treat alchemy a little differently - most spell effects
1812     * use fly as the movement type - for alchemy, consider it
1813     * ground level effect.
1814     */
1815     if (GET_MAP_MOVE_BLOCK(mp, nx, ny) & MOVE_WALK)
1816     continue;
1817    
1818     small_nuggets=0;
1819     large_nuggets=0;
1820    
1821     for(tmp=get_map_ob(mp,nx,ny);tmp!=NULL;tmp=next) {
1822     next=tmp->above;
1823     if (tmp->weight>0 && !QUERY_FLAG(tmp, FLAG_NO_PICK) &&
1824     !QUERY_FLAG(tmp, FLAG_ALIVE) &&
1825     !QUERY_FLAG(tmp, FLAG_IS_CAULDRON)) {
1826    
1827     if (tmp->inv) {
1828     object *next1, *tmp1;
1829     for (tmp1 = tmp->inv; tmp1!=NULL; tmp1=next1) {
1830     next1 = tmp1->below;
1831     if (tmp1->weight>0 && !QUERY_FLAG(tmp1, FLAG_NO_PICK) &&
1832     !QUERY_FLAG(tmp1, FLAG_ALIVE) &&
1833     !QUERY_FLAG(tmp1, FLAG_IS_CAULDRON))
1834     alchemy_object(tmp1, &small_nuggets, &large_nuggets,
1835     &weight);
1836     }
1837     }
1838     alchemy_object(tmp, &small_nuggets, &large_nuggets, &weight);
1839    
1840     if (weight>weight_max) {
1841     update_map(op, mp, small_nuggets, large_nuggets, nx, ny);
1842     free_object(large);
1843     free_object(small);
1844     return 1;
1845     }
1846     } /* is alchemable object */
1847     } /* process all objects on this space */
1848    
1849     /* Insert all the nuggets at one time. This probably saves time, but
1850     * it also prevents us from alcheming nuggets that were just created
1851     * with this spell.
1852     */
1853     update_map(op, mp, small_nuggets, large_nuggets, nx, ny);
1854     }
1855     }
1856     free_object(large);
1857     free_object(small);
1858     /* reset this so that if player standing on a big pile of stuff,
1859     * it is redrawn properly.
1860     */
1861     op->contr->socket.look_position = 0;
1862     return 1;
1863     }
1864    
1865    
1866     /* This function removes the cursed/damned status on equipped
1867     * items.
1868     */
1869     int remove_curse(object *op, object *caster, object *spell) {
1870     object *tmp;
1871     int success = 0, was_one = 0;
1872    
1873     for (tmp = op->inv; tmp; tmp = tmp->below)
1874     if (QUERY_FLAG(tmp, FLAG_APPLIED) &&
1875     ((QUERY_FLAG(tmp, FLAG_CURSED) && QUERY_FLAG(spell, FLAG_CURSED)) ||
1876     (QUERY_FLAG(tmp, FLAG_DAMNED) && QUERY_FLAG(spell, FLAG_DAMNED)))) {
1877    
1878     was_one++;
1879     if (tmp->level <= caster_level(caster, spell)) {
1880     success++;
1881     if (QUERY_FLAG(spell, FLAG_DAMNED))
1882     CLEAR_FLAG(tmp, FLAG_DAMNED);
1883    
1884     CLEAR_FLAG(tmp, FLAG_CURSED);
1885     CLEAR_FLAG(tmp, FLAG_KNOWN_CURSED);
1886     tmp->value = 0; /* Still can't sell it */
1887     if (op->type == PLAYER)
1888     esrv_send_item(op, tmp);
1889     }
1890     }
1891    
1892     if (op->type==PLAYER) {
1893     if (success) {
1894     new_draw_info(NDI_UNIQUE, 0,op, "You feel like some of your items are looser now.");
1895     } else {
1896     if (was_one)
1897     new_draw_info(NDI_UNIQUE, 0,op, "You failed to remove the curse.");
1898     else
1899     new_draw_info(NDI_UNIQUE, 0,op, "You are not using any cursed items.");
1900     }
1901     }
1902     return success;
1903     }
1904    
1905     /* Identifies objects in the players inventory/on the ground */
1906    
1907     int cast_identify(object *op, object *caster, object *spell) {
1908     object *tmp;
1909     int success = 0, num_ident;
1910    
1911     num_ident = spell->stats.dam + SP_level_dam_adjust(caster, spell);
1912    
1913     if (num_ident < 1) num_ident=1;
1914    
1915    
1916     for (tmp = op->inv; tmp ; tmp = tmp->below) {
1917     if (!QUERY_FLAG(tmp, FLAG_IDENTIFIED) && !tmp->invisible && need_identify(tmp)) {
1918     identify(tmp);
1919     if (op->type==PLAYER) {
1920     new_draw_info_format(NDI_UNIQUE, 0, op,
1921     "You have %s.", long_desc(tmp, op));
1922     if (tmp->msg) {
1923     new_draw_info(NDI_UNIQUE, 0,op, "The item has a story:");
1924     new_draw_info(NDI_UNIQUE, 0,op, tmp->msg);
1925     }
1926     }
1927     num_ident--;
1928     success=1;
1929     if (!num_ident) break;
1930     }
1931     }
1932     /* If all the power of the spell has been used up, don't go and identify
1933     * stuff on the floor. Only identify stuff on the floor if the spell
1934     * was not fully used.
1935     */
1936     if (num_ident) {
1937     for(tmp = get_map_ob(op->map,op->x,op->y);tmp!=NULL;tmp=tmp->above)
1938     if (!QUERY_FLAG(tmp, FLAG_IDENTIFIED) && !tmp->invisible &&
1939     need_identify(tmp)) {
1940    
1941     identify(tmp);
1942     if (op->type==PLAYER) {
1943     new_draw_info_format(NDI_UNIQUE, 0,op,
1944     "On the ground is %s.", long_desc(tmp, op));
1945     if (tmp->msg) {
1946     new_draw_info(NDI_UNIQUE, 0,op, "The item has a story:");
1947     new_draw_info(NDI_UNIQUE, 0,op, tmp->msg);
1948     }
1949     esrv_send_item(op, tmp);
1950     }
1951     num_ident--;
1952     success=1;
1953     if (!num_ident) break;
1954     }
1955     }
1956     if (!success)
1957     new_draw_info(NDI_UNIQUE, 0,op, "You can't reach anything unidentified.");
1958     else {
1959     spell_effect(spell, op->x, op->y, op->map, op);
1960     }
1961     return success;
1962     }
1963    
1964    
1965     int cast_detection(object *op, object *caster, object *spell, object *skill) {
1966     object *tmp, *last, *god, *detect;
1967     int done_one, range, mflags, floor, level;
1968     sint16 x, y, nx, ny;
1969     mapstruct *m;
1970    
1971     /* We precompute some values here so that we don't have to keep
1972     * doing it over and over again.
1973     */
1974     god=find_god(determine_god(op));
1975     level=caster_level(caster, spell);
1976     range = spell->range + SP_level_range_adjust(caster, spell);
1977    
1978     if (!skill) skill=caster;
1979    
1980     for (x = op->x - range; x <= op->x + range; x++)
1981     for (y = op->y - range; y <= op->y + range; y++) {
1982    
1983     m = op->map;
1984     mflags = get_map_flags(m, &m, x, y, &nx, &ny);
1985     if (mflags & P_OUT_OF_MAP) continue;
1986    
1987     /* For most of the detections, we only detect objects above the
1988     * floor. But this is not true for show invisible.
1989     * Basically, we just go and find the top object and work
1990     * down - that is easier than working up.
1991     */
1992    
1993     for (last=NULL, tmp=get_map_ob(m, nx, ny); tmp; tmp=tmp->above) last=tmp;
1994     /* Shouldn't happen, but if there are no objects on a space, this
1995     * would happen.
1996     */
1997     if (!last) continue;
1998    
1999     done_one=0;
2000     floor=0;
2001     detect = NULL;
2002     for (tmp=last; tmp; tmp=tmp->below) {
2003    
2004     /* show invisible */
2005     if (QUERY_FLAG(spell, FLAG_MAKE_INVIS) &&
2006     /* Might there be other objects that we can make visibile? */
2007     (tmp->invisible && (QUERY_FLAG(tmp, FLAG_MONSTER) ||
2008     (tmp->type==PLAYER && !QUERY_FLAG(tmp, FLAG_WIZ)) ||
2009     tmp->type==CF_HANDLE ||
2010     tmp->type==TRAPDOOR || tmp->type==EXIT || tmp->type==HOLE ||
2011     tmp->type==BUTTON || tmp->type==TELEPORTER ||
2012     tmp->type==GATE || tmp->type==LOCKED_DOOR ||
2013     tmp->type==WEAPON || tmp->type==ALTAR || tmp->type==SIGN ||
2014     tmp->type==TRIGGER_PEDESTAL || tmp->type==SPECIAL_KEY ||
2015     tmp->type==TREASURE || tmp->type==BOOK ||
2016     tmp->type==HOLY_ALTAR))) {
2017     if(random_roll(0, skill->level-1, op, PREFER_HIGH) > level/4) {
2018     tmp->invisible=0;
2019     done_one = 1;
2020     }
2021     }
2022     if (QUERY_FLAG(tmp, FLAG_IS_FLOOR)) floor=1;
2023    
2024     /* All detections below this point don't descend beneath the floor,
2025     * so just continue on. We could be clever and look at the type of
2026     * detection to completely break out if we don't care about objects beneath
2027     * the floor, but once we get to the floor, not likely a very big issue anyways.
2028     */
2029     if (floor) continue;
2030    
2031     /* I had thought about making detect magic and detect curse
2032     * show the flash the magic item like it does for detect monster.
2033     * however, if the object is within sight, this would then make it
2034     * difficult to see what object is magical/cursed, so the
2035     * effect wouldn't be as apparant.
2036     */
2037    
2038     /* detect magic */
2039     if (QUERY_FLAG(spell, FLAG_KNOWN_MAGICAL) &&
2040     !QUERY_FLAG(tmp,FLAG_KNOWN_MAGICAL) &&
2041     !QUERY_FLAG(tmp, FLAG_IDENTIFIED) &&
2042     is_magical(tmp)) {
2043     SET_FLAG(tmp,FLAG_KNOWN_MAGICAL);
2044     /* make runes more visibile */
2045     if(tmp->type==RUNE && tmp->attacktype&AT_MAGIC)
2046     tmp->stats.Cha/=4;
2047     done_one = 1;
2048     }
2049     /* detect monster */
2050     if (QUERY_FLAG(spell, FLAG_MONSTER) &&
2051     (QUERY_FLAG(tmp, FLAG_MONSTER) || tmp->type==PLAYER)) {
2052     done_one = 2;
2053     if (!detect) detect=tmp;
2054     }
2055     /* Basically, if race is set in the spell, then the creatures race must
2056     * match that. if the spell race is set to GOD, then the gods opposing
2057     * race must match.
2058     */
2059     if (spell->race && QUERY_FLAG(tmp,FLAG_MONSTER) && tmp->race &&
2060     ((!strcmp(spell->race, "GOD") && god && god->slaying && strstr(god->slaying,tmp->race)) ||
2061     (strstr(spell->race, tmp->race)))) {
2062     done_one = 2;
2063     if (!detect) detect=tmp;
2064     }
2065     if (QUERY_FLAG(spell, FLAG_KNOWN_CURSED) && !QUERY_FLAG(tmp, FLAG_KNOWN_CURSED) &&
2066     (QUERY_FLAG(tmp, FLAG_CURSED) || QUERY_FLAG(tmp, FLAG_DAMNED))) {
2067     SET_FLAG(tmp, FLAG_KNOWN_CURSED);
2068     done_one = 1;
2069     }
2070     } /* for stack of objects on this space */
2071    
2072     /* Code here puts an effect of the spell on the space, so you can see
2073     * where the magic is.
2074     */
2075     if (done_one) {
2076     object *detect_ob = arch_to_object(spell->other_arch);
2077     detect_ob->x = nx;
2078     detect_ob->y = ny;
2079     /* if this is set, we want to copy the face */
2080     if (done_one == 2 && detect) {
2081     detect_ob->face = detect->face;
2082     detect_ob->animation_id = detect->animation_id;
2083     detect_ob->anim_speed = detect->anim_speed;
2084     detect_ob->last_anim=0;
2085     /* by default, the detect_ob is already animated */
2086     if (!QUERY_FLAG(detect, FLAG_ANIMATE)) CLEAR_FLAG(detect_ob, FLAG_ANIMATE);
2087     }
2088     insert_ob_in_map(detect_ob, m, op,0);
2089     }
2090     } /* for processing the surrounding spaces */
2091    
2092    
2093     /* Now process objects in the players inventory if detect curse or magic */
2094     if (QUERY_FLAG(spell, FLAG_KNOWN_CURSED) || QUERY_FLAG(spell, FLAG_KNOWN_MAGICAL)) {
2095     done_one = 0;
2096     for (tmp = op->inv; tmp; tmp = tmp->below) {
2097     if (!tmp->invisible && !QUERY_FLAG(tmp, FLAG_IDENTIFIED)) {
2098     if (QUERY_FLAG(spell, FLAG_KNOWN_MAGICAL) &&
2099     is_magical(tmp) && !QUERY_FLAG(tmp,FLAG_KNOWN_MAGICAL)) {
2100     SET_FLAG(tmp,FLAG_KNOWN_MAGICAL);
2101     if (op->type==PLAYER)
2102     esrv_send_item (op, tmp);
2103     }
2104     if (QUERY_FLAG(spell, FLAG_KNOWN_CURSED) && !QUERY_FLAG(tmp, FLAG_KNOWN_CURSED) &&
2105     (QUERY_FLAG(tmp, FLAG_CURSED) || QUERY_FLAG(tmp, FLAG_DAMNED))) {
2106     SET_FLAG(tmp, FLAG_KNOWN_CURSED);
2107     if (op->type==PLAYER)
2108     esrv_send_item (op, tmp);
2109     }
2110     } /* if item is not identified */
2111     } /* for the players inventory */
2112     } /* if detect magic/curse and object is a player */
2113     return 1;
2114     }
2115    
2116    
2117     /**
2118     * Checks if victim has overcharged mana. caster_level is the caster's (skill)
2119     * level whos spell did cause the overcharge.
2120     */
2121     static void charge_mana_effect(object *victim, int caster_level)
2122     {
2123    
2124     /* Prevent explosions for objects without mana. Without this check, doors
2125     * will explode, too.
2126     */
2127     if (victim->stats.maxsp <= 0)
2128     return;
2129    
2130     new_draw_info(NDI_UNIQUE, 0, victim, "You feel energy course through you.");
2131    
2132     if (victim->stats.sp >= victim->stats.maxsp*2) {
2133     object *tmp;
2134    
2135     new_draw_info(NDI_UNIQUE, 0, victim, "Your head explodes!");
2136    
2137     /* Explodes a fireball centered at player */
2138     tmp = get_archetype(EXPLODING_FIREBALL);
2139     tmp->dam_modifier = random_roll(1, caster_level, victim, PREFER_LOW)/5+1;
2140     tmp->stats.maxhp = random_roll(1, caster_level, victim, PREFER_LOW)/10+2;
2141     tmp->x = victim->x;
2142     tmp->y = victim->y;
2143     insert_ob_in_map(tmp, victim->map, NULL, 0);
2144     victim->stats.sp = 2*victim->stats.maxsp;
2145     }
2146     else if (victim->stats.sp >= victim->stats.maxsp*1.88) {
2147     new_draw_info(NDI_UNIQUE, NDI_ORANGE, victim, "You feel like your head is going to explode.");
2148     }
2149     else if (victim->stats.sp >= victim->stats.maxsp*1.66) {
2150     new_draw_info(NDI_UNIQUE, 0, victim, "You get a splitting headache!");
2151     }
2152     else if (victim->stats.sp >= victim->stats.maxsp*1.5) {
2153     new_draw_info(NDI_UNIQUE, 0, victim, "Chaos fills your world.");
2154     confuse_player(victim, victim, 99);
2155     }
2156     else if (victim->stats.sp >= victim->stats.maxsp*1.25) {
2157     new_draw_info(NDI_UNIQUE, 0, victim, "You start hearing voices.");
2158     }
2159     }
2160    
2161     /* cast_transfer
2162     * This spell transfers sp from the player to another person.
2163     * We let the target go above their normal maximum SP.
2164     */
2165    
2166     int cast_transfer(object *op,object *caster, object *spell, int dir) {
2167     object *plyr=NULL;
2168     sint16 x, y;
2169     mapstruct *m;
2170     int mflags;
2171    
2172     m = op->map;
2173     x = op->x+freearr_x[dir];
2174     y = op->y+freearr_y[dir];
2175    
2176     mflags = get_map_flags(m, &m, x, y, &x, &y);
2177    
2178     if (!(mflags & P_OUT_OF_MAP) && mflags & P_IS_ALIVE) {
2179     for(plyr=get_map_ob(m, x, y); plyr!=NULL; plyr=plyr->above)
2180     if (plyr != op && QUERY_FLAG(plyr, FLAG_ALIVE))
2181     break;
2182     }
2183    
2184    
2185     /* If we did not find a player in the specified direction, transfer
2186     * to anyone on top of us. This is used for the rune of transference mostly.
2187     */
2188     if(plyr==NULL)
2189     for(plyr=get_map_ob(op->map,op->x,op->y); plyr!=NULL; plyr=plyr->above)
2190     if (plyr != op && QUERY_FLAG(plyr, FLAG_ALIVE))
2191     break;
2192    
2193     if (!plyr) {
2194     new_draw_info(NDI_BLACK, 0, op, "There is no one there.");
2195     return 0;
2196     }
2197     /* give sp */
2198     if(spell->stats.dam > 0) {
2199     plyr->stats.sp += spell->stats.dam + SP_level_dam_adjust(caster, spell);
2200     charge_mana_effect(plyr, caster_level(caster, spell));
2201     return 1;
2202     }
2203     /* suck sp away. Can't suck sp from yourself */
2204     else if (op != plyr) {
2205     /* old dragin magic used floats. easier to just use ints and divide by 100 */
2206    
2207     int rate = -spell->stats.dam + SP_level_dam_adjust(caster, spell), sucked;
2208    
2209     if (rate > 95) rate=95;
2210    
2211     sucked = (plyr->stats.sp * rate) / 100;
2212     plyr->stats.sp -= sucked;
2213     if (QUERY_FLAG(op, FLAG_ALIVE)) {
2214     /* Player doesn't get full credit */
2215     sucked = (sucked * rate) / 100;
2216     op->stats.sp += sucked;
2217     if (sucked > 0) {
2218     charge_mana_effect(op, caster_level(caster, spell));
2219     }
2220     }
2221     return 1;
2222     }
2223     return 0;
2224     }
2225    
2226    
2227     /* counterspell: nullifies spell effects.
2228     * op is the counterspell object, dir is the direction
2229     * it was cast in.
2230     * Basically, if the object has a magic attacktype,
2231     * this may nullify it.
2232     */
2233     void counterspell(object *op,int dir)
2234     {
2235     object *tmp, *head, *next;
2236     int mflags;
2237     mapstruct *m;
2238     sint16 sx,sy;
2239    
2240     sx = op->x + freearr_x[dir];
2241     sy = op->y + freearr_y[dir];
2242     m = op->map;
2243     mflags = get_map_flags(m, &m, sx, sy, &sx, &sy);
2244     if (mflags & P_OUT_OF_MAP) return;
2245    
2246     for(tmp=get_map_ob(m,sx,sy); tmp!=NULL; tmp=next) {
2247     next = tmp->above;
2248    
2249     /* Need to look at the head object - otherwise, if tmp
2250     * points to a monster, we don't have all the necessary
2251     * info for it.
2252     */
2253     if (tmp->head) head = tmp->head;
2254     else head = tmp;
2255    
2256     /* don't attack our own spells */
2257     if(tmp->owner && tmp->owner == op->owner) continue;
2258    
2259     /* Basically, if the object is magical and not counterspell,
2260     * we will more or less remove the object. Don't counterspell
2261     * monsters either.
2262     */
2263    
2264     if (head->attacktype & AT_MAGIC &&
2265     !(head->attacktype & AT_COUNTERSPELL) &&
2266     !QUERY_FLAG(head,FLAG_MONSTER) &&
2267     (op->level > head->level)) {
2268     remove_ob(head);
2269     free_object(head);
2270     } else switch(head->type) {
2271     case SPELL_EFFECT:
2272     if(op->level > head->level) {
2273     remove_ob(head);
2274     free_object(head);
2275     }
2276     break;
2277    
2278     /* I really don't get this rune code that much - that
2279     * random chance seems really low.
2280     */
2281     case RUNE:
2282     if(rndm(0, 149) == 0) {
2283     head->stats.hp--; /* weaken the rune */
2284     if(!head->stats.hp) {
2285     remove_ob(head);
2286     free_object(head);
2287     }
2288     }
2289     break;
2290     }
2291     }
2292     }
2293    
2294    
2295    
2296     /* cast_consecrate() - a spell to make an altar your god's */
2297     int cast_consecrate(object *op, object *caster, object *spell) {
2298     char buf[MAX_BUF];
2299    
2300     object *tmp, *god=find_god(determine_god(op));
2301    
2302     if(!god) {
2303     new_draw_info(NDI_UNIQUE, 0,op,
2304     "You can't consecrate anything if you don't worship a god!");
2305     return 0;
2306     }
2307    
2308     for(tmp=op->below;tmp;tmp=tmp->below) {
2309     if(QUERY_FLAG(tmp,FLAG_IS_FLOOR)) break;
2310     if(tmp->type==HOLY_ALTAR) {
2311    
2312     if(tmp->level > caster_level(caster, spell)) {
2313     new_draw_info_format(NDI_UNIQUE, 0,op,
2314     "You are not powerful enough to reconsecrate the %s", tmp->name);
2315     return 0;
2316     } else {
2317     /* If we got here, we are consecrating an altar */
2318     if(tmp->name) free_string(tmp->name);
2319     sprintf(buf,"Altar of %s",god->name);
2320     tmp->name = add_string(buf);
2321     tmp->level = caster_level(caster, spell);
2322     tmp->other_arch = god->arch;
2323     if(op->type==PLAYER) esrv_update_item(UPD_NAME, op, tmp);
2324     new_draw_info_format(NDI_UNIQUE,0, op,
2325     "You consecrated the altar to %s!",god->name);
2326     return 1;
2327     }
2328     }
2329     }
2330     new_draw_info(NDI_UNIQUE, 0,op,"You are not standing over an altar!");
2331     return 0;
2332     }
2333    
2334     /* animate_weapon -
2335     * Generalization of staff_to_snake. Makes a golem out of the caster's weapon.
2336     * The golem is based on the archetype specified, modified by the caster's level
2337     * and the attributes of the weapon. The weapon is inserted in the golem's
2338     * inventory so that it falls to the ground when the golem dies.
2339     * This code was very odd - code early on would only let players use the spell,
2340     * yet the code wass full of player checks. I've presumed that the code
2341     * that only let players use it was correct, and removed all the other
2342     * player checks. MSW 2003-01-06
2343     */
2344    
2345     int animate_weapon(object *op,object *caster,object *spell, int dir) {
2346     object *weapon, *tmp;
2347     char buf[MAX_BUF];
2348     int a, i;
2349     sint16 x, y;
2350     mapstruct *m;
2351     materialtype_t *mt;
2352    
2353     if(!spell->other_arch){
2354     new_draw_info(NDI_UNIQUE, 0,op,"Oops, program error!");
2355     LOG(llevError,"animate_weapon failed: spell %s missing other_arch!\n", spell->name);
2356     return 0;
2357     }
2358     /* exit if it's not a player using this spell. */
2359     if(op->type!=PLAYER) return 0;
2360    
2361     /* if player already has a golem, abort */
2362     if(op->contr->ranges[range_golem]!=NULL && op->contr->golem_count == op->contr->ranges[range_golem]->count) {
2363     control_golem(op->contr->ranges[range_golem],dir);
2364     return 0;
2365     }
2366    
2367     /* if no direction specified, pick one */
2368     if(!dir)
2369     dir=find_free_spot(NULL,op->map,op->x,op->y,1,9);
2370    
2371     m = op->map;
2372     x = op->x+freearr_x[dir];
2373     y = op->y+freearr_y[dir];
2374    
2375     /* if there's no place to put the golem, abort */
2376     if((dir==-1) || (get_map_flags(m, &m, x, y, &x, &y) & P_OUT_OF_MAP) ||
2377     ((spell->other_arch->clone.move_type & GET_MAP_MOVE_BLOCK(m, x, y)) == spell->other_arch->clone.move_type)) {
2378     new_draw_info(NDI_UNIQUE, 0,op,"There is something in the way.");
2379     return 0;
2380     }
2381    
2382     /* Use the weapon marked by the player. */
2383     weapon = find_marked_object(op);
2384    
2385     if (!weapon) {
2386     new_draw_info(NDI_BLACK, 0, op, "You must mark a weapon to use with this spell!");
2387     return 0;
2388     }
2389     if (spell->race && strcmp(weapon->arch->name, spell->race)) {
2390     new_draw_info(NDI_UNIQUE, 0,op,"The spell fails to transform your weapon.");
2391     return 0;
2392     }
2393     if (weapon->type != WEAPON) {
2394     new_draw_info(NDI_UNIQUE, 0,op,"You need to wield a weapon to animate it.");
2395     return 0;
2396     }
2397     if (QUERY_FLAG(weapon, FLAG_APPLIED)) {
2398     new_draw_info_format(NDI_BLACK, 0, op, "You need to unequip %s before using it in this spell",
2399     query_name(weapon));
2400     return 0;
2401     }
2402    
2403     if (weapon->nrof > 1) {
2404     tmp = get_split_ob(weapon, 1);
2405     esrv_send_item(op, weapon);
2406     weapon = tmp;
2407     }
2408    
2409     /* create the golem object */
2410     tmp=arch_to_object(spell->other_arch);
2411    
2412     /* if animated by a player, give the player control of the golem */
2413     CLEAR_FLAG(tmp, FLAG_MONSTER);
2414     SET_FLAG(tmp, FLAG_FRIENDLY);
2415     tmp->stats.exp=0;
2416     add_friendly_object(tmp);
2417     tmp->type=GOLEM;
2418     set_owner(tmp,op);
2419     set_spell_skill(op, caster, spell, tmp);
2420     op->contr->ranges[range_golem]=tmp;
2421     op->contr->shoottype=range_golem;
2422     op->contr->golem_count = tmp->count;
2423    
2424     /* Give the weapon to the golem now. A bit of a hack to check the
2425     * removed flag - it should only be set if get_split_object was
2426     * used above.
2427     */
2428     if (!QUERY_FLAG(weapon, FLAG_REMOVED))
2429     remove_ob (weapon);
2430     insert_ob_in_ob (weapon, tmp);
2431     esrv_send_item(op, weapon);
2432     /* To do everything necessary to let a golem use the weapon is a pain,
2433     * so instead, just set it as equipped (otherwise, we need to update
2434     * body_info, skills, etc)
2435     */
2436     SET_FLAG (tmp, FLAG_USE_WEAPON);
2437     SET_FLAG(weapon, FLAG_APPLIED);
2438     fix_player(tmp);
2439    
2440     /* There used to be 'odd' code that basically seemed to take the absolute
2441     * value of the weapon->magic an use that. IMO, that doesn't make sense -
2442     * if you're using a crappy weapon, it shouldn't be as good.
2443     */
2444    
2445     /* modify weapon's animated wc */
2446     tmp->stats.wc = tmp->stats.wc - SP_level_range_adjust(caster,spell)
2447     - 5 * weapon->stats.Dex - 2 * weapon->stats.Str - weapon->magic;
2448     if(tmp->stats.wc<-127) tmp->stats.wc = -127;
2449    
2450     /* Modify hit points for weapon */
2451     tmp->stats.maxhp = tmp->stats.maxhp + spell->duration +
2452     SP_level_duration_adjust(caster, spell) +
2453     + 8 * weapon->magic + 12 * weapon->stats.Con;
2454     if(tmp->stats.maxhp<0) tmp->stats.maxhp=10;
2455     tmp->stats.hp = tmp->stats.maxhp;
2456    
2457     /* Modify weapon's damage */
2458     tmp->stats.dam = spell->stats.dam + SP_level_dam_adjust(caster, spell)
2459     + weapon->stats.dam
2460     + weapon->magic
2461     + 5 * weapon->stats.Str;
2462     if(tmp->stats.dam<0) tmp->stats.dam=127;
2463    
2464    
2465     /* attacktype */
2466     if ( ! tmp->attacktype)
2467     tmp->attacktype = AT_PHYSICAL;
2468    
2469     mt = NULL;
2470     if (op->materialname != NULL)
2471     mt = name_to_material(op->materialname);
2472     if (mt != NULL) {
2473     for (i=0; i < NROFATTACKS; i++)
2474     tmp->resist[i] = 50 - (mt->save[i] * 5);
2475     a = mt->save[0];
2476     } else {
2477     for (i=0; i < NROFATTACKS; i++)
2478     tmp->resist[i] = 5;
2479     a = 10;
2480     }
2481     /* Set weapon's immunity */
2482     tmp->resist[ATNR_CONFUSION] = 100;
2483     tmp->resist[ATNR_POISON] = 100;
2484     tmp->resist[ATNR_SLOW] = 100;
2485     tmp->resist[ATNR_PARALYZE] = 100;
2486     tmp->resist[ATNR_TURN_UNDEAD] = 100;
2487     tmp->resist[ATNR_FEAR] = 100;
2488     tmp->resist[ATNR_DEPLETE] = 100;
2489     tmp->resist[ATNR_DEATH] = 100;
2490     tmp->resist[ATNR_BLIND] = 100;
2491    
2492     /* Improve weapon's armour value according to best save vs. physical of its material */
2493    
2494     if (a > 14) a = 14;
2495     tmp->resist[ATNR_PHYSICAL] = 100 - (int)((100.0-(float)tmp->resist[ATNR_PHYSICAL])/(30.0-2.0*a));
2496    
2497     /* Determine golem's speed */
2498     tmp->speed = 0.4 + 0.1 * SP_level_range_adjust(caster,spell);
2499    
2500     if(tmp->speed > 3.33) tmp->speed = 3.33;
2501    
2502     if (!spell->race) {
2503     sprintf(buf, "animated %s", weapon->name);
2504     if(tmp->name) free_string(tmp->name);
2505     tmp->name = add_string(buf);
2506    
2507     tmp->face = weapon->face;
2508     tmp->animation_id = weapon->animation_id;
2509     tmp->anim_speed = weapon->anim_speed;
2510     tmp->last_anim = weapon->last_anim;
2511     tmp->state = weapon->state;
2512     if(QUERY_FLAG(weapon, FLAG_ANIMATE)) {
2513     SET_FLAG(tmp,FLAG_ANIMATE);
2514     } else {
2515     CLEAR_FLAG(tmp,FLAG_ANIMATE);
2516     }
2517     update_ob_speed(tmp);
2518     }
2519    
2520     /* make experience increase in proportion to the strength of the summoned creature. */
2521     tmp->stats.exp *= 1 + (MAX(spell->stats.maxgrace, spell->stats.sp) / caster_level(caster, spell));
2522    
2523     tmp->speed_left= -1;
2524     tmp->x=x;
2525     tmp->y=y;
2526     tmp->direction=dir;
2527     insert_ob_in_map(tmp,m,op,0);
2528     return 1;
2529     }
2530    
2531     /* cast_daylight() - changes the map darkness level *lower* */
2532    
2533     /* cast_change_map_lightlevel: Was cast_daylight/nightfall.
2534     * This changes the light level for the entire map.
2535     */
2536    
2537     int cast_change_map_lightlevel( object *op, object *caster, object *spell ) {
2538     int success;
2539    
2540     if(!op->map) return 0; /* shouldnt happen */
2541    
2542     success=change_map_light(op->map,spell->stats.dam);
2543     if(!success) {
2544     if (spell->stats.dam < 0)
2545     new_draw_info(NDI_UNIQUE,0,op,"It can be no brighter here.");
2546     else
2547     new_draw_info(NDI_UNIQUE,0,op,"It can be no darker here.");
2548     }
2549     return success;
2550     }
2551    
2552    
2553    
2554    
2555    
2556     /* create an aura spell object and put it in the player's inventory.
2557     * as usual, op is player, caster is the object casting the spell,
2558     * spell is the spell object itself.
2559     */
2560     int create_aura(object *op, object *caster, object *spell)
2561     {
2562     int refresh=0;
2563     object *new_aura;
2564    
2565     new_aura = present_arch_in_ob(spell->other_arch, op);
2566     if (new_aura) refresh=1;
2567     else new_aura = arch_to_object(spell->other_arch);
2568    
2569     new_aura->duration = spell->duration +
2570     10* SP_level_duration_adjust(caster,spell);
2571    
2572     new_aura->stats.dam = spell->stats.dam
2573     +SP_level_dam_adjust(caster,spell);
2574    
2575     set_owner(new_aura,op);
2576     set_spell_skill(op, caster, spell, new_aura);
2577     new_aura->attacktype= spell->attacktype;
2578    
2579     new_aura->level = caster_level(caster, spell);
2580     if (refresh)
2581     new_draw_info(NDI_UNIQUE, 0, op, "You recast the spell while in effect.");
2582     else
2583     insert_ob_in_ob(new_aura, op);
2584     return 1;
2585     }
2586    
2587    
2588     /* move aura function. An aura is a part of someone's inventory,
2589     * which he carries with him, but which acts on the map immediately
2590     * around him.
2591     * Aura parameters:
2592     * duration: duration counter.
2593     * attacktype: aura's attacktype
2594     * other_arch: archetype to drop where we attack
2595     */
2596    
2597     void move_aura(object *aura) {
2598     int i, mflags;
2599     object *env;
2600     mapstruct *m;
2601    
2602     /* auras belong in inventories */
2603     env = aura->env;
2604    
2605     /* no matter what we've gotta remove the aura...
2606     * we'll put it back if its time isn't up.
2607     */
2608     remove_ob(aura);
2609    
2610     /* exit if we're out of gas */
2611     if(aura->duration--< 0) {
2612     free_object(aura);
2613     return;
2614     }
2615    
2616     /* auras only exist in inventories */
2617     if(env == NULL || env->map==NULL) {
2618     free_object(aura);
2619     return;
2620     }
2621     aura->x = env->x;
2622     aura->y = env->y;
2623    
2624     /* we need to jump out of the inventory for a bit
2625     * in order to hit the map conveniently.
2626     */
2627     insert_ob_in_map(aura,env->map,aura,0);
2628    
2629     for(i=1;i<9;i++) {
2630     sint16 nx, ny;
2631     nx = aura->x + freearr_x[i];
2632     ny = aura->y + freearr_y[i];
2633     mflags = get_map_flags(env->map, &m, nx, ny, &nx, &ny);
2634    
2635     /* Consider the movement tyep of the person with the aura as
2636     * movement type of the aura. Eg, if the player is flying, the aura
2637     * is flying also, if player is walking, it is on the ground, etc.
2638     */
2639     if (!(mflags & P_OUT_OF_MAP) && !(OB_TYPE_MOVE_BLOCK(env, GET_MAP_MOVE_BLOCK(m, nx, ny)))) {
2640     hit_map(aura,i,aura->attacktype,0);
2641    
2642     if(aura->other_arch) {
2643     object *new_ob;
2644    
2645     new_ob = arch_to_object(aura->other_arch);
2646     new_ob->x = nx;
2647     new_ob->y = ny;
2648     insert_ob_in_map(new_ob,m,aura,0);
2649     }
2650     }
2651     }
2652     /* put the aura back in the player's inventory */
2653     remove_ob(aura);
2654     insert_ob_in_ob(aura, env);
2655     }
2656    
2657     /* moves the peacemaker spell.
2658     * op is the piece object.
2659     */
2660    
2661     void move_peacemaker(object *op) {
2662     object *tmp;
2663    
2664     for(tmp=get_map_ob(op->map,op->x,op->y);tmp!=NULL;tmp=tmp->above) {
2665     int atk_lev, def_lev;
2666     object *victim=tmp;
2667    
2668     if (tmp->head) victim=tmp->head;
2669     if (!QUERY_FLAG(victim,FLAG_MONSTER)) continue;
2670     if (QUERY_FLAG(victim,FLAG_UNAGGRESSIVE)) continue;
2671     if (victim->stats.exp == 0) continue;
2672    
2673     def_lev = MAX(1,victim->level);
2674     atk_lev = MAX(1,op->level);
2675    
2676     if (rndm(0, atk_lev-1) > def_lev) {
2677     /* make this sucker peaceful. */
2678    
2679     change_exp(get_owner(op),victim->stats.exp, op->skill, 0);
2680     victim->stats.exp=0;
2681     #if 0
2682     /* No idea why these were all set to zero - if something
2683     * makes this creature agressive, he should still do damage.
2684     */
2685     victim->stats.dam = 0;
2686     victim->stats.sp = 0;
2687     victim->stats.grace = 0;
2688     victim->stats.Pow = 0;
2689     #endif
2690     victim->attack_movement = RANDO2;
2691     SET_FLAG(victim,FLAG_UNAGGRESSIVE);
2692     SET_FLAG(victim,FLAG_RUN_AWAY);
2693     SET_FLAG(victim,FLAG_RANDOM_MOVE);
2694     CLEAR_FLAG(victim,FLAG_MONSTER);
2695     if(victim->name) {
2696     new_draw_info_format(NDI_UNIQUE,0,op->owner,"%s no longer feels like fighting.",victim->name);
2697     }
2698     }
2699     }
2700     }
2701    
2702    
2703     /* This writes a rune that contains the appropriate message.
2704     * There really isn't any adjustments we make.
2705     */
2706    
2707     int write_mark(object *op, object *spell, const char *msg) {
2708     char rune[HUGE_BUF];
2709     object *tmp;
2710    
2711     if (!msg || msg[0] == 0) {
2712     new_draw_info(NDI_UNIQUE, 0, op, "Write what?");
2713     return 0;
2714     }
2715    
2716     if (strcasestr_local(msg, "endmsg")) {
2717     new_draw_info(NDI_UNIQUE, 0, op, "Trying to cheat are we?");
2718     LOG(llevInfo,"write_rune: player %s tried to write bogus rune %s\n", op->name, msg);
2719     return 0;
2720     }
2721     if (!spell->other_arch) return 0;
2722     tmp = arch_to_object(spell->other_arch);
2723     strncpy(rune, msg, HUGE_BUF-2);
2724     rune[HUGE_BUF-2] = 0;
2725     strcat(rune, "\n");
2726     tmp->race = add_string (op->name); /*Save the owner of the rune*/
2727     tmp->msg = add_string(rune);
2728     tmp->x = op->x;
2729     tmp->y = op->y;
2730     insert_ob_in_map(tmp, op->map, op, INS_BELOW_ORIGINATOR);
2731     return 1;
2732     }