ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_effect.C
Revision: 1.2
Committed: Thu Aug 17 20:23:32 2006 UTC (17 years, 10 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.1: +1 -3 lines
Log Message:
get rid of esrv_map_scroll and MapNewmapCmd, map update will handle it automatically

File Contents

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