ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_effect.C
Revision: 1.7
Committed: Sun Sep 3 00:18:42 2006 UTC (17 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.6: +58 -68 lines
Log Message:
THIS CODE WILL NOT COMPILE
use the STABLE tag instead.

- major changes in object lifetime and memory management
- replaced manual refcounting by shstr class
- removed quest system
- many optimisations
- major changes

File Contents

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