Annotation of early-roguelike/urogue/magic.c, Revision 1.1
1.1 ! rubenllo 1: /*
! 2: magic.c - This file contains functions for casting magic spells
! 3:
! 4: UltraRogue: The Ultimate Adventure in the Dungeons of Doom
! 5: Copyright (C) 1986, 1992, 1993, 1995 Herb Chong
! 6: All rights reserved.
! 7:
! 8: Based on "Advanced Rogue"
! 9: Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
! 10: All rights reserved.
! 11:
! 12: Based on "Rogue: Exploring the Dungeons of Doom"
! 13: Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
! 14: All rights reserved.
! 15:
! 16: See the file LICENSE.TXT for full copyright and licensing information.
! 17: */
! 18:
! 19: #include <stdlib.h>
! 20: #include <string.h>
! 21: #include <ctype.h>
! 22: #include "rogue.h"
! 23:
! 24: /*
! 25: Cost for each level of spells level:
! 26: */
! 27:
! 28: static const int spell_cost[] = {1, 5, 17, 29, 53, 91, 159, 247, 396};
! 29:
! 30: static struct spells monst_spells[] =
! 31: {
! 32: {5, S_SELFTELEP, SCR_MAGIC},
! 33: {4, P_HEALING, POT_MAGIC | _TWO_},
! 34: {3, P_REGENERATE, POT_MAGIC},
! 35: {2, P_HEALING, POT_MAGIC},
! 36: {4, P_HASTE, POT_MAGIC},
! 37: {2, P_SEEINVIS, POT_MAGIC},
! 38: {3, P_SHERO, POT_MAGIC},
! 39: {5, P_PHASE, POT_MAGIC},
! 40: {4, P_INVIS, POT_MAGIC},
! 41: {4, WS_CANCEL, ZAP_MAGIC},
! 42:
! 43: /* In reverse order of damage ability */
! 44: {6, WS_ELECT, ZAP_MAGIC | _TWO_},
! 45: {6, WS_FIRE, ZAP_MAGIC | _TWO_},
! 46: {6, WS_COLD, ZAP_MAGIC | _TWO_},
! 47: {6, WS_MISSILE, ZAP_MAGIC | _TWO_},
! 48: {5, WS_ELECT, ZAP_MAGIC},
! 49: {5, WS_FIRE, ZAP_MAGIC},
! 50: {5, WS_COLD, ZAP_MAGIC},
! 51: {4, WS_ELECT, ZAP_MAGIC | ISCURSED},
! 52: {4, WS_FIRE, ZAP_MAGIC | ISCURSED},
! 53: {4, WS_COLD, ZAP_MAGIC | ISCURSED},
! 54: {3, WS_MISSILE, ZAP_MAGIC},
! 55: {1, WS_MISSILE, ZAP_MAGIC | ISCURSED},
! 56:
! 57: {-1, -1, 0}
! 58: };
! 59:
! 60: /*
! 61: Spells that a player can cast Non-mus only know ISKNOW spells until found
! 62: in the dungeon. Special classes know their spells one level lower, and
! 63: blessed one above.
! 64: */
! 65:
! 66: static struct spells player_spells[] =
! 67: {
! 68: {1, WS_KNOCK, ZAP_MAGIC | ISKNOW},
! 69: {1, S_SUMFAMILIAR, SCR_MAGIC | SP_DRUID | SP_MAGIC | SP_CLERIC, SP_ILLUSION },
! 70: {1, S_GFIND, SCR_MAGIC | ISKNOW},
! 71: {1, P_MONSTDET, POT_MAGIC | ISKNOW | SP_DRUID},
! 72: {1, P_TREASDET, POT_MAGIC | ISKNOW | SP_MAGIC},
! 73: {1, S_FOODDET, SCR_MAGIC | ISKNOW | SP_CLERIC},
! 74: {1, S_LIGHT, SCR_MAGIC | ISKNOW | SP_ILLUSION},
! 75:
! 76: {2, WS_CLOSE, ZAP_MAGIC | ISKNOW},
! 77: {2, S_IDENTIFY, SCR_MAGIC | ISKNOW},
! 78: {2, WS_HIT, ZAP_MAGIC | ISKNOW | SP_PRAYER},
! 79: {2, P_SHIELD, POT_MAGIC | ISKNOW | SP_MAGIC},
! 80: {2, P_COLDRESIST, POT_MAGIC | SP_WIZARD},
! 81: {2, P_SEEINVIS, POT_MAGIC | SP_ILLUSION},
! 82: {2, S_CONFUSE, SCR_MAGIC | SP_CLERIC},
! 83: {2, P_SMELL, POT_MAGIC | SP_DRUID},
! 84: {2, WS_MISSILE, ZAP_MAGIC | SP_MAGIC},
! 85: {2, P_HEAR, POT_MAGIC},
! 86:
! 87: {3, P_CLEAR, POT_MAGIC | ISKNOW},
! 88: {3, P_HEALING, POT_MAGIC | ISKNOW | SP_PRAYER},
! 89: {3, S_CURING, SCR_MAGIC | ISKNOW | SP_PRAYER},
! 90: {3, WS_MONSTELEP, ZAP_MAGIC | SP_MAGIC},
! 91: {3, WS_CANCEL, ZAP_MAGIC | SP_WIZARD},
! 92: {3, S_SELFTELEP, SCR_MAGIC | SP_WIZARD},
! 93: {3, P_FIRERESIST, POT_MAGIC | SP_WIZARD | SP_DRUID},
! 94: {3, S_MAP, SCR_MAGIC | SP_ILLUSION | SP_DRUID},
! 95: {3, S_REMOVECURSE, SCR_MAGIC | SP_PRAYER},
! 96: {3, S_HOLD, SCR_MAGIC | SP_CLERIC},
! 97: {3, S_SLEEP, SCR_MAGIC | SP_DRUID},
! 98: {3, P_HASOXYGEN, POT_MAGIC | SP_DRUID},
! 99: {3, WS_XENOHEALING, ZAP_MAGIC | SP_DRUID},
! 100: {3, P_RESTORE, POT_MAGIC},
! 101:
! 102: {4, S_MSHIELD, SCR_MAGIC | ISKNOW | SP_ILLUSION},
! 103: {4, P_INVIS, POT_MAGIC | SP_ILLUSION},
! 104: {4, S_REFLECT, SCR_MAGIC | SP_ILLUSION},
! 105: {4, P_TRUESEE, POT_MAGIC | SP_ILLUSION},
! 106: {4, P_REGENERATE, POT_MAGIC | SP_CLERIC},
! 107: {4, WS_DRAIN, ZAP_MAGIC | SP_CLERIC},
! 108: {4, P_HASTE, POT_MAGIC | SP_ILLUSION | SP_CLERIC},
! 109: {4, P_LEVITATION, POT_MAGIC | SP_WIZARD | SP_DRUID},
! 110: {4, WS_WEB, ZAP_MAGIC | SP_MAGIC},
! 111: {4, P_PHASE, POT_MAGIC},
! 112:
! 113: {5, P_SHERO, POT_MAGIC | ISKNOW},
! 114: {5, S_PETRIFY, SCR_MAGIC | SP_MAGIC},
! 115: {5, S_SCARE, SCR_MAGIC | _TWO_ | SP_PRAYER},
! 116: {5, WS_COLD, ZAP_MAGIC | SP_DRUID},
! 117: {5, WS_FIRE, ZAP_MAGIC | SP_CLERIC},
! 118: {5, WS_ELECT, ZAP_MAGIC | SP_WIZARD},
! 119: {5, WS_ANTIMATTER, ZAP_MAGIC | SP_ILLUSION},
! 120: {5, S_ELECTRIFY, SCR_MAGIC | SP_ILLUSION},
! 121:
! 122: {6, WS_DISINTEGRATE, ZAP_MAGIC | ISKNOW},
! 123: {6, S_OWNERSHIP, SCR_MAGIC | SP_ALL},
! 124:
! 125: {7, S_ENCHANT, SCR_MAGIC | SP_MAGIC},
! 126:
! 127: {-1, -1, 0}
! 128: };
! 129:
! 130: /*
! 131: incant()
! 132: Cast a spell
! 133: */
! 134:
! 135: void
! 136: incant(struct thing *caster, coord dir)
! 137: {
! 138: int i;
! 139: struct stats *curp;
! 140: struct stats *maxp;
! 141: int is_player = (caster == &player);
! 142: int points_casters;
! 143: char *casters_name = (on(player, ISBLIND)) ? "it" :
! 144: monsters[caster->t_index].m_name;
! 145: struct spells *sp;
! 146: char *cast_name; /* = spell_name(sp) */
! 147: char *spell_type; /* spell or prayer */
! 148: int casting_cost; /* from spell_cost[] */
! 149: int spell_roll; /* sucess/fail 1D100 die roll */
! 150: int fumble_chance; /* Spell fumble chance */
! 151: int num_fumbles = 0; /* for fumble_spell() */
! 152: int bless_or_curse = ISNORMAL; /* blessed or cursed? */
! 153: int message_flags = CAST_NORMAL; /* which message to print out */
! 154: int class_casters; /* For determining ISKNOW */
! 155: int stat_casters; /* s_intel or s_wisdom */
! 156: int level_casters; /* spellcasting level */
! 157: char buf[2 * LINELEN];
! 158: struct spells sorted_spells[MAX_SPELLS];
! 159: char spellbuf[2 * LINELEN];
! 160: char spellbuf2[2 * LINELEN];
! 161:
! 162: curp = &(caster->t_stats);
! 163: maxp = &(caster->maxstats);
! 164: points_casters = curp->s_power;
! 165:
! 166: if (points_casters <= 0)
! 167: {
! 168: if (is_player)
! 169: msg("You don't have any spell points.");
! 170:
! 171: return;
! 172: }
! 173:
! 174: /*
! 175: * Paladins, Rangers, ringwearers, and monsters cast at 4 levels
! 176: * below. Other non-specialists at 8 below
! 177: */
! 178:
! 179: level_casters = curp->s_lvl;
! 180:
! 181: switch (caster->t_ctype)
! 182: {
! 183: case C_PALADIN:
! 184: level_casters -= 4;
! 185: /* fallthrough */
! 186: case C_CLERIC:
! 187: class_casters = SP_CLERIC;
! 188: stat_casters = curp->s_wisdom;
! 189: break;
! 190: case C_RANGER:
! 191: level_casters -= 4;
! 192: /* fallthrough */
! 193: case C_DRUID:
! 194: class_casters = SP_DRUID;
! 195: stat_casters = curp->s_wisdom;
! 196: break;
! 197: case C_MAGICIAN:
! 198: class_casters = SP_WIZARD;
! 199: stat_casters = curp->s_intel;
! 200: break;
! 201: case C_ILLUSION:
! 202: class_casters = SP_ILLUSION;
! 203: stat_casters = curp->s_intel;
! 204: break;
! 205: case C_MONSTER:
! 206: if (off(*caster, ISUNIQUE))
! 207: level_casters -= 4;
! 208: class_casters = 0x0;
! 209: stat_casters = curp->s_intel;
! 210: break;
! 211:
! 212: default:
! 213: if (is_wearing(R_WIZARD))
! 214: {
! 215: level_casters -= 4;
! 216: class_casters = (rnd(4) ? SP_WIZARD : SP_ILLUSION);
! 217: stat_casters = curp->s_intel;
! 218: }
! 219: else if (is_wearing(R_PIETY))
! 220: {
! 221: level_casters -= 4;
! 222: class_casters = (rnd(4) ? SP_CLERIC : SP_DRUID);
! 223: stat_casters = curp->s_wisdom;
! 224: }
! 225: else
! 226: {
! 227: level_casters -= 8;
! 228: class_casters = 0x0;
! 229: stat_casters = (rnd(2) ? curp->s_wisdom : curp->s_intel);
! 230: }
! 231: }
! 232:
! 233: /* Bug - What about when WIS == INT? */
! 234:
! 235: spell_type = (stat_casters == curp->s_intel) ? "spell" : "prayer";
! 236:
! 237: if (!is_player && (sp = pick_monster_spell(caster)) == NULL)
! 238: return;
! 239: else if (is_player)
! 240: {
! 241: int num_spells = -1; /* num of spells cheap enough */
! 242:
! 243: sorted_spells[0].sp_cost = -1;
! 244:
! 245: for (sp = player_spells; sp->sp_level != -1; sp++)
! 246: {
! 247: if (sp->sp_flags & class_casters) /* Does class know spell? */
! 248: {
! 249: int rnd_number = rnd(2 * sp->sp_level) - sp->sp_level;
! 250:
! 251: /* Knows normal spell one level below others */
! 252:
! 253: casting_cost = spell_cost[sp->sp_level - 1] + rnd_number;
! 254:
! 255: if (points_casters >= casting_cost)
! 256: {
! 257: sorted_spells[++num_spells] = *sp;
! 258: sorted_spells[num_spells].sp_cost = casting_cost;
! 259: sorted_spells[num_spells].sp_level = sp->sp_level - 1;
! 260: }
! 261:
! 262: /* Knows blessed spell one level above others */
! 263:
! 264: casting_cost = spell_cost[sp->sp_level + 1] + rnd_number;
! 265:
! 266: if (points_casters >= casting_cost)
! 267: {
! 268: sorted_spells[++num_spells] = *sp;
! 269: sorted_spells[num_spells].sp_level = sp->sp_level + 1;
! 270: sorted_spells[num_spells].sp_cost = casting_cost;
! 271: sorted_spells[num_spells].sp_flags |= ISBLESSED;
! 272: }
! 273: } /* If class doesn't know spell, see if its a ISKNOW */
! 274: else if (sp->sp_flags & ISKNOW)
! 275: {
! 276: int rnd_number = rnd(4 * sp->sp_level) - sp->sp_level;
! 277:
! 278: casting_cost = spell_cost[sp->sp_level] + rnd_number;
! 279:
! 280: if (points_casters >= casting_cost)
! 281: {
! 282: sorted_spells[++num_spells] = *sp;
! 283: sorted_spells[num_spells].sp_cost = casting_cost;
! 284: }
! 285: }
! 286: /* else this spell is unknown */
! 287: }
! 288:
! 289: if (sorted_spells[0].sp_cost == -1)
! 290: {
! 291: msg("You don't have enough %s points.", spell_type);
! 292: after = FALSE;
! 293: return;
! 294: }
! 295:
! 296: qsort(sorted_spells,num_spells + 1,sizeof(struct spells),sort_spells);
! 297:
! 298: do /* Prompt for spells */
! 299: {
! 300: struct spells *which_spell = NULL;
! 301:
! 302: buf[0] = '\0';
! 303: msg("");/* Get rid of --More-- */
! 304: msg("Which %s are you casting [%d points left] (* for list)? ",
! 305: spell_type, points_casters);
! 306:
! 307: switch(get_string(buf, cw))
! 308: {
! 309: case NORM: break;
! 310: case QUIT: return; /* ESC - lose turn */
! 311: default: continue;
! 312: }
! 313:
! 314: if (buf[0] == '*') /* print list */
! 315: {
! 316: add_line("Cost Abbreviation Full Name");
! 317:
! 318: for (i = 0; i <= num_spells; i++)
! 319: {
! 320: sp = &sorted_spells[i];
! 321: sprintf(buf, "[%3d] %-12s\t%s",
! 322: sp->sp_cost, spell_abrev(sp,spellbuf2),
! 323: spell_name(sp,spellbuf));
! 324: add_line(buf);
! 325: }
! 326: end_line();
! 327: sp = NULL;
! 328: continue;
! 329: }
! 330:
! 331: if (isupper(buf[0])) /* Uppercase Abbreviation */
! 332: {
! 333: for (i = 0; i <= num_spells; i++)
! 334: {
! 335: sp = &sorted_spells[i];
! 336:
! 337: if ((strcmp(spell_abrev(sp,spellbuf2), buf) == 0))
! 338: {
! 339: which_spell = sp;
! 340: break;
! 341: }
! 342: }
! 343: }
! 344: else /* Full Spell Name */
! 345: {
! 346: for (i = 0; i <= num_spells; i++)
! 347: {
! 348: sp = &sorted_spells[i];
! 349:
! 350: if ((strcmp(spell_name(sp,spellbuf), buf) == 0))
! 351: {
! 352: which_spell = sp;
! 353: break;
! 354: }
! 355: }
! 356: }
! 357:
! 358: sp = which_spell;
! 359: }
! 360: while (sp == NULL);
! 361: }
! 362:
! 363: /* Common monster and player code */
! 364:
! 365: cast_name = spell_name(sp,spellbuf);
! 366:
! 367: fumble_chance = (10 * sp->sp_level / 4 - 10 * level_casters / 13) * 5;
! 368:
! 369: if (cur_weapon != NULL && wield_ok(caster, cur_weapon, FALSE) == FALSE)
! 370: {
! 371: switch (caster->t_ctype)
! 372: {
! 373: case C_MAGICIAN:
! 374: case C_ILLUSION:
! 375: msg("You should have both hands free.");
! 376: fumble_chance += rnd(level_casters) * 5;
! 377: break;
! 378:
! 379: case C_CLERIC:
! 380: case C_DRUID:
! 381: case C_PALADIN:
! 382: msg("Your god looks askance at the weapon you wield.");
! 383: fumble_chance += rnd(level_casters) * 5;
! 384: break;
! 385:
! 386: default:
! 387: break;
! 388: }
! 389: }
! 390:
! 391: if (fumble_chance >= MAX_FUMBLE_CHANCE)
! 392: fumble_chance = MAX_FUMBLE_CHANCE;
! 393: else if (fumble_chance <= MIN_FUMBLE_CHANCE + sp->sp_level)
! 394: fumble_chance = MIN_FUMBLE_CHANCE + sp->sp_level;
! 395:
! 396: if (fumble_chance > (30 + rnd(50)))
! 397: {
! 398: if (is_player)
! 399: {
! 400: int answer;
! 401:
! 402: msg("Are you sure you want to try for that hard a %s? [n]",
! 403: spell_type);
! 404:
! 405: answer = readchar();
! 406:
! 407: if (tolower(answer) != 'y')
! 408: {
! 409: after = FALSE;
! 410: return;
! 411: }
! 412: else
! 413: msg("Here goes...");
! 414: }
! 415: else /* Only if the monster is desperate */
! 416: {
! 417: if (curp->s_hpt > maxp->s_hpt / 2)
! 418: return;
! 419: }
! 420: }
! 421:
! 422: /* casting costs food energy */
! 423:
! 424: food_left -= sp->sp_cost;
! 425:
! 426: spell_roll = rnd(100);
! 427:
! 428: debug("%s(%d) cast '%s' fumble %%%d (rolled %d) ",
! 429: monsters[caster->t_index].m_name, curp->s_power, cast_name,
! 430: fumble_chance, spell_roll);
! 431:
! 432: caster->t_rest_hpt = caster->t_rest_pow = 0;
! 433:
! 434: if (!is_player) /* Stop running. */
! 435: {
! 436: running = FALSE;
! 437: msg("The %s is casting '%s'.", casters_name, cast_name);
! 438: }
! 439:
! 440: /* The Crown of Might insures that your spells never fumble */
! 441:
! 442: if (spell_roll < fumble_chance)
! 443: {
! 444: if (is_carrying(TR_CROWN))
! 445: message_flags |= CAST_CROWN;
! 446: else
! 447: {
! 448: message_flags |= CAST_CURSED;
! 449:
! 450: curp->s_power -= min(curp->s_power,
! 451: (2 * sp->sp_cost)); /* 2x cost */
! 452: num_fumbles = rnd(((fumble_chance - spell_roll) / 10)
! 453: + 1) + rnd(sp->sp_level) + rnd(curp->s_lvl);
! 454: num_fumbles = min(10, max(0, num_fumbles));
! 455:
! 456: if (num_fumbles >= 6 && rnd(1) == 0)
! 457: bless_or_curse = ISCURSED;
! 458: else if (num_fumbles < 4)
! 459: {
! 460: if (is_player)
! 461: msg("Your %s fails.", spell_type);
! 462: return;
! 463: }
! 464: }
! 465: }
! 466: else if (spell_roll > MAX_FUMBLE_CHANCE)
! 467: {
! 468: if (is_player)
! 469: {
! 470: message_flags |= CAST_BLESSED;
! 471: pstats.s_exp += 3 * sp->sp_cost * curp->s_lvl;
! 472: check_level();
! 473: }
! 474:
! 475: maxp->s_power += sp->sp_cost;
! 476: bless_or_curse = ISBLESSED;
! 477: }
! 478: else
! 479: {
! 480: if (is_player) /* extra exp for sucessful spells */
! 481: {
! 482: if (player.t_ctype == C_MAGICIAN || player.t_ctype == C_ILLUSION)
! 483: {
! 484: pstats.s_exp += sp->sp_cost * curp->s_lvl;
! 485: check_level();
! 486: }
! 487: }
! 488:
! 489: bless_or_curse = sp->sp_flags & ISBLESSED;
! 490: curp->s_power -= sp->sp_cost;
! 491: }
! 492:
! 493: /* The Sceptre of Might blesses all your spells */
! 494:
! 495: if (is_player && ((bless_or_curse & ISBLESSED) == 0) &&
! 496: is_carrying(TR_SCEPTRE))
! 497: {
! 498: message_flags |= CAST_SEPTRE;
! 499: bless_or_curse = ISBLESSED;
! 500: }
! 501:
! 502: if (sp->sp_flags & POT_MAGIC)
! 503: quaff(caster, sp->sp_which, bless_or_curse);
! 504: else if (sp->sp_flags & SCR_MAGIC)
! 505: read_scroll(caster, sp->sp_which, bless_or_curse);
! 506: else if (sp->sp_flags & ZAP_MAGIC)
! 507: {
! 508: if (is_player)
! 509: {
! 510: do /* Must pick a direction */
! 511: {
! 512: msg("Which direction?");
! 513: }
! 514: while (get_dir() == FALSE);
! 515: }
! 516: else
! 517: {
! 518: delta.x = dir.x;
! 519: delta.y = dir.y;
! 520: }
! 521: do_zap(caster, sp->sp_which, bless_or_curse);
! 522: }
! 523: else
! 524: msg("What a strange %s!", spell_type);
! 525:
! 526: /*
! 527: * Print messages and take fumbles *after* spell has gone off. This
! 528: * makes ENCHANT, etc more dangerous
! 529: */
! 530:
! 531: if (is_player)
! 532: {
! 533: if (message_flags & CAST_SEPTRE)
! 534: msg("The Sceptre enhanced your %s.", spell_type);
! 535: if (message_flags & CAST_CROWN)
! 536: msg("The Crown wordlessly corrected your %s.",
! 537: spell_type);
! 538:
! 539: switch (message_flags & 0x1)
! 540: {
! 541: case CAST_CURSED:
! 542: msg("You botched your '%s' %s.", cast_name,
! 543: spell_type);
! 544: fumble_spell(caster, num_fumbles);
! 545: break;
! 546: case CAST_NORMAL:
! 547: msg("You sucessfully cast your '%s' %s.",
! 548: cast_name, spell_type);
! 549: break;
! 550:
! 551: case CAST_BLESSED:
! 552: msg("Your '%s' %s went superbly.", cast_name,
! 553: spell_type);
! 554: break;
! 555: }
! 556: }
! 557: }
! 558:
! 559: /*
! 560: spell_name()
! 561: returns pointer to spell name
! 562: */
! 563:
! 564: char *
! 565: spell_name(struct spells *sp, char *buf)
! 566: {
! 567: if (buf == NULL)
! 568: return("UltraRogue Bug #105");
! 569:
! 570: if (sp->sp_flags & POT_MAGIC)
! 571: strcpy(buf, p_magic[sp->sp_which].mi_name);
! 572: else if (sp->sp_flags & SCR_MAGIC)
! 573: strcpy(buf, s_magic[sp->sp_which].mi_name);
! 574: else if (sp->sp_flags & ZAP_MAGIC)
! 575: strcpy(buf, ws_magic[sp->sp_which].mi_name);
! 576: else
! 577: strcpy(buf, "unknown spell type");
! 578:
! 579: if (sp->sp_flags & ISBLESSED)
! 580: strcat(buf, " 2");
! 581:
! 582: return(buf);
! 583: }
! 584:
! 585: /*
! 586: spell_abrev()
! 587: returns pointer to capital letter spell abbreviation
! 588: */
! 589:
! 590: char *
! 591: spell_abrev(struct spells *sp, char *buf)
! 592: {
! 593: if (buf == NULL)
! 594: return("UltraRogue Bug #106");
! 595:
! 596: if (sp->sp_flags & POT_MAGIC)
! 597: strcpy(buf, p_magic[sp->sp_which].mi_abrev);
! 598: else if (sp->sp_flags & SCR_MAGIC)
! 599: strcpy(buf, s_magic[sp->sp_which].mi_abrev);
! 600: else if (sp->sp_flags & ZAP_MAGIC)
! 601: strcpy(buf, ws_magic[sp->sp_which].mi_abrev);
! 602: else
! 603: strcpy(buf, "?????");
! 604:
! 605: if (sp->sp_flags & ISBLESSED)
! 606: strcat(buf, " 2");
! 607:
! 608: return(buf);
! 609: }
! 610:
! 611: /*
! 612: fumble_spell()
! 613: he blew it. Make him pay
! 614: */
! 615:
! 616: void
! 617: fumble_spell(struct thing *caster, int num_fumbles)
! 618: {
! 619: struct stats *curp = &(caster->t_stats);
! 620: struct stats *maxp = &(caster->maxstats);
! 621: int is_player = (caster == &player);
! 622:
! 623: debug("Taking %d fumbles.", num_fumbles);
! 624:
! 625: switch (num_fumbles)
! 626: {
! 627: case 10: /* Lose ability */
! 628: if (rnd(5) == 0)
! 629: quaff(caster, P_GAINABIL, ISCURSED);
! 630: break;
! 631:
! 632: case 9: /* Lose max spell points */
! 633:
! 634: if (rnd(4) == 0)
! 635: {
! 636: maxp->s_power -= rnd(10);
! 637:
! 638: if (maxp->s_power <= 5)
! 639: maxp->s_power = 5;
! 640: }
! 641: break;
! 642:
! 643: case 8: /* Lose all current spell points */
! 644:
! 645: if (rnd(3) == 0)
! 646: curp->s_power = 0;
! 647: else
! 648: curp->s_power /= 2;
! 649: break;
! 650:
! 651: case 7: /* Freeze */
! 652:
! 653: if (rnd(2) == 0)
! 654: {
! 655: if (is_player)
! 656: no_command++;
! 657: else
! 658: caster->t_no_move++;
! 659: }
! 660: break;
! 661:
! 662: case 6: /* Cast a cursed spell - see below */
! 663: break;
! 664:
! 665: case 5: /* Become dazed and confused */
! 666:
! 667: if (rnd(5) == 0)
! 668: quaff(caster, P_CLEAR, ISCURSED);
! 669: break;
! 670:
! 671: case 4: /* Lose hit points */
! 672:
! 673: if (is_player)
! 674: feel_message();
! 675: if ((curp->s_hpt -= rnd(10)) <= 0)
! 676: {
! 677: if (is_player)
! 678: death(D_SPELLFUMBLE);
! 679: else
! 680: killed(caster, find_mons(caster->t_pos.y, caster->t_pos.x),
! 681: NOMESSAGE, NOPOINTS);
! 682: return;
! 683: }
! 684: break;
! 685:
! 686: case 3: /* Spell fails */
! 687: break;
! 688:
! 689: case 2: /* Freeze */
! 690:
! 691: if (is_player)
! 692: no_command++;
! 693: else
! 694: caster->t_no_move++;
! 695:
! 696: break;
! 697:
! 698: default:
! 699: case 1: /* Take double spell points - handled in incant() */
! 700: break;
! 701: }
! 702: }
! 703:
! 704: /*
! 705: learn_new_spells()
! 706: go through player_spells and ISKNOW identified potions,
! 707: scrolls, and sticks
! 708: */
! 709:
! 710: void
! 711: learn_new_spells(void)
! 712: {
! 713: struct spells *sp;
! 714: int kludge = 0;
! 715: char spellbuf[2*LINELEN];
! 716:
! 717: for (sp = player_spells; sp->sp_level != -1; sp++)
! 718: {
! 719: if (sp->sp_flags & POT_MAGIC)
! 720: kludge = TYP_POTION;
! 721: else if (sp->sp_flags & SCR_MAGIC)
! 722: kludge = TYP_SCROLL;
! 723: else if (sp->sp_flags & ZAP_MAGIC)
! 724: kludge = TYP_STICK;
! 725:
! 726: if (know_items[kludge][sp->sp_which])
! 727: {
! 728: if ((sp->sp_flags & ISKNOW) == FALSE)
! 729: debug("Learned new spell '%s'", spell_name(sp,spellbuf));
! 730: sp->sp_flags |= ISKNOW;
! 731: }
! 732: }
! 733: }
! 734:
! 735: /*
! 736: pick_monster_spell()
! 737: decide which spell from monst_spells will be cast
! 738: returns pointer to spell in monst_spells
! 739: */
! 740:
! 741: struct spells *
! 742: pick_monster_spell(struct thing *caster)
! 743: {
! 744: struct spells *sp = NULL;
! 745: struct stats *curp = &(caster->t_stats);
! 746: int points_casters = curp->s_power;
! 747:
! 748: /* Discover castable spells */
! 749:
! 750: for (sp = monst_spells; sp->sp_level != -1; sp++)
! 751: {
! 752: int rnd_number = rnd(2 * sp->sp_level) - sp->sp_level;
! 753: int casting_cost = spell_cost[sp->sp_level] + rnd_number;
! 754:
! 755: if (points_casters >= casting_cost)
! 756: sp->sp_flags |= ISKNOW;
! 757: }
! 758:
! 759: /* Decide which spell to cast */
! 760:
! 761: if (curp->s_hpt < rnd(caster->maxstats.s_hpt)) /* think defense */
! 762: {
! 763: int i;
! 764: static const int run_or_heal[NUM_RUN] =
! 765: { M_SELFTELEP, M_HLNG2, M_HLNG, M_REGENERATE };
! 766:
! 767: for (i = 0; i < NUM_RUN; i++)
! 768: {
! 769: sp = &monst_spells[run_or_heal[i]];
! 770:
! 771: if ((sp->sp_flags & ISKNOW) && rnd(1))
! 772: return(sp);
! 773: }
! 774: }
! 775:
! 776: if (on(*caster, ISSLOW)) /* cancel a slow */
! 777: {
! 778: sp = &monst_spells[M_HASTE];
! 779:
! 780: if (sp->sp_flags & ISKNOW)
! 781: return (sp);
! 782: }
! 783:
! 784: if (on(*caster, ISFLEE)) /* stop running away */
! 785: {
! 786: sp = &monst_spells[M_SHERO];
! 787:
! 788: if (sp->sp_flags & ISKNOW)
! 789: return (sp);
! 790: }
! 791:
! 792: if (on(player, ISINVIS) || on(player, ISDISGUISE))
! 793: {
! 794: if (off(*caster, CANSEE)) /* look for him */
! 795: {
! 796: sp = &monst_spells[M_SEEINVIS];
! 797:
! 798: if (sp->sp_flags & ISKNOW)
! 799: return (sp);
! 800: }
! 801: else if (off(*caster, ISINVIS)) /* go invisible */
! 802: {
! 803: sp = &monst_spells[M_INVIS];
! 804:
! 805: if (sp->sp_flags & ISKNOW)
! 806: return (sp);
! 807: }
! 808: }
! 809:
! 810: if (on(player, CANINWALL) && (off(*caster, CANINWALL)) &&
! 811: (rnd(5) == 0))
! 812: {
! 813: sp = &monst_spells[M_PHASE];
! 814:
! 815: if (sp->sp_flags & ISKNOW)
! 816: return (sp);
! 817: }
! 818:
! 819: if (rnd(5) == 0 && has_defensive_spell(player))
! 820: {
! 821: sp = &monst_spells[M_CANCEL];
! 822:
! 823: if (sp->sp_flags & ISKNOW)
! 824: return (sp);
! 825: }
! 826:
! 827: /* Cast an offensive spell */
! 828:
! 829: for (sp = &monst_spells[M_OFFENSE]; sp->sp_level != 1; sp++)
! 830: {
! 831: if ((rnd(3) == 0) && (sp->sp_flags & ISKNOW))
! 832: return (sp);
! 833:
! 834: if ((rnd(3) == 0) && (sp->sp_flags & ISKNOW))
! 835: {
! 836: if (sp->sp_which != WS_MISSILE &&
! 837: DISTANCE(caster->t_pos, hero) > BOLT_LENGTH)
! 838: continue;
! 839: else
! 840: return(sp);
! 841: }
! 842: }
! 843:
! 844: return(NULL);
! 845: }
! 846:
! 847: /*
! 848: sort_spells()
! 849: called by qsort()
! 850: */
! 851:
! 852: int
! 853: sort_spells(const void *a, const void *b)
! 854: {
! 855: struct spells *sp1, *sp2;
! 856: int diff;
! 857: char spellbuf[2 * LINELEN];
! 858: char spellbuf2[2 * LINELEN];
! 859:
! 860: union /* hack to prevent 'lint' from complaining */
! 861: {
! 862: struct spells *s;
! 863: const void *vptr;
! 864: } s1,s2;
! 865:
! 866: s1.vptr = a;
! 867: s2.vptr = b;
! 868:
! 869: sp1 = s1.s;
! 870: sp2 = s2.s;
! 871:
! 872: diff = sp1->sp_cost - sp2->sp_cost;
! 873:
! 874: if (diff != 0)
! 875: return(diff);
! 876: else
! 877: return(strcmp(spell_name(sp1,spellbuf), spell_name(sp1,spellbuf2)));
! 878: }
CVSweb