ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_effect.c
Revision: 1.11
Committed: Fri Jun 2 02:09:02 2006 UTC (17 years, 11 months ago) by pippijn
Content type: text/plain
Branch: MAIN
CVS Tags: LAST_C_VERSION, difficulty_fix_merge_060810_2300
Branch point for: difficulty_fix
Changes since 1.10: +3 -3 lines
Log Message:
Fixed typo.

File Contents

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