/*
* $Id: handler.c,v 1.101 1998/12/23 16:59:21 fjoe Exp $
*/
/***************************************************************************
* ANATOLIA 2.1 is copyright 1996-1997 Serdar BULUT, Ibrahim CANPUNAR *
* ANATOLIA has been brought to you by ANATOLIA consortium *
* Serdar BULUT {Chronos} bulut@rorqual.cc.metu.edu.tr *
* Ibrahim Canpunar {Asena} canpunar@rorqual.cc.metu.edu.tr *
* Murat BICER {KIO} mbicer@rorqual.cc.metu.edu.tr *
* D.Baris ACAR {Powerman} dbacar@rorqual.cc.metu.edu.tr *
* By using this code, you have agreed to follow the terms of the *
* ANATOLIA license, in the file Anatolia/anatolia.licence *
***************************************************************************/
/**************************************************************************r
* Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, *
* Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. *
* *
* Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael *
* Chastain, Michael Quan, and Mitchell Tse. *
* *
* In order to use any part of this Merc Diku Mud, you must comply with *
* both the original Diku license in 'license.doc' as well the Merc *
* license in 'license.txt'. In particular, you may not remove either of *
* these copyright notices. *
* *
* Much time and thought has gone into this software and you are *
* benefitting. We hope that you share your changes too. What goes *
* around, comes around. *
***************************************************************************/
/***************************************************************************
* ROM 2.4 is copyright 1993-1995 Russ Taylor *
* ROM has been brought to you by the ROM consortium *
* Russ Taylor (rtaylor@pacinfo.com) *
* Gabrielle Taylor (gtaylor@pacinfo.com) *
* Brian Moore (rom@rom.efn.org) *
* By using this code, you have agreed to follow the terms of the *
* ROM license, in the file Rom24/doc/rom.license *
***************************************************************************/
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include "merc.h"
#include "hometown.h"
#include "obj_prog.h"
#include "raffects.h"
#include "fight.h"
#include "quest.h"
DECLARE_DO_FUN(do_raffects );
DECLARE_DO_FUN(do_return );
DECLARE_DO_FUN(do_say );
DECLARE_DO_FUN(do_track );
/*
* Local functions.
*/
void affect_modify (CHAR_DATA *ch, AFFECT_DATA *paf, bool fAdd);
int age_to_num (int age);
/* friend stuff -- for NPC's mostly */
bool is_friend(CHAR_DATA *ch, CHAR_DATA *victim)
{
flag_t off;
if (is_same_group(ch, victim))
return TRUE;
if (!IS_NPC(ch))
return FALSE;
off = ch->pIndexData->off_flags;
if (!IS_NPC(victim)) {
if (IS_SET(off, ASSIST_PLAYERS))
return TRUE;
else
return FALSE;
}
if (IS_AFFECTED(ch, AFF_CHARM))
return FALSE;
if (IS_SET(off, ASSIST_ALL))
return TRUE;
if (ch->group && ch->group == victim->group)
return TRUE;
if (IS_SET(off, ASSIST_VNUM)
&& ch->pIndexData == victim->pIndexData)
return TRUE;
if (IS_SET(off, ASSIST_RACE) && ch->race == victim->race)
return TRUE;
if (IS_SET(off, ASSIST_ALIGN)
&& !IS_SET(ch->pIndexData->act, ACT_NOALIGN)
&& !IS_SET(victim->pIndexData->act, ACT_NOALIGN)
&& ((IS_GOOD(ch) && IS_GOOD(victim)) ||
(IS_EVIL(ch) && IS_EVIL(victim)) ||
(IS_NEUTRAL(ch) && IS_NEUTRAL(victim))))
return TRUE;
return FALSE;
}
/*
* Room record:
* For less than 5 people in room create a new record.
* Else use the oldest one.
*/
void room_record(const char *name,ROOM_INDEX_DATA *room,int door)
{
ROOM_HISTORY_DATA *rec;
int i;
for (i=0,rec = room->history;i < 5 && rec != NULL;
i++,rec = rec->next);
if (i < 5) {
rec = calloc(1, sizeof(*rec));
rec->next = room->history;
if (rec->next != NULL)
rec->next->prev = rec;
room->history = rec;
rec->name = NULL;
}
else {
rec = room->history->next->next->next->next;
rec->prev->next = NULL;
rec->next = room->history;
rec->next->prev = rec;
room->history = rec;
}
rec->prev = NULL;
if(rec->name) {
free_string(rec->name);
}
rec->name = str_dup(name);
rec->went = door;
}
/* returns number of people on an object */
int count_users(OBJ_DATA *obj)
{
CHAR_DATA *fch;
int count = 0;
if (obj->in_room == NULL)
return 0;
for (fch = obj->in_room->people; fch != NULL; fch = fch->next_in_room)
if (fch->on == obj)
count++;
return count;
}
/*
* Check the material
*/
bool check_material(OBJ_DATA *obj, char *material)
{
return strstr(obj->material, material) ? TRUE : FALSE;
}
bool is_metal(OBJ_DATA *obj)
{
if (check_material(obj, "silver") ||
check_material(obj, "gold") ||
check_material(obj, "iron") ||
check_material(obj, "mithril") ||
check_material(obj, "adamantite") ||
check_material(obj, "steel") ||
check_material(obj, "lead") ||
check_material(obj, "bronze") ||
check_material(obj, "copper") ||
check_material(obj, "brass") ||
check_material(obj, "platinium") ||
check_material(obj, "titanium") ||
check_material(obj, "aliminum"))
return TRUE;
return FALSE;
}
bool may_float(OBJ_DATA *obj)
{
if (check_material(obj, "wood") ||
check_material(obj, "ebony") ||
check_material(obj, "ice") ||
check_material(obj, "energy") ||
check_material(obj, "hardwood") ||
check_material(obj, "softwood") ||
check_material(obj, "flesh") ||
check_material(obj, "silk") ||
check_material(obj, "wool") ||
check_material(obj, "cloth") ||
check_material(obj, "fur") ||
check_material(obj, "water") ||
check_material(obj, "ice") ||
check_material(obj, "oak"))
return TRUE;
if (obj->pIndexData->item_type == ITEM_BOAT)
return TRUE;
return FALSE;
}
bool cant_float(OBJ_DATA *obj)
{
if (check_material(obj, "steel") ||
check_material(obj, "iron") ||
check_material(obj, "brass") ||
check_material(obj, "silver") ||
check_material(obj, "gold") ||
check_material(obj, "ivory") ||
check_material(obj, "copper") ||
check_material(obj, "diamond") ||
check_material(obj, "pearl") ||
check_material(obj, "gem") ||
check_material(obj, "platinium") ||
check_material(obj, "ruby") ||
check_material(obj, "bronze") ||
check_material(obj, "titanium") ||
check_material(obj, "mithril") ||
check_material(obj, "obsidian") ||
check_material(obj, "lead"))
return TRUE;
return FALSE;
}
int floating_time(OBJ_DATA *obj)
{
int ftime;
ftime = 0;
switch(obj->pIndexData->item_type)
{
default: break;
case ITEM_KEY : ftime = 1; break;
case ITEM_ARMOR : ftime = 2; break;
case ITEM_TREASURE : ftime = 2; break;
case ITEM_PILL : ftime = 2; break;
case ITEM_POTION : ftime = 3; break;
case ITEM_TRASH : ftime = 3; break;
case ITEM_FOOD : ftime = 4; break;
case ITEM_CONTAINER : ftime = 5; break;
case ITEM_CORPSE_NPC: ftime = 10; break;
case ITEM_CORPSE_PC : ftime = 10; break;
}
ftime = number_fuzzy(ftime) ;
return (ftime < 0 ? 0 : ftime);
}
/* for immunity, vulnerabiltiy, and resistant
the 'globals' (magic and weapons) may be overriden
three other cases -- wood, silver, and iron -- are checked in fight.c */
int check_immune(CHAR_DATA *ch, int dam_type)
{
int immune, def;
int bit;
immune = -1;
def = IS_NORMAL;
if (dam_type == DAM_NONE)
return immune;
if (dam_type <= 3)
{
if (IS_SET(ch->imm_flags,IMM_WEAPON))
def = IS_IMMUNE;
else if (IS_SET(ch->res_flags,RES_WEAPON))
def = IS_RESISTANT;
else if (IS_SET(ch->vuln_flags,VULN_WEAPON))
def = IS_VULNERABLE;
}
else /* magical attack */
{
if (IS_SET(ch->imm_flags,IMM_MAGIC))
def = IS_IMMUNE;
else if (IS_SET(ch->res_flags,RES_MAGIC))
def = IS_RESISTANT;
else if (IS_SET(ch->vuln_flags,VULN_MAGIC))
def = IS_VULNERABLE;
}
/* set bits to check -- VULN etc. must ALL be the same or this will fail */
switch (dam_type)
{
case(DAM_BASH): bit = IMM_BASH; break;
case(DAM_PIERCE): bit = IMM_PIERCE; break;
case(DAM_SLASH): bit = IMM_SLASH; break;
case(DAM_FIRE): bit = IMM_FIRE; break;
case(DAM_COLD): bit = IMM_COLD; break;
case(DAM_LIGHTNING): bit = IMM_LIGHTNING; break;
case(DAM_ACID): bit = IMM_ACID; break;
case(DAM_POISON): bit = IMM_POISON; break;
case(DAM_NEGATIVE): bit = IMM_NEGATIVE; break;
case(DAM_HOLY): bit = IMM_HOLY; break;
case(DAM_ENERGY): bit = IMM_ENERGY; break;
case(DAM_MENTAL):
if (IS_IMMORTAL(ch))
return IS_IMMUNE;
bit = IMM_MENTAL;
break;
case(DAM_DISEASE): bit = IMM_DISEASE; break;
case(DAM_DROWNING): bit = IMM_DROWNING; break;
case(DAM_LIGHT): bit = IMM_LIGHT; break;
case(DAM_CHARM):
if (IS_IMMORTAL(ch))
return IS_IMMUNE;
bit = IMM_CHARM;
break;
case(DAM_SOUND): bit = IMM_SOUND; break;
default: return def;
}
if (IS_SET(ch->imm_flags, bit))
immune = IS_IMMUNE;
else if (IS_SET(ch->res_flags, bit) && immune != IS_IMMUNE)
immune = IS_RESISTANT;
else if (IS_SET(ch->vuln_flags, bit)) {
if (immune == IS_IMMUNE)
immune = IS_RESISTANT;
else if (immune == IS_RESISTANT)
immune = IS_NORMAL;
else
immune = IS_VULNERABLE;
}
if (!IS_NPC(ch) && get_curr_stat(ch, STAT_CHA) < 18
&& dam_type == DAM_CHARM)
immune = IS_VULNERABLE;
if (immune == -1)
return def;
else
return immune;
}
void reset_obj_affects(CHAR_DATA *ch, OBJ_DATA *obj, AFFECT_DATA *af)
{
for (; af != NULL; af = af->next) {
int mod = af->modifier;
switch(af->location) {
case APPLY_MANA:
ch->max_mana -= mod;
break;
case APPLY_HIT:
ch->max_hit -= mod;
break;
case APPLY_MOVE:
ch->max_move -= mod;
break;
}
}
}
/* used to de-screw characters */
void reset_char(CHAR_DATA *ch)
{
int loc,mod,stat;
OBJ_DATA *obj;
AFFECT_DATA *af;
int i;
if (IS_NPC(ch))
return;
if (ch->pcdata->perm_hit == 0
|| ch->pcdata->perm_mana == 0
|| ch->pcdata->perm_move == 0
|| ch->pcdata->last_level == 0) {
/* do a FULL reset */
for (loc = 0; loc < MAX_WEAR; loc++) {
obj = get_eq_char(ch,loc);
if (obj == NULL)
continue;
if (!IS_SET(obj->extra_flags, ITEM_ENCHANTED))
reset_obj_affects(ch, obj,
obj->pIndexData->affected);
reset_obj_affects(ch, obj, obj->affected);
}
/* now reset the permanent stats */
ch->pcdata->perm_hit = ch->max_hit;
ch->pcdata->perm_mana = ch->max_mana;
ch->pcdata->perm_move = ch->max_move;
ch->pcdata->last_level = ch->played/3600;
if (ch->pcdata->true_sex < 0 || ch->pcdata->true_sex > 2)
if (ch->sex > 0 && ch->sex < 3)
ch->pcdata->true_sex = ch->sex;
else
ch->pcdata->true_sex = 0;
}
/* now restore the character to his/her true condition */
for (stat = 0; stat < MAX_STATS; stat++)
ch->mod_stat[stat] = 0;
if (ch->pcdata->true_sex < 0 || ch->pcdata->true_sex > 2)
ch->pcdata->true_sex = 0;
ch->sex = ch->pcdata->true_sex;
ch->max_hit = ch->pcdata->perm_hit;
ch->max_mana = ch->pcdata->perm_mana;
ch->max_move = ch->pcdata->perm_move;
for (i = 0; i < 4; i++)
ch->armor[i] = 100;
ch->hitroll = 0;
ch->damroll = 0;
ch->saving_throw = 0;
/* now start adding back the effects */
for (loc = 0; loc < MAX_WEAR; loc++)
{
obj = get_eq_char(ch,loc);
if (obj == NULL)
continue;
for (i = 0; i < 4; i++)
ch->armor[i] -= apply_ac(obj, loc, i);
if (!IS_SET(obj->extra_flags, ITEM_ENCHANTED))
for (af = obj->pIndexData->affected; af != NULL; af = af->next)
{
mod = af->modifier;
switch(af->location)
{
case APPLY_STR: ch->mod_stat[STAT_STR] += mod; break;
case APPLY_DEX: ch->mod_stat[STAT_DEX] += mod; break;
case APPLY_INT: ch->mod_stat[STAT_INT] += mod; break;
case APPLY_WIS: ch->mod_stat[STAT_WIS] += mod; break;
case APPLY_CON: ch->mod_stat[STAT_CON] += mod; break;
case APPLY_CHA: ch->mod_stat[STAT_CHA] += mod; break;
case APPLY_MANA: ch->max_mana += mod; break;
case APPLY_HIT: ch->max_hit += mod; break;
case APPLY_MOVE: ch->max_move += mod; break;
case APPLY_AGE: ch->played += age_to_num(mod); break;
case APPLY_AC:
for (i = 0; i < 4; i ++)
ch->armor[i] += mod;
break;
case APPLY_HITROLL: ch->hitroll += mod; break;
case APPLY_DAMROLL: ch->damroll += mod; break;
case APPLY_SIZE: ch->size += mod; break;
case APPLY_SAVES: ch->saving_throw += mod; break;
case APPLY_SAVING_ROD: ch->saving_throw += mod; break;
case APPLY_SAVING_PETRI: ch->saving_throw += mod; break;
case APPLY_SAVING_BREATH: ch->saving_throw += mod; break;
case APPLY_SAVING_SPELL: ch->saving_throw += mod; break;
}
}
for (af = obj->affected; af != NULL; af = af->next)
{
mod = af->modifier;
switch(af->location)
{
case APPLY_STR: ch->mod_stat[STAT_STR] += mod; break;
case APPLY_DEX: ch->mod_stat[STAT_DEX] += mod; break;
case APPLY_INT: ch->mod_stat[STAT_INT] += mod; break;
case APPLY_WIS: ch->mod_stat[STAT_WIS] += mod; break;
case APPLY_CON: ch->mod_stat[STAT_CON] += mod; break;
case APPLY_CHA: ch->mod_stat[STAT_CHA] += mod; break;
case APPLY_MANA: ch->max_mana += mod; break;
case APPLY_HIT: ch->max_hit += mod; break;
case APPLY_MOVE: ch->max_move += mod; break;
case APPLY_AGE: ch->played += age_to_num(mod); break;
case APPLY_AC:
for (i = 0; i < 4; i ++)
ch->armor[i] += mod;
break;
case APPLY_HITROLL: ch->hitroll += mod; break;
case APPLY_DAMROLL: ch->damroll += mod; break;
case APPLY_SIZE: ch->size += mod; break;
case APPLY_SAVES: ch->saving_throw += mod; break;
case APPLY_SAVING_ROD: ch->saving_throw += mod; break;
case APPLY_SAVING_PETRI: ch->saving_throw += mod; break;
case APPLY_SAVING_BREATH: ch->saving_throw += mod; break;
case APPLY_SAVING_SPELL: ch->saving_throw += mod; break;
}
}
}
/* now add back spell effects */
for (af = ch->affected; af != NULL; af = af->next)
{
mod = af->modifier;
switch(af->location)
{
case APPLY_STR: ch->mod_stat[STAT_STR] += mod; break;
case APPLY_DEX: ch->mod_stat[STAT_DEX] += mod; break;
case APPLY_INT: ch->mod_stat[STAT_INT] += mod; break;
case APPLY_WIS: ch->mod_stat[STAT_WIS] += mod; break;
case APPLY_CON: ch->mod_stat[STAT_CON] += mod; break;
case APPLY_CHA: ch->mod_stat[STAT_CHA] += mod; break;
case APPLY_MANA: ch->max_mana += mod; break;
case APPLY_HIT: ch->max_hit += mod; break;
case APPLY_MOVE: ch->max_move += mod; break;
case APPLY_AC:
for (i = 0; i < 4; i ++)
ch->armor[i] += mod;
break;
case APPLY_HITROLL: ch->hitroll += mod; break;
case APPLY_DAMROLL: ch->damroll += mod; break;
case APPLY_SIZE: ch->size += mod; break;
case APPLY_SAVES: ch->saving_throw += mod; break;
case APPLY_SAVING_ROD: ch->saving_throw += mod; break;
case APPLY_SAVING_PETRI: ch->saving_throw += mod; break;
case APPLY_SAVING_BREATH: ch->saving_throw += mod; break;
case APPLY_SAVING_SPELL: ch->saving_throw += mod; break;
}
}
/* make sure sex is RIGHT! */
if (ch->sex < 0 || ch->sex > 2)
ch->sex = ch->pcdata->true_sex;
}
/*
* Retrieve a character's age.
*/
int get_age(CHAR_DATA *ch)
{
return 17 + (ch->played + (int) (current_time - ch->logon)) / 72000;
}
int age_to_num(int age)
{
return age * 72000;
}
/*
* Retrieve a character's carry capacity.
*/
int can_carry_n(CHAR_DATA *ch)
{
if (IS_IMMORTAL(ch))
return 1000;
if (IS_NPC(ch) && IS_SET(ch->pIndexData->act, ACT_PET))
return 0;
return MAX_WEAR + get_curr_stat(ch,STAT_DEX) - 10 + ch->size;
}
/*
* Retrieve a character's carry capacity.
*/
int can_carry_w(CHAR_DATA *ch)
{
if (IS_IMMORTAL(ch))
return 10000000;
if (IS_NPC(ch) && IS_SET(ch->pIndexData->act, ACT_PET))
return 0;
return str_app[get_curr_stat(ch,STAT_STR)].carry * 10 + ch->level * 25;
}
/*
* See if a string is one of the names of an object.
*/
bool is_name_raw(const char *str, const char *namelist,
int (*cmpfun)(const char*, const char*))
{
char name[MAX_INPUT_LENGTH], part[MAX_INPUT_LENGTH];
const char *list, *string;
if (IS_NULLSTR(namelist) || IS_NULLSTR(str))
return FALSE;
if (!str_cmp(namelist, "all"))
return TRUE;
string = str;
/* we need ALL parts of string to match part of namelist */
for (; ;) { /* start parsing string */
str = one_argument(str, part);
if (part[0] == '\0')
return TRUE;
/* check to see if this is part of namelist */
list = namelist;
for (; ;) { /* start parsing namelist */
list = one_argument(list, name);
if (name[0] == '\0') /* this name was not found */
return FALSE;
if (!cmpfun(string, name))
return TRUE; /* full pattern match */
if (!cmpfun(part, name))
break;
}
}
}
bool is_name(const char *str, const char *namelist)
{
return is_name_raw(str, namelist, str_prefix);
}
void cat_name(char *buf, const char *name, size_t len)
{
bool have_spaces = strpbrk(name, " \t") != NULL;
if (buf[0])
strnzcat(buf, " ", len);
if (have_spaces)
strnzcat(buf, "'", len);
strnzcat(buf, name, len);
if (have_spaces)
strnzcat(buf, "'", len);
}
#define NE_F_DELETE (A) /* delete name if found */
#define NE_F_ADD (B) /* add name if not found */
void name_edit(CHAR_DATA *ch, const char *name,
const char *editor_name, const char **nl, int flags)
{
bool found;
const char *p;
char buf[MAX_STRING_LENGTH];
if (!str_cmp(name, "all")) {
free_string(*nl);
*nl = str_dup(name);
char_printf(ch, "%s: name list set to ALL.\n", editor_name);
return;
}
if (!str_cmp(name, "none")) {
free_string(*nl);
*nl = str_empty;
char_printf(ch, "%s: name list reset.\n", editor_name);
return;
}
if (!str_cmp(*nl, "all")) {
free_string(*nl);
*nl = str_empty;
}
found = FALSE;
p = *nl;
buf[0] = '\0';
for (;;) {
char arg[MAX_STRING_LENGTH];
p = one_argument(p, arg);
if (arg[0] == '\0')
break;
if (!str_cmp(name, arg)) {
found = TRUE;
if (IS_SET(flags, NE_F_DELETE))
continue;
}
cat_name(buf, arg, sizeof(buf));
}
if (!found) {
if (!IS_SET(flags, NE_F_ADD))
return;
if (strlen(buf) + strlen(name) + 4 > MAX_STRING_LENGTH) {
if (editor_name)
char_printf(ch, "%s: name list too long\n",
editor_name);
return;
}
cat_name(buf, name, sizeof(buf));
if (editor_name)
char_printf(ch, "%s: %s: name added.\n",
editor_name, name);
}
else {
if (!IS_SET(flags, NE_F_DELETE))
return;
if (editor_name)
char_printf(ch, "%s: %s: name removed.\n",
editor_name, name);
}
free_string(*nl);
*nl = str_dup(buf);
}
void name_add(CHAR_DATA *ch, const char *name,
const char *editor_name, const char **nl)
{
name_edit(ch, name, editor_name, nl, NE_F_ADD);
}
void name_delete(CHAR_DATA *ch, const char *name,
const char *editor_name, const char **nl)
{
name_edit(ch, name, editor_name, nl, NE_F_DELETE);
}
void name_toggle(CHAR_DATA *ch, const char *name,
const char *editor_name, const char **nl)
{
name_edit(ch, name, editor_name, nl, NE_F_ADD | NE_F_DELETE);
}
/* enchanted stuff for eq */
void affect_enchant(OBJ_DATA *obj)
{
/* okay, move all the old flags into new vectors if we have to */
if (!IS_SET(obj->extra_flags, ITEM_ENCHANTED)) {
AFFECT_DATA *paf, *af_new;
SET_BIT(obj->extra_flags, ITEM_ENCHANTED);
for (paf = obj->pIndexData->affected;
paf != NULL; paf = paf->next)
{
af_new = aff_new();
af_new->next = obj->affected;
obj->affected = af_new;
af_new->where = paf->where;
af_new->type = UMAX(0,paf->type);
af_new->level = paf->level;
af_new->duration = paf->duration;
af_new->location = paf->location;
af_new->modifier = paf->modifier;
af_new->bitvector = paf->bitvector;
}
}
}
/*
* Apply or remove an affect to a character.
*/
void affect_modify(CHAR_DATA *ch, AFFECT_DATA *paf, bool fAdd)
{
OBJ_DATA *wield, *obj2;
int mod, i;
mod = paf->modifier;
if (fAdd) {
switch (paf->where) {
case TO_AFFECTS:
SET_BIT(ch->affected_by, paf->bitvector);
break;
case TO_IMMUNE:
SET_BIT(ch->imm_flags, paf->bitvector);
break;
case TO_RESIST:
SET_BIT(ch->res_flags, paf->bitvector);
break;
case TO_VULN:
SET_BIT(ch->vuln_flags, paf->bitvector);
break;
}
}
else {
switch (paf->where) {
case TO_AFFECTS:
REMOVE_BIT(ch->affected_by, paf->bitvector);
break;
case TO_IMMUNE:
REMOVE_BIT(ch->imm_flags, paf->bitvector);
break;
case TO_RESIST:
REMOVE_BIT(ch->res_flags, paf->bitvector);
break;
case TO_VULN:
REMOVE_BIT(ch->vuln_flags, paf->bitvector);
break;
}
mod = 0 - mod;
}
switch (paf->location) {
default:
bug("Affect_modify: unknown location %d.", paf->location);
return;
case APPLY_NONE: break;
case APPLY_CLASS: break;
case APPLY_LEVEL: break;
case APPLY_HEIGHT: break;
case APPLY_WEIGHT: break;
case APPLY_GOLD: break;
case APPLY_EXP: break;
case APPLY_STR: ch->mod_stat[STAT_STR] += mod; break;
case APPLY_DEX: ch->mod_stat[STAT_DEX] += mod; break;
case APPLY_INT: ch->mod_stat[STAT_INT] += mod; break;
case APPLY_WIS: ch->mod_stat[STAT_WIS] += mod; break;
case APPLY_CON: ch->mod_stat[STAT_CON] += mod; break;
case APPLY_CHA: ch->mod_stat[STAT_CHA] += mod; break;
case APPLY_AGE: ch->played += age_to_num(mod); break;
case APPLY_MANA: ch->max_mana += mod; break;
case APPLY_HIT: ch->max_hit += mod; break;
case APPLY_MOVE: ch->max_move += mod; break;
case APPLY_AC:
for (i = 0; i < 4; i ++)
ch->armor[i] += mod;
break;
case APPLY_HITROLL: ch->hitroll += mod; break;
case APPLY_DAMROLL: ch->damroll += mod; break;
case APPLY_SIZE: ch->size += mod; break;
case APPLY_SAVES: ch->saving_throw += mod; break;
case APPLY_SAVING_ROD: ch->saving_throw += mod; break;
case APPLY_SAVING_PETRI: ch->saving_throw += mod; break;
case APPLY_SAVING_BREATH: ch->saving_throw += mod; break;
case APPLY_SAVING_SPELL: ch->saving_throw += mod; break;
case APPLY_SPELL_AFFECT: break;
case APPLY_RACE:
{
int from;
int to;
RACE_DATA *rto;
RACE_DATA *rfrom;
if (fAdd) {
from = ORG_RACE(ch);
to = ch->race = paf->modifier;
}
else {
from = ch->race;
to = ch->race = ORG_RACE(ch);
}
rfrom = race_lookup(from);
rto = race_lookup(to);
if (!rfrom || !rto || !rfrom->pcdata || !rto->pcdata)
return;
REMOVE_BIT(ch->affected_by, rfrom->aff);
SET_BIT(ch->affected_by, rto->aff);
affect_check(ch, TO_AFFECTS, rfrom->aff);
REMOVE_BIT(ch->imm_flags, rfrom->imm);
SET_BIT(ch->imm_flags, rto->imm);
affect_check(ch, TO_IMMUNE, rfrom->imm);
REMOVE_BIT(ch->res_flags, rfrom->res);
SET_BIT(ch->res_flags, rto->res);
affect_check(ch, TO_RESIST, rfrom->res);
REMOVE_BIT(ch->vuln_flags, rfrom->vuln);
SET_BIT(ch->vuln_flags, rto->vuln);
affect_check(ch, TO_VULN, rfrom->vuln);
ch->form = rto->form;
ch->parts = rto->parts;
ch->size = rto->pcdata->size;
update_skills(ch);
}
break;
}
/*
* Check for weapon wielding.
* Guard against recursion (for weapons with affects).
*/
if (!IS_NPC(ch) && (wield = get_eq_char(ch, WEAR_WIELD)) != NULL
&& get_obj_weight(wield) > (str_app[get_curr_stat(ch,STAT_STR)].wield*10))
{
static int depth;
if (depth == 0) {
depth++;
act("You drop $p.", ch, wield, NULL, TO_CHAR);
act("$n drops $p.", ch, wield, NULL, TO_ROOM);
obj_from_char(wield);
obj_to_room(wield, ch->in_room);
if ((obj2 = get_eq_char(ch, WEAR_SECOND_WIELD)) != NULL) {
act("You wield his second weapon as your first!", ch, NULL,NULL,TO_CHAR);
act("$n wields his second weapon as first!", ch, NULL,NULL,TO_ROOM);
unequip_char(ch, obj2);
equip_char(ch, obj2 , WEAR_WIELD);
}
depth--;
}
}
}
/* find an effect in an affect list */
AFFECT_DATA *affect_find(AFFECT_DATA *paf, int sn)
{
AFFECT_DATA *paf_find;
for (paf_find = paf; paf_find != NULL; paf_find = paf_find->next)
{
if (paf_find->type == sn)
return paf_find;
}
return NULL;
}
void affect_check_list(CHAR_DATA *ch, AFFECT_DATA *paf,
int where, flag_t vector)
{
for (; paf; paf = paf->next)
if ((where < 0 || paf->where == where)
&& (paf->bitvector & vector))
switch (paf->where) {
case TO_AFFECTS:
SET_BIT(ch->affected_by, paf->bitvector);
break;
case TO_IMMUNE:
SET_BIT(ch->imm_flags, paf->bitvector);
break;
case TO_RESIST:
SET_BIT(ch->res_flags, paf->bitvector);
break;
case TO_VULN:
SET_BIT(ch->vuln_flags, paf->bitvector);
break;
}
}
/* fix object affects when removing one */
void affect_check(CHAR_DATA *ch, int where, flag_t vector)
{
OBJ_DATA *obj;
if (where == TO_OBJECT || where == TO_WEAPON || vector == 0)
return;
affect_check_list(ch, ch->affected, where, vector);
for (obj = ch->carrying; obj != NULL; obj = obj->next_content) {
if (obj->wear_loc == -1 || obj->wear_loc == WEAR_STUCK_IN)
continue;
affect_check_list(ch, obj->affected, where, vector);
if (IS_SET(obj->extra_flags, ITEM_ENCHANTED))
continue;
affect_check_list(ch, obj->pIndexData->affected, where, vector);
}
}
/*
* Give an affect to a char.
*/
void affect_to_char(CHAR_DATA *ch, AFFECT_DATA *paf)
{
AFFECT_DATA *paf_new;
paf_new = aff_new();
*paf_new = *paf;
paf_new->next = ch->affected;
ch->affected = paf_new;
affect_modify(ch, paf_new, TRUE);
}
/* give an affect to an object */
void affect_to_obj(OBJ_DATA *obj, AFFECT_DATA *paf)
{
AFFECT_DATA *paf_new;
paf_new = aff_new();
*paf_new = *paf;
paf_new->next = obj->affected;
obj->affected = paf_new;
/* apply any affect vectors to the object's extra_flags */
if (paf->bitvector)
switch (paf->where) {
case TO_OBJECT:
SET_BIT(obj->extra_flags,paf->bitvector);
break;
case TO_WEAPON:
if (obj->pIndexData->item_type == ITEM_WEAPON)
SET_BIT(obj->value[4],paf->bitvector);
break;
}
}
/*
* Remove an affect from a char.
*/
void affect_remove(CHAR_DATA *ch, AFFECT_DATA *paf)
{
int where;
int vector;
if (ch->affected == NULL) {
bug("Affect_remove: no affect.", 0);
return;
}
affect_modify(ch, paf, FALSE);
where = paf->where;
vector = paf->bitvector;
if (paf == ch->affected)
ch->affected = paf->next;
else {
AFFECT_DATA *prev;
for (prev = ch->affected; prev; prev = prev->next) {
if (prev->next == paf) {
prev->next = paf->next;
break;
}
}
if (prev == NULL) {
bug("Affect_remove: cannot find paf.", 0);
return;
}
}
aff_free(paf);
affect_check(ch, where, vector);
}
void affect_remove_obj(OBJ_DATA *obj, AFFECT_DATA *paf)
{
int where, vector;
if (obj->affected == NULL)
return;
if (obj->carried_by != NULL && obj->wear_loc != -1)
affect_modify(obj->carried_by, paf, FALSE);
where = paf->where;
vector = paf->bitvector;
/* remove flags from the object if needed */
if (paf->bitvector)
switch(paf->where) {
case TO_OBJECT:
REMOVE_BIT(obj->extra_flags,paf->bitvector);
break;
case TO_WEAPON:
if (obj->pIndexData->item_type == ITEM_WEAPON)
REMOVE_BIT(obj->value[4],paf->bitvector);
break;
}
if (paf == obj->affected)
obj->affected = paf->next;
else
{
AFFECT_DATA *prev;
for (prev = obj->affected; prev != NULL; prev = prev->next)
{
if (prev->next == paf)
{
prev->next = paf->next;
break;
}
}
if (prev == NULL)
{
bug("Affect_remove_object: cannot find paf.", 0);
return;
}
}
aff_free(paf);
if (obj->carried_by != NULL && obj->wear_loc != -1)
affect_check(obj->carried_by,where,vector);
}
/*
* Strip all affects of a given sn.
*/
void affect_strip(CHAR_DATA *ch, int sn)
{
AFFECT_DATA *paf;
AFFECT_DATA *paf_next;
for (paf = ch->affected; paf; paf = paf_next) {
paf_next = paf->next;
if (paf->type == sn)
affect_remove(ch, paf);
}
}
/*
* strip all affects which affect given bitvector
*/
void affect_bit_strip(CHAR_DATA *ch, int where, flag_t bits)
{
AFFECT_DATA *paf;
AFFECT_DATA *paf_next;
for (paf = ch->affected; paf; paf = paf_next) {
paf_next = paf->next;
if (paf->where == where && (paf->bitvector & bits))
affect_remove(ch, paf);
}
}
/*
* Return true if a char is affected by a spell.
*/
bool is_affected(CHAR_DATA *ch, int sn)
{
AFFECT_DATA *paf;
for (paf = ch->affected; paf; paf = paf->next)
if (paf->type == sn)
return TRUE;
return FALSE;
}
bool is_bit_affected(CHAR_DATA *ch, int where, flag_t bits)
{
AFFECT_DATA *paf;
for (paf = ch->affected; paf; paf = paf->next)
if (paf->where == where && (paf->bitvector & bits))
return TRUE;
return FALSE;
}
bool has_obj_affect(CHAR_DATA *ch, int vector)
{
OBJ_DATA *obj;
for (obj = ch->carrying; obj; obj = obj->next_content) {
AFFECT_DATA *paf;
if (obj->wear_loc == -1 || obj->wear_loc == WEAR_STUCK_IN)
continue;
for (paf = obj->affected; paf; paf = paf->next)
if (paf->bitvector & vector)
return TRUE;
if (IS_SET(obj->extra_flags, ITEM_ENCHANTED))
continue;
for (paf = obj->pIndexData->affected; paf; paf = paf->next)
if (paf->bitvector & vector)
return TRUE;
}
return FALSE;
}
/*
* Add or enhance an affect.
*/
void affect_join(CHAR_DATA *ch, AFFECT_DATA *paf)
{
AFFECT_DATA *paf_old;
bool found;
found = FALSE;
for (paf_old = ch->affected; paf_old != NULL; paf_old = paf_old->next)
{
if (paf_old->type == paf->type)
{
paf->level = (paf->level += paf_old->level) / 2;
paf->duration += paf_old->duration;
paf->modifier += paf_old->modifier;
affect_remove(ch, paf_old);
break;
}
}
affect_to_char(ch, paf);
return;
}
/*
* Move a char out of a room.
*/
void char_from_room(CHAR_DATA *ch)
{
OBJ_DATA *obj;
ROOM_INDEX_DATA *prev_room = ch->in_room;
if (ch->in_room == NULL)
{
bug("Char_from_room: NULL.", 0);
return;
}
if (!IS_NPC(ch))
--ch->in_room->area->nplayer;
if ((obj = get_eq_char(ch, WEAR_LIGHT)) != NULL
&& obj->pIndexData->item_type == ITEM_LIGHT
&& obj->value[2] != 0
&& ch->in_room->light > 0)
--ch->in_room->light;
if (ch == ch->in_room->people)
ch->in_room->people = ch->next_in_room;
else
{
CHAR_DATA *prev;
for (prev = ch->in_room->people; prev; prev = prev->next_in_room)
{
if (prev->next_in_room == ch)
{
prev->next_in_room = ch->next_in_room;
break;
}
}
if (prev == NULL)
bug("Char_from_room: ch not found.", 0);
}
ch->in_room = NULL;
ch->next_in_room = NULL;
ch->on = NULL; /* sanity check! */
if (MOUNTED(ch))
{
ch->mount->riding = FALSE;
ch->riding = FALSE;
}
if (RIDDEN(ch))
{
ch->mount->riding = FALSE;
ch->riding = FALSE;
}
if (prev_room && prev_room->affected_by)
raffect_back_char(prev_room, ch);
return;
}
/*
* Move a char into a room.
*/
void char_to_room(CHAR_DATA *ch, ROOM_INDEX_DATA *pRoomIndex)
{
OBJ_DATA *obj;
if (pRoomIndex == NULL)
{
ROOM_INDEX_DATA *room;
bug("Char_to_room: NULL.", 0);
if ((room = get_room_index(ROOM_VNUM_TEMPLE)) != NULL)
char_to_room(ch,room);
return;
}
ch->in_room = pRoomIndex;
ch->next_in_room = pRoomIndex->people;
pRoomIndex->people = ch;
if (!IS_NPC(ch))
{
if (ch->in_room->area->empty)
{
ch->in_room->area->empty = FALSE;
ch->in_room->area->age = 0;
}
++ch->in_room->area->nplayer;
}
if ((obj = get_eq_char(ch, WEAR_LIGHT)) != NULL
&& obj->pIndexData->item_type == ITEM_LIGHT
&& obj->value[2] != 0)
++ch->in_room->light;
while (IS_AFFECTED(ch,AFF_PLAGUE))
{
AFFECT_DATA *af, plague;
CHAR_DATA *vch;
for (af = ch->affected; af != NULL; af = af->next)
{
if (af->type == gsn_plague)
break;
}
if (af == NULL)
{
REMOVE_BIT(ch->affected_by,AFF_PLAGUE);
break;
}
if (af->level == 1)
break;
plague.where = TO_AFFECTS;
plague.type = gsn_plague;
plague.level = af->level - 1;
plague.duration = number_range(1,2 * plague.level);
plague.location = APPLY_STR;
plague.modifier = -5;
plague.bitvector = AFF_PLAGUE;
for (vch = ch->in_room->people; vch != NULL; vch = vch->next_in_room)
{
if (!saves_spell(plague.level - 2,vch,DAM_DISEASE)
&& !IS_IMMORTAL(vch) &&
!IS_AFFECTED(vch,AFF_PLAGUE) && number_bits(6) == 0)
{
char_puts("You feel hot and feverish.\n",vch);
act("$n shivers and looks very ill.",vch,NULL,NULL,TO_ROOM);
affect_join(vch,&plague);
}
}
break;
}
if (ch->in_room->affected_by) {
if (IS_IMMORTAL(ch))
do_raffects(ch,str_empty);
else
raffect_to_char(ch->in_room, ch);
}
}
/*
* Give an obj to a char.
*/
void obj_to_char(OBJ_DATA *obj, CHAR_DATA *ch)
{
obj->next_content = ch->carrying;
ch->carrying = obj;
obj->carried_by = ch;
obj->in_room = NULL;
obj->in_obj = NULL;
ch->carry_number += get_obj_number(obj);
ch->carry_weight += get_obj_weight(obj);
}
/*
* Take an obj from its character.
*/
void obj_from_char(OBJ_DATA *obj)
{
CHAR_DATA *ch;
if ((ch = obj->carried_by) == NULL) {
bug("Obj_from_char: null ch.", 0);
return;
}
if (obj->wear_loc != WEAR_NONE)
unequip_char(ch, obj);
if (ch->carrying == obj)
ch->carrying = obj->next_content;
else {
OBJ_DATA *prev;
for (prev = ch->carrying; prev; prev = prev->next_content) {
if (prev->next_content == obj) {
prev->next_content = obj->next_content;
break;
}
}
if (prev == NULL)
bug("Obj_from_char: obj not in list.", 0);
}
obj->carried_by = NULL;
obj->next_content = NULL;
ch->carry_number -= get_obj_number(obj);
ch->carry_weight -= get_obj_weight(obj);
/* XXX */
if (!IS_NPC(ch)) {
int vnum = obj->pIndexData->vnum;
const char *p = mlstr_mval(obj->short_descr);
if (p && strstr(p, ch->name)
&& ch->level < obj->pIndexData->level
&& IS_SET(obj->pIndexData->extra_flags, ITEM_QUEST)) {
ch->pcdata->questpoints += 1000;
qtrouble_set(ch, vnum, 4);
}
}
}
/*
* Find the ac value of an obj, including position effect.
*/
int apply_ac(OBJ_DATA *obj, int iWear, int type)
{
if (obj->pIndexData->item_type != ITEM_ARMOR)
return 0;
switch (iWear) {
case WEAR_BODY: return 3 * obj->value[type];
case WEAR_HEAD: return 2 * obj->value[type];
case WEAR_LEGS: return 2 * obj->value[type];
case WEAR_FEET: return obj->value[type];
case WEAR_HANDS: return obj->value[type];
case WEAR_ARMS: return obj->value[type];
case WEAR_SHIELD: return obj->value[type];
case WEAR_FINGER_L: return 0;
case WEAR_FINGER_R: return obj->value[type];
case WEAR_NECK_1: return obj->value[type];
case WEAR_NECK_2: return obj->value[type];
case WEAR_ABOUT: return 2 * obj->value[type];
case WEAR_WAIST: return obj->value[type];
case WEAR_WRIST_L: return obj->value[type];
case WEAR_WRIST_R: return obj->value[type];
case WEAR_HOLD: return obj->value[type];
}
return 0;
}
/*
* Find a piece of eq on a character.
*/
OBJ_DATA *get_eq_char(CHAR_DATA *ch, int iWear)
{
OBJ_DATA *obj;
if (ch == NULL)
return NULL;
for (obj = ch->carrying; obj != NULL; obj = obj->next_content)
if (obj->wear_loc == iWear)
return obj;
return NULL;
}
/*
* Equip a char with an obj. Return obj on success. Otherwise returns NULL.
*/
OBJ_DATA * equip_char(CHAR_DATA *ch, OBJ_DATA *obj, int iWear)
{
AFFECT_DATA *paf;
int i;
if (iWear == WEAR_STUCK_IN) {
obj->wear_loc = iWear;
return obj;
}
if (get_eq_char(ch, iWear)) {
bug("Equip_char: already equipped (%d).", iWear);
return NULL;
}
if ((IS_OBJ_STAT(obj, ITEM_ANTI_EVIL) && IS_EVIL(ch) )
|| (IS_OBJ_STAT(obj, ITEM_ANTI_GOOD) && IS_GOOD(ch) )
|| (IS_OBJ_STAT(obj, ITEM_ANTI_NEUTRAL) && IS_NEUTRAL(ch))) {
/*
* Thanks to Morgenes for the bug fix here!
*/
act("You are zapped by $p and drop it.", ch, obj, NULL, TO_CHAR);
act("$n is zapped by $p and drops it.", ch, obj, NULL, TO_ROOM);
obj_from_char(obj);
obj_to_room(obj, ch->in_room);
return NULL;
}
for (i = 0; i < 4; i++)
ch->armor[i] -= apply_ac(obj, iWear,i);
obj->wear_loc = iWear;
if (!IS_SET(obj->extra_flags, ITEM_ENCHANTED))
for (paf = obj->pIndexData->affected; paf; paf = paf->next)
if (paf->location != APPLY_SPELL_AFFECT)
affect_modify(ch, paf, TRUE);
for (paf = obj->affected; paf; paf = paf->next)
if (paf->location == APPLY_SPELL_AFFECT)
affect_to_char(ch, paf);
else
affect_modify(ch, paf, TRUE);
if (obj->pIndexData->item_type == ITEM_LIGHT
&& obj->value[2] != 0
&& ch->in_room != NULL)
++ch->in_room->light;
oprog_call(OPROG_WEAR, obj, ch, NULL);
return obj;
}
void strip_obj_affects(CHAR_DATA *ch, OBJ_DATA *obj, AFFECT_DATA *paf)
{
AFFECT_DATA *lpaf_next = NULL;
AFFECT_DATA *lpaf = NULL;
for (; paf != NULL; paf = paf->next) {
if (paf->location == APPLY_SPELL_AFFECT) {
for (lpaf = ch->affected; lpaf != NULL; lpaf = lpaf_next) {
lpaf_next = lpaf->next;
if ((lpaf->type == paf->type)
&& (lpaf->level == paf->level)
&& (lpaf->location == APPLY_SPELL_AFFECT)) {
affect_remove(ch, lpaf);
lpaf_next = NULL;
}
}
}
else {
affect_modify(ch, paf, FALSE);
affect_check(ch,paf->where,paf->bitvector);
}
}
}
/*
* Unequip a char with an obj.
*/
void unequip_char(CHAR_DATA *ch, OBJ_DATA *obj)
{
int i;
if (obj->wear_loc == WEAR_NONE) {
bug("Unequip_char: already unequipped.", 0);
return;
}
if (obj->wear_loc == WEAR_STUCK_IN) {
obj->wear_loc = WEAR_NONE;
return;
}
for (i = 0; i < 4; i++)
ch->armor[i] += apply_ac(obj, obj->wear_loc,i);
obj->wear_loc = -1;
if (!IS_SET(obj->extra_flags, ITEM_ENCHANTED))
strip_obj_affects(ch, obj, obj->pIndexData->affected);
strip_obj_affects(ch, obj, obj->affected);
if (obj->pIndexData->item_type == ITEM_LIGHT
&& obj->value[2] != 0
&& ch->in_room != NULL
&& ch->in_room->light > 0)
--ch->in_room->light;
oprog_call(OPROG_REMOVE, obj, ch, NULL);
}
/*
* Count occurrences of an obj in a list.
*/
int count_obj_list(OBJ_INDEX_DATA *pObjIndex, OBJ_DATA *list)
{
OBJ_DATA *obj;
int nMatch;
nMatch = 0;
for (obj = list; obj != NULL; obj = obj->next_content)
{
if (obj->pIndexData == pObjIndex)
nMatch++;
}
return nMatch;
}
/*
* Move an obj out of a room.
*/
void obj_from_room(OBJ_DATA *obj)
{
ROOM_INDEX_DATA *in_room;
CHAR_DATA *ch;
if ((in_room = obj->in_room) == NULL) {
bug("obj_from_room: NULL.", 0);
return;
}
for (ch = in_room->people; ch != NULL; ch = ch->next_in_room)
if (ch->on == obj)
ch->on = NULL;
if (obj == in_room->contents)
in_room->contents = obj->next_content;
else {
OBJ_DATA *prev;
for (prev = in_room->contents; prev; prev = prev->next_content) {
if (prev->next_content == obj) {
prev->next_content = obj->next_content;
break;
}
}
if (prev == NULL) {
bug("Obj_from_room: obj not found.", 0);
return;
}
}
obj->in_room = NULL;
obj->next_content = NULL;
return;
}
/*
* Move an obj into a room.
*/
void obj_to_room(OBJ_DATA *obj, ROOM_INDEX_DATA *pRoomIndex)
{
obj->next_content = pRoomIndex->contents;
pRoomIndex->contents = obj;
obj->in_room = pRoomIndex;
obj->carried_by = NULL;
obj->in_obj = NULL;
if (IS_WATER(pRoomIndex))
if (may_float(obj))
obj->water_float = -1;
else
obj->water_float = floating_time(obj);
}
/*
* Move an object into an object.
*/
void obj_to_obj(OBJ_DATA *obj, OBJ_DATA *obj_to)
{
if (obj == obj_to) {
log_printf("obj_to_obj: obj == obj_to (vnum %d)",
obj->pIndexData->vnum);
return;
}
obj->next_content = obj_to->contains;
obj_to->contains = obj;
obj->in_obj = obj_to;
obj->in_room = NULL;
obj->carried_by = NULL;
if (obj_is_pit(obj_to))
obj->cost = 0;
for (; obj_to != NULL; obj_to = obj_to->in_obj) {
if (obj_to->carried_by != NULL)
{
/* obj_to->carried_by->carry_number += get_obj_number(obj); */
obj_to->carried_by->carry_weight += get_obj_weight(obj)
* WEIGHT_MULT(obj_to) / 100;
}
}
}
/*
* Move an object out of an object.
*/
void obj_from_obj(OBJ_DATA *obj)
{
OBJ_DATA *obj_from;
if ((obj_from = obj->in_obj) == NULL) {
bug("Obj_from_obj: null obj_from.", 0);
return;
}
if (obj == obj_from->contains)
obj_from->contains = obj->next_content;
else {
OBJ_DATA *prev;
for (prev = obj_from->contains; prev; prev = prev->next_content) {
if (prev->next_content == obj) {
prev->next_content = obj->next_content;
break;
}
}
if (prev == NULL) {
bug("Obj_from_obj: obj not found.", 0);
return;
}
}
obj->next_content = NULL;
obj->in_obj = NULL;
for (; obj_from != NULL; obj_from = obj_from->in_obj) {
if (obj_from->carried_by != NULL)
/* obj_from->carried_by->carry_number -= get_obj_number(obj); */
obj_from->carried_by->carry_weight -= get_obj_weight(obj) * WEIGHT_MULT(obj_from) / 100;
}
}
/*
* Extract an obj from the world.
*/
void extract_obj_raw(OBJ_DATA *obj, int flags)
{
OBJ_DATA *obj_content;
OBJ_DATA *obj_next;
if (obj->extracted) {
log_printf("extract_obj_raw: %s, vnum %d: already extracted",
obj->name, obj->pIndexData->vnum);
return;
}
else
obj->extracted = TRUE;
for (obj_content = obj->contains; obj_content; obj_content = obj_next) {
obj_next = obj_content->next_content;
if (!IS_SET(flags, X_F_NORECURSE)) {
extract_obj_raw(obj_content, flags);
continue;
}
obj_from_obj(obj_content);
if (obj->in_room)
obj_to_room(obj_content, obj->in_room);
else if (obj->carried_by)
obj_to_char(obj_content, obj->carried_by);
else if (obj->in_obj)
obj_to_obj(obj_content, obj->in_obj);
else
extract_obj(obj_content);
}
if (obj->in_room)
obj_from_room(obj);
else if (obj->carried_by)
obj_from_char(obj);
else if (obj->in_obj)
obj_from_obj(obj);
if (obj->pIndexData->vnum == OBJ_VNUM_MAGIC_JAR) {
CHAR_DATA *wch;
for (wch = char_list; wch != NULL ; wch = wch->next) {
if (IS_NPC(wch)) continue;
if (is_name(obj->name, wch->name)) {
REMOVE_BIT(wch->plr_flags, PLR_NOEXP);
char_puts("Now you catch your spirit.\n", wch);
break;
}
}
}
if (object_list == obj)
object_list = obj->next;
else {
OBJ_DATA *prev;
for (prev = object_list; prev != NULL; prev = prev->next)
{
if (prev->next == obj)
{
prev->next = obj->next;
break;
}
}
if (prev == NULL)
{
bug("Extract_obj: obj %d not found.", obj->pIndexData->vnum);
return;
}
}
if (!IS_SET(flags, X_F_NOCOUNT))
--obj->pIndexData->count;
free_obj(obj);
}
void extract_char(CHAR_DATA *ch, bool fPull)
{
extract_char_org(ch, fPull, TRUE);
return;
}
void extract_char_nocount(CHAR_DATA *ch, bool fPull)
{
extract_char_org(ch, fPull, FALSE);
return;
}
/*
* Extract a char from the world.
*/
void extract_char_org(CHAR_DATA *ch, bool fPull, bool Count)
{
CHAR_DATA *wch;
OBJ_DATA *obj;
OBJ_DATA *obj_next;
OBJ_DATA *wield;
int i;
char buf[MAX_STRING_LENGTH];
if (fPull) /* only for total extractions should it check */
{
if (ch->extracted) /* if the char has already been extracted once */
{
sprintf(buf, "Warning! Extraction of %s.", ch->name);
bug(buf, 0);
return; /* if it's already been extracted, something bad is going on */
}
else
ch->extracted = TRUE; /* if it hasn't been extracted yet, now
* it's being extracted. */
}
if (ch->in_room == NULL)
{
bug("Extract_char: NULL.", 0);
return;
}
nuke_pets(ch);
ch->pet = NULL; /* just in case */
if (fPull)
die_follower(ch);
stop_fighting(ch, TRUE);
if ((wield = get_eq_char(ch, WEAR_WIELD)) != NULL)
unequip_char(ch, wield);
for (obj = ch->carrying; obj != NULL; obj = obj_next)
{
obj_next = obj->next_content;
if (Count)
extract_obj(obj);
else
extract_obj_nocount(obj);
}
char_from_room(ch);
if (!fPull)
{
if (IS_GOOD(ch))
i = 0;
if (IS_EVIL(ch))
i = 2;
else
i = 1;
char_to_room(ch, get_room_index(hometown_table[ch->hometown].altar[i]));
return;
}
if (IS_NPC(ch))
--ch->pIndexData->count;
if (ch->desc != NULL && ch->desc->original != NULL) {
do_return(ch, str_empty);
ch->desc = NULL;
}
for (wch = char_list; wch != NULL; wch = wch->next) {
if (wch->reply == ch)
wch->reply = NULL;
if (ch->mprog_target == wch)
wch->mprog_target = NULL;
}
if (ch == char_list)
char_list = ch->next;
else {
CHAR_DATA *prev;
for (prev = char_list; prev != NULL; prev = prev->next)
{
if (prev->next == ch)
{
prev->next = ch->next;
break;
}
}
if (prev == NULL)
{
bug("Extract_char: char not found.", 0);
return;
}
}
if (ch->desc != NULL)
ch->desc->character = NULL;
free_char(ch);
}
/*
* Find a char in the room.
*/
CHAR_DATA *get_char_room(CHAR_DATA *ch, const char *argument)
{
char arg[MAX_INPUT_LENGTH];
CHAR_DATA *rch;
int number;
int count;
bool ugly = FALSE;
if (IS_NULLSTR(argument))
return NULL;
number = number_argument(argument, arg);
count = 0;
if (!str_cmp(arg, "self"))
return ch;
if (!str_cmp(arg, "ugly"))
ugly = TRUE;
for (rch = ch->in_room->people; rch; rch = rch->next_in_room) {
CHAR_DATA *vch;
if (!can_see(ch, rch))
continue;
if (ugly && (count + 1) == number
&& is_affected(rch, gsn_vampire))
return rch;
vch = (is_affected(rch, gsn_doppelganger) &&
(IS_NPC(ch) || !IS_SET(ch->plr_flags, PLR_HOLYLIGHT))) ?
rch->doppel : rch;
if (!is_name(arg, vch->name))
continue;
if (++count == number)
return rch;
}
return NULL;
}
/*
* Find a char in the room.
* Chronos uses in act_move.c
*/
CHAR_DATA *get_char_room2(CHAR_DATA *ch, ROOM_INDEX_DATA *room, const char *argument, int *number)
{
CHAR_DATA *rch;
int count;
bool ugly = FALSE;
if (IS_NULLSTR(argument))
return NULL;
if (room == NULL) return NULL;
count = 0;
if (!str_cmp(argument, "ugly"))
ugly = TRUE;
for (rch = room->people; rch != NULL; rch = rch->next_in_room) {
CHAR_DATA *vch;
if (!can_see(ch, rch))
continue;
if (ugly && (count + 1) == *number
&& is_affected(rch, gsn_vampire))
return rch;
vch = (is_affected(rch, gsn_doppelganger) &&
(IS_NPC(ch) || !IS_SET(ch->plr_flags, PLR_HOLYLIGHT))) ?
rch->doppel : rch;
if (!is_name(argument, vch->name))
continue;
if (++count == *number)
return rch;
}
number -= count;
return NULL;
}
/*
* Find a char in the world.
*/
CHAR_DATA *get_char_world(CHAR_DATA *ch, const char *argument)
{
char arg[MAX_INPUT_LENGTH];
CHAR_DATA *wch;
int number;
int count;
if (IS_NULLSTR(argument))
return NULL;
if ((wch = get_char_room(ch, argument)) != NULL)
return wch;
number = number_argument(argument, arg);
count = 0;
for (wch = char_list; wch != NULL ; wch = wch->next)
{
if (wch->in_room == NULL || !can_see(ch, wch)
|| !is_name(arg, wch->name))
continue;
if (++count == number)
return wch;
}
return NULL;
}
/*
* Find some object with a given index data.
* Used by area-reset 'P' command.
*/
OBJ_DATA *get_obj_type(OBJ_INDEX_DATA *pObjIndex)
{
OBJ_DATA *obj;
for (obj = object_list; obj != NULL; obj = obj->next)
{
if (obj->pIndexData == pObjIndex)
return obj;
}
return NULL;
}
/*
* Find an obj in a list.
*/
OBJ_DATA *get_obj_list(CHAR_DATA *ch, const char *argument, OBJ_DATA *list)
{
char arg[MAX_INPUT_LENGTH];
OBJ_DATA *obj;
int number;
int count;
if (IS_NULLSTR(argument))
return NULL;
number = number_argument(argument, arg);
count = 0;
for (obj = list; obj; obj = obj->next_content)
if (can_see_obj(ch, obj) && is_name(arg, obj->name))
if (++count == number)
return obj;
return NULL;
}
/*
* Find an obj in player's inventory.
*/
OBJ_DATA *get_obj_carry(CHAR_DATA *ch, const char *argument)
{
char arg[MAX_INPUT_LENGTH];
OBJ_DATA *obj;
int number;
int count;
if (IS_NULLSTR(argument))
return NULL;
number = number_argument(argument, arg);
count = 0;
for (obj = ch->carrying; obj; obj = obj->next_content)
if (obj->wear_loc == WEAR_NONE
&& can_see_obj(ch, obj)
&& is_name(arg, obj->name)
&& ++count == number)
return obj;
return NULL;
}
/*
* Find an obj in player's equipment.
*/
OBJ_DATA *get_obj_wear(CHAR_DATA *ch, const char *argument)
{
char arg[MAX_INPUT_LENGTH];
OBJ_DATA *obj;
int number;
int count;
if (IS_NULLSTR(argument))
return NULL;
number = number_argument(argument, arg);
count = 0;
for (obj = ch->carrying; obj; obj = obj->next_content)
if (obj->wear_loc != WEAR_NONE
&& can_see_obj(ch, obj)
&& is_name(arg, obj->name)
&& ++count == number)
return obj;
return NULL;
}
/*
* Find an obj in the room or in inventory.
*/
OBJ_DATA *get_obj_here(CHAR_DATA *ch, const char *argument)
{
OBJ_DATA *obj;
if (IS_NULLSTR(argument))
return NULL;
obj = get_obj_list(ch, argument, ch->in_room->contents);
if (obj)
return obj;
if ((obj = get_obj_carry(ch, argument)))
return obj;
if ((obj = get_obj_wear(ch, argument)))
return obj;
return NULL;
}
OBJ_DATA *get_obj_room(CHAR_DATA *ch, const char *argument)
{
OBJ_DATA *obj;
CHAR_DATA *vch;
if (IS_NULLSTR(argument))
return NULL;
if ((obj = get_obj_here(ch, argument)))
return obj;
for (vch = ch->in_room->people; vch; vch = vch->next_in_room) {
if ((obj = get_obj_carry(vch, argument)))
return obj;
if ((obj = get_obj_wear(vch, argument)))
return obj;
}
return NULL;
}
/*
* Find an obj in the world.
*/
OBJ_DATA *get_obj_world(CHAR_DATA *ch, const char *argument)
{
char arg[MAX_INPUT_LENGTH];
OBJ_DATA *obj;
int number;
int count;
if (IS_NULLSTR(argument))
return NULL;
if ((obj = get_obj_here(ch, argument)) != NULL)
return obj;
number = number_argument(argument, arg);
count = 0;
for (obj = object_list; obj; obj = obj->next)
if (can_see_obj(ch, obj)
&& is_name(arg, obj->name)
&& ++count == number)
return obj;
return NULL;
}
/* deduct cost from a character */
void deduct_cost(CHAR_DATA *ch, uint cost)
{
uint silver = 0, gold = 0;
silver = UMIN(ch->silver, cost);
if (silver < cost) {
gold = ((cost - silver + 99) / 100);
silver = cost - 100 * gold;
}
if (ch->gold < gold) {
log_printf("deduct cost: %s: ch->gold (%d) < gold (%d)",
ch->name, ch->gold, gold);
ch->gold = gold;
}
if (ch->silver < silver) {
log_printf("deduct cost: %s: ch->silver (%d) < silver (%d)",
ch->name, ch->silver, silver);
ch->silver = silver;
}
ch->gold -= gold;
ch->silver -= silver;
}
/*
* Create a 'money' obj.
*/
OBJ_DATA *create_money(int gold, int silver)
{
OBJ_DATA *obj;
if (gold < 0 || silver < 0 || (gold == 0 && silver == 0))
{
bug("Create_money: zero or negative money.",UMIN(gold,silver));
gold = UMAX(1,gold);
silver = UMAX(1,silver);
}
if (gold == 0 && silver == 1)
{
obj = create_obj(get_obj_index(OBJ_VNUM_SILVER_ONE), 0);
}
else if (gold == 1 && silver == 0)
{
obj = create_obj(get_obj_index(OBJ_VNUM_GOLD_ONE), 0);
}
else if (silver == 0)
{
obj = create_obj(get_obj_index(OBJ_VNUM_GOLD_SOME), 0);
obj->short_descr = mlstr_printf(obj->pIndexData->short_descr, gold);
obj->value[1] = gold;
obj->cost = gold;
obj->weight = gold/5;
}
else if (gold == 0)
{
obj = create_obj(get_obj_index(OBJ_VNUM_SILVER_SOME), 0);
obj->short_descr = mlstr_printf(obj->pIndexData->short_descr, silver);
obj->value[0] = silver;
obj->cost = silver;
obj->weight = silver/20;
}
else
{
obj = create_obj(get_obj_index(OBJ_VNUM_COINS), 0);
obj->short_descr = mlstr_printf(obj->pIndexData->short_descr, silver, gold);
obj->value[0] = silver;
obj->value[1] = gold;
obj->cost = 100 * gold + silver;
obj->weight = gold / 5 + silver / 20;
}
return obj;
}
/*
* Return # of objects which an object counts as.
* Thanks to Tony Chamberlain for the correct recursive code here.
*/
int get_obj_number(OBJ_DATA *obj)
{
int number;
/*
if (obj->pIndexData->item_type == ITEM_CONTAINER || obj->pIndexData->item_type == ITEM_MONEY
|| obj->pIndexData->item_type == ITEM_GEM || obj->pIndexData->item_type == ITEM_JEWELRY)
number = 0;
*/
if (obj->pIndexData->item_type == ITEM_MONEY)
number = 0;
else
number = 1;
/*
for (obj = obj->contains; obj != NULL; obj = obj->next_content)
number += get_obj_number(obj);
*/
return number;
}
int get_obj_realnumber(OBJ_DATA *obj)
{
int number = 1;
for (obj = obj->contains; obj != NULL; obj = obj->next_content)
number += get_obj_number(obj);
return number;
}
/*
* Return weight of an object, including weight of contents.
*/
int get_obj_weight(OBJ_DATA *obj)
{
int weight;
OBJ_DATA *tobj;
weight = obj->weight;
for (tobj = obj->contains; tobj != NULL; tobj = tobj->next_content)
weight += get_obj_weight(tobj) * WEIGHT_MULT(obj) / 100;
return weight;
}
int get_true_weight(OBJ_DATA *obj)
{
int weight;
weight = obj->weight;
for (obj = obj->contains; obj != NULL; obj = obj->next_content)
weight += get_obj_weight(obj);
return weight;
}
/*
* True if room is dark.
*/
bool room_is_dark(CHAR_DATA *ch)
{
ROOM_INDEX_DATA * pRoomIndex = ch->in_room;
if (!IS_NPC(ch) && IS_SET(ch->plr_flags, PLR_HOLYLIGHT))
return FALSE;
if (is_affected(ch, gsn_vampire))
return FALSE;
if (pRoomIndex->light > 0)
return FALSE;
if (IS_SET(pRoomIndex->room_flags, ROOM_DARK))
return TRUE;
if (pRoomIndex->sector_type == SECT_INSIDE
|| pRoomIndex->sector_type == SECT_CITY)
return FALSE;
if (weather_info.sunlight == SUN_SET
|| weather_info.sunlight == SUN_DARK)
return TRUE;
return FALSE;
}
bool room_dark(ROOM_INDEX_DATA *pRoomIndex)
{
if (pRoomIndex->light > 0)
return FALSE;
if (IS_SET(pRoomIndex->room_flags, ROOM_DARK))
return TRUE;
if (pRoomIndex->sector_type == SECT_INSIDE
|| pRoomIndex->sector_type == SECT_CITY)
return FALSE;
if (weather_info.sunlight == SUN_SET
|| weather_info.sunlight == SUN_DARK)
return TRUE;
return FALSE;
}
bool is_room_owner(CHAR_DATA *ch, ROOM_INDEX_DATA *room)
{
if (room->owner == NULL || room->owner[0] == '\0')
return FALSE;
return is_name(ch->name,room->owner);
}
/*
* True if room is private.
*/
bool room_is_private(ROOM_INDEX_DATA *pRoomIndex)
{
CHAR_DATA *rch;
int count;
/*
if (pRoomIndex->owner != NULL && pRoomIndex->owner[0] != '\0')
return TRUE;
*/
count = 0;
for (rch = pRoomIndex->people; rch != NULL; rch = rch->next_in_room)
count++;
if (IS_SET(pRoomIndex->room_flags, ROOM_PRIVATE) && count >= 2)
return TRUE;
if (IS_SET(pRoomIndex->room_flags, ROOM_SOLITARY) && count >= 1)
return TRUE;
if (IS_SET(pRoomIndex->room_flags, ROOM_IMP_ONLY))
return TRUE;
return FALSE;
}
/* visibility on a room -- for entering and exits */
bool can_see_room(CHAR_DATA *ch, ROOM_INDEX_DATA *pRoomIndex)
{
if (IS_SET(pRoomIndex->room_flags, ROOM_IMP_ONLY)
&& !IS_TRUSTED(ch, IMPLEMENTOR))
return FALSE;
if (IS_SET(pRoomIndex->room_flags, ROOM_GODS_ONLY)
&& !IS_TRUSTED(ch, GOD))
return FALSE;
if (IS_SET(pRoomIndex->room_flags, ROOM_HEROES_ONLY)
&& !IS_TRUSTED(ch, HERO))
return FALSE;
if (IS_SET(pRoomIndex->room_flags, ROOM_NEWBIES_ONLY)
&& ch->level > LEVEL_NEWBIE && !IS_IMMORTAL(ch))
return FALSE;
return TRUE;
}
/*
* True if char can see victim.
*/
bool can_see(CHAR_DATA *ch, CHAR_DATA *victim)
{
/* RT changed so that WIZ_INVIS has levels */
if (ch == victim)
return TRUE;
if (ch == NULL || victim == NULL)
dump_to_scr(">>>>>>>> CAN_ SEE ERROR <<<<<<<<<<<\n");
if (!IS_NPC(victim) && !IS_TRUSTED(ch, victim->invis_level))
return FALSE;
if (IS_CLAN_GUARD(ch)) return TRUE;
if (!IS_TRUSTED(ch, victim->incog_level)
&& ch->in_room != victim->in_room)
return FALSE;
if (!IS_NPC(ch) && IS_SET(ch->plr_flags, PLR_HOLYLIGHT))
return TRUE;
if (IS_NPC(victim) && !IS_TRUSTED(ch, victim->invis_level)) {
AREA_DATA *pArea = area_vnum_lookup(victim->pIndexData->vnum);
if (pArea == NULL
|| !IS_BUILDER(ch, pArea))
return FALSE;
}
if (IS_AFFECTED(ch, AFF_BLIND))
return FALSE;
if (ch->in_room == NULL)
return FALSE;
if (room_is_dark(ch) && !IS_AFFECTED(ch, AFF_INFRARED))
return FALSE;
if (IS_AFFECTED(victim, AFF_INVIS)
&& !IS_AFFECTED(ch, AFF_DETECT_INVIS))
return FALSE;
if (IS_AFFECTED(victim, AFF_IMP_INVIS)
&& !IS_AFFECTED(ch, AFF_DETECT_IMP_INVIS))
return FALSE;
if (IS_AFFECTED(victim,AFF_CAMOUFLAGE) &&
!IS_AFFECTED(ch,AFF_ACUTE_VISION))
return FALSE;
if (IS_AFFECTED(victim, AFF_HIDE)
&& !IS_AFFECTED(ch, AFF_DETECT_HIDDEN)
&& victim->fighting == NULL)
return FALSE;
if (IS_AFFECTED(victim, AFF_FADE)
&& !IS_AFFECTED(ch, AFF_DETECT_FADE)
&& victim->fighting == NULL)
return FALSE;
return TRUE;
}
/*
* True if char can see obj.
*/
bool can_see_obj(CHAR_DATA *ch, OBJ_DATA *obj)
{
if (!IS_NPC(ch) && IS_SET(ch->plr_flags, PLR_HOLYLIGHT))
return TRUE;
if (IS_SET(obj->extra_flags, ITEM_VIS_DEATH))
return FALSE;
if (IS_AFFECTED(ch, AFF_BLIND) && obj->pIndexData->item_type != ITEM_POTION)
return FALSE;
if (obj->pIndexData->item_type == ITEM_LIGHT && obj->value[2] != 0)
return TRUE;
if (IS_SET(obj->extra_flags, ITEM_INVIS)
&& !IS_AFFECTED(ch, AFF_DETECT_INVIS))
return FALSE;
if (IS_OBJ_STAT(obj, ITEM_GLOW))
return TRUE;
if (room_is_dark(ch) && !IS_AFFECTED(ch, AFF_INFRARED))
return FALSE;
return TRUE;
}
/*
* True if char can drop obj.
*/
bool can_drop_obj(CHAR_DATA *ch, OBJ_DATA *obj)
{
if (!IS_SET(obj->extra_flags, ITEM_NODROP))
return TRUE;
if (IS_IMMORTAL(ch))
return TRUE;
return FALSE;
}
int isn_dark_safe(CHAR_DATA *ch)
{
CHAR_DATA *rch;
OBJ_DATA *light;
int light_exist;
if (!is_affected(ch, gsn_vampire)
|| IS_SET(ch->in_room->room_flags, ROOM_DARK))
return 0;
if (weather_info.sunlight == SUN_LIGHT
|| weather_info.sunlight == SUN_RISE)
return 2;
light_exist = 0;
for (rch = ch->in_room->people; rch; rch = rch->next_in_room) {
if ((light = get_eq_char(rch, WEAR_LIGHT))
&& IS_OBJ_STAT(light, ITEM_MAGIC)) {
light_exist = 1;
break;
}
}
return light_exist;
}
int count_charmed(CHAR_DATA *ch)
{
CHAR_DATA *gch;
int count = 0;
for (gch = char_list; gch != NULL; gch = gch->next)
{
if (IS_AFFECTED(gch,AFF_CHARM) && gch->master == ch)
count++;
}
if (count >= MAX_CHARM(ch))
{
char_puts("You are already controlling as many charmed mobs as you can!\n",ch);
return count;
}
return 0;
}
/*
* add_mind - remember 'str' in mind buffer of 'ch'
* remember the place to return in mind buffer
*/
void add_mind(CHAR_DATA *ch, const char *str)
{
if (!IS_NPC(ch) || ch->in_room == NULL)
return;
if (ch->in_mind == NULL)
/* remember a place to return */
ch->in_mind = str_printf("%d", ch->in_room->vnum);
if (!is_name(str, ch->in_mind)) {
const char *p = ch->in_mind;
ch->in_mind = str_add(ch->in_mind, " ", str, NULL);
free_string(p);
}
}
/*
* remove_mind - remove 'str' from mind buffer of 'ch'
* if it was the last revenge - return home
*/
void remove_mind(CHAR_DATA *ch, const char *str)
{
char buf[MAX_STRING_LENGTH];
char buff[MAX_STRING_LENGTH];
char arg[MAX_INPUT_LENGTH];
const char *mind = ch->in_mind;
if (!IS_NPC(ch) || ch->in_room == NULL
|| mind == NULL || !is_name(str, mind)) return;
buf[0] = '\0';
do {
mind = one_argument(mind, arg);
if (!is_name(str,arg)) {
if (buf[0] == '\0')
strcpy(buff, arg);
else
snprintf(buff, sizeof(buff), "%s %s", buf, arg);
strcpy(buf,buff);
}
}
while (mind[0] != '\0');
free_string(ch->in_mind);
if (is_number(buf)) {
do_say(ch, "At last, I took my revenge!");
back_home(ch);
ch->in_mind = NULL;
}
else
ch->in_mind = str_dup(buf);
}
int opposite_door(int door)
{
int opdoor;
switch (door) {
case 0: opdoor=2; break;
case 1: opdoor=3; break;
case 2: opdoor=0; break;
case 3: opdoor=1; break;
case 4: opdoor=5; break;
case 5: opdoor=4; break;
default: opdoor=-1; break;
}
return opdoor;
}
void back_home(CHAR_DATA *ch)
{
ROOM_INDEX_DATA *location;
char arg[MAX_INPUT_LENGTH];
if (!IS_NPC(ch) || ch->in_mind == NULL)
return;
one_argument(ch->in_mind, arg);
if ((location = find_location(ch, arg)) == NULL) {
log("back_home: reset place not found");
return;
}
if (ch->fighting == NULL && location != ch->in_room) {
act("$n prays for transportation.",ch,NULL,NULL,TO_ROOM);
char_from_room(ch);
char_to_room(ch, location);
act("$n appears in the room.",ch,NULL,NULL,TO_ROOM);
}
}
CHAR_DATA * find_char(CHAR_DATA *ch, const char *argument,int door, int range)
{
EXIT_DATA *pExit,*bExit;
ROOM_INDEX_DATA *dest_room,*back_room;
CHAR_DATA *target;
int number = 0,opdoor;
char arg[MAX_INPUT_LENGTH];
number = number_argument(argument,arg);
dest_room = ch->in_room;
if ((target = get_char_room2(ch,dest_room,arg,&number)) != NULL)
return target;
if ((opdoor = opposite_door(door)) == -1)
{
bug("In find_char wrong door: %d",door);
char_puts("You don't see that there.\n",ch);
return NULL;
}
while (range > 0)
{
range--;
/* find target room */
back_room = dest_room;
if ((pExit = dest_room->exit[door]) == NULL
|| (dest_room = pExit->u1.to_room) == NULL
|| IS_SET(pExit->exit_info,EX_CLOSED))
break;
if ((bExit = dest_room->exit[opdoor]) == NULL
|| bExit->u1.to_room != back_room)
{
char_puts("The path you choose prevents your power to pass.\n",ch);
return NULL;
}
if ((target = get_char_room2(ch,dest_room,arg,&number)) != NULL)
return target;
}
char_puts("You don't see that there.\n",ch);
return NULL;
}
int check_exit(char *arg)
{
int door = -1;
if (!str_cmp(arg, "n") || !str_cmp(arg, "north")) door = 0;
else if (!str_cmp(arg, "e") || !str_cmp(arg, "east" )) door = 1;
else if (!str_cmp(arg, "s") || !str_cmp(arg, "south")) door = 2;
else if (!str_cmp(arg, "w") || !str_cmp(arg, "west" )) door = 3;
else if (!str_cmp(arg, "u") || !str_cmp(arg, "up" )) door = 4;
else if (!str_cmp(arg, "d") || !str_cmp(arg, "down" )) door = 5;
return door;
}
/*
* Find a char for spell usage.
*/
CHAR_DATA *get_char_spell(CHAR_DATA *ch, const char *argument, int *door, int range)
{
char buf[MAX_INPUT_LENGTH];
int i;
for(i=0;argument[i] != '\0' && argument[i] != '.';i++)
buf[i] = argument[i];
buf[i] = '\0';
if (i == 0 || (*door = check_exit(buf)) == -1)
return get_char_room(ch,argument);
return find_char(ch,(argument+i+1),*door,range);
}
void path_to_track(CHAR_DATA *ch, CHAR_DATA *victim, int door)
{
ROOM_INDEX_DATA *temp;
EXIT_DATA *pExit;
int opdoor;
int range = 0;
SET_FIGHT_TIME(ch);
if (!IS_NPC(victim))
SET_FIGHT_TIME(victim);
if (IS_NPC(victim) && victim->position != POS_DEAD)
{
victim->last_fought = ch;
if ((opdoor = opposite_door(door)) == -1)
{
bug("In path_to_track wrong door: %d",door);
return;
}
temp = ch->in_room;
while (1)
{
range++;
if (victim->in_room == temp) break;
if ((pExit = temp->exit[ door ]) == NULL
|| (temp = pExit->u1.to_room) == NULL)
{
bug("In path_to_track: couldn't calculate range %d",range);
return;
}
if (range > 100)
{
bug("In path_to_track: range exceeded 100",0);
return;
}
}
temp = victim->in_room;
while (--range > 0)
{
room_record(ch->name,temp, opdoor);
if ((pExit = temp->exit[opdoor]) == NULL
|| (temp = pExit->u1.to_room) == NULL)
{
log_printf("[*****] Path to track: Range: %d Room: %d opdoor:%d",
range,temp->vnum,opdoor);
return;
}
}
do_track(victim,str_empty);
}
}
int pk_range(int level)
{
return UMAX(4, level/10 + 2);
}
bool in_PK(CHAR_DATA *ch, CHAR_DATA *victim)
{
if (IS_NPC(ch) || IS_NPC(victim))
return TRUE;
if (victim->level < PK_MIN_LEVEL || ch->level < PK_MIN_LEVEL)
return FALSE;
/* level adjustment */
if (ch != victim && !IS_IMMORTAL(ch)
&& (ch->level >= (victim->level + pk_range(ch->level)) ||
ch->level <= (victim->level - pk_range(ch->level)))
&& (victim->level >= (ch->level + pk_range(victim->level)) ||
victim->level <= (ch->level - pk_range(victim->level))))
return FALSE;
return TRUE;
}
bool can_gate(CHAR_DATA *ch, CHAR_DATA *victim)
{
if (victim == ch
|| ch->fighting != NULL
|| victim->in_room == NULL
|| !can_see_room(ch, victim->in_room)
|| IS_SET(ch->in_room->room_flags, ROOM_SAFE | ROOM_NORECALL |
ROOM_PEACE | ROOM_NOSUMMON)
|| IS_SET(victim->in_room->room_flags, ROOM_SAFE | ROOM_NORECALL |
ROOM_PEACE | ROOM_NOSUMMON)
|| IS_SET(ch->in_room->area->flags, AREA_UNDER_CONSTRUCTION)
|| room_is_private(victim->in_room)
|| IS_SET(victim->imm_flags, IMM_SUMMON))
return FALSE;
if (IS_NPC(victim))
return TRUE;
if (((!in_PK(ch, victim) ||
ch->in_room->area != victim->in_room->area) &&
IS_SET(victim->plr_flags, PLR_NOSUMMON))
|| victim->level >= LEVEL_HERO
|| guild_check(ch, victim->in_room) < 0)
return FALSE;
return TRUE;
}
const char *PERS(CHAR_DATA *ch, CHAR_DATA *looker)
{
if (is_affected(ch, gsn_doppelganger)
&& (IS_NPC(looker) || !IS_SET(looker->plr_flags, PLR_HOLYLIGHT)))
ch = ch->doppel;
if (can_see(looker, ch)) {
if (IS_NPC(ch))
return mlstr_cval(ch->short_descr, looker);
else if (is_affected(ch, gsn_vampire) && !IS_IMMORTAL(looker))
return "an ugly creature";
return ch->name;
}
if (IS_IMMORTAL(ch))
return "an immortal";
return "someone";
}
bool obj_is_pit(OBJ_DATA *obj)
{
HOMETOWN_DATA *h;
for (h = hometown_table; h->name != NULL; h++) {
int i;
for (i = 0; i < 3; i++)
if (obj->pIndexData->vnum == h->pit[i])
return TRUE;
}
return FALSE;
}
void format_obj(BUFFER *output, OBJ_DATA *obj)
{
buf_printf(output,
"Object '%s' is type %s, extra flags %s.\n"
"Weight is %d, value is %d, level is %d.\n",
obj->name,
flag_string(item_types, obj->pIndexData->item_type),
flag_string(extra_flags, obj->extra_flags & ~ITEM_ENCHANTED),
obj->weight / 10,
obj->cost,
obj->level);
if (obj->pIndexData->limit != -1)
buf_printf(output,
"This equipment has been LIMITED by number %d \n",
obj->pIndexData->limit);
switch (obj->pIndexData->item_type) {
case ITEM_SCROLL:
case ITEM_POTION:
case ITEM_PILL:
buf_printf(output, "Level %d spells of:", obj->value[0]);
if (obj->value[1] >= 0)
buf_printf(output, " '%s'", skill_name(obj->value[1]));
if (obj->value[2] >= 0)
buf_printf(output, " '%s'", skill_name(obj->value[2]));
if (obj->value[3] >= 0)
buf_printf(output, " '%s'", skill_name(obj->value[3]));
if (obj->value[4] >= 0)
buf_printf(output, " '%s'", skill_name(obj->value[4]));
buf_add(output, ".\n");
break;
case ITEM_WAND:
case ITEM_STAFF:
buf_printf(output, "Has %d charges of level %d",
obj->value[2], obj->value[0]);
if (obj->value[3] >= 0)
buf_printf(output, " '%s'", skill_name(obj->value[3]));
buf_add(output, ".\n");
break;
case ITEM_DRINK_CON:
buf_printf(output, "It holds %s-colored %s.\n",
liq_table[obj->value[2]].liq_color,
liq_table[obj->value[2]].liq_name);
break;
case ITEM_CONTAINER:
buf_printf(output,
"Capacity: %d# Maximum weight: %d# flags: %s\n",
obj->value[0], obj->value[3],
flag_string(cont_flags, obj->value[1]));
if (obj->value[4] != 100)
buf_printf(output, "Weight multiplier: %d%%\n",
obj->value[4]);
break;
case ITEM_WEAPON:
buf_printf(output, "Weapon type is %s.\n",
flag_string(weapon_class, obj->value[0]));
buf_printf(output, "Damage is %dd%d (average %d).\n",
obj->value[1],obj->value[2],
(1 + obj->value[2]) * obj->value[1] / 2);
if (obj->value[4])
buf_printf(output, "Weapons flags: %s\n",
flag_string(weapon_type2, obj->value[4]));
break;
case ITEM_ARMOR:
buf_printf(output, "Armor class is %d pierce, "
"%d bash, %d slash, and %d vs. magic.\n",
obj->value[0], obj->value[1],
obj->value[2], obj->value[3]);
break;
}
}
void format_obj_affects(BUFFER *output, AFFECT_DATA *paf, int flags)
{
for (; paf; paf = paf->next) {
WHERE_DATA *w;
if (paf->location != APPLY_NONE && paf->modifier) {
buf_printf(output, "Affects %s by %d",
flag_string(apply_flags, paf->location),
paf->modifier);
if (!IS_SET(flags, FOA_F_NODURATION)
&& paf->duration > -1)
buf_printf(output, " for %d hours",
paf->duration);
buf_add(output, ".\n");
}
if (IS_SET(flags, FOA_F_NOAFFECTS))
continue;
if ((w = where_lookup(paf->where)) && paf->bitvector) {
buf_add(output, "Adds ");
buf_printf(output, w->format,
flag_string(w->table, paf->bitvector));
buf_add(output, ".\n");
}
}
}
int get_wear_level(CHAR_DATA *ch, OBJ_DATA *obj)
{
int wear_level = ch->level;
CLASS_DATA *cl;
if ((cl = class_lookup(ch->class)) == NULL)
return wear_level;
switch (obj->pIndexData->item_type) {
case ITEM_POTION:
case ITEM_PILL:
case ITEM_WAND:
case ITEM_STAFF:
case ITEM_SCROLL:
return wear_level;
}
if (!IS_SET(obj->pIndexData->extra_flags, ITEM_QUEST)
&& (obj->pIndexData->limit < 0 || obj->pIndexData->limit > 1))
wear_level += pk_range(wear_level);
if (IS_SET(cl->flags, CLASS_MAGIC)) {
if (obj->pIndexData->item_type == ITEM_ARMOR)
wear_level += 3;
}
else if (obj->pIndexData->item_type == ITEM_WEAPON)
wear_level += 3;
return wear_level;
}
/*
* Compute a saving throw.
* Negative apply's make saving throw better.
*/
bool saves_spell(int level, CHAR_DATA *victim, int dam_type)
{
CLASS_DATA *vcl;
int save;
save = 40 + (victim->level - level) * 4 -
(victim->saving_throw * 90) / UMAX(45, victim->level);
if (IS_AFFECTED(victim, AFF_BERSERK))
save += victim->level / 5;
switch(check_immune(victim, dam_type)) {
case IS_IMMUNE:
return TRUE;
case IS_RESISTANT:
save += victim->level / 5;
break;
case IS_VULNERABLE:
save -= victim->level / 5;
break;
}
if (!IS_NPC(victim) && (vcl = class_lookup(victim->class))
&& IS_SET(vcl->flags, CLASS_MAGIC))
save = 9 * save / 10;
save = URANGE(5, save, 95);
return number_percent() < save;
}
/* RT configuration smashed */
bool saves_dispel(int dis_level, int spell_level, int duration)
{
int save;
/* impossible to dispel permanent effects */
if (duration == -2) return 1;
if (duration == -1) spell_level += 5;
save = 50 + (spell_level - dis_level) * 5;
save = URANGE(5, save, 95);
return number_percent() < save;
}
/* co-routine for dispel magic and cancellation */
bool check_dispel(int dis_level, CHAR_DATA *victim, int sn)
{
AFFECT_DATA *af;
if (is_affected(victim, sn)) {
for (af = victim->affected; af != NULL; af = af->next) {
if (af->type == sn) {
if (!saves_dispel(dis_level,af->level,af->duration)) {
SKILL_DATA *sk;
affect_strip(victim,sn);
if ((sk = skill_lookup(sn))
&& !IS_NULLSTR(sk->msg_off))
char_printf(victim, "%s\n", sk->msg_off);
return TRUE;
} else
af->level--;
}
}
}
return FALSE;
}
bool check_blind_raw(CHAR_DATA *ch)
{
if (!IS_NPC(ch) && IS_SET(ch->plr_flags, PLR_HOLYLIGHT))
return TRUE;
if (IS_AFFECTED(ch, AFF_BLIND))
return FALSE;
return TRUE;
}
bool check_blind(CHAR_DATA *ch)
{
bool can_see = check_blind_raw(ch);
if (!can_see)
char_puts("You can't see a thing!\n", ch);
return can_see;
}
/*----------------------------------------------------------------------------
* show affects stuff
*/
void show_name(CHAR_DATA *ch, BUFFER *output,
AFFECT_DATA *paf, AFFECT_DATA *paf_last)
{
if (paf_last && paf->type == paf_last->type)
if (ch && ch->level < 20)
return;
else
buf_add(output, " ");
else
buf_printf(output, "Spell: {c%-15s{x", skill_name(paf->type));
}
void show_duration(BUFFER *output, AFFECT_DATA *paf)
{
if (paf->duration == -1 || paf->duration == -2)
buf_add(output, "permanently.");
else
buf_printf(output, "for {c%d{x hours.", paf->duration);
buf_add(output, "\n");
}
void show_loc_affect(CHAR_DATA *ch, BUFFER *output,
AFFECT_DATA *paf, AFFECT_DATA **ppaf)
{
if (ch->level < 20) {
show_name(ch, output, paf, *ppaf);
if (*ppaf && (*ppaf)->type == paf->type)
return;
buf_add(output, "\n");
*ppaf = paf;
return;
}
if (paf->location > 0) {
show_name(ch, output, paf, *ppaf);
buf_printf(output, ": modifies {c%s{x by {c%d{x ",
flag_string(apply_flags, paf->location),
paf->modifier);
show_duration(output, paf);
*ppaf = paf;
}
}
void show_bit_affect(BUFFER *output, AFFECT_DATA *paf, AFFECT_DATA **ppaf,
sflag_t where)
{
char buf[MAX_STRING_LENGTH];
WHERE_DATA *w;
if (paf->where != where
|| (w = where_lookup(paf->where)) == NULL
|| !paf->bitvector)
return;
show_name(NULL, output, paf, *ppaf);
snprintf(buf, sizeof(buf), ": adds %s ", w->format);
buf_printf(output, buf, flag_string(w->table, paf->bitvector));
show_duration(output, paf);
*ppaf = paf;
}
void show_obj_affects(CHAR_DATA *ch, BUFFER *output, AFFECT_DATA *paf)
{
AFFECT_DATA *paf_last = NULL;
for (; paf; paf = paf->next)
if (paf->location != APPLY_SPELL_AFFECT)
show_bit_affect(output, paf, &paf_last, TO_AFFECTS);
}
void show_affects(CHAR_DATA *ch, BUFFER *output)
{
OBJ_DATA *obj;
AFFECT_DATA *paf, *paf_last = NULL;
buf_add(output, "You are affected by the following spells:\n");
for (paf = ch->affected; paf; paf = paf->next) {
show_loc_affect(ch, output, paf, &paf_last);
if (ch->level < 20)
continue;
show_bit_affect(output, paf, &paf_last, TO_AFFECTS);
}
if (ch->level < 20)
return;
for (obj = ch->carrying; obj; obj = obj->next_content)
if (obj->wear_loc != WEAR_NONE) {
if (!IS_SET(obj->extra_flags, ITEM_ENCHANTED))
show_obj_affects(ch, output,
obj->pIndexData->affected);
show_obj_affects(ch, output, obj->affected);
}
}
#ifdef WIN32
void SET_ORG_RACE(CHAR_DATA *ch, int race)
{
if (IS_NPC(ch))
ch->pIndexData->race = race;
else
ch->pcdata->race = race;
}
#endif