ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_effect.c
Revision: 1.4
Committed: Fri Apr 28 13:56:27 2006 UTC (18 years, 1 month ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.3: +5 -3 lines
Log Message:
Adding setting to allow for portals in apartments and other personal maps.

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