ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_effect.C
Revision: 1.5
Committed: Tue Aug 29 08:01:38 2006 UTC (17 years, 8 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.4: +1051 -1051 lines
Log Message:
expand initial tabs to spaces

File Contents

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