/* *******************************************************************
* file: newmagic.cc *
* authors: Christopher J. Dickey and Andrew Hynek *
* purpose: this defines all the new magic routines for the mud *
* (c)1997-2000 Christopher J. Dickey, Andrew Hynek, and Nick *
* Robertson, (c)2001 The AwakeMUD Consortium *
******************************************************************* */
#define _newmagic_cc_
#include <fstream.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
#include "structs.h"
#include "awake.h"
#include "db.h"
#include "comm.h"
#include "interpreter.h"
#include "utils.h"
#include "handler.h"
#include "newmagic.h"
#include "spells.h"
#include "mag_create.h"
#include "shop.h"
// extern vars
extern struct time_info_data time_info;
extern struct room_data *world;
extern struct char_data *character_list;
extern struct index_data *obj_index;
extern struct zone_data *zone_table;
extern int material_ratings[];
extern int pk_allowed;
extern int top_of_world;
extern const char *material_names[];
extern const char *item_types[];
extern const char *wear_bits[];
extern const char *affected_bits[];
extern const char *apply_types[];
extern const char *wound_name[];
extern const char *spells[];
extern const char *drinks[];
extern const char *gear_name[];
extern const char *patch_names[];
extern const char *attack_types[];
extern const char *program_types[];
extern const char *spell_target[];
extern const char *wound_arr[];
extern const char *elements[];
extern const char *foci_types[];
extern const char *shape_forms[];
extern const char *spell_wear_off_msg[];
extern const char *spirits[];
extern const char *spell_categories[];
extern const char *lookdirs[];
extern int convert_look[];
// extern funcs
extern void resist_drain(struct char_data *ch, int power, spell_t *spell, int wound);
extern void damage_obj(struct char_data *, struct obj_data *, int, int);
extern void look_at_room(struct char_data * ch, int ignore_brief);
extern void add_follower(struct char_data * ch, struct char_data * leader);
extern void ranged_response(struct char_data *ch, struct char_data *vict);
extern void die(struct char_data *);
extern bool in_group(char_t *, char_t *);
extern int modify_target(char_t *);
extern int ok_damage_shopkeeper(struct char_data * ch, struct char_data * victim);
extern int find_sight(struct char_data * ch);
extern char *get_power(int);
extern char *get_attrib(int);
extern void damage_door(struct char_data *ch, int room, int dir, int power, int type);
#define FORCE_PENALTY(spell) (0-((spell)->damage <= LIGHT ? 100 : 8 - 2*((spell)->damage)))
// drain is compacted into 1 int...i % 10 = drain_level, i - (i % 10) = drain_add
spell_a grimoire[] =
{ // physical, category, target, drain, damage_level
{0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0},
{ TRUE, DETECT, TOUCH, 12, 0 }, // analyze device
{ TRUE, MANIPU, RANGED, 12, 0 }, // anti_ballistic barrier
{FALSE, MANIPU, RANGED, 11, 0 }, // 5 - anti_mana barrier
{ TRUE, HEALTH, TOUCH, 0, 0 }, // antidote
{ TRUE, MANIPU, RANGED, 22, 0 }, // armor
{ TRUE, ILLUSI, RANGED, 22, 0 }, // chaos
{ TRUE, ILLUSI, AREA, 23, 0 }, // chaotic_world
{FALSE, DETECT, RANGED, 2, 0 }, // 10 - clairvoyance
{ TRUE, MANIPU, RANGED, 12, MODERATE}, // clout
{ TRUE, DETECT, RANGED, 13, 0 }, // combat_sense
{FALSE, ILLUSI, RANGED, 3, 0 }, // confusion
{ TRUE, HEALTH, TOUCH, 0, 0 }, // cure disease
{ TRUE, COMBAT, TOUCH, 13, DEADLY}, // 15 - death_touch
{FALSE, DETECT, RANGED, 1, 0 }, // detect_align
{FALSE, DETECT, RANGED, 1, 0 }, // detect_invis
{FALSE, DETECT, RANGED, 1, 0 }, // detect_magic
{FALSE, HEALTH, TOUCH, 0, 0 }, // heal
{ TRUE, COMBAT, AREA, 64, DEADLY}, // hellblast
{ TRUE, ILLUSI, TOUCH, 12, 0 }, // 20 - improved_invisibility
{FALSE, MANIPU, RANGED, 23, 0 }, // influence
{FALSE, ILLUSI, TOUCH, 2, 0 }, // invisibility
{FALSE, COMBAT, AREA, 3, MODERATE}, // mana_ball
{FALSE, COMBAT, AREA, 4, SERIOUS}, // mana_blast
{FALSE, COMBAT, RANGED, 3, SERIOUS}, // 25 - mana_bolt
{FALSE, COMBAT, AREA, 2, LIGHT}, // mana_cloud
{FALSE, COMBAT, RANGED, 1, LIGHT}, // mana_dart
{FALSE, COMBAT, RANGED, 2, MODERATE}, // mana_missile
{FALSE, ILLUSI, RANGED, 12, 0 }, // overstimulation
{ TRUE, MANIPU, RANGED, 64, 0 }, // 30 - petrify
{ TRUE, COMBAT, AREA, 13, MODERATE}, // power_ball
{ TRUE, COMBAT, AREA, 14, SERIOUS}, // power_blast
{ TRUE, COMBAT, RANGED, 13, SERIOUS}, // power_bolt
{ TRUE, COMBAT, AREA, 12, LIGHT}, // power_cloud
{ TRUE, COMBAT, RANGED, 11, LIGHT}, // 35 - power_dart
{ TRUE, COMBAT, RANGED, 12, MODERATE}, // power_missile
{ TRUE, COMBAT, RANGED, 13, SERIOUS}, // ram
{ TRUE, COMBAT, TOUCH, 12, SERIOUS}, // ram_touch
{FALSE, HEALTH, TOUCH, 0, 0 }, // resist_pain
{ TRUE, MANIPU, CASTER, 34, 0 }, // 40 - shape_change
{FALSE, HEALTH, RANGED, 1, 0 }, // stabilize
{FALSE, COMBAT, AREA, -7, MODERATE}, // stun_ball
{FALSE, COMBAT, AREA, -6, SERIOUS}, // stun_blast
{FALSE, COMBAT, RANGED, -7, SERIOUS}, // stun_bolt
{FALSE, COMBAT, AREA, -8, LIGHT}, // 45 - stun_cloud
{FALSE, COMBAT, RANGED, -8, MODERATE}, // stun_missile
{FALSE, COMBAT, RANGED, -7, DEADLY}, // stun_touch
{ TRUE, MANIPU, AREA, 84, DEADLY}, // toxic_wave
{ TRUE, COMBAT, RANGED, 14, DEADLY}, // power_shaft
{ TRUE, COMBAT, AREA, 34, DEADLY}, // 50 - power_burst
{FALSE, COMBAT, RANGED, 4, DEADLY}, // mana_shaft
{FALSE, COMBAT, AREA, 24, DEADLY}, // mana_burst
{FALSE, COMBAT, RANGED, -6, DEADLY}, // stun_shaft
{FALSE, COMBAT, AREA, 14, DEADLY}, // stun_burst
{FALSE, COMBAT, AREA, -9, LIGHT}, // 55 - stun_dart
{0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}, // 60
{0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}, // 65
{0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}, // 70
{0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}, // 75
{0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}, // 80
{0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}, {0,0,0,0,0}, // 85
{0,0,0,0,0},
{ TRUE, DETECT, TOUCH, 2, 0 }, // analyze magic
{ TRUE, DETECT, TOUCH, 2, 0 }, // analyze person
{ TRUE, HEALTH, TOUCH, 10, 0 }, // decrease attribute
{ TRUE, COMBAT, AREA, 34, SERIOUS}, // 90 - <element>ball
{ TRUE, COMBAT, RANGED, 14, SERIOUS}, // <element>bolt
{ TRUE, COMBAT, AREA, 13, LIGHT}, // <element>_cloud
{ TRUE, COMBAT, RANGED, 12, LIGHT}, // <element>_dart
{ TRUE, COMBAT, RANGED, 13, MODERATE}, // <element>_missile
{ TRUE, HEALTH, TOUCH, 10, 0 }, // 95 - increase attribute
{ TRUE, HEALTH, TOUCH, 0, 0 }, // increase reflexes
{ TRUE, MANIPU, CASTER, 22, 0 }, // light
{ TRUE, HEALTH, TOUCH, 2, 0 }, // poison
{FALSE, MANIPU, CASTER, 33, 0 }, // teleport
};
/* affect_update: called from comm.c (causes spells to wear off) */
void affect_update(void)
{
static struct affected_type *af;
static struct char_data *i, *j;
extern const char *spell_wear_off_msg[];
// loop through all the characters in the mud--eek
for (i = character_list; i; i = i->next) {
// reset their # of sustained spells
GET_SUSTAINED(i) = 0;
// then loop through the affected structs
for (af = i->affected; af; af = af->next) {
// and here we add up the # of sustained spells
if (af->caster)
GET_SUSTAINED(i)++;
else if (!mag_can_see(i, af->sustained_by) && af->type != SPELL_HEAL && af->type != SPELL_ANTIDOTE &&
af->type != SPELL_STABILIZE && af->type != SPELL_CURE_DISEASE) {
send_to_char(i, "%s\r\n", spell_wear_off_msg[af->type]);
affect_remove(i, af, 1);
}
}
}
}
void check_spell_drain( struct char_data *ch, spell_t *spell )
{
if (DRAIN_LEVEL(spell->drain) <= 4)
return;
sprintf(buf2, "Correcting drain code for %s from %d to %d",
spell->name, spell->drain, grimoire[spell->type].drain);
mudlog(buf2, ch, LOG_SYSLOG, TRUE);
spell->drain = grimoire[spell->type].drain;
}
int mag_can_see(struct char_data *ch, int id)
{
int sight, room, nextroom, dir, distance;
struct char_data *i, *vict, *tch = NULL;
bool found = FALSE;
for (i = character_list; i && !tch; i = i->next)
if ((IS_NPC(i) ? -i->nr : GET_IDNUM(i)) == id)
tch = i;
if (!tch)
return(FALSE);
sight = find_sight(tch);
for (vict = world[tch->in_room].people; vict && !found; vict = vict->next_in_room)
if (vict == ch)
found = TRUE;
for (dir = 0; dir < (NUM_OF_DIRS - 1) && !found; dir++) {
room = tch->in_room;
if (CAN_GO2(room, dir))
nextroom = EXIT2(room, dir)->to_room;
else nextroom = NOWHERE;
for (distance = 1; ((nextroom != NOWHERE) && !found && (distance <= sight)); distance++) {
for (vict = world[nextroom].people; vict; vict = vict->next_in_room)
if (vict == ch)
found = TRUE;
room = nextroom;
if (CAN_GO2(room, dir))
nextroom = EXIT2(room, dir)->to_room;
else nextroom = NOWHERE;
}
}
return found;
}
int spell_resist(struct char_data *ch)
{
struct affected_type *af;
int resist = (int)(GET_MAGIC(ch) / 4);
for (af = ch->affected; af; af = af->next)
if (af->type == SPELL_ANTI_SPELL && af->modifier > 0)
resist += af->modifier;
return resist;
}
int foci_bonus(struct char_data *ch, struct spell_data *spell,
int force, bool fCast)
{
int i;
int bonus=0;
struct obj_data *obj;
for (i = 0; i < (NUM_WEARS - 1); i++)
{
if ((obj = GET_EQ(ch, i))
&& GET_OBJ_TYPE(obj) == ITEM_FOCUS
&& GET_OBJ_VAL(obj, VALUE_FOCUS_BONDED) == 1
&& GET_OBJ_VAL(obj, VALUE_FOCUS_CHAR_IDNUM) == GET_IDNUM(ch))
{
switch (GET_OBJ_VAL(obj, VALUE_FOCUS_TYPE))
{
case FOCI_SPELL:
if (spell->type == GET_OBJ_VAL(obj, VALUE_FOCUS_SPECIFY))
bonus += GET_OBJ_VAL(obj, VALUE_FOCUS_RATING);
break;
case FOCI_SPELL_CAT:
if (spell->category == GET_OBJ_VAL(obj, VALUE_FOCUS_SPECIFY))
bonus += GET_OBJ_VAL(obj, VALUE_FOCUS_RATING);
break;
}
}
}
/* for (obj = ch->carrying; obj; obj = obj->next_content)
{
if (GET_OBJ_TYPE(obj) == ITEM_FOCUS
&& GET_OBJ_VAL(obj, VALUE_FOCUS_BONDED) == 1
&& GET_OBJ_VAL(obj, VALUE_FOCUS_CHAR_IDNUM) == GET_IDNUM(ch))
{
switch (GET_OBJ_VAL(obj, VALUE_FOCUS_TYPE))
{
case FOCI_SPELL:
if (spell->type == GET_OBJ_VAL(obj, VALUE_FOCUS_SPECIFY))
bonus += GET_OBJ_VAL(obj, VALUE_FOCUS_RATING);
break;
case FOCI_SPELL_CAT:
if (spell->category == GET_OBJ_VAL(obj, VALUE_FOCUS_SPECIFY))
bonus += GET_OBJ_VAL(obj, VALUE_FOCUS_RATING);
break;
}
}
}
*/
if ( !fCast )
bonus += 1;
return bonus/2;
}
int magic_pool_bonus(struct char_data *ch, struct spell_data *spell,
int force, bool fCast)
{
int bonus;
bonus = GET_MAGIC(ch);
#if 0
if ( fCast )
{
if ( bonus > GET_MAG(ch) )
bonus = GET_MAG(ch);
}
else
{
bonus -= GET_MAG(ch);
if (bonus < 0)
bonus = 0;
}
#else
bonus = (bonus + (fCast ? 1 : 0)) / 2;
#endif
return bonus;
}
int totem_bonus(struct char_data *ch, struct spell_data *spell)
{
int bonus = 0;
if (GET_TRADITION(ch) == TRAD_SHAMANIC) {
switch (spell->category) {
case SPELL_CATEGORY_COMBAT:
switch (GET_TOTEM(ch)) {
case TOTEM_OWL:
if (time_info.hours > 6 && time_info.hours < 19)
break;
case TOTEM_GATOR: case TOTEM_LION: case TOTEM_SHARK: case TOTEM_WOLF:
bonus += 2;
break;
case TOTEM_SNAKE:
if (!FIGHTING(ch))
break;
case TOTEM_RAVEN: case TOTEM_RAT: case TOTEM_RACCOON:
bonus -= 1;
break;
default:
break;
}
break;
case SPELL_CATEGORY_DETECTION:
switch (GET_TOTEM(ch)) {
case TOTEM_SNAKE:
if (FIGHTING(ch))
bonus -= 1;
else bonus += 2;
break;
case TOTEM_OWL:
if (time_info.hours > 6 && time_info.hours < 19)
break;
case TOTEM_DOG: case TOTEM_EAGLE: case TOTEM_GATOR: case TOTEM_RAT:
case TOTEM_SHARK: case TOTEM_WOLF:
bonus += 2;
break;
default:
break;
}
break;
case SPELL_CATEGORY_HEALTH:
switch (GET_TOTEM(ch)) {
case TOTEM_SNAKE:
if (FIGHTING(ch))
bonus -= 1;
else bonus += 2;
break;
case TOTEM_OWL:
if (time_info.hours > 6 && time_info.hours < 19)
break;
case TOTEM_BEAR:
bonus += 2;
break;
case TOTEM_LION:
bonus -= 1;
break;
default:
break;
}
break;
case SPELL_CATEGORY_ILLUSION:
switch (GET_TOTEM(ch)) {
case TOTEM_SNAKE:
if (FIGHTING(ch))
bonus -= 1;
else bonus += 2;
break;
case TOTEM_OWL:
if (time_info.hours > 6 && time_info.hours < 19)
break;
case TOTEM_CAT: case TOTEM_RAT:
bonus += 2;
break;
case TOTEM_GATOR:
bonus -= 1;
break;
default:
break;
}
break;
case SPELL_CATEGORY_MANIPULATION:
switch (GET_TOTEM(ch)) {
case TOTEM_OWL:
if (time_info.hours > 6 && time_info.hours < 19)
break;
case TOTEM_RACCOON: case TOTEM_RAVEN:
bonus += 2;
break;
case TOTEM_SNAKE:
if (!FIGHTING(ch))
break;
bonus -= 1;
break;
default:
break;
}
break;
default:
break;
}
}
return bonus;
}
void resist_drain(struct char_data *ch, int force, spell_t *spell, int wound)
{
int successes, drain;
int old_physical, old_mental;
int staged_wound;
int wil_dice, foci_dice, pool_dice, tnum;
bool is_physical = FALSE;
if (!IS_NPC(ch) && access_level(ch, LVL_PRESIDENT))
return;
if (force > (GET_MAG(ch) / 100))
is_physical = TRUE;
wil_dice = GET_WIL(ch);
foci_dice = foci_bonus(ch, spell, force, FALSE);
pool_dice = magic_pool_bonus(ch, spell, force, FALSE);
tnum = MAX(2, (force >> 1) + DRAIN_POWER(spell->drain));
successes = success_test(wil_dice + foci_dice + pool_dice, tnum);
staged_wound = dec_staging(successes, wound);
drain = convert_damage(staged_wound);
old_physical = GET_PHYSICAL(ch);
old_mental = GET_MENTAL(ch);
if (is_physical)
{
GET_PHYSICAL(ch) -= drain * 100;
}
else
{
GET_MENTAL(ch) -= drain * 100;
if (GET_MENTAL(ch) < 0)
{
GET_PHYSICAL(ch) += GET_MENTAL(ch);
GET_MENTAL(ch) = 0;
}
}
if (1)
{
char rbuf[MAX_STRING_LENGTH];
sprintf( rbuf,
"Drain: F:%d/%d, Mag:%d, WFP/T %d+%d+%d/%d. %d(%d)->%d, D: %d%c. %d->%d/%d->%d",
force, spell->force,
GET_MAG(ch), wil_dice, foci_dice, pool_dice, tnum, wound,
successes, staged_wound, drain,
is_physical ? 'P' : 'M',
old_physical, GET_PHYSICAL(ch), old_mental, GET_MENTAL(ch));
act( rbuf, 1, ch, NULL, NULL, TO_ROLLS );
}
update_pos(ch);
if ((GET_POS(ch) <= POS_STUNNED) && (GET_POS(ch) > POS_DEAD)) {
if (FIGHTING(ch))
stop_fighting(ch);
send_to_char("You are unable to resist the drain from using magic and fall unconscious!\r\n", ch);
act("$n collapses unconscious from the use of magic!", FALSE, ch, 0, 0, TO_ROOM);
} else {
if (GET_POS(ch) == POS_DEAD) {
if (FIGHTING(ch))
stop_fighting(ch);
send_to_char("The energy from the spell overloads your systems, killing you...\r\n", ch);
act("$n collapses DEAD from an overload of magic!", FALSE, ch, 0, 0, TO_ROOM);
die(ch);
}
}
}
void sustain_spell(int force, struct char_data *ch, struct char_data *victim, spell_t *spell, int level)
{
char xbuf[MAX_STRING_LENGTH];
struct affected_type af, af2;
int success, stat1 = 0, stat2 = 0;
int dice, tnum;
int fbonus, tbonus, pbonus;
int mod;
int shop;
extern int top_of_shopt;
extern struct shop_data *shop_table;
sh_int health = 0, attrib = 0;
char *to_vict = NULL;
char *to_room = NULL;
if (victim == NULL || ch == NULL)
return;
if (spell->type == SPELL_HEAL || spell->type == SPELL_ANTIDOTE ||
spell->type == SPELL_STABILIZE || spell->type == SPELL_CURE_DISEASE)
health = 1;
else if (spell->type == SPELL_DECREASE_ATTRIB || spell->type == SPELL_INCREASE_ATTRIB ||
spell->type == SPELL_INCREASE_REFLEXES)
attrib = 1;
if (affected_by_spell(victim, spell->type)) {
if (!health)
sprintf(buf, "%s already affected by that spell.", (ch == victim ?
"You are" : "$N is"));
else strcpy(buf, "The spell has no effect.");
act(buf, FALSE, ch, 0, victim, TO_CHAR);
return;
}
if (GET_SUSTAINED(ch) >= (ubyte)(GET_SKILL(ch, SKILL_SORCERY)) && !health) {
send_to_char("You can't sustain any more spells. Release one first.\r\n", ch);
return;
}
af.type = spell->type;
af.bitvector = 0;
af.modifier = 0;
af.location = APPLY_NONE;
af.duration = -1;
af.sustained_by = (IS_NPC(ch) ? -ch->nr : GET_IDNUM(ch));
af.caster = FALSE;
af2.type = spell->type;
af2.bitvector = 0;
af2.modifier = 0;
af2.location = APPLY_NONE;
af2.duration = -1;
af2.sustained_by = (IS_NPC(victim) ? -victim->nr : GET_IDNUM(victim));
af2.caster = TRUE;
tbonus = totem_bonus(ch, spell);
fbonus = foci_bonus(ch, spell, force, TRUE);
pbonus = magic_pool_bonus(ch, spell, force, TRUE);
dice = force + tbonus + pbonus + fbonus;
tnum = (spell->type == SPELL_ANTI_BULLET ||
spell->type == SPELL_ANTI_SPELL) ? 6 : 4;
xbuf[0] = ' ';
xbuf[1] = 0;
mod = modify_target_rbuf(ch, xbuf);
success = success_test(dice, tnum + mod);
if ( 1 )
{
char rbuf[MAX_STRING_LENGTH];
sprintf(rbuf,
"SusSpell: F:%d/%d, Mag:%d, FFPT/TM %d+%d+%d+%d/%d+%d. %d.%s",
force, spell->force,
GET_MAG(ch),
force, fbonus, pbonus, tbonus,
tnum, mod, success,
xbuf);
act(rbuf, 1, ch, NULL, NULL, TO_ROLLS);
}
if (success < 1 && !health && !attrib) {
send_to_char("Your spell force doesn't seem powerful enough.\r\n", ch);
return;
}
switch (spell->type) {
case SPELL_ANTIDOTE: case SPELL_CURE_DISEASE:
case SPELL_HEAL: case SPELL_STABILIZE:
af.duration = level;
af2.duration = level;
break;
case SPELL_ANTI_BULLET:
to_vict = "A shimmering sphere surrounds you.";
to_room = "A shimmering sphere surrounds $n.";
af.modifier = force;
af.location = APPLY_BALLISTIC;
break;
case SPELL_ANTI_SPELL:
to_vict = "A glowing sphere surrounds you briefly, then disappears.";
to_room = "A glowing sphere surrounds $n briefly.";
af.modifier = (int)(force / 2);
break;
case SPELL_ARMOR:
af.modifier = (int)(success / 2);
af.location = APPLY_BOD;
to_vict = "You feel your skin toughen!";
break;
case SPELL_CHAOTIC_WORLD:
af.type = SPELL_CHAOS;
af2.type = SPELL_CHAOS;
case SPELL_CHAOS:
success -= success_test(GET_WIL(victim) + spell_resist(victim),
force + modify_target(victim));
if (success < 1) {
act("$N seems to resist the effects!", FALSE, ch, 0, victim, TO_CHAR);
return;
}
af.modifier = success;
af.location = APPLY_TARGET;
to_vict = "You feel disorientated!";
break;
case SPELL_COMBAT_SENSE:
af.modifier = (int)(success / 2);
af.location = APPLY_COMBAT_POOL;
to_vict = "You feel your combat sense improve!";
if ( af.modifier == 0 )
{
send_to_char("Your casting wasn't powerful enough.\r\n", ch);
return;
}
break;
case SPELL_CONFUSION:
success -= success_test(GET_WIL(victim) + spell_resist(victim),
force + modify_target(victim));
if (success < 1) {
act("$N seems to resist the effects!", FALSE, ch, 0, victim, TO_CHAR);
return;
}
success = stage(success, 1);
af.modifier = success;
af.location = APPLY_TARGET;
to_vict = "You feel confused!";
break;
case SPELL_DECREASE_ATTRIB:
case SPELL_INCREASE_ATTRIB:
switch (spell->effect) {
case SPELL_EFFECT_DECREASE_BOD:
case SPELL_EFFECT_INCREASE_BOD:
stat1 = GET_BOD(victim);
stat2 = victim->real_abils.bod;
af.location = APPLY_BOD;
break;
case SPELL_EFFECT_DECREASE_CHA:
case SPELL_EFFECT_INCREASE_CHA:
stat1 = GET_CHA(victim);
stat2 = victim->real_abils.cha;
af.location = APPLY_CHA;
break;
case SPELL_EFFECT_DECREASE_INT:
case SPELL_EFFECT_INCREASE_INT:
stat1 = GET_INT(victim);
stat2 = victim->real_abils.intel;
af.location = APPLY_INT;
break;
case SPELL_EFFECT_DECREASE_QUI:
case SPELL_EFFECT_INCREASE_QUI:
stat1 = GET_QUI(victim);
stat2 = victim->real_abils.qui;
af.location = APPLY_QUI;
break;
case SPELL_EFFECT_DECREASE_REA:
case SPELL_EFFECT_INCREASE_REA:
stat1 = GET_REA(victim);
stat2 = victim->real_abils.rea;
af.location = APPLY_REA;
break;
case SPELL_EFFECT_DECREASE_STR:
case SPELL_EFFECT_INCREASE_STR:
stat1 = GET_STR(victim);
stat2 = victim->real_abils.str;
af.location = APPLY_STR;
break;
case SPELL_EFFECT_DECREASE_WIL:
case SPELL_EFFECT_INCREASE_WIL:
stat1 = GET_WIL(victim);
stat2 = victim->real_abils.wil;
af.location = APPLY_WIL;
break;
default:
send_to_char("Undefined attribute.\r\n", ch);
return;
}
if (stat1 != stat2) {
send_to_char(ch, "You can't %s an already modified attribute.\r\n",
(spell->type == SPELL_INCREASE_ATTRIB ? "increase" : "decrease"));
return;
}
if (spell->type == SPELL_DECREASE_ATTRIB)
{
success = resisted_test(force + spell_bonus(ch, spell),
10 - (int)(GET_ESS(victim) / 100)
+ modify_target(ch),
stat1 + spell_resist(victim),
10 - (int)(GET_ESS(victim) / 100)
+ modify_target(victim));
}
else
{
success = success_test(force + spell_bonus(ch, spell),
2 * stat1 + modify_target(ch));
if ( 1 )
{
char rbuf[MAX_STRING_LENGTH];
sprintf(rbuf,
"IncrAttrib: F:%d/%d, Mag:%d, FB/TM %d+%d/%d+%d. %d.",
force, spell->force,
GET_MAG(ch),
force, spell_bonus(ch, spell),
2*stat1, modify_target(ch),
success);
act(rbuf, 1, ch, NULL, NULL, TO_ROLLS);
}
}
if (success < 1) {
if (ch == victim)
send_to_char(NOEFFECT, ch);
else
act("Your spell has no effect on $M.", FALSE, ch, 0, victim, TO_CHAR);
return;
}
af.modifier = spell->damage;
if (spell->type == SPELL_DECREASE_ATTRIB)
af.modifier = - af.modifier;
break;
case SPELL_DETECT_ALIGNMENT:
af.bitvector = AFF_DETECT_ALIGN;
to_vict = "Your eyes tingle.";
break;
case SPELL_DETECT_INVIS:
to_vict = "Your eyes tingle.";
af.bitvector = AFF_DETECT_INVIS;
break;
case SPELL_DETECT_MAGIC:
to_vict = "Your eyes tingle.";
af.bitvector = AFF_DETECT_MAGIC;
break;
case SPELL_INCREASE_REFLEXES:
af.modifier = spell->damage;
af.location = APPLY_INITIATIVE_DICE;
if (GET_INIT_DICE(ch) > 0) {
if (ch == victim)
send_to_char("Your reflexes are already modified.", ch);
else act("$S reflexes are already modified.", FALSE, ch, 0, victim, TO_CHAR);
return;
}
success = success_test(force + spell_bonus(ch, spell),
2 * GET_REA(victim) + modify_target(ch));
if (success < 1) {
if (ch == victim)
send_to_char(NOEFFECT, ch);
else act("Your spell has no effect on $M.", FALSE, ch, 0, victim, TO_CHAR);
return;
}
break;
case SPELL_INFLUENCE:
success -= success_test(GET_WIL(victim) + spell_resist(victim), force + modify_target(victim));
if (success < 1 || MOB_FLAGGED(victim, MOB_NOCHARM)) {
act("$N seems to resist the effects!", FALSE, ch, 0, victim, TO_CHAR);
return;
}
for (shop = 0; shop < top_of_shopt; shop++)
if (SHOP_KEEPER(shop) == GET_MOB_VNUM(victim))
{
send_to_char("They see right through your game.\n\r",ch);
return;
}
if (circle_follow(victim, ch)) {
act("You cannot charm someone you are following!", FALSE, ch, 0, 0, TO_CHAR);
return;
}
if (victim->master)
stop_follower(victim);
REMOVE_BIT(AFF_FLAGS(victim), AFF_GROUP);
add_follower(victim, ch);
af.bitvector = AFF_CHARM;
to_vict = "You feel an irrestible compulsion to follow $N.";
act("$N promises to obey your every command.", FALSE, ch, 0, victim, TO_CHAR);
break;
case SPELL_IMPROVED_INVIS:
to_room = "$n slowly fades out of existence.";
to_vict = "You vanish.";
af.bitvector = AFF_IMP_INVIS;
break;
case SPELL_INVISIBILITY:
to_room = "$n slowly fades out of existence.";
to_vict = "You vanish.";
af.bitvector = AFF_INVISIBLE;
break;
case SPELL_LIGHT:
to_room = "A softly glowing sphere appears from $n's hands.";
to_vict = "A small sphere of light appears and begins to hover about your head.";
world[victim->in_room].light++;
break;
case SPELL_OVERSTIMULATION:
success -= success_test(GET_WIL(victim) + spell_resist(victim), force + modify_target(victim));
if (success < 1) {
act("$N seems to resist the effects!", FALSE, ch, 0, victim, TO_CHAR);
return;
}
if (success >= 10) {
af.bitvector = AFF_PETRIFY;
to_vict = "Your brain screams in pain, and your muscles become distant!";
}
if (success >= 6)
af.modifier = 3;
else if (success >= 3)
af.modifier = 2;
else if (success >= 1)
af.modifier = 1;
else af.modifier = 0;
af.location = APPLY_TARGET;
break;
case SPELL_PETRIFY:
success -= success_test(GET_BOD(victim) + spell_resist(victim), force + modify_target(victim));
if (success < 1) {
act("$N seems to resist the effects!", FALSE, ch, 0, victim, TO_CHAR);
return;
}
af.bitvector = AFF_PETRIFY;
af.modifier = success;
to_vict = "Your muscles seem to become solid stone.";
to_room = "$n freezes in place, $s skin turning a textured gray.";
break;
case SPELL_POISON:
success -= resisted_test(GET_BOD(victim) + spell_resist(victim), force + modify_target(victim),
force, GET_BOD(victim) + modify_target(ch));
if (success < 1) {
act("$N seems to resist the effects!", FALSE, ch, 0, victim, TO_CHAR);
return;
}
af.modifier = level;
af.duration = success;
af.bitvector = AFF_POISON;
to_vict = "You feel very sick.";
to_room = "$n gets violently ill!";
break;
case SPELL_RESIST_PAIN:
to_vict = "You lose feeling of your physical wounds.";
af.modifier = level;
break;
}
affect_to_char(victim, &af);
affect_to_char(ch, &af2);
GET_SUSTAINED(ch) += 1;
if (!health)
send_to_char("The spell is sustained.\r\n", ch);
/* send messages to room and victim if necessary */
if (to_vict != NULL)
act(to_vict, FALSE, victim, 0, ch, TO_CHAR);
if (to_room != NULL)
act(to_room, TRUE, victim, 0, ch, TO_ROOM);
}
/* the way a mage/shaman stops sustaining a spell */
ACMD(do_release)
{
char who[255], *spell;
struct char_data *vict;
int spellnum;
static struct affected_type *af;
if (!*argument) {
send_to_char("What spell and who do you wish to release it from?\r\n", ch);
return;
}
spell = any_one_arg(argument, who);
if (!(vict = get_char_room_vis(ch, who))) {
send_to_char("You can't seem to find that person here.\r\n", ch);
return;
}
if (!spell) {
send_to_char("What spell do you wish to release?\r\n", ch);
return;
}
spellnum = find_skill_num(spell);
if (spellnum == -1) {
send_to_char("What spell is that?\r\n", ch);
return;
} else if (spellnum == SPELL_HEAL || spellnum == SPELL_CURE_DISEASE || spellnum == SPELL_STABILIZE ||
spellnum == SPELL_ANTIDOTE) {
send_to_char("How do you expect to release that?!\r\n", ch);
return;
}
if (affected_by_spell(vict, spellnum) != 1) {
act("$N doesn't have that spell sustained on $M.", FALSE, ch, 0, vict, TO_CHAR);
return;
}
for (af = vict->affected; af; af = af->next)
if ((af->type == spellnum) && (af->caster == FALSE)) {
if (af->sustained_by != (IS_NPC(ch) ? -ch->nr : GET_IDNUM(ch))) {
send_to_char("But you aren't sustaining that spell!\r\n", ch);
return;
} else {
sprintf(buf, "%s\r\n", spell_wear_off_msg[af->type]);
send_to_char(buf, vict);
affect_remove(vict, af, 1);
return;
}
}
}
#define NUM_SPIRITS 17
ACMD(do_bond)
{
struct affected_type *af;
int i, spellnum;
struct obj_data *obj = NULL, *weapon = NULL, *temp;
spell_t *spell;
char *pbuf;
pbuf = any_one_arg(argument, arg);
while(*pbuf == ' ')
pbuf++;
if (!*arg) {
send_to_char("Usage: bond <focus> <spell/category/weapon>\r\n"
" bond <docwagon>\r\n", ch);
return;
}
if (IS_NPC(ch)) {
send_to_char("Mobs can't bond; go away.\r\n", ch);
return;
}
for (i = 0; !obj && i < NUM_WEARS; i++)
if (GET_EQ(ch, i) && isname(arg, GET_EQ(ch, i)->name))
obj = GET_EQ(ch, i);
if (!obj)
for (temp = ch->carrying; !obj && temp; temp = temp->next_content)
if (isname(arg, temp->name))
obj = temp;
if (!obj) {
send_to_char(ch, "You do not seem to have a '%s'.\r\n", arg);
return;
}
if (GET_OBJ_TYPE(obj) == ITEM_DOCWAGON) {
if (GET_OBJ_VAL(obj, 1)) {
act("$p has already been activated.", FALSE, ch, obj, 0, TO_CHAR);
return;
}
GET_OBJ_VAL(obj, 1) = GET_IDNUM(ch);
act("$p's lights begin to subtly flash in a rhythmic sequence.", FALSE,
ch, obj, 0, TO_CHAR);
return;
}
if (GET_OBJ_TYPE(obj) != ITEM_FOCUS) {
send_to_char("You can only bond foci and DocWagon contracts.\r\n", ch);
return;
}
if (GET_TRADITION(ch) == TRAD_MUNDANE) {
send_to_char("Mundanes can't bond foci.\r\n", ch);
return;
} else if (GET_FOCI(ch) >= GET_INT(ch)) {
send_to_char("You cannot bond any more foci.\r\n", ch);
return;
} else if (GET_OBJ_VAL(obj, VALUE_FOCUS_BONDED) > 0
|| GET_OBJ_VAL(obj, VALUE_FOCUS_CHAR_IDNUM)) {
send_to_char("That focus has already been bonded.\r\n", ch);
return;
} else if (GET_TRADITION(ch) == TRAD_ADEPT
&& GET_OBJ_VAL(obj, VALUE_FOCUS_TYPE) != FOCI_WEAPON) {
send_to_char("Adepts can only bond weapon foci.\r\n", ch);
return;
}
if (obj->worn_by == ch)
for (i = 0; i < MAX_OBJ_AFFECT; i++)
affect_modify(ch, obj->affected[i].location, obj->affected[i].modifier,
obj->obj_flags.bitvector, FALSE);
switch (GET_OBJ_VAL(obj, VALUE_FOCUS_TYPE)) {
case FOCI_SPELL:
if (GET_KARMA(ch) < (GET_OBJ_VAL(obj, VALUE_FOCUS_RATING) * 100)) {
send_to_char(ch, "You do not have %d karma to bond this focus.\r\n",
GET_OBJ_VAL(obj, VALUE_FOCUS_RATING));
return;
}
spell = find_spell( ch, pbuf );
if ( !spell )
{
send_to_char(ch, "You do not know spell '%s'.\r\n", pbuf);
return;
}
GET_OBJ_VAL(obj, VALUE_FOCUS_CHAR_IDNUM) = GET_IDNUM(ch);
GET_OBJ_VAL(obj, VALUE_FOCUS_CAT) = spell->type;
GET_OBJ_VAL(obj, VALUE_FOCUS_SPECIFY) = spell->type;
GET_OBJ_VAL(obj, VALUE_FOCUS_BONDED) = 1;
sprintf(buf, "You have successfully bonded $p (%s).",
spells[GET_OBJ_VAL(obj, VALUE_FOCUS_SPECIFY)]);
act(buf, FALSE, ch, obj, 0, TO_CHAR);
GET_KARMA(ch) -= GET_OBJ_VAL(obj, VALUE_FOCUS_RATING) * 100;
GET_FOCI(ch)++;
break;
case FOCI_SPELL_CAT:
if (GET_KARMA(ch) < (GET_OBJ_VAL(obj, VALUE_FOCUS_RATING) * 300)) {
send_to_char(ch, "You do not have %d karma to bond this focus.\r\n",
GET_OBJ_VAL(obj, VALUE_FOCUS_RATING) * 3);
return;
}
for( i = 0; *spell_categories[i] != '\n'; i++ )
if (is_abbrev(pbuf, spell_categories[i]))
break;
if ( *spell_categories[i] == '\n' )
{
send_to_char("You must specify a category for this focus to assist.\r\n", ch);
return;
}
GET_OBJ_VAL(obj, VALUE_FOCUS_CHAR_IDNUM) = GET_IDNUM(ch);
GET_OBJ_VAL(obj, VALUE_FOCUS_SPECIFY) = i;
GET_OBJ_VAL(obj, VALUE_FOCUS_CAT) = i;
GET_OBJ_VAL(obj, VALUE_FOCUS_BONDED) = 1;
GET_KARMA(ch) -= GET_OBJ_VAL(obj, VALUE_FOCUS_RATING) * 300;
GET_FOCI(ch)++;
sprintf(buf, "You have successfully bonded $p (%s).",
spell_categories[GET_OBJ_VAL(obj, VALUE_FOCUS_SPECIFY)]);
act(buf, FALSE, ch, obj, 0, TO_CHAR);
break;
case FOCI_SPIRIT:
if (GET_KARMA(ch) < (GET_OBJ_VAL(obj, VALUE_FOCUS_RATING) * 200)) {
send_to_char(ch, "You do not have %d karma to bond this focus.\r\n",
GET_OBJ_VAL(obj, VALUE_FOCUS_RATING) * 2);
return;
}
for( i = 0; *spirits[i] != '\n'; i++ )
if (is_abbrev(pbuf, spirits[i]))
break;
if ( *spell_categories[i] == '\n' )
{
send_to_char("You must specify a spirit type for this focus to assist.\r\n", ch);
return;
}
GET_OBJ_VAL(obj, VALUE_FOCUS_CHAR_IDNUM) = GET_IDNUM(ch);
GET_OBJ_VAL(obj, VALUE_FOCUS_SPECIFY) = i;
GET_OBJ_VAL(obj, VALUE_FOCUS_CAT) = i;
GET_OBJ_VAL(obj, VALUE_FOCUS_BONDED) = 1;
GET_KARMA(ch) -= GET_OBJ_VAL(obj, VALUE_FOCUS_RATING) * 200;
GET_FOCI(ch)++;
sprintf(buf, "You bond $p (%s).",
spirits[GET_OBJ_VAL(obj, VALUE_FOCUS_SPECIFY)]);
act(buf, FALSE, ch, obj, 0, TO_CHAR);
break;
case FOCI_POWER:
if (GET_KARMA(ch) < (GET_OBJ_VAL(obj, VALUE_FOCUS_RATING) * 500)) {
send_to_char(ch, "You do not have %d karma to bond this focus.\r\n",
GET_OBJ_VAL(obj, VALUE_FOCUS_RATING) * 5);
return;
}
GET_KARMA(ch) -= GET_OBJ_VAL(obj, VALUE_FOCUS_RATING) * 500;
GET_OBJ_VAL(obj, VALUE_FOCUS_CHAR_IDNUM) = GET_IDNUM(ch);
GET_OBJ_VAL(obj, VALUE_FOCUS_BONDED) = 1;
for (i = 0; i < MAX_OBJ_AFFECT; i++)
if (!obj->affected[i].modifier) {
obj->affected[i].modifier = GET_OBJ_VAL(obj, VALUE_FOCUS_RATING);
obj->affected[i].location = APPLY_MAG;
affect_modify(ch, obj->affected[i].location, obj->affected[i].modifier,
obj->obj_flags.bitvector, TRUE);
break;
}
for (i = 0; i < MAX_OBJ_AFFECT; i++)
if (!obj->affected[i].modifier) {
obj->affected[i].modifier = GET_OBJ_VAL(obj, VALUE_FOCUS_RATING);
obj->affected[i].location = APPLY_MAGIC_POOL;
affect_modify(ch, obj->affected[i].location, obj->affected[i].modifier,
obj->obj_flags.bitvector, TRUE);
break;
}
act("You have successfully bonded $p.", FALSE, ch, obj, 0, TO_CHAR);
GET_FOCI(ch)++;
break;
case FOCI_LOCK:
if (!*pbuf) {
send_to_char("You need to select a spell to lock.\r\n", ch);
return;
}
if (GET_KARMA(ch) < 100) {
send_to_char("You do not have the karma point to lock any spell.\r\n", ch);
return;
}
spellnum = find_skill_num(pbuf);
if (spellnum <= 0) {
act("That spell doesn't exist.", FALSE, ch, 0, 0, TO_CHAR);
return;
}
if (affected_by_spell(ch, spellnum) != 1) {
act("You are not affected by that spell.", FALSE, ch, 0, 0, TO_CHAR);
return;
}
for (af = ch->affected; af; af = af->next)
if (af->type == spellnum && af->caster == FALSE) {
if (af->sustained_by != GET_IDNUM(ch))
send_to_char("You can only lock spells that you are sustaining.\r\n", ch);
else {
GET_KARMA(ch) -= 100;
GET_FOCI(ch)++;
GET_OBJ_VAL(obj, VALUE_FOCUS_CHAR_IDNUM) = GET_IDNUM(ch);
GET_OBJ_VAL(obj, VALUE_FOCUS_BONDED) = 1;
GET_OBJ_VAL(obj, VALUE_FOCUS_SPECIFY) = af->type;
if (af->bitvector)
SET_BIT(obj->obj_flags.bitvector, af->bitvector);
for (i = 0; i < MAX_OBJ_AFFECT; i++)
if (!obj->affected[i].modifier) {
obj->affected[i].location = af->location;
obj->affected[i].modifier = af->modifier;
affect_modify(ch, obj->affected[i].location, obj->affected[i].modifier,
obj->obj_flags.bitvector, TRUE);
break;
}
sprintf(buf, "You lock %s to $p.",
spells[GET_OBJ_VAL(obj, VALUE_FOCUS_SPECIFY)]);
act(buf, FALSE, ch, obj, 0, TO_CHAR);
affect_remove(ch, af, 1);
}
return;
}
break;
case FOCI_WEAPON:
if (GET_KARMA(ch) < (GET_OBJ_VAL(obj, VALUE_FOCUS_RATING) * 500)) {
send_to_char(ch, "You do not have %d karma to bond this focus.\r\n",
GET_OBJ_VAL(obj, VALUE_FOCUS_RATING) * 5);
return;
}
for (i = 0; !weapon && i < NUM_WEARS; i++)
if (GET_EQ(ch, i) && isname(pbuf, GET_EQ(ch, i)->name))
weapon = GET_EQ(ch, i);
if (!weapon)
for (temp = ch->carrying; !weapon && temp; temp = temp->next_content)
if (isname(pbuf, temp->name))
weapon = temp;
if (!weapon) {
send_to_char(ch, "You do not seem to have a '%s'.\r\n", pbuf);
break;
}
if (GET_OBJ_TYPE(weapon) != ITEM_WEAPON) {
send_to_char("You can only bond weapon foci to weapons.\r\n", ch);
break;
}
if (GET_OBJ_VAL(weapon, 3) == TYPE_HIT || GET_OBJ_VAL(weapon, 3) >= TYPE_TASER) {
send_to_char("That is not a suitable weapon to bond a foci to.\r\n", ch);
return;
}
GET_KARMA(ch) -= GET_OBJ_VAL(obj, 1) * 500;
GET_FOCI(ch)++;
GET_OBJ_VAL(weapon, 9) = GET_IDNUM(ch);
GET_OBJ_VAL(weapon, 8) = GET_OBJ_VAL(obj, VALUE_FOCUS_RATING);
GET_OBJ_VAL(weapon, 7) = GET_OBJ_VNUM(obj);
GET_OBJ_VAL(obj, VALUE_FOCUS_BONDED) = 1;
sprintf(buf, "%s melts as its power flows into %s.\r\n",
CAP(obj->short_description),
weapon->short_description);
send_to_char(buf, ch);
extract_obj(obj);
break;
}
}
ACMD(do_status)
{
struct affected_type *af;
bool last_cast = FALSE, found = FALSE;
struct char_data *tch, *target;
struct obj_data *obj;
int i;
if (IS_AFFECTED(ch, AFF_DETECT_MAGIC) || IS_ASTRAL(ch) || IS_DUAL(ch)) {
skip_spaces(&argument);
if (!*argument)
target = ch;
else target = get_char_room_vis(ch, argument);
} else target = ch;
if (!target) {
send_to_char("You can't seem to find that person.\r\n", ch);
return;
}
sprintf(buf, "%s affected by:", (ch == target ? "You are" : "$N is"));
act(buf, FALSE, ch, 0, target, TO_CHAR);
if (ch == target) {
for (i = 0; i < NUM_WEARS; i++)
if ((obj = GET_EQ(ch, i))
&& GET_OBJ_TYPE(obj) == ITEM_FOCUS
&& GET_OBJ_VAL(obj, VALUE_FOCUS_TYPE) == FOCI_LOCK
&& GET_OBJ_VAL(obj, VALUE_FOCUS_CHAR_IDNUM) == GET_IDNUM(ch)) {
sprintf(buf, " %-20s Locked on: $p",
spells[GET_OBJ_VAL(obj, VALUE_FOCUS_SPECIFY)]);
act(buf, FALSE, ch, obj, 0, TO_CHAR);
found = TRUE;
}
/*
for (obj = ch->carrying; obj; obj = obj->next_content)
if (GET_OBJ_TYPE(obj) == ITEM_FOCUS
&& GET_OBJ_VAL(obj, VALUE_FOCUS_TYPE) == FOCI_LOCK
&& GET_OBJ_VAL(obj, VALUE_FOCUS_CHAR_IDNUM) == GET_IDNUM(ch)) {
sprintf(buf, " %-20s Locked on: $p",
spells[GET_OBJ_VAL(obj, VALUE_FOCUS_SPECIFY)]);
act(buf, FALSE, ch, obj, 0, TO_CHAR);
found = TRUE;
}*/
}
for (af = target->affected; af; af = af->next) {
if (af->caster == TRUE && af->sustained_by ==
(IS_NPC(target) ? -target->nr : GET_IDNUM(target)))
last_cast = TRUE;
else {
if (af->caster == FALSE && af->type != SPELL_HEAL && af->type != SPELL_CURE_DISEASE &&
af->type != SPELL_STABILIZE && af->type != SPELL_ANTIDOTE) {
if (last_cast == TRUE) {
last_cast = FALSE;
if (ch == target)
sprintf(buf, " %-20s Sustained by: yourself", spells[af->type]);
else sprintf(buf, " %-20s", spells[af->type]);
act(buf, FALSE, ch, 0, target, TO_CHAR);
found = TRUE;
} else {
tch = character_list;
if (ch == target)
sprintf(buf, " %-20s Sustained by: $N", spells[af->type]);
else sprintf(buf, " %-20s", spells[af->type]);
found = TRUE;
if (af->sustained_by < 0)
while (tch != NULL && (IS_NPC(tch) ? tch->nr : 0) != -af->sustained_by)
tch = tch->next;
else while (tch != NULL && (!IS_NPC(tch) ? GET_IDNUM(tch) : 0) != af->sustained_by)
tch = tch->next;
act(buf, FALSE, ch, 0, tch, TO_CHAR);
}
}
}
}
if (!found)
send_to_char(" Nothing.\r\n", ch);
found = FALSE;
last_cast = FALSE;
if (ch != target)
return;
if (GET_TRADITION(ch) != TRAD_SHAMANIC && GET_TRADITION(ch) != TRAD_HERMETIC &&
!(!IS_NPC(ch) && access_level(ch, LVL_PRESIDENT)))
return;
send_to_char("\r\nYou are sustaining:\r\n", ch);
if (!ch->affected)
send_to_char(" Nothing.\r\n", ch);
else {
for (af = ch->affected; af; af = af->next) {
if (af->caster == TRUE
&& af->type != SPELL_HEAL
&& af->type != SPELL_CURE_DISEASE
&& af->type != SPELL_STABILIZE
&& af->type != SPELL_ANTIDOTE) {
if (af->sustained_by == (IS_NPC(ch) ? -ch->nr : GET_IDNUM(ch)))
sprintf(buf, " %-20s Sustained on: yourself", spells[af->type]);
else
sprintf(buf, " %-20s Sustained on: $N", spells[af->type]);
found = TRUE;
tch = character_list;
if (af->sustained_by < 0)
while (tch != NULL && (IS_NPC(tch) ? tch->nr : 0) != -af->sustained_by)
tch = tch->next;
else while (tch != NULL && (!IS_NPC(tch) ? GET_IDNUM(tch) : 0) != af->sustained_by)
tch = tch->next;
act(buf, FALSE, ch, 0, tch, TO_CHAR);
}
}
if (!found)
send_to_char(" Nothing.\r\n", ch);
}
}
int check_spirit_sector(int room, int spirit)
{
if (spirit < 5)
return 1;
switch (spirit) {
case 5:
if (world[room].sector_type != SECT_CITY)
return 0;
break;
case 6:
if (world[room].sector_type != SECT_INSIDE)
return 0;
break;
case 7: case 8: case 11:
if (world[room].sector_type != SECT_FIELD)
return 0;
break;
case 9:
if (world[room].sector_type != SECT_FOREST)
return 0;
break;
case 10:
if (world[room].sector_type != SECT_MOUNTAIN && world[room].sector_type != SECT_HILLS)
return 0;
break;
case 12: case 13:
if (world[room].sector_type == SECT_INSIDE || world[room].sector_type > SECT_FLYING)
return 0;
break;
case 14: case 15: case 17:
if (world[room].sector_type != SECT_WATER_SWIM && world[room].sector_type != SECT_WATER_NOSWIM)
return 0;
break;
case 16:
if (world[room].sector_type != SECT_WATER_NOSWIM && world[room].sector_type != SECT_UNDERWATER)
return 0;
break;
}
return 1;
}
int spirit_bonus(struct char_data *ch, int spirit)
{
int i, bonus = 0;
struct obj_data *obj;
if (IS_NPC(ch))
return 0;
for (i = 0; !bonus && i < (NUM_WEARS - 1); i++)
if ((obj = GET_EQ(ch, i))
&& GET_OBJ_TYPE(obj) == ITEM_FOCUS
&& GET_OBJ_VAL(obj, VALUE_FOCUS_CHAR_IDNUM) == GET_IDNUM(ch)
&& GET_OBJ_VAL(obj, VALUE_FOCUS_SPECIFY) == spirit
&& GET_OBJ_VAL(obj, VALUE_FOCUS_BONDED) == 1)
bonus = GET_OBJ_VAL(obj, VALUE_FOCUS_RATING);
for (obj = ch->carrying; !bonus && obj; obj = obj->next_content)
if (GET_OBJ_TYPE(obj) == ITEM_FOCUS
&& GET_OBJ_VAL(obj, VALUE_FOCUS_CHAR_IDNUM) == GET_IDNUM(ch)
&& GET_OBJ_VAL(obj, VALUE_FOCUS_SPECIFY) == spirit
&& GET_OBJ_VAL(obj, VALUE_FOCUS_BONDED) == 1)
bonus = GET_OBJ_VAL(obj, VALUE_FOCUS_RATING);
if (GET_TRADITION(ch) == TRAD_SHAMANIC)
switch (GET_TOTEM(ch)) {
case TOTEM_BEAR:
if (spirit == 9)
bonus += 2;
break;
case TOTEM_RACCOON: case TOTEM_CAT:
if (spirit == 5)
bonus += 2;
break;
case TOTEM_DOG:
if (spirit == 6 || spirit == 7)
bonus += 2;
break;
case TOTEM_EAGLE: case TOTEM_RAVEN:
if (spirit == 13)
bonus += 2;
break;
case TOTEM_GATOR:
if ((!number(0, 1) ? spirit == 5 : spirit == 14 || spirit == 15 || spirit == 17))
bonus += 2;
case TOTEM_LION:
if (spirit == 11)
bonus += 2;
break;
case TOTEM_OWL:
if (time_info.hours <= 6 || time_info.hours >= 19)
bonus += 2;
break;
case TOTEM_RAT:
if (spirit >= 5 && spirit <= 7)
bonus += 2;
break;
case TOTEM_SHARK:
if (spirit == 16)
bonus += 2;
break;
case TOTEM_SNAKE:
if (!number(0, 1)) {
if (spirit == (5 + number(0, 2)))
bonus += 2;
} else if (spirit == (7 + number(0, 2)))
bonus += 2;
break;
case TOTEM_WOLF:
if ((!number(0, 1) ? spirit == 9 : spirit == 11))
bonus += 2;
break;
}
return bonus;
}
ACMD(do_conjure)
{
int num, i, force, successes, drain, wound, is_physical;
struct char_data *spirit;
char *s;
if (IS_NPC(ch) || (GET_TRADITION(ch) != TRAD_HERMETIC &&
GET_TRADITION(ch) != TRAD_SHAMANIC && !access_level(ch, LVL_OWNER))) {
send_to_char("You aren't able to conjure beings!\r\n", ch);
return;
}
if (GET_MAG(ch) < 100) {
send_to_char("You have to have a magic rating of at least one to conjure.\r\n", ch);
return;
} else if (GET_SKILL(ch, SKILL_CONJURING) < 1) {
send_to_char("You have to have some conjuring skill to attempt that!\r\n", ch);
return;
}
any_one_arg(argument, arg);
if (!*arg || !*argument) {
send_to_char("Usage: conjure <force> <spirit/elemental>\r\n", ch);
return;
}
if ((force = atoi(arg)) < 1) {
send_to_char("You must supply a valid force for that to work.\r\n", ch);
return;
}
s = strtok(argument, "'");
if (s == NULL) {
send_to_char("You must specify the name of the spirit you wish to conjure.\r\n", ch);
return;
}
s = strtok(NULL, "'");
if (s == NULL) {
send_to_char("Spirit names must be enclosed in single quotes (').\r\n", ch);
return;
}
for (i = 1; *spirits[i] != '\n'; i++)
if (is_abbrev(s, spirits[i]))
break;
if (*spirits[i] == '\n') {
send_to_char(ch, "There is no '%s' spirit.\r\n", s);
return;
}
if (GET_TRADITION(ch) == TRAD_HERMETIC && i > 4) {
send_to_char("Hermetic mages can only conjure elementals.\r\n", ch);
return;
} else if (GET_TRADITION(ch) == TRAD_HERMETIC &&
!ROOM_FLAGGED(ch->in_room, ROOM_HERMETIC_LIBRARY)) {
send_to_char("Conjuring elementals requires a hermetic library.\r\n", ch);
return;
} else if (GET_TRADITION(ch) == TRAD_SHAMANIC) {
if (i < 5) {
send_to_char("Shamans can only conjure nature spirits.\r\n", ch);
return;
}
if (!check_spirit_sector(ch->in_room, i)) {
send_to_char("You can't conjure that spirit here.\r\n", ch);
return;
}
}
if ((num = real_mobile(24 + i)) < 0) {
sprintf(buf, "No %s mob", spirits[i]);
log(buf);
send_to_char("The conjuring system seems to be screwed up right now...\r\n", ch);
return;
}
if (ROOM_FLAGGED(ch->in_room, ROOM_NOMAGIC)) {
send_to_char(ch, "Your attempt to conjure %s fizzles into oblivion.\r\n", spirits[i]);
return;
}
successes = success_test(GET_CHA(ch) + (spirit_bonus(ch,i)/2),
force + modify_target(ch));
if (force < (GET_CHA(ch) / 2)) {
wound = LIGHT;
is_physical = FALSE;
} else if (force <= GET_CHA(ch)) {
wound = MODERATE;
is_physical = FALSE;
} else if (force > (GET_CHA(ch) * 2)) {
wound = DEADLY;
is_physical = TRUE;
} else {
wound = SERIOUS;
is_physical = TRUE;
}
drain = convert_damage(dec_staging(successes, wound));
if (is_physical)
GET_PHYSICAL(ch) -= drain * 100;
else if ((int)(GET_MENTAL(ch) / 100) < drain) {
GET_PHYSICAL(ch) -= (drain - (int)(GET_MENTAL(ch) / 100)) * 100;
GET_MENTAL(ch) = 0;
}
else GET_MENTAL(ch) -= drain * 100;
update_pos(ch);
if (GET_POS(ch) <= POS_STUNNED && GET_POS(ch) > POS_DEAD) {
if (FIGHTING(ch))
stop_fighting(ch);
send_to_char("You are unable to resist the drain from the evocation and fall unconscious!\r\n", ch);
act("$n collapses unconscious from the use of magic!", FALSE, ch, 0, 0, TO_ROOM);
return;
} else if (GET_POS(ch) == POS_DEAD) {
if (FIGHTING(ch))
stop_fighting(ch);
send_to_char("The energy from the evocation overloads your systems, killing you...\r\n", ch);
act("$n collapses DEAD from an overload of magic!", FALSE, ch, 0, 0, TO_ROOM);
die(ch);
return;
}
if ((successes = success_test(GET_SKILL(ch, SKILL_CONJURING)
+ (spirit_bonus(ch, i)+1)/2,
force + modify_target(ch))) < 1) {
send_to_char(ch, "You fail to conjure %s!\r\n", spirits[i]);
return;
}
spirit = read_mobile(num, REAL);
char_to_room(spirit, ch->in_room);
GET_ACTIVE(spirit) = successes;
spirit->real_abils.bod = force;
spirit->real_abils.qui = force;
spirit->real_abils.str = force;
spirit->real_abils.cha = force;
spirit->real_abils.intel = force;
spirit->real_abils.wil = force;
spirit->real_abils.ess = force * 100;
GET_SKILL(spirit, SKILL_UNARMED_COMBAT) = force;
GET_LEVEL(spirit) = force;
switch (i) {
case 1:
spirit->real_abils.bod -= 2; spirit->real_abils.qui += 3; spirit->real_abils.str -= 3;
break;
case 2:
spirit->real_abils.bod += 4; spirit->real_abils.qui -= 2; spirit->real_abils.str += 4;
break;
case 3:
spirit->real_abils.bod += 1; spirit->real_abils.qui += 2; spirit->real_abils.str -= 2;
break;
case 4:
spirit->real_abils.bod += 2;
break;
case 5: case 6: case 7:
spirit->real_abils.bod += 1; spirit->real_abils.qui += 2; spirit->real_abils.str -= 2;
break;
case 8: case 9: case 10: case 11:
spirit->real_abils.bod += 4; spirit->real_abils.qui -= 2; spirit->real_abils.str += 4;
break;
case 12: case 13:
spirit->real_abils.bod -= 2; spirit->real_abils.qui += 3; spirit->real_abils.str -= 3;
break;
case 14: case 15: case 16: case 17:
spirit->real_abils.bod += 2;
break;
}
affect_total(spirit);
act("$n appears from thin air.", TRUE, spirit, 0, 0, TO_ROOM);
act("$n fades in from the air.", FALSE, spirit, 0, 0, TO_CHAR);
if (!AFF_FLAGGED(spirit, AFF_CHARM))
SET_BIT(AFF_FLAGS(spirit), AFF_CHARM);
add_follower(spirit, ch);
}
void add_to_spell_q(struct char_data *ch, spell_t *spell, int force, char *arg)
{
spell_t *temp, *i;
temp = new spell_t;
*temp = *spell;
temp->force = force;
if (arg) {
temp->name = new char[strlen(arg)+1];
strcpy(temp->name, arg);
} else temp->name = NULL;
if (!GET_SPELL_Q(ch)) {
GET_SPELL_Q(ch) = temp;
GET_SPELL_Q(ch)->next = NULL;
} else {
// this loop goes until i->next is NULL, or until temp is the last
for (i = GET_SPELL_Q(ch); i->next; i = i->next);
i->next = temp;
temp->next = NULL;
}
}
void delete_top_of_spell_q(struct char_data *ch)
{
if (!GET_SPELL_Q(ch))
return;
spell_t *temp = GET_SPELL_Q(ch);
GET_SPELL_Q(ch) = GET_SPELL_Q(ch)->next;
if (temp->name)
delete [] temp->name;
delete temp;
}
void purge_spell_q(struct char_data *ch)
{
while (GET_SPELL_Q(ch))
delete_top_of_spell_q(ch);
}
bool cycle_spell_q(struct char_data *ch)
{
spell_t *temp = GET_SPELL_Q(ch);
spell_t spellcopy;
bool success;
if (!temp)
return FALSE;
// Make a copy of the spell data so any frees won't affect us.
spellcopy = *temp;
temp = &spellcopy;
switch (temp->category) {
case SPELL_CATEGORY_COMBAT:
success = process_combat_target(ch, temp, temp->name, temp->force);
break;
case SPELL_CATEGORY_HEALTH:
success = process_health_target(ch, temp, temp->name, temp->force);
break;
case SPELL_CATEGORY_ILLUSION:
success = process_illusion_target(ch, temp, temp->name, temp->force);
break;
case SPELL_CATEGORY_MANIPULATION:
success = process_manipulation_target(ch, temp, temp->name, temp->force);
break;
default:
send_to_char("Your spell seems to make no sense to you whatsoever.\r\n", ch);
mudlog("Unknown spell category in newmagic.cc", ch, LOG_SYSLOG, TRUE);
delete_top_of_spell_q(ch);
return FALSE;
}
// success determines if the mud found a target and the spell was cast
if (success) {
if (temp->type == SPELL_RESIST_PAIN)
resist_drain(ch, temp->force, temp, success + 1);
else if (temp->type != SPELL_HEAL && temp->type != SPELL_ANTIDOTE &&
temp->type != SPELL_CURE_DISEASE && temp->type != SPELL_POISON)
resist_drain(ch, temp->force, temp, DRAIN_LEVEL(temp->drain));
else resist_drain(ch, temp->force, temp, success);
delete_top_of_spell_q(ch);
return TRUE;
}
delete_top_of_spell_q(ch);
return FALSE;
}
// the actual cast command
ACMD(do_cast)
{
spell_t *spell;
char *s, *t;
bool newforce = FALSE;
int i, spellnum = 0;
int delete_spell = 0;
char argcopy[MAX_STRING_LENGTH];
if (!IS_NPC(ch) && !access_level(ch, LVL_PRESIDENT) && GET_TRADITION(ch) != TRAD_SHAMANIC &&
GET_TRADITION(ch) != TRAD_HERMETIC) {
send_to_char("You are but a mundane, sorry.\r\n", ch);
return;
}
if (GET_MAG(ch) < 100) {
send_to_char("You must have a magic rating of at least one to cast spells.\r\n", ch);
return;
}
any_one_arg(argument, arg);
int force = atoi(arg);
if (force > 0)
newforce = TRUE;
/* get: blank, spell name, target name */
strcpy(argcopy, argument);
s = strtok(argcopy, "'");
if (s == NULL) {
send_to_char("You must specify the name of the spell you wish to cast.\r\n", ch);
return;
}
s = strtok(NULL, "'");
if (s == NULL) {
send_to_char("Spell names must be enclosed in single quotes (').\r\n", ch);
return;
}
if (!access_level(ch, LVL_PRESIDENT))
spell = find_spell(ch, s);
else {
spell = find_spell(ch, s);
if (!spell)
{
for (i = 3; !spellnum && i <= MAX_SPELLS; i++)
if (is_abbrev(s, spells[i]))
spellnum = i;
if (!spellnum) {
send_to_char(ch, "'%s' doesn't seem to be a standard spell.\r\n", s);
return;
}
delete_spell = 1;
spell = new spell_t;
spell->name = str_dup(spells[spellnum]);
spell->physical = grimoire[spellnum].physical;
spell->category = grimoire[spellnum].category;
spell->force = 10;
spell->target = grimoire[spellnum].target;
spell->drain = grimoire[spellnum].drain;
spell->damage = grimoire[spellnum].damage;
spell->effect = SPELL_EFFECT_NONE;
spell->type = spellnum;
spell->next = NULL;
}
}
if (!spell) {
send_to_char(ch, "You don't seem to know a spell named '%s'.\r\n", s);
return;
}
if (newforce) {
if (spell->force < force) {
send_to_char("You can't cast a spell at a force higher than you learned it.\r\n", ch);
return;
}
} else force = spell->force;
if (ROOM_FLAGGED(ch->in_room, ROOM_NOMAGIC)) {
send_to_char("Your magic fizzles into oblivion.\r\n", ch);
return;
}
// pull off the last of the arguments and put it in t
t = strtok(NULL, "\0");
while(t && *t == ' ')
t++;
if (FIGHTING(ch) && spell->category != SPELL_CATEGORY_DETECTION) {
add_to_spell_q(ch, spell, force, t);
send_to_char(ch, "You begin to concentrate on casting %s.\r\n",
spell->name);
if (delete_spell) {
if (spell->name)
delete [] spell->name;
delete spell;
}
return;
}
bool success;
switch (spell->category) {
case SPELL_CATEGORY_COMBAT:
success = process_combat_target(ch, spell, t, force);
break;
case SPELL_CATEGORY_DETECTION:
success = process_detection_target(ch, spell, t, force);
break;
case SPELL_CATEGORY_HEALTH:
success = process_health_target(ch, spell, t, force);
break;
case SPELL_CATEGORY_ILLUSION:
success = process_illusion_target(ch, spell, t, force);
break;
case SPELL_CATEGORY_MANIPULATION:
success = process_manipulation_target(ch, spell, t, force);
break;
default:
send_to_char("Your spell seems to make no sense to you whatsoever.\r\n", ch);
mudlog("Unknown spell category in newmagic.cc", ch, LOG_SYSLOG, TRUE);
return;
}
// success determines if the mud found a target and the spell was cast
if (success) {
if (spell->type == SPELL_RESIST_PAIN)
resist_drain(ch, force, spell, success + 1);
else if (spell->type != SPELL_HEAL && spell->type != SPELL_ANTIDOTE &&
spell->type != SPELL_CURE_DISEASE && spell->type != SPELL_POISON)
resist_drain(ch, force, spell, DRAIN_LEVEL(spell->drain));
else resist_drain(ch, force, spell, success);
// if they are in combat, they lose a turn
if (FIGHTING(ch) && !AFF_FLAGGED(ch, AFF_ACTION))
SET_BIT(AFF_FLAGS(ch), AFF_ACTION);
// also, they get a wait state for casting
WAIT_STATE(ch, PULSE_VIOLENCE);
}
if (delete_spell) {
if (spell->name)
delete [] spell->name;
delete spell;
}
}
struct char_data *range_spell(struct char_data *ch, char *target, char *direction)
{
int room = ch->in_room, nextroom, dir, sight, distance;
struct char_data *vict;
bool found = FALSE;
if ((dir = search_block(direction, lookdirs, FALSE)) == -1)
return NULL;
dir = convert_look[dir];
if (CAN_GO2(room, dir))
nextroom = EXIT2(room, dir)->to_room;
else nextroom = NOWHERE;
sight = find_sight(ch);
for (distance = 1; ((nextroom != NOWHERE) && (distance <= sight)); distance++) {
for (vict = world[nextroom].people; vict; vict = vict->next_in_room) {
if (isname(target, GET_NAME(vict)) && vict != ch && CAN_SEE(ch, vict)) {
found = TRUE;
break;
}
}
if (found == TRUE) {
if (IS_SET(ROOM_FLAGS(vict->in_room), ROOM_PEACEFUL)) {
send_to_char("Nah - leave them in peace.\r\n", ch);
return ch;
}
if (ROOM_FLAGGED(vict->in_room, ROOM_NOMAGIC)) {
act("Your spell vanishes before reaching $M.", FALSE, ch, 0, vict, TO_CHAR);
return ch;
}
if ( !IS_NPC(vict) && str_cmp(vict->player.name,target) )
{
send_to_char("You need to type the player's ENTIRE name.\n\r",ch);
return ch;
}
if (!ok_damage_shopkeeper(ch, vict)) {
send_to_char("Maybe that's not such a good idea.\r\n", ch);
return ch;
}
return vict;
}
room = nextroom;
if (CAN_GO2(room, dir))
nextroom = EXIT2(room, dir)->to_room;
else nextroom = NOWHERE;
}
return NULL;
}
int spell_damage_door(struct char_data *ch, spell_t *spell, char *target)
{
int dir;
char type[MAX_INPUT_LENGTH], door[MAX_INPUT_LENGTH];
bool found = FALSE;
two_arguments(target, type, door);
if (!spell->physical) {
send_to_char("You can only cast that spell on living targets.\r\n", ch);
return -1;
}
if (*door) {
if ((dir = search_block(door, lookdirs, FALSE)) == -1)
return 0;
dir = convert_look[dir];
int dist, nextroom, sight = find_sight(ch), room = ch->in_room;
if (EXIT(ch, dir) && EXIT(ch, dir)->keyword &&
isname(type, EXIT(ch, dir)->keyword) &&
!IS_SET(EXIT(ch, dir)->exit_info, EX_DESTROYED)) {
if (FIGHTING(ch)) {
send_to_char("Maybe you'd better wait...\r\n", ch);
return -1;
} else if (!IS_SET(EXIT(ch, dir)->exit_info, EX_CLOSED)) {
send_to_char("You can only damage closed doors!\r\n", ch);
return -1;
} else if (IS_SET(ROOM_FLAGS(ch->in_room), ROOM_PEACEFUL)) {
send_to_char("Nah - leave it in peace.\r\n", ch);
return -1;
} else if (ROOM_FLAGGED(ch->in_room, ROOM_NOMAGIC)) {
send_to_char(ch, "Your spell vanishes before reaching the %s.\r\n",
EXIT(ch, dir)->keyword ? fname(EXIT(ch, dir)->keyword)
: "door");
return -1;
}
if (spell->category == SPELL_CATEGORY_MANIPULATION)
damage_door(ch, ch->in_room, dir, (int)(spell->force),
spell->effect | DAMOBJ_MANIPULATION);
else
damage_door(ch, ch->in_room, dir, (int)(spell->force),
spell->effect);
return 1;
}
if (CAN_GO2(room, dir))
nextroom = EXIT2(room, dir)->to_room;
else
nextroom = NOWHERE;
for (dist = 1; nextroom != NOWHERE && dist <= sight; dist++) {
if (EXIT2(nextroom, dir) && EXIT2(nextroom, dir)->keyword &&
isname(type, EXIT2(nextroom, dir)->keyword) &&
!IS_SET(EXIT2(nextroom, dir)->exit_info, EX_DESTROYED)) {
if (FIGHTING(ch)) {
send_to_char("Maybe you'd better wait...\r\n", ch);
return -1;
} else if (!IS_SET(EXIT2(nextroom, dir)->exit_info, EX_CLOSED)) {
send_to_char("You can only damage closed doors!\r\n", ch);
return -1;
} else if (IS_SET(ROOM_FLAGS(nextroom), ROOM_PEACEFUL)) {
send_to_char("Nah - leave it in peace.\r\n", ch);
return -1;
} else if (ROOM_FLAGGED(nextroom, ROOM_NOMAGIC)) {
send_to_char(ch, "Your spell vanishes before reaching the %s.\r\n",
EXIT2(nextroom, dir)->keyword ?
fname(EXIT2(nextroom, dir)->keyword) : "door");
return -1;
}
if (spell->category == SPELL_CATEGORY_MANIPULATION)
damage_door(ch, nextroom, dir, (int)(spell->force),
spell->effect | DAMOBJ_MANIPULATION);
else damage_door(ch, nextroom, dir, (int)(spell->force),
spell->effect);
return 1;
}
room = nextroom;
if (CAN_GO2(room, dir))
nextroom = EXIT2(room, dir)->to_room;
else nextroom = NOWHERE;
}
} else if (*type) {
for (dir = 0; dir < NUM_OF_DIRS; dir++)
if (EXIT(ch, dir) && EXIT(ch, dir)->keyword &&
isname(type, EXIT(ch, dir)->keyword) &&
!IS_SET(EXIT(ch, dir)->exit_info, EX_DESTROYED)) {
if (FIGHTING(ch)) {
send_to_char("Maybe you'd better wait...\r\n", ch);
return -1;
} else if (!IS_SET(EXIT(ch, dir)->exit_info, EX_CLOSED)) {
send_to_char("You can only damage closed doors!\r\n", ch);
return -1;
} else if (IS_SET(ROOM_FLAGS(ch->in_room), ROOM_PEACEFUL)) {
send_to_char("Nah - leave it in peace.\r\n", ch);
return -1;
}
if (spell->category == SPELL_CATEGORY_MANIPULATION)
damage_door(ch, ch->in_room, dir, (int)(spell->force),
spell->effect | DAMOBJ_MANIPULATION);
else damage_door(ch, ch->in_room, dir, (int)(spell->force),
spell->effect);
return 1;
}
}
return 0;
}
// the processing of the spells follow by category
bool process_combat_target(char_t *ch, spell_t *spell, char *t, int force)
{
char_t *vict = NULL;
obj_t *obj = NULL;
char *temp, targ1[80], targ2[80];
int num_targets=0;
sh_int room_num;
int val;
if (t)
skip_spaces(&t);
// first we find the appropriate target
switch (spell->target) {
case SPELL_TARGET_CASTER:
if (t && strcmp(t, GET_NAME(ch))) {
send_to_char("You can only target yourself with this spell.\r\n", ch);
return FALSE;
}
process_combat_spell(ch, ch, (obj_t *)NULL, spell, force);
break;
case SPELL_TARGET_TOUCH:
if (!t) {
if (!FIGHTING(ch)) {
send_to_char("You must specify the target you wish to cast this spell on.\r\n", ch);
return FALSE;
} else vict = FIGHTING(ch);
} else {
// here we look for a mob in the room first, then search for an item
// in the room, then for an item in inventory
if (!(vict = get_char_room_vis(ch, t)))
if (!(val = spell_damage_door(ch, spell, t))) {
if (!(obj = get_obj_in_list_vis(ch, t, world[ch->in_room].contents)))
if (!(obj = get_obj_in_list_vis(ch, t, ch->carrying))) {
send_to_char("You can't seem to find the target you are "
"looking for.\r\n", ch);
return FALSE;
}
} else return (val == 1 ? TRUE : FALSE);
}
if (vict && GET_POS(vict) == POS_STANDING) {
if (resisted_test(GET_QUI(ch),
GET_QUI(vict) + modify_target(ch),
GET_QUI(vict),
GET_QUI(ch) + modify_target(vict)) < 1) {
act("You stumble over your own legs as you try to touch $N!", FALSE, ch, 0, vict, TO_CHAR);
act("$n stumbles over $s legs as $e reaches to touch $N!", FALSE, ch, 0, vict, TO_NOTVICT);
act("$n stumbles over $s legs as $e reaches to touch you!", FALSE, ch, 0, vict, TO_VICT);
if (!FIGHTING(vict))
set_fighting(vict, ch);
if (!FIGHTING(ch))
set_fighting(ch, vict);
WAIT_STATE(ch, PULSE_VIOLENCE);
return FALSE;
}
} else if (vict && AWAKE(vict)) {
if (resisted_test(GET_QUI(ch),
(GET_QUI(vict) / 2) + modify_target(ch),
(GET_QUI(vict) / 2),
GET_QUI(ch) + modify_target(vict)) < 1) {
act("You stumble over your own legs as you try to touch $N!", FALSE, ch, 0, vict, TO_CHAR);
act("$n stumbles over $s legs as $e reaches to touch $N!", FALSE, ch, 0, vict, TO_NOTVICT);
act("$n stumbles over $s legs as $e reaches to touch you!", FALSE, ch, 0, vict, TO_VICT);
if (!FIGHTING(vict))
set_fighting(vict, ch);
if (!FIGHTING(ch))
set_fighting(ch, vict);
WAIT_STATE(ch, PULSE_VIOLENCE);
return FALSE;
}
}
if (!vict || (!IS_ASTRAL(ch) && !IS_ASTRAL(vict)))
process_combat_spell(ch, vict, obj, spell, force);
else if (IS_ASTRAL(vict) && (IS_ASTRAL(ch) || IS_DUAL(ch) ||
(PLR_FLAGGED(ch, PLR_PERCEIVE) && vict == FIGHTING(ch))))
process_combat_spell(ch, vict, obj, spell, force);
else if (IS_ASTRAL(ch) && (IS_ASTRAL(vict) || IS_DUAL(vict) ||
PLR_FLAGGED(vict, PLR_PERCEIVE)))
process_combat_spell(ch, vict, obj, spell, force);
else {
if (IS_ASTRAL(vict) && PLR_FLAGGED(ch, PLR_PERCEIVE))
send_to_char("You can't initiate attacks on astral beings!\r\n", ch);
else if (IS_ASTRAL(vict))
send_to_char("You can't target astral beings!\r\n", ch);
else send_to_char("You can't target physical beings!\r\n", ch);
return FALSE;
}
break;
case SPELL_TARGET_RANGE:
if (!t) {
if (!FIGHTING(ch)) {
send_to_char("You must specify the target you wish to cast this spell on.\r\n", ch);
return FALSE;
} else vict = FIGHTING(ch);
} else {
any_one_arg(any_one_arg(t, targ1), targ2);
// if there's not another argument in targ2, we assume it's not
// an object on a mob
if (!*targ2) {
if (!(vict = get_char_room_vis(ch, targ1)))
if (!(val = spell_damage_door(ch, spell, t))) {
if (!(obj = get_obj_in_list_vis(ch, targ1, world[ch->in_room].contents)) &&
!(obj = get_obj_in_list_vis(ch, targ1, ch->carrying))) {
send_to_char("You can't seem to find the target you are "
"looking for.\r\n", ch);
return FALSE;
}
} else return (val == 1 ? TRUE : FALSE);
} else {
/* if there's a targ2, we know it's either <obj> <victim>, <victim> <direction>
or <door> <direction> */
if (!(vict = range_spell(ch, targ1, targ2))) {
if (!(val = spell_damage_door(ch, spell, t))) {
if (!(vict = get_char_room_vis(ch, targ2))) {
send_to_char("You can't seem to find the target you are looking for.\r\n", ch);
return FALSE;
} else {
// then we search for the item equiped by the victim
for (register int i = 0; i < NUM_WEARS; ++i)
if (GET_EQ(vict, i) && isname(targ1, GET_EQ(vict, i)->name)) {
obj = GET_EQ(vict, i);
break; // and get out when we do
}
}
} else return (val == 1 ? TRUE : FALSE);
} else if (vict == ch)
return FALSE;
}
// finally, we make sure they live up to the restriction that
// mana spells may only be cast on living targets.
if (!spell->physical && obj) {
send_to_char("You can only cast that spell on living targets.\r\n", ch);
return FALSE;
}
// at the end of all this, we have an object pointed to by *obj if
// available, and at minimum a victim pointed to by *vict
}
if (!vict || (!IS_ASTRAL(ch) && !IS_ASTRAL(vict)))
process_combat_spell(ch, vict, obj, spell, force);
else if (IS_ASTRAL(vict) && (IS_ASTRAL(ch) || IS_DUAL(ch) ||
(PLR_FLAGGED(ch, PLR_PERCEIVE) && vict == FIGHTING(ch))))
process_combat_spell(ch, vict, obj, spell, force);
else if (IS_ASTRAL(ch) && (IS_ASTRAL(vict) || IS_DUAL(vict) ||
PLR_FLAGGED(vict, PLR_PERCEIVE)))
process_combat_spell(ch, vict, obj, spell, force);
else {
if (IS_ASTRAL(vict) && PLR_FLAGGED(ch, PLR_PERCEIVE))
send_to_char("You can't initiate attacks on astral beings!\r\n", ch);
else if (IS_ASTRAL(vict))
send_to_char("You can't target astral beings!\r\n", ch);
else send_to_char("You can't target physical beings!\r\n", ch);
return FALSE;
}
break;
case SPELL_TARGET_AREA:
// here we run through a loop and damage lots of folks (=
// also, you can't single out objects with area effects spells
any_one_arg(any_one_arg(t, targ1), targ2);
if (!t) {
vict = ch;
}
else {
any_one_arg(any_one_arg(t, targ1), targ2);
// if there's not another argument in targ2, we assume it's not
// an object on a mob
if (!*targ2) {
if (!(vict = get_char_room_vis(ch, targ1)))
if (!(val = spell_damage_door(ch, spell, t))) {
if (!(obj = get_obj_in_list_vis(ch, targ1, world[ch->in_room].contents)) &&
!(obj = get_obj_in_list_vis(ch, targ1, ch->carrying))) {
send_to_char("You can't seem to find the target you are "
"looking for.\r\n", ch);
return FALSE;
}
} else return (val == 1 ? TRUE : FALSE);
} else {
/* if there's a targ2, we know it's either <obj> <victim>, <victim> <direction>
or <door> <direction> */
if (!(vict = range_spell(ch, targ1, targ2))) {
if (!(val = spell_damage_door(ch, spell, t))) {
if (!(vict = get_char_room_vis(ch, targ2))
||!(vict = get_char_room_vis(ch, targ1))) {
send_to_char("You can't seem to find the target you are looking for.\r\n", ch);
return FALSE;
} else {
// then we search for the item equiped by the victim
for (register int i = 0; i < NUM_WEARS; ++i)
if (GET_EQ(vict, i) && isname(targ1, GET_EQ(vict, i)->name)) {
obj = GET_EQ(vict, i);
break; // and get out when we do
}
}
} else return (val == 1 ? TRUE : FALSE);
} else if (vict == ch)
return FALSE;
}
// finally, we make sure they live up to the restriction that
// mana spells may only be cast on living targets.
if (!spell->physical && obj) {
send_to_char("You can only cast that spell on living targets.\r\n", ch);
return FALSE;
}
// at the end of all this, we have an object pointed to by *obj if
// available, and at minimum a victim pointed to by *vict
}
if ( !vict )
{
send_to_char("Your spell cannot find that target.\r\n", ch);
return FALSE;
}
room_num = vict->in_room;
struct char_data *tch, *next_tch;
num_targets = 0;
for (tch = world[room_num].people; tch; tch = next_tch) {
next_tch = tch->next_in_room;
if (tch == ch)
continue;
if (!IS_NPC(tch) && GET_LEVEL(tch) >= LVL_LEGEND)
continue;
if (!pk_allowed && !IS_NPC(tch) && !IS_NPC(ch))
continue;
if (in_group(ch, tch))
continue;
num_targets++;
if (!IS_ASTRAL(ch) && !IS_ASTRAL(tch))
process_combat_spell(ch, tch, (obj_t *) NULL, spell, force);
else if (IS_ASTRAL(tch) && (IS_ASTRAL(ch) || IS_DUAL(ch) ||
(PLR_FLAGGED(ch, PLR_PERCEIVE) && tch == FIGHTING(ch))))
process_combat_spell(ch, tch, (obj_t *) NULL, spell, force);
else if (IS_ASTRAL(ch) && (IS_ASTRAL(tch) || IS_DUAL(tch) ||
PLR_FLAGGED(tch, PLR_PERCEIVE)))
process_combat_spell(ch, tch, (obj_t *) NULL, spell, force);
else
num_targets--;
}
struct obj_data *obj, *next;
if (spell->physical) {
for (obj = world[room_num].contents; obj; obj = next) {
next = obj->next_content;
damage_obj(NULL, obj, force + FORCE_PENALTY(spell), spell->effect);
num_targets++;
}
for (val = 0; val < (NUM_OF_DIRS - 1); val++)
if (EXIT(ch, val) && EXIT(ch, val)->keyword &&
IS_SET(EXIT(ch, val)->exit_info, EX_CLOSED))
{
damage_door(NULL, ch->in_room, val, (int)(force), spell->effect);
num_targets++;
}
}
if ( num_targets == 0 )
{
send_to_char("Your area affect spell would hit nothing.\r\n", ch );
return FALSE;
}
break;
default:
send_to_char("You can't seem to target this spell for some reason.\r\n", ch);
mudlog("Illegal target in newmagic.cc.", ch, LOG_SYSLOG, TRUE);
return FALSE;
}
return TRUE;
}
// now for the fun part
void process_combat_spell(char_t *ch, char_t *vict, obj_t *obj, spell_t *spell, int force)
{
struct obj_data *next;
int resist = 0, success = 0, dam, i, chance;
int pbonus, fbonus, tbonus;
int tnum;
int rsuccess;
if (!obj) {
char xbuf[MAX_STRING_LENGTH];
// figure out if the spell is physical or mana
if (spell->physical)
resist = GET_BOD(vict);
else
resist = GET_WIL(vict);
tbonus = totem_bonus(ch, spell);
pbonus = magic_pool_bonus(ch, spell, force, TRUE);
fbonus = foci_bonus(ch, spell, force, TRUE);
xbuf[0] = ' ';
xbuf[1] = 0;
tnum = modify_target_rbuf(ch, xbuf);
// we include totem bonuses and target modifiers to the test
success = success_test(force + pbonus + fbonus + tbonus, resist + tnum );
if (access_level(ch, LVL_OWNER) && spell->target != SPELL_TARGET_AREA)
send_to_char(ch, "(%s) F: %d, R: %d, S: %d, D: %d\r\n",
spell->physical ? "Physical" : "Mana", force, resist, success, 0);
if ( 1 )
{
char rbuf[MAX_STRING_LENGTH];
sprintf(rbuf,
"ComSpell: F:%d/%d,%s%s Mag:%d, FFPT/RM %d+%d+%d+%d/%d+%d. %d.%s",
force, spell->force,
spell->target == SPELL_TARGET_AREA ? " (area)" : "",
spell->effect != SPELL_ELEMENT_NONE ? " (elem)" : "",
GET_MAG(ch),
force, fbonus, pbonus, tbonus,
resist, tnum, success,
xbuf);
act(rbuf, 1, ch, NULL, NULL, TO_ROLLS);
}
if (success < 1 && AWAKE(vict)) {
damage(ch, vict, 0, spell->type, FALSE);
ranged_response(ch, vict);
return;
}
if (spell->effect != SPELL_ELEMENT_NONE) {
elemental_damage(ch, vict, spell, force, success);
return;
}
int srvict = spell_resist(vict);
int mtvict = modify_target(vict);
rsuccess = success_test(resist + spell_resist(vict),
force + modify_target(vict));
int basedamage;
if (IS_ASTRAL(ch))
basedamage = DRAIN_LEVEL(grimoire[spell->type].drain);
else
basedamage = grimoire[spell->type].damage;
// here we stage the damage up or down
int stagedamage = stage(success - rsuccess, basedamage);
dam = convert_damage(stagedamage);
int is_physicaldam = (((spell->type >= SPELL_STUNBALL)
&& (spell->type <= SPELL_STUN_TOUCH))
||((spell->type >= SPELL_STUN_SHAFT)
&& (spell->type <= SPELL_STUN_DART)))
? FALSE : TRUE;
if (1)
{
char rbuf[MAX_STRING_LENGTH];
sprintf( rbuf,
"ComSpell: %c RSr/FM %d+%d/%d+%d. %d-%d=%d, %d->%d. %d/%d. D: %d%c.",
spell->physical ? 'B' : 'W',
resist, srvict,
force, mtvict,
success, rsuccess, success-rsuccess,
basedamage, stagedamage,
GET_PHYSICAL(vict), GET_MENTAL(vict),
dam,
is_physicaldam ? 'P' : 'M' );
act( rbuf, 1, ch, NULL, NULL, TO_ROLLS );
}
if (spell->physical) {
if (spell->target == SPELL_TARGET_AREA)
chance = 10;
else
chance = 2;
for (i = 0; i < (NUM_WEARS - 1); i++)
if (GET_EQ(vict, i) && number(1, 100) < chance) {
damage_obj(NULL, GET_EQ(vict, i), force + FORCE_PENALTY(spell),
DAMOBJ_PROJECTILE);
if (spell->target != SPELL_TARGET_AREA)
break;
}
chance = (int)(chance / 2);
for (obj = vict->carrying; obj; obj = next) {
next = obj->next_content;
if (number(1, 100) < chance)
damage_obj(NULL, obj, force + FORCE_PENALTY(spell),
DAMOBJ_PROJECTILE);
}
}
if (((spell->type >= SPELL_STUNBALL) && (spell->type <= SPELL_STUN_TOUCH))
||((spell->type >= SPELL_STUN_SHAFT)
&& (spell->type <= SPELL_STUN_DART)))
damage(ch, vict, dam, spell->type, FALSE);
else
damage(ch, vict, dam, spell->type, TRUE);
if (ch->in_room != vict->in_room)
ranged_response(ch, vict);
} else { // end combat section to living targets
// this is how magic affects objects
// first we find the target number for the spell
damage_obj(ch, obj, force + FORCE_PENALTY(spell), spell->effect);
// gotta make em attack if they are trying to blow up an object on a mob
if (vict && IS_NPC(vict) && !FIGHTING(vict))
set_fighting(vict, ch);
if (access_level(ch, LVL_OWNER) && spell->target != SPELL_TARGET_AREA)
send_to_char(ch, "(%s) F: %d, R: %d, S: %d, D: %d\r\n",
spell->physical ? "Physical" : "Mana", force, resist, success, 0);
}
}
void elemental_damage(char_t *ch, char_t *vict, spell_t *spell, int force, int success)
{
// if the spell doesn't do greater than light damage, it won't have
// secondary effects -- ie, the mage has to take a little risk at least
if (spell->effect == SPELL_ELEMENT_NONE
|| DRAIN_LEVEL(spell->drain) < MODERATE)
return;
int modifier = 0, resist, dam, i, chance, num;
if (spell->category == SPELL_CATEGORY_COMBAT)
modifier = 4;
else switch (DRAIN_LEVEL(spell->drain)) {
case 2: modifier = 4; break;
case 3: modifier = 2; break;
case 4: modifier = 0; break;
default: modifier = 4;
}
if (spell->effect == SPELL_ELEMENT_ICE)
resist = GET_IMPACT(vict);
else resist = GET_IMPACT(vict) >> 1;
success -= success_test(resist, force + modify_target(vict));
if (IS_ASTRAL(ch))
dam = convert_damage(stage(success, grimoire[spell->type].drain % 10));
else dam = convert_damage(stage(success, grimoire[spell->type].damage));
if (spell->category == SPELL_CATEGORY_COMBAT)
num = 0;
else num = DAMOBJ_MANIPULATION;
num += spell->effect;
if (success > 0) {
struct obj_data *obj, *next;
if (spell->physical) {
if (spell->target == SPELL_TARGET_AREA)
chance = 10;
else chance = 2;
for (i = 0; i < (NUM_WEARS - 1); i++)
if (GET_EQ(vict, i) && number(1, 100) < chance) {
damage_obj(NULL, GET_EQ(vict, i),
force + FORCE_PENALTY(spell), num);
if (spell->target != SPELL_TARGET_AREA)
break;
}
chance = (int)(chance / 2);
for (obj = vict->carrying; obj; obj = next) {
next = obj->next_content;
if (number(1, 100) < chance)
damage_obj(NULL, obj, force + FORCE_PENALTY(spell), num);
}
}
damage(ch, vict, dam, spell->type, TRUE);
ranged_response(ch, vict);
}
}
// finds the target for the detection spells
bool process_detection_target(char_t *ch, spell_t *spell, char *t, int force)
{
char_t *vict = NULL;
obj_t *obj = NULL;
char *temp, targ1[80], targ2[80];
if (t)
skip_spaces(&t);
// first we find the appropriate target
switch (spell->target) {
case SPELL_TARGET_CASTER:
if (t && strcmp(t, GET_NAME(ch))) {
send_to_char("You can only target yourself with this spell.\r\n", ch);
return FALSE;
}
process_combat_spell(ch, ch, (obj_t *)NULL, spell, force);
break;
case SPELL_TARGET_TOUCH:
if (FIGHTING(ch)) {
send_to_char("You can't cast this spell during combat.\r\n", ch);
return FALSE;
}
if (!t) {
send_to_char("You must specify the target you wish to cast this spell on.\r\n", ch);
return FALSE;
} else {
// for detection spells, we search the room for a character first,
// then for an object in inventory, then an object in the room
if (!(vict = get_char_room_vis(ch, t)))
if (!(obj = get_obj_in_list_vis(ch, t, ch->carrying)))
if (!(obj = get_obj_in_list_vis(ch, t, world[ch->in_room].contents))) {
send_to_char("You can't seem to find the target you wish to cast this spell on.\r\n", ch);
return FALSE;
}
}
if (!vict || (!IS_ASTRAL(ch) && !IS_ASTRAL(vict)))
process_detection_spell(ch, vict, obj, spell, force);
else if (IS_ASTRAL(vict) && (IS_ASTRAL(ch) || IS_DUAL(ch) ||
PLR_FLAGGED(ch, PLR_PERCEIVE)))
process_detection_spell(ch, vict, obj, spell, force);
else if (IS_ASTRAL(ch) && (IS_ASTRAL(vict) || IS_DUAL(vict) ||
PLR_FLAGGED(vict, PLR_PERCEIVE)))
process_detection_spell(ch, vict, obj, spell, force);
else {
if (IS_ASTRAL(vict))
send_to_char("You can't target astral beings!\r\n", ch);
else send_to_char("You can't target physical beings!\r\n", ch);
return FALSE;
}
break;
case SPELL_TARGET_RANGE:
if (!t) {
send_to_char("You must specify the target you wish to cast this spell on.\r\n", ch);
return FALSE;
}
any_one_arg(any_one_arg(t, targ1), targ2);
if (!*targ2) {
if (!(vict = get_char_room_vis(ch, targ1))) {
send_to_char("You can't seem to find the target you are looking for.\r\n", ch);
return FALSE;
}
} else {
if (!(vict = range_spell(ch, targ1, targ2))) {
if (!(vict = get_char_room_vis(ch, targ2))
||!(vict = get_char_room_vis(ch, targ1))) {
send_to_char("You can't seem to find the target you are looking for.\r\n", ch);
return FALSE;
} else {
for (register int i = 0; i < NUM_WEARS; ++i)
if (GET_EQ(vict, i) && isname(targ1, GET_EQ(vict, i)->name)) {
obj = GET_EQ(vict, i);
break;
}
}
} else if (vict == ch)
return FALSE;
}
if (!vict || (!IS_ASTRAL(ch) && !IS_ASTRAL(vict)))
process_detection_spell(ch, vict, obj, spell, force);
else if (IS_ASTRAL(vict) && (IS_ASTRAL(ch) || IS_DUAL(ch) ||
PLR_FLAGGED(ch, PLR_PERCEIVE)))
process_detection_spell(ch, vict, obj, spell, force);
else if (IS_ASTRAL(ch) && (IS_ASTRAL(vict) || IS_DUAL(vict) ||
PLR_FLAGGED(vict, PLR_PERCEIVE)))
process_detection_spell(ch, vict, obj, spell, force);
else {
if (IS_ASTRAL(vict))
send_to_char("You can't target astral beings!\r\n", ch);
else send_to_char("You can't target physical beings!\r\n", ch);
return FALSE;
}
break;
case SPELL_TARGET_AREA:
if (!t) {
send_to_char("You must specify the target you wish to cast this spell on.\r\n", ch);
return FALSE;
}
any_one_arg(any_one_arg(t, targ1), targ2);
// if there's not another argument in targ2, we assume it's not
// an object on a mob
if (!*targ2) {
if (!(vict = get_char_room_vis(ch, targ1)) &&
!(obj = get_obj_in_list_vis(ch, targ1, ch->carrying)) &&
!(obj = get_obj_in_list_vis(ch, targ1, world[ch->in_room].contents))) {
send_to_char("You can't seem to find the target you are looking for.\r\n", ch);
return FALSE;
}
} else { // if there's a targ2, we know it's in the form 'spell' <obj> <mob>
// here we grab the pointer to the victim if it's there
if (!(vict = get_char_room_vis(ch, targ2))) {
send_to_char("You can't seem to find the target you are looking for.\r\n", ch);
return FALSE;
} else { // then we search for the item equiped by the victim
for (register int i = 0; i < NUM_WEARS; ++i)
if (GET_EQ(vict, i) && isname(targ1, GET_EQ(vict, i)->name)) {
obj = GET_EQ(vict, i);
break; // and get out when we do
}
}
}
if (!spell->physical && obj) {
send_to_char("You can only cast that spell on living targets.\r\n", ch);
return FALSE;
}
// there's not really any area detection spells, but if I ever come
// up with some, I'll need to set up a loop here to proccess it
if (!vict || (!IS_ASTRAL(ch) && !IS_ASTRAL(vict)))
process_detection_spell(ch, vict, obj, spell, force);
else if (IS_ASTRAL(vict) && (IS_ASTRAL(ch) || IS_DUAL(ch) ||
PLR_FLAGGED(ch, PLR_PERCEIVE)))
process_detection_spell(ch, vict, obj, spell, force);
else if (IS_ASTRAL(ch) && (IS_ASTRAL(vict) || IS_DUAL(vict) ||
PLR_FLAGGED(vict, PLR_PERCEIVE)))
process_detection_spell(ch, vict, obj, spell, force);
else {
if (IS_ASTRAL(vict))
send_to_char("You can't target astral beings!\r\n", ch);
else send_to_char("You can't target physical beings!\r\n", ch);
return FALSE;
}
break;
default:
send_to_char("You can't seem to target this spell for some reason.\r\n", ch);
mudlog("Illegal target in newmagic.cc.", ch, LOG_SYSLOG, TRUE);
return FALSE;
}
return TRUE;
}
// and finally for the fun part of the detection effects
void process_detection_spell(char_t *ch, char_t * vict, obj_t *obj, spell_t *spell, int force)
{
static int success;
static int resist;
static bool found;
static struct affected_type af, af2;
switch (spell->type) {
case SPELL_ANALYZE_DEVICE:
if (!obj) {
send_to_char("You realize as you cast the spell that it only works on inanimate objects.\r\n", ch);
return;
}
// resistance is based off the material of the object
resist = material_ratings[GET_OBJ_MATERIAL(obj)];
success = success_test(force + spell_bonus(ch, spell), resist + modify_target(ch));
// if there were no successes, we just return
if (success == 0) {
send_to_char("You seem unable to learn anything new about it.\r\n", ch);
return;
}
if (success >= 1) {
send_to_char(ch, "%s is %s %s weighing %d.\r\n", CAP(obj->short_description),
AN(item_types[obj->obj_flags.type_flag]),
item_types[obj->obj_flags.type_flag], obj->obj_flags.weight);
if (GET_OBJ_TYPE(obj) != ITEM_FOOD)
send_to_char(ch, "It appears to be made of %s.\r\n", material_names[GET_OBJ_MATERIAL(obj)]);
}
if (success >= 2) {
sprintbit(obj->obj_flags.wear_flags, wear_bits, buf1);
send_to_char(ch, "It is useable in the following positions: %s\r\n", buf1);
send_to_char(ch, "It has a durability rating of %d.\r\n", GET_OBJ_BARRIER(obj));
}
if (success >= 3) {
if (obj->obj_flags.bitvector) {
sprintbit(obj->obj_flags.bitvector, affected_bits, buf1);
send_to_char(ch, "It grants following abilities: %s\r\n", buf1);
}
send_to_char("It has the following affections:", ch);
for (register int i = 0; i < MAX_OBJ_AFFECT; i++)
if (obj->affected[i].modifier) {
strcpy(buf2, apply_types[obj->affected[i].location]);
send_to_char(ch, "%s %+d to %s", found++ ? "," : "",
obj->affected[i].modifier, buf2);
}
if (!found)
send_to_char(" None\r\n", ch);
else send_to_char("\r\n", ch);
}
if (success >= 4) {
switch (GET_OBJ_TYPE(obj)) {
case ITEM_LIGHT:
if (GET_OBJ_VAL(obj, 2) < 0)
send_to_char("Light is permanent.\r\n", ch);
else send_to_char(ch, "Hours left for light: %d\r\n", GET_OBJ_VAL(obj, 2));
break;
case ITEM_WEAPON:
send_to_char(ch, "Power: %s, Damage: %s, Skill needed: %s\r\n",
get_power(GET_OBJ_VAL(obj, 0)), wound_name[GET_OBJ_VAL(obj, 1)],
spells[GET_OBJ_VAL(obj, 4)]);
break;
case ITEM_FIREWEAPON:
send_to_char(ch, "Str. Minimum: %d, Str+: %d, Power: %d, Skill needed: %s\r\n",
GET_OBJ_VAL(obj, 6), GET_OBJ_VAL(obj, 2), GET_OBJ_VAL(obj, 0), spells[GET_OBJ_VAL(obj, 4)]);
break;
case ITEM_ARMOR:
send_to_char(ch, "Ballistic rating: %d, Impact Rating: %d\r\n",
GET_OBJ_VAL(obj, 0), GET_OBJ_VAL(obj, 1));
break;
case ITEM_CONTAINER:
send_to_char(ch, "Max weight containable: %d pounds\r\n", GET_OBJ_VAL(obj, 0));
break;
case ITEM_DRINKCON:
send_to_char(ch, "Max contains: %d, contains: %d, poisoned: %s, "
"liquid: %s\r\n", GET_OBJ_VAL(obj, 0), GET_OBJ_VAL(obj, 1),
GET_OBJ_VAL(obj, 3) ? "Yes" : "No", drinks[GET_OBJ_VAL(obj, 2)]);
break;
case ITEM_FOOD:
send_to_char(ch, "Filling for %d hours, poisoned: %s\r\n",
GET_OBJ_VAL(obj, 0), GET_OBJ_VAL(obj, 3) ? "Yes" : "No");
break;
case ITEM_WORKING_GEAR:
send_to_char(ch, "Type: %s\r\n", gear_name[GET_OBJ_VAL(obj, 0)]);
break;
case ITEM_QUIVER:
send_to_char(ch, "Max contains: %d, Type contains: %s\r\n", GET_OBJ_VAL(obj, 0),
(GET_OBJ_VAL(obj, 1) == 0 ? "Arrow" : (GET_OBJ_VAL(obj, 1) == 1 ? "Bolt" :
(GET_OBJ_VAL(obj, 1) == 2 ? "Shuriken" : (GET_OBJ_VAL(obj, 1) == 3 ? "Throwing knife" :
"Undefined")))));
break;
case ITEM_PATCH:
send_to_char(ch, "Type: %s, Rating: %d\r\n",
patch_names[GET_OBJ_VAL(obj, 0)], GET_OBJ_VAL(obj, 1));
break;
case ITEM_CYBERDECK:
send_to_char(ch, "MPCP: %d, Hardening: %d, Active: %d, Storage: %d, Load: %d\r\n",
GET_OBJ_VAL(obj, 0), GET_OBJ_VAL(obj, 1), GET_OBJ_VAL(obj, 2),
GET_OBJ_VAL(obj, 3), GET_OBJ_VAL(obj, 4));
break;
case ITEM_PROGRAM:
if (GET_PROG_TYPE(obj) == PROG_ATTACK)
sprintf(buf2, " DamType: %s, ", attack_types[GET_OBJ_VAL(obj, 3) - TYPE_HIT]);
else sprintf(buf2, " ");
send_to_char(ch, "Type: %s, Rating: %d, Size: %d,%sInstalled?: %s\r\n",
program_types[GET_OBJ_VAL(obj, 0)], GET_OBJ_VAL(obj, 1), GET_OBJ_VAL(obj, 2), buf2,
(GET_OBJ_VAL(obj, 6) ? "yes" : "no"));
break;
case ITEM_POTION: case ITEM_SCROLL: case ITEM_WAND: case ITEM_STAFF: case ITEM_FOCUS:
case ITEM_SPELL_FORMULA:
send_to_char(ch, "%s cannot ascertain detailed information about magical objects.\r\n",
spell->name);
break;
}
}
break;
case SPELL_CLAIRVOYANCE:
if (obj) {
send_to_char("View what an item sees?\r\n", ch);
return;
}
GET_WAS_IN(ch) = ch->in_room;
char_from_room(ch);
char_to_room(ch, vict->in_room);
look_at_room(ch, 1);
char_from_room(ch);
char_to_room(ch, GET_WAS_IN(ch));
GET_WAS_IN(ch) = NOWHERE;
break;
case SPELL_COMBAT_SENSE:
if (obj) {
send_to_char("That spell can only be cast on living targets.\r\n", ch);
return;
} else sustain_spell(force, ch, vict, spell, 0);
break;
case SPELL_DETECT_ALIGNMENT:
if (obj) {
send_to_char("Items are most definately neutral.\r\n", ch);
return;
} else sustain_spell(force, ch, vict, spell, 0);
break;
case SPELL_DETECT_INVIS:
if (obj) {
send_to_char("That just doesn't make sense.\r\n", ch);
return;
} else sustain_spell(force, ch, vict, spell, 0);
break;
case SPELL_DETECT_MAGIC:
if (obj) {
send_to_char("That just doesn't make sense.\r\n", ch);
return;
} else sustain_spell(force, ch, vict, spell, 0);
break;
case SPELL_ANALYZE_MAGIC:
if (obj) {
switch (GET_OBJ_TYPE(obj)) {
case ITEM_SPELL_FORMULA:
send_to_char(ch, "(%s) Category: %s, Force: %d, Target: %s, Drain %d%s\r\n"
"Damage: %s, Type: %s, Effect: %s, For: %s",
(GET_OBJ_VAL(obj, 0) ? "Physical" : "Mana"),
spell_categories[GET_OBJ_VAL(obj, 1)], GET_OBJ_VAL(obj, 2),
spell_target[GET_OBJ_VAL(obj, 3)],
((GET_OBJ_VAL(obj, 2) >> 1) + (int)(GET_OBJ_VAL(obj, 4) / 10)),
wound_arr[GET_OBJ_VAL(obj, 4) % 10], wound_arr[GET_OBJ_VAL(obj, 5)],
spells[GET_OBJ_VAL(obj, 6)], elements[GET_OBJ_VAL(obj, 8)],
(GET_OBJ_VAL(obj, 7) ? "Shaman" : "Mage"));
break;
case ITEM_FOCUS:
if (GET_OBJ_VAL(obj, VALUE_FOCUS_TYPE) == FOCI_LOCK)
send_to_char(ch, "Spell lock, Spell: %s, Bonded by: %s",
(!GET_OBJ_VAL(obj, 8)
? "None"
: spells[GET_OBJ_VAL(obj, 8)]),
GET_OBJ_VAL(obj, 9) > 0
? get_name_by_id(GET_OBJ_VAL(obj, 9))
: "No one");
else
sprintf(buf, "%s, Rating: %d, Spec.: %d, Bonded by: %s",
foci_types[GET_OBJ_VAL(obj, 0)],
GET_OBJ_VAL(obj, 1), GET_OBJ_VAL(obj, 8),
GET_OBJ_VAL(obj, 9) > 0
? get_name_by_id(GET_OBJ_VAL(obj, 9))
: "No one");
break;
case ITEM_SCROLL: case ITEM_POTION:
send_to_char(ch, "Force: %d, Spell: %s", GET_OBJ_VAL(obj, 0), spells[GET_OBJ_VAL(obj, 3)]);
break;
case ITEM_WAND: case ITEM_STAFF:
send_to_char(ch, "Force: %d, Max: %d, Remaining: %d, Spell: %s", GET_OBJ_VAL(obj, 0),
GET_OBJ_VAL(obj, 1), GET_OBJ_VAL(obj, 2), spells[GET_OBJ_VAL(obj, 3)]);
break;
}
} else send_to_char("You need to target an object with this spell.\r\n", ch);
break;
case SPELL_ANALYZE_PERSON:
assert(vict);
if (spell->physical)
resist = GET_BOD(vict);
else resist = GET_WIL(vict);
success = resisted_test(force + spell_bonus(ch, spell), resist + modify_target(ch),
resist + spell_resist(vict), force + modify_target(vict));
if (success <= 1) {
send_to_char("You don't learn anything new.\r\n", ch);
return;
}
if (success >= 2) {
switch (GET_SEX(vict)) {
case SEX_MALE: strcpy(buf1, "He"); break;
case SEX_FEMALE: strcpy(buf1, "She"); break;
default: strcpy(buf1, "It"); break;
}
send_to_char(ch, "%s has %s strength, %s quickness, and %s body.\r\n",
buf1, get_attrib(GET_STR(vict)), get_attrib(GET_QUI(vict)),
get_attrib(GET_BOD(vict)));
}
if (success >= 3) {
send_to_char(ch, "%s has %s charisma, %s intelligence, %s willpower.\r\n",
buf1, get_attrib(GET_CHA(vict)), get_attrib(GET_INT(vict)),
get_attrib(GET_WIL(vict)));
}
if (success >= 5) {
send_to_char(ch, "%s has %s reaction, %s magic.\r\n",
buf1, get_attrib(GET_REA(vict)), get_attrib(GET_MAG(vict) / 100));
}
if (success >= 7) {
send_to_char(ch, "%s knows:\r\n", buf1);
for (int i = 100; i < MAX_SKILLS; i++)
if (GET_SKILL(vict, i) > 0)
send_to_char(ch, "%s\r\n", spells[i]);
}
break;
default:
send_to_char("Your spell fizzles into oblivion.\r\n", ch);
mudlog("Illegal type in newmagic.cc.", ch, LOG_SYSLOG, TRUE);
return;
}
}
int process_health_target(char_t *ch, spell_t *spell, char *t, int force)
{
char_t *vict;
char *temp, targ1[80], targ2[80], targ3[80];
int mode = 1;
if (t)
skip_spaces(&t);
// first we find the appropriate target
switch (spell->target) {
case SPELL_TARGET_CASTER:
if (spell->type == SPELL_HEAL || spell->type == SPELL_ANTIDOTE || spell->type == SPELL_RESIST_PAIN ||
spell->type == SPELL_CURE_DISEASE || spell->type == SPELL_POISON) {
any_one_arg(t, targ1);
if (!targ1) {
send_to_char("At what level would you like to cast this spell?\r\n", ch);
return FALSE;
}
if (is_abbrev(targ1, "light"))
mode = LIGHT;
else if (is_abbrev(targ1, "moderate"))
mode = MODERATE;
else if (is_abbrev(targ1, "serious"))
mode = SERIOUS;
else if (is_abbrev(targ1, "deadly"))
mode = DEADLY;
else {
send_to_char("At what level would you like to cast this spell?\r\n", ch);
return FALSE;
}
}
if (t && strcmp(t, GET_NAME(ch))) {
send_to_char("You can only target yourself with this spell.\r\n", ch);
return FALSE;
}
if (mode == DEADLY && spell->type == SPELL_RESIST_PAIN) {
send_to_char("You can't resist the effects of deadly wounds.\r\n", ch);
return FALSE;
}
process_health_spell(ch, ch, mode, spell, force);
break;
case SPELL_TARGET_TOUCH:
if (spell->type == SPELL_HEAL || spell->type == SPELL_ANTIDOTE ||
spell->type == SPELL_RESIST_PAIN ||
spell->type == SPELL_CURE_DISEASE || spell->type == SPELL_POISON) {
any_one_arg(any_one_arg(t, targ1), targ2);
if (!targ1 || !targ2) {
send_to_char("Who do you wish to cast this spell on?\r\n", ch);
return FALSE;
}
if (is_abbrev(targ1, "light"))
mode = LIGHT;
else if (is_abbrev(targ1, "moderate"))
mode = MODERATE;
else if (is_abbrev(targ1, "serious"))
mode = SERIOUS;
else if (is_abbrev(targ1, "deadly"))
mode = DEADLY;
else {
send_to_char("At what level would you like to cast this spell?\r\n", ch);
return FALSE;
}
} else any_one_arg(t, targ2);
if (!(vict = get_char_room_vis(ch, targ2))) {
send_to_char("You can't seem to find the target you wish to cast "
"this spell on.\r\n", ch);
return FALSE;
}
if (mode == DEADLY && spell->type == SPELL_RESIST_PAIN) {
send_to_char("You can't resist the effects of deadly wounds.\r\n", ch);
return FALSE;
}
if (!vict || (!IS_ASTRAL(ch) && !IS_ASTRAL(vict)))
process_health_spell(ch, vict, mode, spell, force);
else if (IS_ASTRAL(vict) && (IS_ASTRAL(ch) || IS_DUAL(ch) ||
PLR_FLAGGED(ch, PLR_PERCEIVE)))
process_health_spell(ch, vict, mode, spell, force);
else if (IS_ASTRAL(ch) && (IS_ASTRAL(vict) || IS_DUAL(vict) ||
PLR_FLAGGED(vict, PLR_PERCEIVE)))
process_health_spell(ch, vict, mode, spell, force);
else {
if (IS_ASTRAL(vict))
send_to_char("You can't target astral beings!\r\n", ch);
else send_to_char("You can't target physical beings!\r\n", ch);
return FALSE;
}
break;
case SPELL_TARGET_RANGE:
if (spell->type == SPELL_HEAL || spell->type == SPELL_ANTIDOTE ||
spell->type == SPELL_RESIST_PAIN ||
spell->type == SPELL_CURE_DISEASE || spell->type == SPELL_POISON) {
any_one_arg(any_one_arg(any_one_arg(t, targ1), targ2), targ3);
if (!targ1 || !targ2) {
send_to_char("Who do you wish to cast this spell on?\r\n", ch);
return FALSE;
}
if (is_abbrev(targ1, "light"))
mode = LIGHT;
else if (is_abbrev(targ1, "moderate"))
mode = MODERATE;
else if (is_abbrev(targ1, "serious"))
mode = SERIOUS;
else if (is_abbrev(targ1, "deadly"))
mode = DEADLY;
else {
send_to_char("At what level would you like to cast this spell?\r\n", ch);
return FALSE;
}
} else any_one_arg(any_one_arg(t, targ2), targ3);
if (!targ1 || !targ2) {
send_to_char("Who do you wish to cast this spell on?\r\n", ch);
return FALSE;
}
if (!*targ3) {
if (!(vict = get_char_room_vis(ch, targ2))) {
send_to_char("You can't seem to find the target you are looking for.\r\n", ch);
return FALSE;
}
} else {
if (!(vict = range_spell(ch, targ2, targ3))) {
if (!(vict = get_char_room_vis(ch, targ2))) {
send_to_char("You can't seem to find the target you are looking "
"for.\r\n", ch);
return FALSE;
}
} else if (vict == ch)
return FALSE;
}
if (!vict || (!IS_ASTRAL(ch) && !IS_ASTRAL(vict)))
process_health_spell(ch, vict, mode, spell, force);
else if (IS_ASTRAL(vict) && (IS_ASTRAL(ch) || IS_DUAL(ch) ||
PLR_FLAGGED(ch, PLR_PERCEIVE)))
process_health_spell(ch, vict, mode, spell, force);
else if (IS_ASTRAL(ch) && (IS_ASTRAL(vict) || IS_DUAL(vict) ||
PLR_FLAGGED(vict, PLR_PERCEIVE)))
process_health_spell(ch, vict, mode, spell, force);
else {
if (IS_ASTRAL(vict))
send_to_char("You can't target astral beings!\r\n", ch);
else send_to_char("You can't target physical beings!\r\n", ch);
return FALSE;
}
break;
case SPELL_TARGET_AREA:
send_to_char("That is not currently a valid spell type.", ch);
mudlog("Undefined (area or ranged) health spell", ch, LOG_SYSLOG, TRUE);
return(FALSE);
default:
send_to_char("You can't seem to target this spell for some reason.\r\n", ch);
mudlog("Illegal target in newmagic.cc.", ch, LOG_SYSLOG, TRUE);
return FALSE;
}
return mode;
}
void process_health_spell(char_t *ch, char_t *vict, int level, spell_t *spell, int force)
{
int success, time = (int)(level * 5/4);
int mod = 0, min = 0;
struct affected_type *af;
switch (spell->type) {
case SPELL_ANTIDOTE:
if (affected_by_spell(vict, SPELL_POISON) != 1) {
sprintf(buf, "%s not affected by any toxin.", (ch == vict ? "You are" : "$N is"));
act(buf, FALSE, ch, 0, vict, TO_CHAR);
return;
}
for (af = vict->affected; af; af = af->next)
if (af->type == SPELL_POISON) {
if (af->duration > level) {
send_to_char(NOEFFECT, ch);
sustain_spell(force, ch, vict, spell, time);
return;
}
success = success_test(force + spell_bonus(ch, spell), af->modifier + modify_target(ch));
if (!success) {
send_to_char("You fail to dispel the toxin.\r\n", ch);
sustain_spell(force, ch, vict, spell, time);
return;
}
time = (int)(time / success);
send_to_char("Your flows of magic erradicate the toxin.\r\n", ch);
send_to_char(vict, "%s\r\n", spell_wear_off_msg[af->type]);
affect_remove(vict, af, 1);
sustain_spell(force, ch, vict, spell, time);
return;
}
break;
case SPELL_CURE_DISEASE:
send_to_char("This spell is useless at the moment.\r\n", ch);
break;
case SPELL_HEAL:
if (level == LIGHT) {
mod = 1; min = (int)(GET_MAX_PHYSICAL(vict) * 4/500);
} else if (level == MODERATE) {
mod = 3; min = (int)(GET_MAX_PHYSICAL(vict) * 3/500);
} else if (level == SERIOUS) {
mod = 6; min = (int)(GET_MAX_PHYSICAL(vict) / 1000);
} else if (level == DEADLY) {
mod = 10; min = -(int)(GET_MAX_PHYSICAL(vict) / 100);
}
success = success_test(force + spell_bonus(ch, spell), (9 - (GET_ESS(vict) / 100)) + modify_target(ch));
if (success < 1) {
if (ch == vict)
sprintf(buf, "You can't get your healing magic to bind with your life force!\r\n");
else sprintf(buf, "You can't get your healing magic to bind with %s's life force!\r\n", GET_NAME(vict));
send_to_char(buf, ch);
sustain_spell(force, ch, vict, spell, time);
return;
}
time = (int)(time / success);
sustain_spell(force, ch, vict, spell, time);
if ((int)(GET_PHYSICAL(vict) / 100) < min) {
sprintf(buf, "Your healing magic isn't powerful enough to help %s.\r\n",
(ch != vict ? GET_NAME(vict) : "yourself"));
send_to_char(buf, ch);
return;
}
LAST_HEAL(vict) = -1;
send_to_char("A warm feeling floods your body.\r\n", vict);
act("$n appears better.", TRUE, vict, 0, 0, TO_ROOM);
GET_PHYSICAL(vict) = MIN(GET_MAX_PHYSICAL(vict), GET_PHYSICAL(vict) + (mod * 100));
update_pos(vict);
break;
case SPELL_DECREASE_ATTRIB:
case SPELL_INCREASE_ATTRIB:
case SPELL_INCREASE_REFLEXES:
case SPELL_POISON:
case SPELL_RESIST_PAIN:
sustain_spell(force, ch, vict, spell, level);
break;
case SPELL_STABILIZE:
time = 5;
if (GET_POS(vict) > POS_INCAP) {
if (ch == vict)
sprintf(buf, "You aren't in any danger of dying!");
else sprintf(buf, "$N isn't in any danger of dying!");
act(buf, FALSE, ch, 0, vict, TO_CHAR);
return;
}
success = success_test(force + spell_bonus(ch, spell), 4 + modify_target(ch) -
(int)(GET_PHYSICAL(vict) / 100));
if (success) {
if (ch == vict)
log("ERROR: In newmagic.cc, stabilizing self!");
act("You succeed in stabilizing $N.", FALSE, ch, 0, vict, TO_CHAR);
act("Your wounds stop bleeding.", FALSE, vict, 0, 0, TO_CHAR);
SET_BIT(AFF_FLAGS(vict), AFF_STABILIZE);
time = (int)(time / success);
} else send_to_char(NOEFFECT, ch);
break;
default:
send_to_char("Your spell fizzles into oblivion.\r\n", ch);
mudlog("Illegal type in newmagic.cc.", ch, LOG_SYSLOG, TRUE);
return;
}
return;
}
bool process_illusion_target(char_t *ch, spell_t *spell, char *t, int force)
{
char_t *vict = NULL;
obj_t *obj = NULL;
char *temp, targ1[80], targ2[80];
if (t)
skip_spaces(&t);
switch (spell->target) {
case SPELL_TARGET_CASTER:
if (t && strcmp(t, GET_NAME(ch))) {
send_to_char("You can only target yourself with this spell.\r\n",
ch);
return FALSE;
}
process_illusion_spell(ch, ch, (obj_t *)NULL, spell, force);
break;
case SPELL_TARGET_TOUCH:
if (!t) {
if (!FIGHTING(ch)) {
send_to_char("You must specify the target you wish to cast this "
"spell on.\r\n", ch);
return FALSE;
} else vict = FIGHTING(ch);
} else {
if (!(vict = get_char_room_vis(ch, t)))
if (!(obj = get_obj_in_list_vis(ch, t, world[ch->in_room].contents)))
if (!(obj = get_obj_in_list_vis(ch, t, ch->carrying))) {
send_to_char("You can't seem to find the target you wish to cast this spell on.\r\n", ch);
return FALSE;
}
}
if (vict && GET_POS(vict) == POS_STANDING && spell->type != SPELL_INVISIBILITY && spell->type != SPELL_IMPROVED_INVIS) {
if (resisted_test(GET_QUI(ch), GET_QUI(vict) + modify_target(ch), GET_QUI(vict), GET_QUI(ch) + modify_target(vict)) < 1) {
act("You stumble over your own legs as you try to touch $N!", FALSE, ch, 0, vict, TO_CHAR);
act("$n stumbles over $s legs as $e reaches to touch $N!", FALSE, ch, 0, vict, TO_NOTVICT);
act("$n stumbles over $s legs as $e reaches to touch you!", FALSE, ch, 0, vict, TO_VICT);
if (!FIGHTING(vict))
set_fighting(vict, ch);
if (!FIGHTING(ch))
set_fighting(ch, vict);
WAIT_STATE(ch, PULSE_VIOLENCE);
return FALSE;
}
} else if (vict && spell->type != SPELL_INVISIBILITY && spell->type != SPELL_IMPROVED_INVIS) {
if (resisted_test(GET_QUI(ch), (GET_QUI(vict) / 2) + modify_target(ch),
(GET_QUI(vict) / 2), GET_QUI(ch) + modify_target(vict)) < 1) {
act("You stumble over your own legs as you try to touch $N!", FALSE, ch, 0, vict, TO_CHAR);
act("$n stumbles over $s legs as $e reaches to touch $N!", FALSE, ch, 0, vict, TO_NOTVICT);
act("$n stumbles over $s legs as $e reaches to touch you!", FALSE, ch, 0, vict, TO_VICT);
if (!FIGHTING(vict))
set_fighting(vict, ch);
if (!FIGHTING(ch))
set_fighting(ch, vict);
WAIT_STATE(ch, PULSE_VIOLENCE);
return FALSE;
}
}
if (!vict || (!IS_ASTRAL(ch) && !IS_ASTRAL(vict)))
process_illusion_spell(ch, vict, obj, spell, force);
else if (IS_ASTRAL(vict) && (IS_ASTRAL(ch) || IS_DUAL(ch) ||
(PLR_FLAGGED(ch, PLR_PERCEIVE) && vict == FIGHTING(ch))))
process_illusion_spell(ch, vict, obj, spell, force);
else if (IS_ASTRAL(ch) && (IS_ASTRAL(vict) || IS_DUAL(vict) ||
PLR_FLAGGED(vict, PLR_PERCEIVE)))
process_illusion_spell(ch, vict, obj, spell, force);
else {
if (IS_ASTRAL(vict) && PLR_FLAGGED(ch, PLR_PERCEIVE))
send_to_char("You can't initiate attacks on astral beings!\r\n", ch);
else if (IS_ASTRAL(vict))
send_to_char("You can't target astral beings!\r\n", ch);
else send_to_char("You can't target physical beings!\r\n", ch);
return FALSE;
}
break;
case SPELL_TARGET_RANGE:
if (!t) {
if (!FIGHTING(ch)) {
send_to_char("You must specify the target you wish to cast this "
"spell on.\r\n", ch);
return FALSE;
} else vict = FIGHTING(ch);
} else {
any_one_arg(any_one_arg(t, targ1), targ2);
if (!*targ2) {
if (!(vict = get_char_room_vis(ch, targ1)) &&
!(obj = get_obj_in_list_vis(ch, targ1, world[ch->in_room].contents)) &&
!(obj = get_obj_in_list_vis(ch, targ1, ch->carrying))) {
send_to_char("You can't seem to find the target you are looking "
"for.\r\n", ch);
return FALSE;
}
} else {
if (!(vict = range_spell(ch, targ1, targ2))) {
if (!(vict = get_char_room_vis(ch, targ2))) {
send_to_char("You can't seem to find the target you are looking "
"for.\r\n", ch);
return FALSE;
} else {
for (register int i = 0; i < NUM_WEARS; ++i)
if (GET_EQ(vict, i) && isname(targ1, GET_EQ(vict, i)->name)) {
obj = GET_EQ(vict, i);
break; // and get out when we do
}
}
} else if (vict == ch)
return FALSE;
}
if (!spell->physical && obj) {
send_to_char("You can only cast that spell on living targets.\r\n", ch);
return FALSE;
}
}
if (!vict || (!IS_ASTRAL(ch) && !IS_ASTRAL(vict)))
process_illusion_spell(ch, vict, obj, spell, force);
else if (IS_ASTRAL(vict) && (IS_ASTRAL(ch) || IS_DUAL(ch) ||
(PLR_FLAGGED(ch, PLR_PERCEIVE) && vict == FIGHTING(ch))))
process_illusion_spell(ch, vict, obj, spell, force);
else if (IS_ASTRAL(ch) && (IS_ASTRAL(vict) || IS_DUAL(vict) ||
PLR_FLAGGED(vict, PLR_PERCEIVE)))
process_illusion_spell(ch, vict, obj, spell, force);
else {
if (IS_ASTRAL(vict) && PLR_FLAGGED(ch, PLR_PERCEIVE))
send_to_char("You can't initiate attacks on astral beings!\r\n", ch);
else if (IS_ASTRAL(vict))
send_to_char("You can't target astral beings!\r\n", ch);
else send_to_char("You can't target physical beings!\r\n", ch);
return FALSE;
}
break;
case SPELL_TARGET_AREA:
struct char_data *tch, *next_tch;
for (tch = world[ch->in_room].people; tch; tch = next_tch) {
next_tch = tch->next_in_room;
if (tch == ch)
continue;
if (!IS_NPC(tch) && GET_LEVEL(tch) >= LVL_LEGEND)
continue;
if (!pk_allowed && !IS_NPC(tch) && !IS_NPC(ch))
continue;
if (in_group(ch, tch))
continue;
if (!IS_ASTRAL(ch) && !IS_ASTRAL(tch))
process_illusion_spell(ch, tch, (obj_t *) NULL, spell, force);
else if (IS_ASTRAL(tch) && (IS_ASTRAL(ch) || IS_DUAL(ch) ||
(PLR_FLAGGED(ch, PLR_PERCEIVE) && tch == FIGHTING(ch))))
process_illusion_spell(ch, tch, (obj_t *) NULL, spell, force);
else if (IS_ASTRAL(ch) && (IS_ASTRAL(tch) || IS_DUAL(tch) ||
PLR_FLAGGED(tch, PLR_PERCEIVE)))
process_illusion_spell(ch, tch, (obj_t *) NULL, spell, force);
}
break;
default:
send_to_char("You can't seem to target this spell for some reason.\r\n", ch);
mudlog("Illegal target in newmagic.cc.", ch, LOG_SYSLOG, TRUE);
return FALSE;
}
return TRUE;
}
void process_illusion_spell(char_t *ch, char_t *vict, obj_t *obj, spell_t *spell, int force)
{
int success;
switch (spell->type) {
case SPELL_CHAOS:
case SPELL_CHAOTIC_WORLD:
case SPELL_CONFUSION:
case SPELL_INVISIBILITY:
case SPELL_OVERSTIMULATION:
case SPELL_IMPROVED_INVIS:
sustain_spell(force, ch, vict, spell, 0);
break;
default:
send_to_char("Your spell fizzles into oblivion.\r\n", ch);
mudlog("Illegal type in newmagic.cc.", ch, LOG_SYSLOG, TRUE);
return;
}
return;
}
bool process_manipulation_target(char_t *ch, spell_t *spell, char *t, int force)
{
char_t *vict = NULL;
obj_t *obj = NULL;
char *temp, targ1[80], targ2[80];
int i, vnum = -1, val;
if (t)
skip_spaces(&t);
if (spell->type == SPELL_SHAPE_CHANGE) {
if (ch->desc->original) {
send_to_char("You can't shape change in your current form!\r\n", ch);
return FALSE;
}
if (!t) {
send_to_char("What do you want to transform into?\r\n", ch);
return FALSE;
}
for (i = 0; *shape_forms[i] != '\n'; i++)
if (!str_cmp(t, (char *)shape_forms[i])) {
vnum = 50 + i;
break;
}
if (vnum == -1) {
send_to_char("What do you want to transform into?\r\n", ch);
return FALSE;
}
vict = read_mobile(vnum, VIRTUAL);
act("You feel your body morph into its new shape.", FALSE, ch, 0, 0, TO_CHAR);
sprintf(arg, "$n disappears, only to be replaced by %s!", GET_NAME(vict));
act(arg, TRUE, ch, 0, 0, TO_ROOM);
SET_BIT(PLR_FLAGS(ch), PLR_SWITCHED);
char_to_room(vict, ch->in_room);
GET_WAS_IN(ch) = ch->in_room;
char_from_room(ch);
char_to_room(ch, 0);
ch->desc->character = vict;
ch->desc->original = ch;
vict->desc = ch->desc;
ch->desc = NULL;
look_at_room(vict, 1);
return TRUE;
}
switch (spell->target) {
case SPELL_TARGET_CASTER:
if (t && strcmp(t, GET_NAME(ch))) {
send_to_char("You can only target yourself with this spell.\r\n", ch);
return FALSE;
}
process_manipulation_spell(ch, ch, (obj_t *)NULL, spell, force);
break;
case SPELL_TARGET_TOUCH:
if (!t) {
if (!FIGHTING(ch)) {
send_to_char("You must specify the target you wish to cast this spell on.\r\n", ch);
return FALSE;
} else vict = FIGHTING(ch);
} else {
if (!(vict = get_char_room_vis(ch, t)))
if (!(val = spell_damage_door(ch, spell, t))) {
if (!(obj = get_obj_in_list_vis(ch, t, world[ch->in_room].contents)))
if (!(obj = get_obj_in_list_vis(ch, t, ch->carrying))) {
send_to_char("You can't seem to find the target you "
"wish to cast this spell on.\r\n", ch);
return FALSE;
}
} else return (val == 1 ? TRUE : FALSE);
}
if (vict && GET_POS(vict) == POS_STANDING) {
if (resisted_test(GET_QUI(ch), GET_QUI(vict) + modify_target(ch), GET_QUI(vict), GET_QUI(ch) + modify_target(vict)) < 1) {
act("You stumble over your own legs as you try to touch $N!", FALSE, ch, 0, vict, TO_CHAR);
act("$n stumbles over $s legs as $e reaches to touch $N!", FALSE, ch, 0, vict, TO_NOTVICT);
act("$n stumbles over $s legs as $e reaches to touch you!", FALSE, ch, 0, vict, TO_VICT);
if (!FIGHTING(vict))
set_fighting(vict, ch);
if (!FIGHTING(ch))
set_fighting(ch, vict);
WAIT_STATE(ch, PULSE_VIOLENCE);
return FALSE;
}
} else if (vict) {
if (resisted_test(GET_QUI(ch), (GET_QUI(vict) / 2) + modify_target(ch),
(GET_QUI(vict) / 2), GET_QUI(ch) + modify_target(vict)) < 1) {
act("You stumble over your own legs as you try to touch $N!", FALSE, ch, 0, vict, TO_CHAR);
act("$n stumbles over $s legs as $e reaches to touch $N!", FALSE, ch, 0, vict, TO_NOTVICT);
act("$n stumbles over $s legs as $e reaches to touch you!", FALSE, ch, 0, vict, TO_VICT);
if (!FIGHTING(vict))
set_fighting(vict, ch);
if (!FIGHTING(ch))
set_fighting(ch, vict);
WAIT_STATE(ch, PULSE_VIOLENCE);
return FALSE;
}
}
if (!vict || (!IS_ASTRAL(ch) && !IS_ASTRAL(vict)))
process_manipulation_spell(ch, vict, obj, spell, force);
else if (IS_ASTRAL(vict) && (IS_ASTRAL(ch) || IS_DUAL(ch) ||
(PLR_FLAGGED(ch, PLR_PERCEIVE) && vict == FIGHTING(ch))))
process_manipulation_spell(ch, vict, obj, spell, force);
else if (IS_ASTRAL(ch) && (IS_ASTRAL(vict) || IS_DUAL(vict) ||
PLR_FLAGGED(vict, PLR_PERCEIVE)))
process_manipulation_spell(ch, vict, obj, spell, force);
else {
if (IS_ASTRAL(vict) && PLR_FLAGGED(ch, PLR_PERCEIVE))
send_to_char("You can't initiate attacks on astral beings!\r\n", ch);
else if (IS_ASTRAL(vict))
send_to_char("You can't target astral beings!\r\n", ch);
else send_to_char("You can't target physical beings!\r\n", ch);
return FALSE;
}
break;
case SPELL_TARGET_RANGE:
if (!t) {
if (!FIGHTING(ch)) {
send_to_char("You must specify the target you wish to cast this spell on.\r\n", ch);
return FALSE;
} else vict = FIGHTING(ch);
} else {
any_one_arg(any_one_arg(t, targ1), targ2);
if (!*targ2) {
if (!(vict = get_char_room_vis(ch, targ1)))
if (!(val = spell_damage_door(ch, spell, t))) {
if (!(obj = get_obj_in_list_vis(ch, targ1, world[ch->in_room].contents)) &&
!(obj = get_obj_in_list_vis(ch, targ1, ch->carrying))) {
send_to_char("You can't seem to find the target you "
"are looking for.\r\n", ch);
return FALSE;
}
} else return (val == 1 ? TRUE : FALSE);
} else {
if (!(vict = range_spell(ch, targ1, targ2))) {
if (!(val = spell_damage_door(ch, spell, t))) {
if (!(vict = get_char_room_vis(ch, targ2))) {
send_to_char("You can't seem to find the target you are looking for.\r\n", ch);
return FALSE;
} else {
for (i = 0; i < NUM_WEARS; ++i)
if (GET_EQ(vict, i) && isname(targ1, GET_EQ(vict, i)->name)) {
obj = GET_EQ(vict, i);
break; // and get out when we do
}
}
} else return (val == 1 ? TRUE : FALSE);
} else if (vict == ch)
return FALSE;
}
if (!spell->physical && obj) {
send_to_char("You can only cast that spell on living targets.\r\n", ch);
return FALSE;
}
}
if (!vict || (!IS_ASTRAL(ch) && !IS_ASTRAL(vict)))
process_manipulation_spell(ch, vict, obj, spell, force);
else if (IS_ASTRAL(vict) && (IS_ASTRAL(ch) || IS_DUAL(ch) ||
(PLR_FLAGGED(ch, PLR_PERCEIVE) && vict == FIGHTING(ch))))
process_manipulation_spell(ch, vict, obj, spell, force);
else if (IS_ASTRAL(ch) && (IS_ASTRAL(vict) || IS_DUAL(vict) ||
PLR_FLAGGED(vict, PLR_PERCEIVE)))
process_manipulation_spell(ch, vict, obj, spell, force);
else {
if (IS_ASTRAL(vict) && PLR_FLAGGED(ch, PLR_PERCEIVE))
send_to_char("You can't initiate attacks on astral beings!\r\n", ch);
else if (IS_ASTRAL(vict))
send_to_char("You can't target astral beings!\r\n", ch);
else send_to_char("You can't target physical beings!\r\n", ch);
return FALSE;
}
break;
case SPELL_TARGET_AREA:
struct char_data *tch, *next_tch;
for (tch = world[ch->in_room].people; tch; tch = next_tch) {
next_tch = tch->next_in_room;
if (tch == ch)
continue;
if (!IS_NPC(tch) && GET_LEVEL(tch) >= LVL_LEGEND)
continue;
if (!pk_allowed && !IS_NPC(tch) && !IS_NPC(ch))
continue;
if (in_group(ch, tch))
continue;
if (!IS_ASTRAL(ch) && !IS_ASTRAL(tch))
process_manipulation_spell(ch, tch, (obj_t *) NULL, spell, force);
else if (IS_ASTRAL(tch) && (IS_ASTRAL(ch) || IS_DUAL(ch) ||
(PLR_FLAGGED(ch, PLR_PERCEIVE) && tch == FIGHTING(ch))))
process_manipulation_spell(ch, tch, (obj_t *) NULL, spell, force);
else if (IS_ASTRAL(ch) && (IS_ASTRAL(tch) || IS_DUAL(tch) ||
PLR_FLAGGED(tch, PLR_PERCEIVE)))
process_manipulation_spell(ch, tch, (obj_t *) NULL, spell, force);
}
struct obj_data *obj, *next;
if (spell->physical) {
for (obj = world[ch->in_room].contents; obj; obj = next) {
next = obj->next_content;
damage_obj(NULL, obj, force + FORCE_PENALTY(spell),
spell->effect | DAMOBJ_MANIPULATION);
}
for (val = 0; val < (NUM_OF_DIRS - 1); val++)
if (EXIT(ch, val) && EXIT(ch, val)->keyword &&
IS_SET(EXIT(ch, val)->exit_info, EX_CLOSED))
damage_door(ch, ch->in_room, val, (int)(force), spell->effect);
}
break;
default:
send_to_char("You can't seem to target this spell for some reason.\r\n", ch);
mudlog("Illegal target in newmagic.cc.", ch, LOG_SYSLOG, TRUE);
return FALSE;
}
return TRUE;
}
void process_manipulation_spell(char_t *ch, char_t *vict, obj_t *obj, spell_t *spell, int force)
{
struct obj_data *next;
int resist = 0, success = 0, dam, i, low = NOWHERE, high = NOWHERE;
int chance, room;
switch (spell->type) {
case SPELL_ANTI_BULLET:
case SPELL_ANTI_SPELL:
case SPELL_ARMOR:
case SPELL_INFLUENCE:
case SPELL_LIGHT:
case SPELL_PETRIFY:
sustain_spell(force, ch, vict, spell, 0);
break;
case SPELL_CLOUT:
if (obj) {
send_to_char("This spell can't be used on objects\r\n.", ch);
return;
}
resist = GET_WIL(vict);
success = success_test(force + spell_bonus(ch, spell), GET_IMPACT(vict));
success -= success_test(resist + spell_resist(vict), GET_WIL(ch) + modify_target(vict));
if (success < 1) {
damage(ch, vict, 0, spell->type, FALSE);
ranged_response(ch, vict);
return;
}
if (IS_ASTRAL(ch))
dam = convert_damage(stage(success, grimoire[spell->type].drain % 10));
else dam = convert_damage(stage(success, grimoire[spell->type].damage));
if (access_level(ch, LVL_OWNER) && spell->target != SPELL_TARGET_AREA)
send_to_char(ch, "(%s) F: %d, R: %d, S: %d, D: %d\r\n",
spell->physical ? "Physical" : "Mana", force, resist, success, 0);
if (spell->target == SPELL_TARGET_AREA)
chance = 10;
else chance = 2;
for (i = 0; i < (NUM_WEARS - 1); i++)
if (GET_EQ(vict, i) && number(1, 100) < chance) {
damage_obj(NULL, GET_EQ(vict, i), force + FORCE_PENALTY(spell),
DAMOBJ_PROJECTILE);
if (spell->target != SPELL_TARGET_AREA)
break;
}
chance = (int)(chance / 2);
for (obj = vict->carrying; obj; obj = next) {
next = obj->next_content;
if (number(1, 100) < chance)
damage_obj(NULL, obj, force + FORCE_PENALTY(spell),
DAMOBJ_PROJECTILE);
}
damage(ch, vict, dam, spell->type, FALSE);
ranged_response(ch, vict);
break;
case SPELL_TOXIC_WAVE:
case SPELL_ELEMENTBALL:
case SPELL_ELEMENT_BOLT:
case SPELL_ELEMENT_CLOUD:
case SPELL_ELEMENT_DART:
case SPELL_ELEMENT_MISSILE:
if (!obj) {
if (spell->physical)
resist = GET_BOD(vict);
else resist = GET_WIL(vict);
success = success_test(force + spell_bonus(ch, spell), resist + modify_target(ch));
if (access_level(ch, LVL_OWNER) && spell->target != SPELL_TARGET_AREA)
send_to_char(ch, "(%s) F: %d, R: %d, S: %d, D: %d\r\n",
spell->physical ? "Physical" : "Mana", force, resist, success, 0);
if (success < 1) {
damage(ch, vict, 0, spell->type, FALSE);
ranged_response(ch, vict);
return;
}
if (spell->effect != SPELL_EFFECT_NONE) {
elemental_damage(ch, vict, spell, force, success);
return;
}
success -= success_test(resist + spell_resist(vict), force + modify_target(vict));
if (IS_ASTRAL(ch))
dam = convert_damage(stage(success, grimoire[spell->type].drain % 10));
else dam = convert_damage(stage(success, grimoire[spell->type].damage));
if (spell->target == SPELL_TARGET_AREA)
chance = 10;
else chance = 2;
for (i = 0; i < (NUM_WEARS - 1); i++)
if (GET_EQ(vict, i) && number(1, 100) < chance) {
damage_obj(NULL, GET_EQ(vict, i), force + FORCE_PENALTY(spell),
DAMOBJ_PROJECTILE);
if (spell->target != SPELL_TARGET_AREA)
break;
}
chance = (int)(chance / 2);
for (obj = vict->carrying; obj; obj = next) {
next = obj->next_content;
if (number(1, 100) < chance)
damage_obj(NULL, obj, force + FORCE_PENALTY(spell),
DAMOBJ_PROJECTILE);
}
damage(ch, vict, dam, spell->type, TRUE);
ranged_response(ch, vict);
} else {
damage_obj(ch, obj, force + FORCE_PENALTY(spell),
spell->effect | DAMOBJ_MANIPULATION);
if (vict && IS_NPC(vict) && !FIGHTING(vict))
set_fighting(vict, ch);
}
break;
case SPELL_TELEPORT:
for (i = zone_table[world[ch->in_room].zone].number * 100; low == NOWHERE &&
i <= zone_table[world[ch->in_room].zone].top; i++)
low = real_room(i);
for (i = zone_table[world[ch->in_room].zone].top; high == NOWHERE &&
i >= zone_table[world[ch->in_room].zone].number * 100; i--)
high = real_room(i);
if ((low == NOWHERE || high == NOWHERE) || low >= high) {
send_to_char("You are unable to control the necessary forces.\r\n", ch);
return;
}
act("You carefully rip a whole in space and step through it.", FALSE, ch, 0, 0, TO_CHAR);
act("$n tears a whole in space and disappears into it.", TRUE, ch, 0, 0, TO_ROOM);
char_from_room(ch);
for (room = number(low, high), i = 0; i < 50 && ROOM_FLAGGED(room, ROOM_BUILDERROOM |
ROOM_MGRROOM | ROOM_DIRECTORROOM | ROOM_PRESROOM); i++)
room = number(low, high);
char_to_room(ch, room);
act("$n appears from thin air.", TRUE, ch, 0, 0, TO_ROOM);
if (ch->desc)
look_at_room(ch, 0);
break;
default:
send_to_char("Your spell fizzles into oblivion.\r\n", ch);
mudlog("Illegal type in newmagic.cc.", ch, LOG_SYSLOG, TRUE);
return;
}
return;
}
void parse_category(spell_t *spell, struct char_data *ch, struct char_data *tch,
struct obj_data *tobj, int level)
{
if (!tch || (!IS_ASTRAL(ch) && !IS_ASTRAL(tch)));
else if (IS_ASTRAL(tch) && (IS_ASTRAL(ch) || IS_DUAL(ch)));
else if (IS_ASTRAL(ch) && (IS_ASTRAL(tch) || IS_DUAL(tch) ||
PLR_FLAGGED(tch, PLR_PERCEIVE)));
else return;
switch (spell->category) {
case SPELL_CATEGORY_COMBAT:
process_combat_spell(ch, tch, tobj, spell, spell->force);
break;
case SPELL_CATEGORY_DETECTION:
process_detection_spell(ch, tch, tobj, spell, spell->force);
break;
case SPELL_CATEGORY_HEALTH:
process_health_spell(ch, tch, level, spell, spell->force);
break;
case SPELL_CATEGORY_ILLUSION:
process_illusion_spell(ch, tch, tobj, spell, spell->force);
break;
case SPELL_CATEGORY_MANIPULATION:
process_manipulation_spell(ch, tch, tobj, spell, spell->force);
break;
default:
send_to_char("Your spell seems to make no sense to you whatsoever.\r\n", ch);
mudlog("Unknown spell category in newmagic.cc.", ch, LOG_SYSLOG, TRUE);
return;
}
}
void mob_cast(struct char_data * ch, struct char_data * tch, struct obj_data * tobj,
int spellnum, int level)
{
spell_t *spell;
if (GET_POS(ch) < POS_SITTING) {
send_to_char("Not now!\r\n", ch);
return;
} else if (GET_MENTAL(ch) < (GET_MAX_MENTAL(ch) / 3)) {
send_to_char("You fear casting right now would do more harm than good.\r\n", ch);
return;
} else if (IS_AFFECTED(ch, AFF_CHARM) && (ch->master == tch)) {
send_to_char("You are afraid you might hurt your master!\r\n", ch);
return;
} else if (ROOM_FLAGGED(ch->in_room, ROOM_NOMAGIC)) {
send_to_char("You just can't do that here!\r\n", ch);
return;
}
spell = new spell_t;
int i = strlen(spells[spellnum]);
spell->name = new char[i+1];
strcpy(spell->name, spells[spellnum]);
spell->physical = grimoire[spellnum].physical;
spell->category = grimoire[spellnum].category;
spell->force = MIN(GET_MAG(ch) / 100, MIN(10,
(GET_SKILL(ch, SKILL_SORCERY) ? GET_SKILL(ch, SKILL_SORCERY) : 0)));
spell->target = grimoire[spellnum].target;
spell->drain = grimoire[spellnum].drain;
spell->damage = grimoire[spellnum].damage;
spell->type = spellnum;
spell->effect = level;
spell->next = NULL;
if (spell->force < 1) {
send_to_char("You need some knowledge of sorcery to cast spells!\r\n", ch);
if (spell->name)
delete [] spell->name;
delete spell;
return;
}
if ((tch != ch) && spell->target == CASTER) {
send_to_char("You can only cast this spell upon yourself!\r\n", ch);
if (spell->name)
delete [] spell->name;
delete spell;
return;
}
if (!tch || (!IS_ASTRAL(ch) && !IS_ASTRAL(tch)));
else if (IS_ASTRAL(tch) && (IS_ASTRAL(ch) || IS_DUAL(ch)));
else if (IS_ASTRAL(ch) && (IS_ASTRAL(tch) || IS_DUAL(tch) ||
PLR_FLAGGED(tch, PLR_PERCEIVE)));
else {
if (IS_ASTRAL(tch))
send_to_char("You can't target astral beings.\r\n", ch);
else send_to_char("You can't target physical beings.\r\n", ch);
if (spell->name)
delete [] spell->name;
delete spell;
return;
}
if (spell->target == SPELL_TARGET_TOUCH) {
if (GET_POS(tch) == POS_STANDING) {
if (resisted_test(GET_QUI(ch), GET_QUI(tch) + modify_target(ch),
GET_QUI(tch), GET_QUI(ch) + modify_target(tch)) < 1) {
act("You stumble over your own legs as you try to touch $N!",
FALSE, ch, 0, tch, TO_CHAR);
act("$n stumbles over $s legs as $e reaches to touch $N!",
FALSE, ch, 0, tch, TO_NOTVICT);
act("$n stumbles over $s legs as $e reaches to touch you!",
FALSE, ch, 0, tch, TO_VICT);
if (!FIGHTING(tch))
set_fighting(tch, ch);
if (!FIGHTING(ch))
set_fighting(ch, tch);
WAIT_STATE(ch, PULSE_VIOLENCE);
if (spell->name)
delete [] spell->name;
delete spell;
return;
}
} else {
if (resisted_test(GET_QUI(ch), (GET_QUI(tch) / 2) + modify_target(ch),
(GET_QUI(tch) / 2), GET_QUI(ch) + modify_target(tch)) < 1) {
act("You stumble over your own legs as you try to touch $N!",
FALSE, ch, 0, tch, TO_CHAR);
act("$n stumbles over $s legs as $e reaches to touch $N!",
FALSE, ch, 0, tch, TO_NOTVICT);
act("$n stumbles over $s legs as $e reaches to touch you!",
FALSE, ch, 0, tch, TO_VICT);
if (!FIGHTING(tch))
set_fighting(tch, ch);
if (!FIGHTING(ch))
set_fighting(ch, tch);
WAIT_STATE(ch, PULSE_VIOLENCE);
if (spell->name)
delete [] spell->name;
delete spell;
return;
}
}
}
if (spell->target == AREA) {
for (tch = world[ch->in_room].people; tch; tch = tch->next_in_room)
if (tch != ch)
parse_category(spell, ch, tch, tobj, level);
} else parse_category(spell, ch, tch, tobj, level);
if (spellnum != SPELL_HEAL && spellnum != SPELL_ANTIDOTE &&
spellnum != SPELL_CURE_DISEASE && spellnum != SPELL_RESIST_PAIN &&
spellnum != SPELL_POISON)
resist_drain(ch, spell->force, spell, DRAIN_LEVEL(spell->drain));
else resist_drain(ch, spell->force, spell, level);
if (FIGHTING(ch) && !AFF_FLAGGED(ch, AFF_ACTION))
SET_BIT(AFF_FLAGS(ch), AFF_ACTION);
WAIT_STATE(ch, PULSE_VIOLENCE);
if (spell->name)
delete [] spell->name;
delete spell;
}
void obj_magic(struct char_data * ch, struct obj_data * obj, char *argument)
{
struct char_data *tch = NULL, *next_tch;
struct obj_data *tobj = NULL;
spell_t *spell = new spell_t;
int k;
one_argument(argument, arg);
k = generic_find(arg, FIND_CHAR_ROOM | FIND_OBJ_INV | FIND_OBJ_ROOM | FIND_OBJ_EQUIP, ch, &tch, &tobj);
if (GET_OBJ_VAL(obj, 3) >= SPELL_ANALYZE_DEVICE && GET_OBJ_VAL(obj, 3) <= MAX_SPELLS) {
int i = strlen(spells[GET_OBJ_VAL(obj, 3)]);
spell->name = new char[i+1];
strcpy(spell->name, spells[GET_OBJ_VAL(obj, 3)]);
spell->physical = grimoire[GET_OBJ_VAL(obj, 3)].physical;
spell->category = grimoire[GET_OBJ_VAL(obj, 3)].category;
spell->force = MAX(GET_OBJ_VAL(obj, 0), 1);
spell->target = grimoire[GET_OBJ_VAL(obj, 3)].target;
spell->drain = grimoire[GET_OBJ_VAL(obj, 3)].drain;
spell->damage = grimoire[GET_OBJ_VAL(obj, 3)].damage;
spell->type = GET_OBJ_VAL(obj, 3);
spell->next = NULL;
} else return;
switch (GET_OBJ_TYPE(obj)) {
case ITEM_STAFF:
if (obj->use_description) {
act(obj->use_description->description2, FALSE, ch, obj, 0, TO_ROOM);
act(obj->use_description->description1, FALSE, ch, obj, 0, TO_CHAR);
} else {
act("$n taps $p three times on the ground.", FALSE, ch, obj, 0, TO_ROOM);
act("You tap $p three times on the ground.", FALSE, ch, obj, 0, TO_CHAR);
}
if (GET_OBJ_VAL(obj, 2) <= 0) {
act("It seems powerless.", FALSE, ch, obj, 0, TO_CHAR);
act("Nothing seems to happen.", FALSE, ch, obj, 0, TO_ROOM);
} else {
GET_OBJ_VAL(obj, 2)--;
for (tch = world[ch->in_room].people; tch; tch = next_tch) {
next_tch = tch->next_in_room;
if (ch == tch)
continue;
if (!IS_NPC(tch) || (IS_ASTRAL(tch) && !(IS_ASTRAL(ch) || IS_DUAL(ch) || PLR_FLAGGED(ch, PLR_PERCEIVE))))
continue;
parse_category(spell, ch, tch, NULL, 2);
}
}
break;
case ITEM_WAND:
if (k == FIND_CHAR_ROOM) {
if (tch == ch) {
act("You point $p at yourself.", FALSE, ch, obj, 0, TO_CHAR);
act("$n points $p at $mself.", FALSE, ch, obj, 0, TO_ROOM);
} else {
if (obj->use_description != NULL) {
act(obj->use_description->description2, FALSE, ch, obj, tch, TO_ROOM);
act(obj->use_description->description1, FALSE, ch, obj, tch, TO_CHAR);
} else {
act("You point $p at $N.", FALSE, ch, obj, tch, TO_CHAR);
act("$n points $p at $N.", TRUE, ch, obj, tch, TO_ROOM);
}
}
} else if (tobj != NULL) {
if (obj->use_description != NULL) {
act(obj->use_description->description2, TRUE, ch, obj, tobj, TO_ROOM);
act(obj->use_description->description1, FALSE, ch, obj, tobj, TO_CHAR);
} else {
act("$n points $p at $P.", TRUE, ch, obj, tobj, TO_ROOM);
act("You point $p at $P.", FALSE, ch, obj, tobj, TO_CHAR);
}
} else {
act("At what should $p be pointed?", FALSE, ch, obj, NULL, TO_CHAR);
return;
}
if (GET_OBJ_VAL(obj, 2) <= 0) {
act("It seems powerless.", FALSE, ch, obj, 0, TO_CHAR);
return;
}
GET_OBJ_VAL(obj, 2)--;
parse_category(spell, ch, tch, tobj, 2);
break;
case ITEM_SCROLL:
if (*arg) {
if (!k) {
act("There is nothing to here to affect with $p.", FALSE, ch, obj, NULL, TO_CHAR);
return;
}
} else tch = ch;
if (obj->use_description) {
act(obj->use_description->description2, FALSE, ch, obj, NULL, TO_ROOM);
act(obj->use_description->description1, TRUE, ch, obj, 0, TO_CHAR);
} else {
act("$n recites $p.", FALSE, ch, obj, NULL, TO_ROOM);
act("You recite $p which dissolves.", TRUE, ch, obj, 0, TO_CHAR);
}
parse_category(spell, ch, tch, tobj, 2);
if (obj != NULL)
extract_obj(obj);
break;
case ITEM_POTION:
tch = ch;
if (obj->use_description) {
act(obj->use_description->description2, FALSE, ch, obj, NULL, TO_ROOM);
act(obj->use_description->description1, FALSE, ch, obj, NULL, TO_CHAR);
} else {
act("$n quaffs $p.", TRUE, ch, obj, NULL, TO_ROOM);
act("You quaff $p.", FALSE, ch, obj, NULL, TO_CHAR);
}
parse_category(spell, ch, tch, tobj, 2);
if (obj != NULL)
extract_obj(obj);
break;
default:
log("SYSERR: Unknown object_type in mag_objectmagic");
break;
}
}
int spell_bonus(char_t *ch, spell_t *spell)
{
return foci_bonus(ch, spell, spell->force, TRUE)
+ magic_pool_bonus(ch, spell, spell->force, TRUE)
+ totem_bonus(ch, spell);
}
// finds the spell by name and returns a pointer to it
spell_t *find_spell(char_t *ch, char *name)
{
register spell_t *temp;
for (temp = ch->spells; temp; temp = temp->next)
if (is_abbrev(name, temp->name))
break;
if (temp)
return temp;
return NULL;
}
void write_spells(char_t *ch)
{
if (!get_filename(GET_NAME(ch), buf2, SPELLS_FILE) || !ch->spells)
return;
FILE *outFile;
if (!(outFile = fopen(buf2, "w+"))) {
sprintf(buf, "Unable to write %s's spell file.\n", GET_NAME(ch));
mudlog(buf, ch, LOG_SYSLOG, TRUE);
return;
}
for (spell_t *temp = ch->spells; temp; temp = temp->next) {
// here we place the name at the end of each line so it's easier
// to read in
fprintf(outFile, "%d %d %d %d %d %d %d %d %-30s\n", temp->physical,
temp->category, temp->force, temp->target, temp->drain,
temp->type, temp->damage, temp->effect, temp->name);
}
fclose(outFile);
}
void read_spells(char_t *ch)
{
if (ch->spells || !get_filename(GET_NAME(ch), buf2, SPELLS_FILE))
return;
FILE *inFile;
if (!(inFile = fopen(buf2, "r"))) {
if (errno != ENOENT) {
sprintf(buf, "Unable to open %s's spell file.\n", GET_NAME(ch));
mudlog(buf, ch, LOG_SYSLOG, TRUE);
}
return;
}
spell_t *temp;
char line[256];
char name[31];
int t[9];
while (get_line(inFile, line) && sscanf(line, "%d %d %d %d %d %d %d %d %30[a-zA-Z0-9 ]\n",
t, t + 1, t + 2, t + 3, t + 4, t + 5, t + 6, t + 7, name) == 9) {
int i;
while( name[(i = strlen(name)-1)] == ' ' && i >= 1 )
name[i] = 0;
// allocate a new spell
temp = new spell_t;
temp->name = new char[strlen(name) + 1];
// set all the values
temp->physical = t[0];
temp->category = t[1];
temp->force = t[2];
temp->target = t[3];
temp->drain = t[4];
temp->type = t[5];
temp->damage = t[6];
temp->effect = t[7];
strcpy(temp->name, name);
// add the spell to the character's spell list
temp->next = ch->spells;
ch->spells = temp;
}
fclose(inFile);
}
#undef _newmagic_cc_