ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_effect.c
Revision: 1.2
Committed: Wed Mar 22 03:13:21 2006 UTC (18 years, 2 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.1: +12 -9 lines
Log Message:
Fix the upstream fix for the bug recently reported by GHJ

File Contents

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