#include <stdlib.h> #include "kernel.h" #include "oflags.h" #include "eflags.h" #include "pflags.h" #include "lflags.h" #include "sendsys.h" #include "verbs.h" #include "mobiles.h" #include "objects.h" #include "locations.h" #include "objsys.h" #include "spell.h" #include "spells.h" #include "bprintf.h" #include "parse.h" #include "fight.h" #include "mobile.h" #include "sflags.h" Boolean cast_spell(int, int, struct SPELL *); void spellscom (void) { struct SPELL *spell; char dam[4], type[9]; if ((pclass(mynum) != PRIEST && pclass(mynum) != MAGE) && plev(mynum) < LVL_ISTARI && !etstflg(mynum, EFL_WHERE)) { bprintf("You have no spells.\n"); return; } bprintf ("You know the following spells:\n"); bprintf ("&+B---------------------------------------------------------------\n"); bprintf ("&+WCommand Spell Mana Damage Chance Type\n"); bprintf ("&+B---------------------------------------------------------------\n"); for (spell = spell_table; spell->verb >= 0; spell++) { if (etstflg(mynum, spell->flag) || plev(mynum) >= LVL_ISTARI) { sprintf (dam, "%d", spell->damage); sprintf (type, "%s", spell->type == ATTACK ? "Attack" : spell->type == HEAL ? "Heal" : spell->duration ? "Duration" : "Special"); bprintf ("&*%-10.10s %-20.20s %4d %6.6s %6d %-9.9s\n", spell->verbname, spell->name, spell->mana, spell->damage ? dam : "---", spell->chance, type); } } bprintf ("&+B---------------------------------------------------------------\n"); } void spellcom (int verb) { struct SPELL *spell; int victim = brkword () < 0 ? pfighting (mynum) : fmbn (wordbuf); for (spell = spell_table; spell->verb != verb; spell++) if (spell->verb < 0) return; if (ststflg(mynum, SFL_DUMB) && plev(mynum) < LVL_WIZARD) { bprintf("Sorry, you been struck dumb.\n"); return; } else if (!is_in_game(victim)) { bprintf ("Who?\n"); return; } else if ((verb==VERB_BABEL || verb==VERB_MAKEPIG) && victim >= max_players) { bprintf("Those spells are for human players only.\n"); return; } else if (plev(mynum) < LVL_ISTARI) { if (cur_player->cast_spell && pfighting(mynum)) bprintf("You can't cast more than one spell per round.\n"); else if (!etstflg(mynum, spell->flag)) bprintf("You have not learned this spell yet.\n"); else if (ploc(mynum) != ploc(victim)) bprintf("%s is not here.\n", pname(victim)); else if (pstr(victim) < 0) bprintf("%s is dead.\n", pname(victim)); else if (pmagic(mynum) < spell->mana) bprintf("You are to weak to cast this spell.\n"); else if (ltstflg (ploc (victim), LFL_NO_MAGIC)) bprintf("Something about this area made you to fumble the magic.\n"); else cast_spell (mynum, victim, spell); } else cast_spell (mynum, victim, spell); } Boolean cast_spell (int caster, int victim, struct SPELL *spell) { int chance, damage; int factor = 1; Boolean miss = False; damage = 0; if (plev (caster) < LVL_WIZARD) { if (spell->type == ATTACK) { if (testpeace (caster)) { sendf (caster, "No, that's violent!\n"); return False; } else if (victim < max_players && linkdead(victim)) { sendf(caster, "That player is linkdead.\n"); return False; } } if (caster < max_players && victim < max_players && !ltstflg(ploc(caster), LFL_PKZONE) && spell->type == ATTACK ) { bprintf("You cannot attack another player here!\n"); send_msg(DEST_ALL, 0, LVL_WIZARD, LVL_MAX, NOBODY, NOBODY, "&#&+R[&+Y%s &+Rhas tried to kill &+Y%s&+R]\n", pname(caster), pname(victim)); sendf(victim, "%s tried to attack you!\n", pname(caster)); return False; } chance = spell->chance; #ifdef LOCMIN_BLIZZARD if (carries_obj_type (caster, OBJ_BLIZZARD_POWERSTONE) > -1) ++chance; if (carries_obj_type (caster, OBJ_BLIZZARD_POWERSTONE1) > -1) ++chance; if (carries_obj_type (caster, OBJ_BLIZZARD_POWERSTONE2) > -1) ++chance; #endif #ifdef LOCMIN_FANTASY if (carries_obj_type (caster, OBJ_FANTASY_MANA) > -1) chance += 2; #endif if (caster < max_players) { players[caster].cast_spell = True; if (randperc () > (chance + 4 * plev(caster))) miss = True; } else if (randperc() > (chance * CHANCE_MULTIPLIER)) miss = True; if (ptstflg (victim, PFL_NOHASSLE)) { sendf (caster, "Something prevents you from casting your spell.\n"); return False; } } /* Attack type spell */ if (spell->type == ATTACK) { if (caster == victim) { sendf (victim, "You're supposed to be killing others, not yourself.\n"); return False; } if( caster < max_players ) setpmagic (caster, pmagic (caster) - spell->mana); send_magic_msg (caster, caster, victim, spell->spell_msg, CASTER); send_magic_msg (victim, caster, victim, spell->spell_msg_vic, VICTIM); send_magic_msg (ploc (caster), caster, victim, spell->to_room, ROOM); if (miss) { send_magic_msg (caster, caster, victim, spell->to_casterm, TOCAST); send_magic_msg (victim, caster, victim, spell->to_victimm, TOVIC); send_magic_msg (ploc(caster), caster, victim, spell->to_othersm, TOROOM); return False; } if (plev(caster) < LVL_WIZARD && wears_antimagic(victim)) { if (randperc() < 50) { sendf(caster, "The spell flashes harmlessly past %s!\n", his_or_her (victim)); send_msg (ploc (caster), 0, LVL_MIN, LVL_MAX, caster, victim, "\001p%s\003 casts a spell on \001p%s\003. It flashes " "harmlessly past %s!\n", pname (caster), pname (victim), his_or_her (victim)); sendf(victim, "%s casts a spell on you, but if flashes past " "harmlessly!", see_name (victim, caster)); return(False); } else { sendf(caster, "%s's antimagic item fails to protect %s!\n", pname(victim), psex(victim) ? "her" : "him"); sendf(victim, "Your antimagic item fails to protect you.\n"); } } if (spell->immune_flag != NOFLAG && etstflg (victim, spell->immune_flag)) { send_magic_msg (caster, caster, victim, spell->to_casteri, TOCAST); send_magic_msg (victim, caster, victim, spell->to_victimi, TOVIC); send_magic_msg (ploc(caster), caster, victim, spell->to_othersi, TOROOM); return False; } if (spell->fear_flag != NOFLAG && etstflg (victim, spell->fear_flag)) factor += 4; if (check_object (caster, spell->obj_flag)) factor += 2; send_magic_msg (caster, caster, victim, spell->to_caster, TOCAST); send_magic_msg (victim, caster, victim, spell->to_victim, TOVIC); send_magic_msg (ploc (caster), caster, victim, spell->to_others, TOROOM); /* calculate damage */ if (plev (caster) < LVL_WIZARD) damage = spell->damage * factor; else damage = pstr (victim) + 1; /* vtouch : a special attack spell */ if (spell->verb == VERB_VTOUCH) { if (etstflg(victim, EFL_N_VTOUCH)) { sendf (caster, "%s drains your life instead!\n", pname(victim)); pscore (caster) = pscore (caster) - 100 * damage; pscore (victim) = pscore (victim) + 100 * damage; } else { pscore (caster) = pscore (caster) + 100 * damage; pscore (victim) = pscore (victim) - 100 * damage; sendf (caster, "&*You gain &+W%d &*experience points!\n", damage * 100); } if (pfighting(victim) == -1) hit_player (victim, caster, pwpn(victim)); return(True); } /* account for all ATTACK spells here, all require Neg entry */ if (spell->verb == VERB_FIREBALL && etstflg(victim, EFL_N_FIREBALL)) sendf (caster, "%s enjoys the &+Rheat&N and gets STRONGER!\n", pname(victim)); else if (spell->verb == VERB_SHOCK && etstflg(victim, EFL_N_SHOCK)) sendf (caster, "%s grows stronger from the charge!\n", pname(victim)); else if (spell->verb == VERB_MISSILE && etstflg(victim, EFL_N_MISSILE)) sendf (caster, "%s absorbs the &+Wmissile&N and grows STRONGER!\n", pname(victim)); else if (spell->verb == VERB_FROST && etstflg(victim, EFL_N_FROST)) sendf (caster, "%s likes the &+Ccold&N!\n", pname(victim)); else if (spell->verb == VERB_ICESTORM && etstflg(victim, EFL_N_ICESTORM)) sendf (caster, "%s relaxes and enjoys the cold weather.\n", pname(victim)); else { switch (spell->verb) { case VERB_DEAFEN: add_duration(victim, VERB_DEAFEN, spell->duration, 0); ssetflg(victim, SFL_DEAF); break; case VERB_CRIPPLE: add_duration(victim, VERB_CRIPPLE, spell->duration, 0); ssetflg(victim, SFL_CRIPPLED); break; case VERB_MUTE: add_duration(victim, VERB_MUTE, spell->duration, 0); ssetflg(victim, SFL_DUMB); break; case VERB_BLIND: add_duration(victim, VERB_BLIND, spell->duration, 0); ssetflg(victim, SFL_BLIND); break; default: setpstr(victim, pstr(victim) - damage); /* a normal spell: */ if (pstr(victim) < 0) /* this place is */ player_died(caster, victim, spell->verb); /* where all damage */ } if (pfighting(victim) == -1 && plev(caster) < LVL_WIZARD) hit_player (victim, caster, pwpn(victim)); return(True); } setpstr(victim, pstr(victim) + damage); /* fall thru - spell negated */ if (pfighting(victim) == -1) hit_player (victim, caster, pwpn(victim)); return True; } /* Heal type spell */ if (spell->type == HEAL) { setpmagic (caster, pmagic (caster) - spell->mana); send_magic_msg (caster, caster, victim, spell->spell_msg, CASTER); send_magic_msg (victim, caster, victim, spell->spell_msg_vic, VICTIM); send_magic_msg (ploc (caster), caster, victim, spell->to_room, ROOM); if (miss) { send_magic_msg (caster, caster, victim, spell->to_casterm, TOCAST); send_magic_msg (victim, caster, victim, spell->to_victimm, TOVIC); send_magic_msg (ploc (caster), caster, victim, spell->to_othersm, TOROOM); return False; } if (check_object (caster, spell->obj_flag)) factor += 2; send_magic_msg (caster, caster, victim, spell->to_caster, TOCAST); send_magic_msg (victim, caster, victim, spell->to_victim, TOVIC); send_magic_msg (ploc (caster), caster, victim, spell->to_others, TOROOM); damage = spell->damage * factor; setpstr (victim, pstr (victim) + damage); } if (spell->type == SPECIAL) { if (victim >= max_players) { if (spell->verb != VERB_CRIPPLE && spell->verb != VERB_DEAFEN && spell->verb != VERB_MUTE && spell->verb != VERB_BLIND) sendf (caster, "That doesn't make any sense.\n"); return(False); } if (check_duration (victim, spell->verb)) { sendf(caster, "%s are already under the effects of that spell.\n", caster == victim ? "You" : "They"); return(False); } setpmagic(caster, pmagic (caster) - spell->mana); send_magic_msg (caster, caster, victim, spell->spell_msg, CASTER); send_magic_msg (victim, caster, victim, spell->spell_msg_vic, VICTIM); send_magic_msg (ploc (caster), caster, victim, spell->to_room, ROOM); if (miss) { send_magic_msg (caster, caster, victim, spell->to_casterm, TOCAST); send_magic_msg (victim, caster, victim, spell->to_victimm, TOVIC); send_magic_msg (ploc (caster), caster, victim, spell->to_othersm, TOROOM); return(False); } if (plev (mynum) < LVL_WIZARD) { if (spell->immune_flag != NOFLAG && etstflg(victim, spell->immune_flag)) { send_magic_msg (caster, caster, victim, spell->to_casteri, TOCAST); send_magic_msg (victim, caster, victim, spell->to_victimi, TOVIC); send_magic_msg (ploc (caster), caster, victim, spell->to_othersi, TOROOM); return False; } if (spell->fear_flag != NOFLAG && etstflg (victim, spell->fear_flag)) factor += 4; if (check_object (caster, spell->obj_flag)) factor += 2; send_magic_msg (caster, caster, victim, spell->to_caster, TOCAST); send_magic_msg (victim, caster, victim, spell->to_victim, TOVIC); send_magic_msg (ploc (caster), caster, victim, spell->to_others, TOROOM); damage = spell->damage * factor; } /* spell has succeeded by this point */ switch (spell->verb) { case VERB_LIT: if (add_duration(victim, VERB_LIT, spell->duration * factor, 0)) ssetflg(victim, SFL_LIT); break; case VERB_DAMAGE: if (add_duration(victim, VERB_DAMAGE, spell->duration * factor, pdam(victim))) setpdam(victim, pdam (victim) + 10); break; case VERB_ARMOR: if (add_duration(victim, VERB_ARMOR, spell->duration * factor, parmor (victim))) { setparmor (victim, parmor (victim) + 10); calc_ac(victim); } break; case VERB_BLUR: add_duration (victim, VERB_BLUR, spell->duration, 0); break; case VERB_BABEL: add_duration(victim, VERB_BABEL, spell->duration, 0); ssetflg(victim, SFL_BABEL); send_msg(DEST_ALL, 0, LVL_ARCHWIZARD, LVL_MAX, mynum, victim, "&+r[&+Y%s has cast babel spell on %s&+r]\n", pname(mynum), pname(victim)); break; case VERB_MAKEPIG: add_duration(victim, VERB_MAKEPIG, spell->duration, 0); ssetflg(victim, SFL_ISPIG); send_msg(DEST_ALL, 0, LVL_ARCHWIZARD, LVL_MAX, mynum, victim, "&+r[&+y%s has cast makepig spell on %s&+r]\n", pname(mynum), pname(victim)); break; } } return(True); } /* improved & more-random */ void mob_cast_spell (int caster, int victim) { struct SPELL *spell; struct SPELL *choices[32]; int len; if (ststflg(caster, SFL_DUMB)) return; for (spell = spell_table, len = 0 ; spell->verb >= 0 ; spell++) { if (etstflg(caster, spell->flag) && spell->type == ATTACK) { choices[len] = spell; len++; } } if (!len || plev(victim) >= LVL_WIZARD || (randperc() > SPELL_CHANCE + len * SPELL_INCR)) return; else cast_spell(caster, victim, choices[randperc() % len]); } Boolean check_object (int plr, int flag) { int i; if (flag == NOFLAG) return False; for (i = 0; i < pnumobs (plr); i++) if (iscarrby (pobj_nr (i, plr), flag) && otstbit (i, flag)) return True; return False; } void send_magic_msg (int dest, int caster, int victim, char *msg, int type) { char xx[120]; char c[30], v[30]; if (msg == NULL) return; sprintf (c, "\001p%s\003", pname (caster)); sprintf (v, "\001p%s\003", pname (victim)); if (type == CASTER && caster == victim) sprintf (v, "yourself"); if (type == ROOM && caster == victim) sprintf (v, "%sself", psex (caster) ? "her" : "him"); if (type == VICTIM && caster == victim) return; if (type == TOCAST && caster == victim) return; if (type == ROOM || type == TOROOM) send_msg (dest, 0, LVL_MIN, LVL_MAX, caster, victim, make_magic_msg (xx, msg, c, v)); else send_msg (dest, 0, LVL_MIN, LVL_MAX, NOBODY, NOBODY, make_magic_msg (xx, msg, c, v)); } char * make_magic_msg (char *b, char *s, char *c, char *v) { char *p, *q, *r; for (p = b, q = s; *q != 0;) { if (*q != '%') *p++ = *q++; else { switch (*++q) { case 'c': /* Caster */ if (c == NULL) return NULL; for (r = c; *r != 0;) *p++ = *r++; break; case 'v': /* Victim */ if (v == NULL) return NULL; for (r = v; *r != 0;) *p++ = *r++; break; case 0: --q; break; default: *p++ = *q; } ++q; } } *p = 0; return b; } /************************************************************************ * Spell Duration Handler Functions * ************************************************************************/ /* This function wipes out all of the duration data. */ void wipe_duration (int plr) { SPELL_DURATION *ptr, *fptr; ptr = players[plr].duration; while (ptr) { duration_end(plr, ptr->spell, ptr->tmp); fptr = ptr; ptr = ptr->next; FREE (fptr); } } void duration_end (int plr, int spell, int tmp) { switch (spell) { case VERB_LIT: sendf (plr, "&+MYour &+Ylit &+Mspell expires.\n"); sclrflg (plr, SFL_LIT); break; case VERB_DAMAGE: sendf (plr, "&+MYou feel your &+Ystrength &+Mspell wearing off.\n"); setpdam (plr, tmp); break; case VERB_ARMOR: sendf (plr, "&+MYou feel your protective &+Yarmor &+Mspell wearing off.\n"); setparmor (plr, tmp); calc_ac(plr); break; case VERB_BLUR: sendf (plr, "&+MYou seem to be more visible as the &+Yblur &+Mspell " "wears off.\n"); break; case VERB_BABEL: sendf (plr, "You don't feel like talking as much anymore!\n"); sclrflg(plr, SFL_BABEL); break; case VERB_MAKEPIG: sendf (plr, "You don't feel like a pig anymore!\n"); sclrflg(plr, SFL_ISPIG); break; case VERB_DEAFEN: sendf (plr, "You can hear again!\n"); sclrflg(plr, SFL_DEAF); break; case VERB_CRIPPLE: sendf (plr, "You can walk again!\n"); sclrflg(plr, SFL_CRIPPLED); break; case VERB_BLIND: sendf (plr, "You can see again!\n"); sclrflg(plr, SFL_BLIND); break; case VERB_MUTE: sendf (plr, "You can talk again!\n"); sclrflg(plr, SFL_DUMB); break; } } /* This function adds a spell to a player's duration linklist. */ Boolean add_duration (int plr, int spell, int duration, int tmp) { /* Convert minutes to seconds. Since the MUD interrupts * once every 2 seconds though, we multiply by 30. */ duration = duration * 30; /* Ptr to see if the spell is already being used */ if (!check_duration (plr, spell)) { push_duration (plr, spell, duration, tmp); return True; } else return False; } /* This function checks if a spell is currently being used. */ Boolean check_duration (int plr, int spell) { SPELL_DURATION *ptr; if (plr >= max_players) return False; ptr = players[plr].duration; /* Check to see if the spell is already being used */ while (ptr != NULL) { if (ptr->spell == spell) return True; ptr = ptr->next; } return False; } /* This function handles going through the linklist to decrement the * duration and check the spells */ void handle_duration (int plr) { SPELL_DURATION *ptr; SPELL_DURATION *prev; SPELL_DURATION *temp; /* Decrement all spells, disable if it ran out, and FREE memory */ ptr = players[plr].duration; prev = NULL; while (ptr != NULL) { if (!ptr->duration--) { duration_end (plr, ptr->spell, ptr->tmp); if (!prev) { /* prev = NULL */ temp = ptr; ptr = ptr->next; players[plr].duration = ptr; /* new first node */ FREE (temp); } else { /* prev unchanged */ prev->next = ptr->next; temp = ptr; ptr = ptr->next; FREE (temp); } } else { /* new prev */ prev = ptr; ptr = ptr->next; } } } /* This function pushes the linklist to add another duration pointer * into it. */ void push_duration (int plr, int spell, int duration, int tmp) { SPELL_DURATION *new; new = NEW (SPELL_DURATION, 1); new->spell = spell; new->duration = duration; new->tmp = tmp; new->next = players[plr].duration; players[plr].duration = new; }