ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_effect.c
Revision: 1.6
Committed: Sun May 7 12:49:26 2006 UTC (18 years, 1 month ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.5: +4 -6 lines
Log Message:
distconf

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