magic.c
1 /* ************************************************************************ 2 * File: magic.c Part of CircleMUD * 3 * Usage: low-level functions for magic; spell template code * 4 * * 5 * All rights reserved. See license.doc for complete information. * 6 * * 7 * Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University * 8 * CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991. * 9 ************************************************************************ */ 10 11 12 #include "conf.h" 13 #include "sysdep.h" 14 15 #include "structs.h" 16 #include "utils.h" 17 #include "comm.h" 18 #include "spells.h" 19 #include "handler.h" 20 #include "db.h" 21 #include "interpreter.h" 22 #include "constants.h" 23 24 25 /* external variables */ 26 extern int mini_mud; 27 extern int pk_allowed; 28 extern struct spell_info_type spell_info[]; 29 30 /* external functions */ 31 byte saving_throws(int class_num, int type, int level); /* class.c */ 32 void clearMemory(struct char_data *ch); 33 void weight_change_object(struct obj_data *obj, int weight); 34 35 /* local functions */ 36 int mag_materials(struct char_data *ch, int item0, int item1, int item2, int extract, int verbose); 37 void perform_mag_groups(int level, struct char_data *ch, struct char_data *tch, int spellnum, int savetype); 38 int mag_savingthrow(struct char_data *ch, int type, int modifier); 39 void affect_update(void); 40 41 /* 42 * Saving throws are now in class.c as of bpl13. 43 */ 44 45 46 /* 47 * Negative apply_saving_throw[] values make saving throws better! 48 * Then, so do negative modifiers. Though people may be used to 49 * the reverse of that. It's due to the code modifying the target 50 * saving throw instead of the random number of the character as 51 * in some other systems. 52 */ 53 int mag_savingthrow(struct char_data *ch, int type, int modifier) 54 { 55 /* NPCs use warrior tables according to some book */ 56 int class_sav = CLASS_WARRIOR; 57 int save; 58 59 if (!IS_NPC(ch)) 60 class_sav = GET_CLASS(ch); 61 62 save = saving_throws(class_sav, type, GET_LEVEL(ch)); 63 save += GET_SAVE(ch, type); 64 save += modifier; 65 66 /* Throwing a 0 is always a failure. */ 67 if (MAX(1, save) < rand_number(0, 99)) 68 return (TRUE); 69 70 /* Oops, failed. Sorry. */ 71 return (FALSE); 72 } 73 74 75 /* affect_update: called from comm.c (causes spells to wear off) */ 76 void affect_update(void) 77 { 78 struct affected_type *af, *next; 79 struct char_data *i; 80 81 for (i = character_list; i; i = i->next) 82 for (af = i->affected; af; af = next) { 83 next = af->next; 84 if (af->duration >= 1) 85 af->duration--; 86 else if (af->duration == -1) /* No action */ 87 af->duration = -1; /* GODs only! unlimited */ 88 else { 89 if ((af->type > 0) && (af->type <= MAX_SPELLS)) 90 if (!af->next || (af->next->type != af->type) || 91 (af->next->duration > 0)) 92 if (spell_info[af->type].wear_off_msg) 93 send_to_char(i, "%s\r\n", spell_info[af->type].wear_off_msg); 94 affect_remove(i, af); 95 } 96 } 97 } 98 99 100 /* 101 * mag_materials: 102 * Checks for up to 3 vnums (spell reagents) in the player's inventory. 103 * 104 * No spells implemented in Circle use mag_materials, but you can use 105 * it to implement your own spells which require ingredients (i.e., some 106 * heal spell which requires a rare herb or some such.) 107 */ 108 int mag_materials(struct char_data *ch, int item0, int item1, int item2, 109 int extract, int verbose) 110 { 111 struct obj_data *tobj; 112 struct obj_data *obj0 = NULL, *obj1 = NULL, *obj2 = NULL; 113 114 for (tobj = ch->carrying; tobj; tobj = tobj->next_content) { 115 if ((item0 > 0) && (GET_OBJ_VNUM(tobj) == item0)) { 116 obj0 = tobj; 117 item0 = -1; 118 } else if ((item1 > 0) && (GET_OBJ_VNUM(tobj) == item1)) { 119 obj1 = tobj; 120 item1 = -1; 121 } else if ((item2 > 0) && (GET_OBJ_VNUM(tobj) == item2)) { 122 obj2 = tobj; 123 item2 = -1; 124 } 125 } 126 if ((item0 > 0) || (item1 > 0) || (item2 > 0)) { 127 if (verbose) { 128 switch (rand_number(0, 2)) { 129 case 0: 130 send_to_char(ch, "A wart sprouts on your nose.\r\n"); 131 break; 132 case 1: 133 send_to_char(ch, "Your hair falls out in clumps.\r\n"); 134 break; 135 case 2: 136 send_to_char(ch, "A huge corn develops on your big toe.\r\n"); 137 break; 138 } 139 } 140 return (FALSE); 141 } 142 if (extract) { 143 if (item0 < 0) 144 extract_obj(obj0); 145 if (item1 < 0) 146 extract_obj(obj1); 147 if (item2 < 0) 148 extract_obj(obj2); 149 } 150 if (verbose) { 151 send_to_char(ch, "A puff of smoke rises from your pack.\r\n"); 152 act("A puff of smoke rises from $n's pack.", TRUE, ch, NULL, NULL, TO_ROOM); 153 } 154 return (TRUE); 155 } 156 157 158 159 160 /* 161 * Every spell that does damage comes through here. This calculates the 162 * amount of damage, adds in any modifiers, determines what the saves are, 163 * tests for save and calls damage(). 164 * 165 * -1 = dead, otherwise the amount of damage done. 166 */ 167 int mag_damage(int level, struct char_data *ch, struct char_data *victim, 168 int spellnum, int savetype) 169 { 170 int dam = 0; 171 172 if (victim == NULL || ch == NULL) 173 return (0); 174 175 switch (spellnum) { 176 /* Mostly mages */ 177 case SPELL_MAGIC_MISSILE: 178 case SPELL_CHILL_TOUCH: /* chill touch also has an affect */ 179 if (IS_MAGIC_USER(ch)) 180 dam = dice(1, 8) + 1; 181 else 182 dam = dice(1, 6) + 1; 183 break; 184 case SPELL_BURNING_HANDS: 185 if (IS_MAGIC_USER(ch)) 186 dam = dice(3, 8) + 3; 187 else 188 dam = dice(3, 6) + 3; 189 break; 190 case SPELL_SHOCKING_GRASP: 191 if (IS_MAGIC_USER(ch)) 192 dam = dice(5, 8) + 5; 193 else 194 dam = dice(5, 6) + 5; 195 break; 196 case SPELL_LIGHTNING_BOLT: 197 if (IS_MAGIC_USER(ch)) 198 dam = dice(7, 8) + 7; 199 else 200 dam = dice(7, 6) + 7; 201 break; 202 case SPELL_COLOR_SPRAY: 203 if (IS_MAGIC_USER(ch)) 204 dam = dice(9, 8) + 9; 205 else 206 dam = dice(9, 6) + 9; 207 break; 208 case SPELL_FIREBALL: 209 if (IS_MAGIC_USER(ch)) 210 dam = dice(11, 8) + 11; 211 else 212 dam = dice(11, 6) + 11; 213 break; 214 215 /* Mostly clerics */ 216 case SPELL_DISPEL_EVIL: 217 dam = dice(6, 8) + 6; 218 if (IS_EVIL(ch)) { 219 victim = ch; 220 dam = GET_HIT(ch) - 1; 221 } else if (IS_GOOD(victim)) { 222 act("The gods protect $N.", FALSE, ch, 0, victim, TO_CHAR); 223 return (0); 224 } 225 break; 226 case SPELL_DISPEL_GOOD: 227 dam = dice(6, 8) + 6; 228 if (IS_GOOD(ch)) { 229 victim = ch; 230 dam = GET_HIT(ch) - 1; 231 } else if (IS_EVIL(victim)) { 232 act("The gods protect $N.", FALSE, ch, 0, victim, TO_CHAR); 233 return (0); 234 } 235 break; 236 237 238 case SPELL_CALL_LIGHTNING: 239 dam = dice(7, 8) + 7; 240 break; 241 242 case SPELL_HARM: 243 dam = dice(8, 8) + 8; 244 break; 245 246 case SPELL_ENERGY_DRAIN: 247 if (GET_LEVEL(victim) <= 2) 248 dam = 100; 249 else 250 dam = dice(1, 10); 251 break; 252 253 /* Area spells */ 254 case SPELL_EARTHQUAKE: 255 dam = dice(2, 8) + level; 256 break; 257 258 } /* switch(spellnum) */ 259 260 261 /* divide damage by two if victim makes his saving throw */ 262 if (mag_savingthrow(victim, savetype, 0)) 263 dam /= 2; 264 265 /* and finally, inflict the damage */ 266 return (damage(ch, victim, dam, spellnum)); 267 } 268 269 270 /* 271 * Every spell that does an affect comes through here. This determines 272 * the effect, whether it is added or replacement, whether it is legal or 273 * not, etc. 274 * 275 * affect_join(vict, aff, add_dur, avg_dur, add_mod, avg_mod) 276 */ 277 278 #define MAX_SPELL_AFFECTS 5 /* change if more needed */ 279 280 void mag_affects(int level, struct char_data *ch, struct char_data *victim, 281 int spellnum, int savetype) 282 { 283 struct affected_type af[MAX_SPELL_AFFECTS]; 284 bool accum_affect = FALSE, accum_duration = FALSE; 285 const char *to_vict = NULL, *to_room = NULL; 286 int i; 287 288 289 if (victim == NULL || ch == NULL) 290 return; 291 292 for (i = 0; i < MAX_SPELL_AFFECTS; i++) { 293 af[i].type = spellnum; 294 af[i].bitvector = 0; 295 af[i].modifier = 0; 296 af[i].location = APPLY_NONE; 297 } 298 299 switch (spellnum) { 300 301 case SPELL_CHILL_TOUCH: 302 af[0].location = APPLY_STR; 303 if (mag_savingthrow(victim, savetype, 0)) 304 af[0].duration = 1; 305 else 306 af[0].duration = 4; 307 af[0].modifier = -1; 308 accum_duration = TRUE; 309 to_vict = "You feel your strength wither!"; 310 break; 311 312 case SPELL_ARMOR: 313 af[0].location = APPLY_AC; 314 af[0].modifier = -20; 315 af[0].duration = 24; 316 accum_duration = TRUE; 317 to_vict = "You feel someone protecting you."; 318 break; 319 320 case SPELL_BLESS: 321 af[0].location = APPLY_HITROLL; 322 af[0].modifier = 2; 323 af[0].duration = 6; 324 325 af[1].location = APPLY_SAVING_SPELL; 326 af[1].modifier = -1; 327 af[1].duration = 6; 328 329 accum_duration = TRUE; 330 to_vict = "You feel righteous."; 331 break; 332 333 case SPELL_BLINDNESS: 334 if (MOB_FLAGGED(victim,MOB_NOBLIND) || mag_savingthrow(victim, savetype, 0)) { 335 send_to_char(ch, "You fail.\r\n"); 336 return; 337 } 338 339 af[0].location = APPLY_HITROLL; 340 af[0].modifier = -4; 341 af[0].duration = 2; 342 af[0].bitvector = AFF_BLIND; 343 344 af[1].location = APPLY_AC; 345 af[1].modifier = 40; 346 af[1].duration = 2; 347 af[1].bitvector = AFF_BLIND; 348 349 to_room = "$n seems to be blinded!"; 350 to_vict = "You have been blinded!"; 351 break; 352 353 case SPELL_CURSE: 354 if (mag_savingthrow(victim, savetype, 0)) { 355 send_to_char(ch, "%s", NOEFFECT); 356 return; 357 } 358 359 af[0].location = APPLY_HITROLL; 360 af[0].duration = 1 + (GET_LEVEL(ch) / 2); 361 af[0].modifier = -1; 362 af[0].bitvector = AFF_CURSE; 363 364 af[1].location = APPLY_DAMROLL; 365 af[1].duration = 1 + (GET_LEVEL(ch) / 2); 366 af[1].modifier = -1; 367 af[1].bitvector = AFF_CURSE; 368 369 accum_duration = TRUE; 370 accum_affect = TRUE; 371 to_room = "$n briefly glows red!"; 372 to_vict = "You feel very uncomfortable."; 373 break; 374 375 case SPELL_DETECT_ALIGN: 376 af[0].duration = 12 + level; 377 af[0].bitvector = AFF_DETECT_ALIGN; 378 accum_duration = TRUE; 379 to_vict = "Your eyes tingle."; 380 break; 381 382 case SPELL_DETECT_INVIS: 383 af[0].duration = 12 + level; 384 af[0].bitvector = AFF_DETECT_INVIS; 385 accum_duration = TRUE; 386 to_vict = "Your eyes tingle."; 387 break; 388 389 case SPELL_DETECT_MAGIC: 390 af[0].duration = 12 + level; 391 af[0].bitvector = AFF_DETECT_MAGIC; 392 accum_duration = TRUE; 393 to_vict = "Your eyes tingle."; 394 break; 395 396 case SPELL_INFRAVISION: 397 af[0].duration = 12 + level; 398 af[0].bitvector = AFF_INFRAVISION; 399 accum_duration = TRUE; 400 to_vict = "Your eyes glow red."; 401 to_room = "$n's eyes glow red."; 402 break; 403 404 case SPELL_INVISIBLE: 405 if (!victim) 406 victim = ch; 407 408 af[0].duration = 12 + (GET_LEVEL(ch) / 4); 409 af[0].modifier = -40; 410 af[0].location = APPLY_AC; 411 af[0].bitvector = AFF_INVISIBLE; 412 accum_duration = TRUE; 413 to_vict = "You vanish."; 414 to_room = "$n slowly fades out of existence."; 415 break; 416 417 case SPELL_POISON: 418 if (mag_savingthrow(victim, savetype, 0)) { 419 send_to_char(ch, "%s", NOEFFECT); 420 return; 421 } 422 423 af[0].location = APPLY_STR; 424 af[0].duration = GET_LEVEL(ch); 425 af[0].modifier = -2; 426 af[0].bitvector = AFF_POISON; 427 to_vict = "You feel very sick."; 428 to_room = "$n gets violently ill!"; 429 break; 430 431 case SPELL_PROT_FROM_EVIL: 432 af[0].duration = 24; 433 af[0].bitvector = AFF_PROTECT_EVIL; 434 accum_duration = TRUE; 435 to_vict = "You feel invulnerable!"; 436 break; 437 438 case SPELL_SANCTUARY: 439 af[0].duration = 4; 440 af[0].bitvector = AFF_SANCTUARY; 441 442 accum_duration = TRUE; 443 to_vict = "A white aura momentarily surrounds you."; 444 to_room = "$n is surrounded by a white aura."; 445 break; 446 447 case SPELL_SLEEP: 448 if (!pk_allowed && !IS_NPC(ch) && !IS_NPC(victim)) 449 return; 450 if (MOB_FLAGGED(victim, MOB_NOSLEEP)) 451 return; 452 if (mag_savingthrow(victim, savetype, 0)) 453 return; 454 455 af[0].duration = 4 + (GET_LEVEL(ch) / 4); 456 af[0].bitvector = AFF_SLEEP; 457 458 if (GET_POS(victim) > POS_SLEEPING) { 459 send_to_char(victim, "You feel very sleepy... Zzzz......\r\n"); 460 act("$n goes to sleep.", TRUE, victim, 0, 0, TO_ROOM); 461 GET_POS(victim) = POS_SLEEPING; 462 } 463 break; 464 465 case SPELL_STRENGTH: 466 if (GET_ADD(victim) == 100) 467 return; 468 469 af[0].location = APPLY_STR; 470 af[0].duration = (GET_LEVEL(ch) / 2) + 4; 471 af[0].modifier = 1 + (level > 18); 472 accum_duration = TRUE; 473 accum_affect = TRUE; 474 to_vict = "You feel stronger!"; 475 break; 476 477 case SPELL_SENSE_LIFE: 478 to_vict = "Your feel your awareness improve."; 479 af[0].duration = GET_LEVEL(ch); 480 af[0].bitvector = AFF_SENSE_LIFE; 481 accum_duration = TRUE; 482 break; 483 484 case SPELL_WATERWALK: 485 af[0].duration = 24; 486 af[0].bitvector = AFF_WATERWALK; 487 accum_duration = TRUE; 488 to_vict = "You feel webbing between your toes."; 489 break; 490 } 491 492 /* 493 * If this is a mob that has this affect set in its mob file, do not 494 * perform the affect. This prevents people from un-sancting mobs 495 * by sancting them and waiting for it to fade, for example. 496 */ 497 if (IS_NPC(victim) && !affected_by_spell(victim, spellnum)) 498 for (i = 0; i < MAX_SPELL_AFFECTS; i++) 499 if (AFF_FLAGGED(victim, af[i].bitvector)) { 500 send_to_char(ch, "%s", NOEFFECT); 501 return; 502 } 503 504 /* 505 * If the victim is already affected by this spell, and the spell does 506 * not have an accumulative effect, then fail the spell. 507 */ 508 if (affected_by_spell(victim,spellnum) && !(accum_duration||accum_affect)) { 509 send_to_char(ch, "%s", NOEFFECT); 510 return; 511 } 512 513 for (i = 0; i < MAX_SPELL_AFFECTS; i++) 514 if (af[i].bitvector || (af[i].location != APPLY_NONE)) 515 affect_join(victim, af+i, accum_duration, FALSE, accum_affect, FALSE); 516 517 if (to_vict != NULL) 518 act(to_vict, FALSE, victim, 0, ch, TO_CHAR); 519 if (to_room != NULL) 520 act(to_room, TRUE, victim, 0, ch, TO_ROOM); 521 } 522 523 524 /* 525 * This function is used to provide services to mag_groups. This function 526 * is the one you should change to add new group spells. 527 */ 528 void perform_mag_groups(int level, struct char_data *ch, 529 struct char_data *tch, int spellnum, int savetype) 530 { 531 switch (spellnum) { 532 case SPELL_GROUP_HEAL: 533 mag_points(level, ch, tch, SPELL_HEAL, savetype); 534 break; 535 case SPELL_GROUP_ARMOR: 536 mag_affects(level, ch, tch, SPELL_ARMOR, savetype); 537 break; 538 case SPELL_GROUP_RECALL: 539 spell_recall(level, ch, tch, NULL); 540 break; 541 } 542 } 543 544 545 /* 546 * Every spell that affects the group should run through here 547 * perform_mag_groups contains the switch statement to send us to the right 548 * magic. 549 * 550 * group spells affect everyone grouped with the caster who is in the room, 551 * caster last. 552 * 553 * To add new group spells, you shouldn't have to change anything in 554 * mag_groups -- just add a new case to perform_mag_groups. 555 */ 556 void mag_groups(int level, struct char_data *ch, int spellnum, int savetype) 557 { 558 struct char_data *tch, *k; 559 struct follow_type *f, *f_next; 560 561 if (ch == NULL) 562 return; 563 564 if (!AFF_FLAGGED(ch, AFF_GROUP)) 565 return; 566 if (ch->master != NULL) 567 k = ch->master; 568 else 569 k = ch; 570 for (f = k->followers; f; f = f_next) { 571 f_next = f->next; 572 tch = f->follower; 573 if (IN_ROOM(tch) != IN_ROOM(ch)) 574 continue; 575 if (!AFF_FLAGGED(tch, AFF_GROUP)) 576 continue; 577 if (ch == tch) 578 continue; 579 perform_mag_groups(level, ch, tch, spellnum, savetype); 580 } 581 582 if ((k != ch) && AFF_FLAGGED(k, AFF_GROUP)) 583 perform_mag_groups(level, ch, k, spellnum, savetype); 584 perform_mag_groups(level, ch, ch, spellnum, savetype); 585 } 586 587 588 /* 589 * mass spells affect every creature in the room except the caster. 590 * 591 * No spells of this class currently implemented. 592 */ 593 void mag_masses(int level, struct char_data *ch, int spellnum, int savetype) 594 { 595 struct char_data *tch, *tch_next; 596 597 for (tch = world[IN_ROOM(ch)].people; tch; tch = tch_next) { 598 tch_next = tch->next_in_room; 599 if (tch == ch) 600 continue; 601 602 switch (spellnum) { 603 } 604 } 605 } 606 607 608 /* 609 * Every spell that affects an area (room) runs through here. These are 610 * generally offensive spells. This calls mag_damage to do the actual 611 * damage -- all spells listed here must also have a case in mag_damage() 612 * in order for them to work. 613 * 614 * area spells have limited targets within the room. 615 */ 616 void mag_areas(int level, struct char_data *ch, int spellnum, int savetype) 617 { 618 struct char_data *tch, *next_tch; 619 const char *to_char = NULL, *to_room = NULL; 620 621 if (ch == NULL) 622 return; 623 624 /* 625 * to add spells to this fn, just add the message here plus an entry 626 * in mag_damage for the damaging part of the spell. 627 */ 628 switch (spellnum) { 629 case SPELL_EARTHQUAKE: 630 to_char = "You gesture and the earth begins to shake all around you!"; 631 to_room ="$n gracefully gestures and the earth begins to shake violently!"; 632 break; 633 } 634 635 if (to_char != NULL) 636 act(to_char, FALSE, ch, 0, 0, TO_CHAR); 637 if (to_room != NULL) 638 act(to_room, FALSE, ch, 0, 0, TO_ROOM); 639 640 641 for (tch = world[IN_ROOM(ch)].people; tch; tch = next_tch) { 642 next_tch = tch->next_in_room; 643 644 /* 645 * The skips: 1: the caster 646 * 2: immortals 647 * 3: if no pk on this mud, skips over all players 648 * 4: pets (charmed NPCs) 649 */ 650 651 if (tch == ch) 652 continue; 653 if (!IS_NPC(tch) && GET_LEVEL(tch) >= LVL_IMMORT) 654 continue; 655 if (!pk_allowed && !IS_NPC(ch) && !IS_NPC(tch)) 656 continue; 657 if (!IS_NPC(ch) && IS_NPC(tch) && AFF_FLAGGED(tch, AFF_CHARM)) 658 continue; 659 660 /* Doesn't matter if they die here so we don't check. -gg 6/24/98 */ 661 mag_damage(level, ch, tch, spellnum, 1); 662 } 663 } 664 665 666 /* 667 * Every spell which summons/gates/conjours a mob comes through here. 668 * 669 * None of these spells are currently implemented in CircleMUD; these 670 * were taken as examples from the JediMUD code. Summons can be used 671 * for spells like clone, ariel servant, etc. 672 * 673 * 10/15/97 (gg) - Implemented Animate Dead and Clone. 674 */ 675 676 /* 677 * These use act(), don't put the \r\n. 678 */ 679 const char *mag_summon_msgs[] = { 680 "\r\n", 681 "$n makes a strange magical gesture; you feel a strong breeze!", 682 "$n animates a corpse!", 683 "$N appears from a cloud of thick blue smoke!", 684 "$N appears from a cloud of thick green smoke!", 685 "$N appears from a cloud of thick red smoke!", 686 "$N disappears in a thick black cloud!" 687 "As $n makes a strange magical gesture, you feel a strong breeze.", 688 "As $n makes a strange magical gesture, you feel a searing heat.", 689 "As $n makes a strange magical gesture, you feel a sudden chill.", 690 "As $n makes a strange magical gesture, you feel the dust swirl.", 691 "$n magically divides!", 692 "$n animates a corpse!" 693 }; 694 695 /* 696 * Keep the \r\n because these use send_to_char. 697 */ 698 const char *mag_summon_fail_msgs[] = { 699 "\r\n", 700 "There are no such creatures.\r\n", 701 "Uh oh...\r\n", 702 "Oh dear.\r\n", 703 "Gosh durnit!\r\n", 704 "The elements resist!\r\n", 705 "You failed.\r\n", 706 "There is no corpse!\r\n" 707 }; 708 709 /* These mobiles do not exist. */ 710 #define MOB_MONSUM_I 130 711 #define MOB_MONSUM_II 140 712 #define MOB_MONSUM_III 150 713 #define MOB_GATE_I 160 714 #define MOB_GATE_II 170 715 #define MOB_GATE_III 180 716 717 /* Defined mobiles. */ 718 #define MOB_ELEMENTAL_BASE 20 /* Only one for now. */ 719 #define MOB_CLONE 10 720 #define MOB_ZOMBIE 11 721 #define MOB_AERIALSERVANT 19 722 723 724 void mag_summons(int level, struct char_data *ch, struct obj_data *obj, 725 int spellnum, int savetype) 726 { 727 struct char_data *mob = NULL; 728 struct obj_data *tobj, *next_obj; 729 int pfail = 0, msg = 0, fmsg = 0, num = 1, handle_corpse = FALSE, i; 730 mob_vnum mob_num; 731 732 if (ch == NULL) 733 return; 734 735 switch (spellnum) { 736 case SPELL_CLONE: 737 msg = 10; 738 fmsg = rand_number(2, 6); /* Random fail message. */ 739 mob_num = MOB_CLONE; 740 pfail = 50; /* 50% failure, should be based on something later. */ 741 break; 742 743 case SPELL_ANIMATE_DEAD: 744 if (obj == NULL || !IS_CORPSE(obj)) { 745 act(mag_summon_fail_msgs[7], FALSE, ch, 0, 0, TO_CHAR); 746 return; 747 } 748 handle_corpse = TRUE; 749 msg = 11; 750 fmsg = rand_number(2, 6); /* Random fail message. */ 751 mob_num = MOB_ZOMBIE; 752 pfail = 10; /* 10% failure, should vary in the future. */ 753 break; 754 755 default: 756 return; 757 } 758 759 if (AFF_FLAGGED(ch, AFF_CHARM)) { 760 send_to_char(ch, "You are too giddy to have any followers!\r\n"); 761 return; 762 } 763 if (rand_number(0, 101) < pfail) { 764 send_to_char(ch, "%s", mag_summon_fail_msgs[fmsg]); 765 return; 766 } 767 for (i = 0; i < num; i++) { 768 if (!(mob = read_mobile(mob_num, VIRTUAL))) { 769 send_to_char(ch, "You don't quite remember how to make that creature.\r\n"); 770 return; 771 } 772 char_to_room(mob, IN_ROOM(ch)); 773 IS_CARRYING_W(mob) = 0; 774 IS_CARRYING_N(mob) = 0; 775 SET_BIT(AFF_FLAGS(mob), AFF_CHARM); 776 if (spellnum == SPELL_CLONE) { 777 /* Don't mess up the prototype; use new string copies. */ 778 mob->player.name = strdup(GET_NAME(ch)); 779 mob->player.short_descr = strdup(GET_NAME(ch)); 780 } 781 act(mag_summon_msgs[msg], FALSE, ch, 0, mob, TO_ROOM); 782 add_follower(mob, ch); 783 } 784 if (handle_corpse) { 785 for (tobj = obj->contains; tobj; tobj = next_obj) { 786 next_obj = tobj->next_content; 787 obj_from_obj(tobj); 788 obj_to_char(tobj, mob); 789 } 790 extract_obj(obj); 791 } 792 } 793 794 795 void mag_points(int level, struct char_data *ch, struct char_data *victim, 796 int spellnum, int savetype) 797 { 798 int healing = 0, move = 0; 799 800 if (victim == NULL) 801 return; 802 803 switch (spellnum) { 804 case SPELL_CURE_LIGHT: 805 healing = dice(1, 8) + 1 + (level / 4); 806 send_to_char(victim, "You feel better.\r\n"); 807 break; 808 case SPELL_CURE_CRITIC: 809 healing = dice(3, 8) + 3 + (level / 4); 810 send_to_char(victim, "You feel a lot better!\r\n"); 811 break; 812 case SPELL_HEAL: 813 healing = 100 + dice(3, 8); 814 send_to_char(victim, "A warm feeling floods your body.\r\n"); 815 break; 816 } 817 GET_HIT(victim) = MIN(GET_MAX_HIT(victim), GET_HIT(victim) + healing); 818 GET_MOVE(victim) = MIN(GET_MAX_MOVE(victim), GET_MOVE(victim) + move); 819 update_pos(victim); 820 } 821 822 823 void mag_unaffects(int level, struct char_data *ch, struct char_data *victim, 824 int spellnum, int type) 825 { 826 int spell = 0, msg_not_affected = TRUE; 827 const char *to_vict = NULL, *to_room = NULL; 828 829 if (victim == NULL) 830 return; 831 832 switch (spellnum) { 833 case SPELL_HEAL: 834 /* 835 * Heal also restores health, so don't give the "no effect" message 836 * if the target isn't afflicted by the 'blindness' spell. 837 */ 838 msg_not_affected = FALSE; 839 /* fall-through */ 840 case SPELL_CURE_BLIND: 841 spell = SPELL_BLINDNESS; 842 to_vict = "Your vision returns!"; 843 to_room = "There's a momentary gleam in $n's eyes."; 844 break; 845 case SPELL_REMOVE_POISON: 846 spell = SPELL_POISON; 847 to_vict = "A warm feeling runs through your body!"; 848 to_room = "$n looks better."; 849 break; 850 case SPELL_REMOVE_CURSE: 851 spell = SPELL_CURSE; 852 to_vict = "You don't feel so unlucky."; 853 break; 854 default: 855 log("SYSERR: unknown spellnum %d passed to mag_unaffects.", spellnum); 856 return; 857 } 858 859 if (!affected_by_spell(victim, spell)) { 860 if (msg_not_affected) 861 send_to_char(ch, "%s", NOEFFECT); 862 return; 863 } 864 865 affect_from_char(victim, spell); 866 if (to_vict != NULL) 867 act(to_vict, FALSE, victim, 0, ch, TO_CHAR); 868 if (to_room != NULL) 869 act(to_room, TRUE, victim, 0, ch, TO_ROOM); 870 871 } 872 873 874 void mag_alter_objs(int level, struct char_data *ch, struct obj_data *obj, 875 int spellnum, int savetype) 876 { 877 const char *to_char = NULL, *to_room = NULL; 878 879 if (obj == NULL) 880 return; 881 882 switch (spellnum) { 883 case SPELL_BLESS: 884 if (!OBJ_FLAGGED(obj, ITEM_BLESS) && 885 (GET_OBJ_WEIGHT(obj) <= 5 * GET_LEVEL(ch))) { 886 SET_BIT(GET_OBJ_EXTRA(obj), ITEM_BLESS); 887 to_char = "$p glows briefly."; 888 } 889 break; 890 case SPELL_CURSE: 891 if (!OBJ_FLAGGED(obj, ITEM_NODROP)) { 892 SET_BIT(GET_OBJ_EXTRA(obj), ITEM_NODROP); 893 if (GET_OBJ_TYPE(obj) == ITEM_WEAPON) 894 GET_OBJ_VAL(obj, 2)--; 895 to_char = "$p briefly glows red."; 896 } 897 break; 898 case SPELL_INVISIBLE: 899 if (!OBJ_FLAGGED(obj, ITEM_NOINVIS | ITEM_INVISIBLE)) { 900 SET_BIT(GET_OBJ_EXTRA(obj), ITEM_INVISIBLE); 901 to_char = "$p vanishes."; 902 } 903 break; 904 case SPELL_POISON: 905 if (((GET_OBJ_TYPE(obj) == ITEM_DRINKCON) || 906 (GET_OBJ_TYPE(obj) == ITEM_FOUNTAIN) || 907 (GET_OBJ_TYPE(obj) == ITEM_FOOD)) && !GET_OBJ_VAL(obj, 3)) { 908 GET_OBJ_VAL(obj, 3) = 1; 909 to_char = "$p steams briefly."; 910 } 911 break; 912 case SPELL_REMOVE_CURSE: 913 if (OBJ_FLAGGED(obj, ITEM_NODROP)) { 914 REMOVE_BIT(GET_OBJ_EXTRA(obj), ITEM_NODROP); 915 if (GET_OBJ_TYPE(obj) == ITEM_WEAPON) 916 GET_OBJ_VAL(obj, 2)++; 917 to_char = "$p briefly glows blue."; 918 } 919 break; 920 case SPELL_REMOVE_POISON: 921 if (((GET_OBJ_TYPE(obj) == ITEM_DRINKCON) || 922 (GET_OBJ_TYPE(obj) == ITEM_FOUNTAIN) || 923 (GET_OBJ_TYPE(obj) == ITEM_FOOD)) && GET_OBJ_VAL(obj, 3)) { 924 GET_OBJ_VAL(obj, 3) = 0; 925 to_char = "$p steams briefly."; 926 } 927 break; 928 } 929 930 if (to_char == NULL) 931 send_to_char(ch, "%s", NOEFFECT); 932 else 933 act(to_char, TRUE, ch, obj, 0, TO_CHAR); 934 935 if (to_room != NULL) 936 act(to_room, TRUE, ch, obj, 0, TO_ROOM); 937 else if (to_char != NULL) 938 act(to_char, TRUE, ch, obj, 0, TO_ROOM); 939 940 } 941 942 943 944 void mag_creations(int level, struct char_data *ch, int spellnum) 945 { 946 struct obj_data *tobj; 947 obj_vnum z; 948 949 if (ch == NULL) 950 return; 951 /* level = MAX(MIN(level, LVL_IMPL), 1); - Hm, not used. */ 952 953 switch (spellnum) { 954 case SPELL_CREATE_FOOD: 955 z = 10; 956 break; 957 default: 958 send_to_char(ch, "Spell unimplemented, it would seem.\r\n"); 959 return; 960 } 961 962 if (!(tobj = read_object(z, VIRTUAL))) { 963 send_to_char(ch, "I seem to have goofed.\r\n"); 964 log("SYSERR: spell_creations, spell %d, obj %d: obj not found", 965 spellnum, z); 966 return; 967 } 968 obj_to_char(tobj, ch); 969 act("$n creates $p.", FALSE, ch, tobj, 0, TO_ROOM); 970 act("You create $p.", FALSE, ch, tobj, 0, TO_CHAR); 971 } 972