ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_effect.c
Revision: 1.6
Committed: Sun May 7 12:49:26 2006 UTC (18 years, 1 month ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.5: +4 -6 lines
Log Message:
distconf

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