ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_effect.c
Revision: 1.5
Committed: Sun May 7 12:41:50 2006 UTC (18 years, 1 month ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.4: +2 -3 lines
Log Message:
clarify code

File Contents

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