#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"
void
spellscom (void)
{
struct SPELL *spell;
char dam[4], type[9];
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)) {
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 spell)
{
int victim = brkword () < 0 ? pfighting (mynum) : fpbn (wordbuf);
if (!is_in_game (victim))
bprintf ("Who?\n");
else
cast_spell (mynum, victim, spell);
}
Boolean
cast_spell (int caster, int victim, int verb)
{
int chance, damage = 0;
int factor = 1;
struct SPELL *spell;
Boolean miss = False;
/* Find spell */
for (spell = spell_table; spell->verb != verb; spell++) {
if (spell->verb < 0)
return False; /* No such spell */
}
if (victim == pfighting (caster) && spell->type != ATTACK) {
bprintf ("Who?\n");
return False;
}
/* Check to see if spell can be casted across a distance */
if (plev (caster) < LVL_WIZARD && ploc (caster) != ploc (victim)) {
if (spell->type != SPECIAL) {
sendf (caster, "%s is not here.\n", pname (victim));
return False;
}
}
/* Check if player knows the spell */
if (!etstflg (caster, spell->flag)) {
bprintf ("You have not learned this spell yet.\n");
return False;
}
/* Check if the spell can be cast */
if (plev (caster) < LVL_WIZARD) {
if (caster < max_players && pmagic (caster) < spell->mana) {
sendf (caster, "You are to weak to cast this spell.\n");
return False;
}
if (testpeace (caster) && spell->type == ATTACK) {
sendf (caster, "No, that's violent!\n");
return False;
}
if (ltstflg (ploc (victim), LFL_NO_MAGIC)) {
sendf (caster, "Something about this location has drained your mana.\n");
return False;
}
chance = (caster >= max_players) ? 60 + spell->chance : spell->chance;
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;
if (carries_obj_type (caster, OBJ_FANTASY_MANA) > -1)
chance += 2;
if (caster < max_players && randperc () > chance + (4 * plev (caster))) {
miss = True;
}
if (ptstflg (victim, PFL_NOHASSLE) != 0 && spell->type == ATTACK) {
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 (!do_okay (caster, victim, PFL_NOHASSLE)) {
sendf (caster, "Something prevents you from casting your spell.\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 &&
#ifdef LOCMIN_TALON
carries_obj_type (victim, OBJ_TALON_TALONSHIELD) > -1 &&
#endif
carries_obj_type (victim, OBJ_CATACOMB_SHIELD) > -1) {
sendf (caster, "The spell is absorbed by %s shield!\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 is absorbed by %s shield!\n",
pname (caster), pname (victim), his_or_her (victim));
sendf (victim, "%s casts a spell on you. It is absorbed by your shield!\n",
see_name (victim, caster));
return False;
}
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);
if (plev (caster) < LVL_WIZARD)
damage = spell->damage * factor;
else
damage = pstr (victim) + 1;
wound_player (caster, victim, damage, 0);
}
/* Heal type spell */
if (spell->type == HEAL) {
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 (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);
}
/* Special Spell */
if (spell->type == SPECIAL) {
/* Check all Special spells that are to the caster's room */
if (spell->verb == VERB_VTOUCH || spell->verb == VERB_LIT ||
spell->verb == VERB_DAMAGE || spell->verb == VERB_ARMOR ||
spell->verb == VERB_BLUR) {
if (ploc (caster) != ploc (victim)) {
sendf (caster, "%s is not here.\n", pname (victim));
}
}
if (!do_okay (caster, victim, PFL_NOHASSLE)) {
sendf (caster, "Something prevents you from casting your spell.\n");
return False;
}
if (spell->verb == VERB_VTOUCH) {
if (caster == victim) {
sendf (victim, "It's pointless to suck your own life away!\n");
return False;
}
}
if (check_duration (victim, spell->verb)) {
sendf (victim, "%s are already under the effects of that spell.\n",
caster == victim ? "You" : "They");
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 (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;
}
/* Vampiric Touch */
if (spell->verb == VERB_VTOUCH) {
pscore (caster) = pscore (caster) + 100 * damage;
sendf (caster, "&*You gain &+W%d &*experience points!\n", damage * 100);
wound_player (caster, victim, damage, 0);
}
/* Light */
if (spell->verb == VERB_LIT) {
if (add_duration (victim, VERB_LIT, spell->duration * factor, 0))
ssetflg (victim, SFL_LIT);
}
/* Damage */
if (spell->verb == VERB_DAMAGE) {
add_duration (victim, VERB_DAMAGE, spell->duration * factor, 0);
}
/* Armor */
if (spell->verb == VERB_ARMOR) {
add_duration (victim, VERB_ARMOR, spell->duration * factor, 0);
}
/* Blur */
if (spell->verb == VERB_BLUR) {
add_duration (victim, VERB_BLUR, spell->duration, 0);
}
}
return True;
}
int
mob_cast_spell (int caster)
{
struct SPELL *spell;
for (spell = spell_table; spell->verb >= 0; spell++) {
if (etstflg (caster, spell->flag) == 0)
continue;
if (randperc () < spell->chance)
return spell->verb;
}
return -1;
}
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,
"%s\n", make_magic_msg (xx, msg, c, v));
else
send_msg (dest, 0, LVL_MIN, LVL_MAX, NOBODY, NOBODY,
"%s\n", 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;
}
}
if (p[-1] == '\n')
--p;
*p = 0;
return b;
}
/************************************************************************
* Spell Duration Handler Functions *
************************************************************************/
/* This function wipes out all of the duration data.
*/
void
wipe_duration (int plr)
{
SPELL_DURATION *check = plr < max_players ? players[plr].duration : NULL;
SPELL_DURATION *nextptr = NULL;
while (check != NULL) {
if (nextptr != NULL)
check = nextptr;
if (check->spell == VERB_LIT)
sclrflg (plr, SFL_LIT);
nextptr = check->next;
FREE (check);
}
}
/* This function sends text to a user that his/her spell has ended.
*/
void
duration_end (int plr, int spell, int tmp)
{
if (spell == VERB_LIT) {
sendf (plr, "Your lit spell expires.\n");
sclrflg (plr, SFL_LIT);
}
if (spell == VERB_DAMAGE) {
sendf (plr, "You feel your strength spell wearing off.\n");
setpdam (plr, tmp);
}
if (spell == VERB_ARMOR) {
sendf (plr, "You feel your protection spell wearing off.\n");
setparmor (plr, tmp);
}
if (spell == VERB_BLUR) {
sendf (plr, "You seem to be more visible.\n");
}
}
/* 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;
/* Check 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 *check = plr < max_players ? players[plr].duration : NULL;
if (check == NULL)
return False;
/* Check to see if the spell is already being used */
while (check != NULL) {
if (check->spell == spell)
return True;
check = check->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 *check = plr < max_players ? players[plr].duration : NULL;
SPELL_DURATION *prev = NULL;
/* Nothing is in the linklist, do not process. */
if (check == NULL)
return;
/* Decrement all spells, disable if it ran out, and free memory */
while (check != NULL) {
if (!check->duration--) {
duration_end (plr, check->spell, check->tmp);
if (prev == NULL) {
players[plr].duration = check->next;
FREE (check);
} else {
prev->next = check->next;
FREE (check);
check = prev;
}
}
prev = check;
check = check->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;
SPELL_DURATION *curr = players[plr].duration;
new = NEW (SPELL_DURATION, 1);
new->spell = spell;
new->duration = duration;
new->tmp = tmp;
if (curr != NULL) {
new->next = curr->next;
curr->next = new;
} else {
new->next = curr;
curr = new;
}
}