/*
************************************************************************
* File: handler.c Part of CircleMUD *
* Usage: internal funcs: moving and finding chars/objs *
* *
* All rights reserved. See license.doc for complete information. *
* *
* Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University *
* CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991. *
************************************************************************ */
#include "conf.h"
#include "sysdep.h"
#include "structs.h"
#include "utils.h"
#include "comm.h"
#include "db.h"
#include "handler.h"
#include "interpreter.h"
#include "spells.h"
#include "dg_scripts.h"
#include "profs.h"
/* external vars */
extern struct char_data *combat_list;
extern struct room_data *world;
extern struct obj_data *object_list;
extern struct char_data *character_list;
extern struct index_data *mob_index;
extern struct index_data *obj_index;
extern struct descriptor_data *descriptor_list;
extern const char *MENU;
/* local functions */
int apply_ac(struct char_data * ch, int eq_pos);
void update_object(struct obj_data * obj, int use);
void update_char_objects(struct char_data * ch);
int obj_sank_or_fell(struct obj_data *obj);
/* external functions */
int invalid_class(struct char_data *ch, struct obj_data *obj);
void remove_follower(struct char_data * ch);
void clearMemory(struct char_data * ch);
void die_follower(struct char_data * ch);
void death_cry(struct char_data *ch);
ACMD(do_return);
int money_obj_value(struct obj_data *obj);
char *fname(const char *namelist)
{
static char holder[30];
register char *point;
for (point = holder; isalpha(*namelist); namelist++, point++)
*point = *namelist;
*point = '\0';
return (holder);
}
int isname(const char *str, const char *namelist)
{
const char *curname, *curstr;
curname = namelist;
for (;;) {
for (curstr = str;; curstr++, curname++) {
if (!*curstr && !isalpha(*curname))
return (1);
if (!*curname)
return (0);
if (!*curstr || *curname == ' ')
break;
if (LOWER(*curstr) != LOWER(*curname))
break;
}
/* skip to next name */
for (; isalpha(*curname); curname++);
if (!*curname)
return (0);
curname++; /* first char of new name */
}
}
void affect_modify(struct char_data * ch, byte loc, sbyte mod,
bitvector_t bitv, bool add)
{
if (add)
SET_BIT(AFF_FLAGS(ch), bitv);
else {
REMOVE_BIT(AFF_FLAGS(ch), bitv);
mod = -mod;
}
switch (loc) {
case APPLY_NONE:
break;
case APPLY_STR:
GET_STR(ch) += mod;
break;
case APPLY_DEX:
GET_DEX(ch) += mod;
break;
case APPLY_INT:
GET_INT(ch) += mod;
break;
case APPLY_WIS:
GET_WIS(ch) += mod;
break;
case APPLY_CON:
GET_CON(ch) += mod;
break;
case APPLY_CHA:
GET_CHA(ch) += mod;
break;
case APPLY_CLASS:
/* ??? GET_CLASS(ch) += mod; */
break;
/*
* My personal thoughts on these two would be to set the person to the
* value of the apply. That way you won't have to worry about people
* making +1 level things to be imp (you restrict anything that gives
* immortal level of course). It also makes more sense to set someone
* to a class rather than adding to the class number. -gg
*/
case APPLY_LEVEL:
/* ??? GET_LEVEL(ch) += mod; */
break;
case APPLY_AGE:
ch->player.time.birth -= (mod * SECS_PER_MUD_YEAR);
break;
case APPLY_CHAR_WEIGHT:
GET_WEIGHT(ch) += mod;
break;
case APPLY_CHAR_HEIGHT:
GET_HEIGHT(ch) += mod;
break;
case APPLY_MANA:
GET_MAX_MANA(ch) += mod;
break;
case APPLY_HIT:
GET_MAX_HIT(ch) += mod;
break;
case APPLY_MOVE:
GET_MAX_MOVE(ch) += mod;
break;
case APPLY_GOLD:
break;
case APPLY_EXP:
break;
case APPLY_AC:
GET_AC(ch) += mod;
break;
case APPLY_HITROLL:
GET_HITROLL(ch) += mod;
break;
case APPLY_DAMROLL:
GET_DAMROLL(ch) += mod;
break;
case APPLY_SAVING_PARA:
GET_SAVE(ch, SAVING_PARA) += mod;
break;
case APPLY_SAVING_ROD:
GET_SAVE(ch, SAVING_ROD) += mod;
break;
case APPLY_SAVING_PETRI:
GET_SAVE(ch, SAVING_PETRI) += mod;
break;
case APPLY_SAVING_BREATH:
GET_SAVE(ch, SAVING_BREATH) += mod;
break;
case APPLY_SAVING_SPELL:
GET_SAVE(ch, SAVING_SPELL) += mod;
break;
default:
log("SYSERR: Unknown apply adjust %d attempt (%s, affect_modify).",loc, GET_NAME(ch));
break;
} /* switch */
}
/* This updates a character by subtracting everything he is affected by */
/* restoring original abilities, and then affecting all again */
void affect_total(struct char_data * ch)
{
struct affected_type *af;
int i, j;
for (i = 0; i < NUM_WEARS; i++) {
if (GET_EQ(ch, i))
for (j = 0; j < MAX_OBJ_AFFECT; j++)
affect_modify(ch, GET_EQ(ch, i)->affected[j].location,
GET_EQ(ch, i)->affected[j].modifier,
GET_EQ(ch, i)->obj_flags.bitvector, FALSE);
}
for (af = ch->affected; af; af = af->next)
affect_modify(ch, af->location, af->modifier, af->bitvector, FALSE);
ch->aff_abils = ch->real_abils;
for (i = 0; i < NUM_WEARS; i++) {
if (GET_EQ(ch, i))
for (j = 0; j < MAX_OBJ_AFFECT; j++)
affect_modify(ch, GET_EQ(ch, i)->affected[j].location,
GET_EQ(ch, i)->affected[j].modifier,
GET_EQ(ch, i)->obj_flags.bitvector, TRUE);
}
for (af = ch->affected; af; af = af->next)
affect_modify(ch, af->location, af->modifier, af->bitvector, TRUE);
/* Make certain values are between 0..25, not < 0 and not > 25! */
i = (IS_NPC(ch) ? 25 : 18);
GET_DEX(ch) = MAX(0, MIN(GET_DEX(ch), i));
GET_INT(ch) = MAX(0, MIN(GET_INT(ch), i));
GET_WIS(ch) = MAX(0, MIN(GET_WIS(ch), i));
GET_CON(ch) = MAX(0, MIN(GET_CON(ch), i));
GET_STR(ch) = MAX(0, GET_STR(ch));
if (IS_NPC(ch)) {
GET_STR(ch) = MIN(GET_STR(ch), i);
} else {
if (GET_STR(ch) > 18) {
i = GET_ADD(ch) + ((GET_STR(ch) - 18) * 10);
GET_ADD(ch) = MIN(i, 100);
GET_STR(ch) = 18;
}
}
}
/* Insert an affect_type in a char_data structure
Automatically sets apropriate bits and apply's */
void affect_to_char(struct char_data * ch, struct affected_type * af)
{
struct affected_type *affected_alloc;
CREATE(affected_alloc, struct affected_type, 1);
*affected_alloc = *af;
affected_alloc->next = ch->affected;
ch->affected = affected_alloc;
affect_modify(ch, af->location, af->modifier, af->bitvector, TRUE);
affect_total(ch);
}
/*
* Remove an affected_type structure from a char (called when duration
* reaches zero). Pointer *af must never be NIL! Frees mem and calls
* affect_location_apply
*/
void affect_remove(struct char_data * ch, struct affected_type * af)
{
struct affected_type *temp;
if (ch->affected == NULL) {
core_dump();
return;
}
affect_modify(ch, af->location, af->modifier, af->bitvector, FALSE);
REMOVE_FROM_LIST(af, ch->affected, next);
free(af);
affect_total(ch);
}
/* Call affect_remove with every spell of spelltype "skill" */
void affect_from_char(struct char_data * ch, int type)
{
struct affected_type *hjp, *next;
for (hjp = ch->affected; hjp; hjp = next) {
next = hjp->next;
if (hjp->type == type)
affect_remove(ch, hjp);
}
}
/*
* Return TRUE if a char is affected by a spell (SPELL_XXX),
* FALSE indicates not affected.
*/
bool affected_by_spell(struct char_data * ch, int type)
{
struct affected_type *hjp;
for (hjp = ch->affected; hjp; hjp = hjp->next)
if (hjp->type == type)
return (TRUE);
return (FALSE);
}
void affect_join(struct char_data * ch, struct affected_type * af,
bool add_dur, bool avg_dur, bool add_mod, bool avg_mod)
{
struct affected_type *hjp;
bool found = FALSE;
for (hjp = ch->affected; !found && hjp; hjp = hjp->next) {
if ((hjp->type == af->type) && (hjp->location == af->location)) {
if (add_dur)
af->duration += hjp->duration;
if (avg_dur)
af->duration /= 2;
if (add_mod)
af->modifier += hjp->modifier;
if (avg_mod)
af->modifier /= 2;
affect_remove(ch, hjp);
affect_to_char(ch, af);
found = TRUE;
}
}
if (!found)
affect_to_char(ch, af);
}
/* move a player out of a room */
void char_from_room(struct char_data * ch)
{
struct char_data *temp;
if (ch == NULL || ch->in_room == NOWHERE) {
log("SYSERR: NULL character or NOWHERE in %s, char_from_room", __FILE__);
exit(1);
}
if (FIGHTING(ch) != NULL)
stop_fighting(ch);
if (GET_EQ(ch, WEAR_LIGHT) != NULL)
if (GET_OBJ_TYPE(GET_EQ(ch, WEAR_LIGHT)) == ITEM_LIGHT)
if (GET_OBJ_VAL(GET_EQ(ch, WEAR_LIGHT), 2)) /* Light is ON */
world[ch->in_room].light--;
REMOVE_FROM_LIST(ch, world[ch->in_room].people, next_in_room);
ch->in_room = NOWHERE;
ch->next_in_room = NULL;
}
/* place a character in a room */
void char_to_room(struct char_data * ch, room_rnum room)
{
if (ch == NULL || room < 0 || room > top_of_world)
log("SYSERR: Illegal value(s) passed to char_to_room. (Room: %d/%d Ch: %p",
room, top_of_world, ch);
else {
ch->next_in_room = world[room].people;
world[room].people = ch;
ch->in_room = room;
if (GET_EQ(ch, WEAR_LIGHT))
if (GET_OBJ_TYPE(GET_EQ(ch, WEAR_LIGHT)) == ITEM_LIGHT)
if (GET_OBJ_VAL(GET_EQ(ch, WEAR_LIGHT), 2)) /* Light ON */
world[room].light++;
/* Stop fighting now, if we left. */
if (FIGHTING(ch) && IN_ROOM(ch) != IN_ROOM(FIGHTING(ch))) {
stop_fighting(FIGHTING(ch));
stop_fighting(ch);
}
}
}
/* give an object to a char */
void obj_to_char(struct obj_data * object, struct char_data * ch)
{
if (object && ch) {
object->next_content = ch->carrying;
ch->carrying = object;
object->carried_by = ch;
object->in_room = NOWHERE;
IS_CARRYING_W(ch) += GET_OBJ_WEIGHT(object);
IS_CARRYING_N(ch)++;
/* set flag for crash-save system, but not on mobs! */
if (!IS_NPC(ch))
SET_BIT(PLR_FLAGS(ch), PLR_CRASH);
} else
log("SYSERR: NULL obj (%p) or char (%p) passed to obj_to_char.", object, ch);
}
/* take an object from a char */
void obj_from_char(struct obj_data * object)
{
struct obj_data *temp;
if (object == NULL) {
log("SYSERR: NULL object passed to obj_from_char.");
return;
}
REMOVE_FROM_LIST(object, object->carried_by->carrying, next_content);
/* set flag for crash-save system, but not on mobs! */
if (!IS_NPC(object->carried_by))
SET_BIT(PLR_FLAGS(object->carried_by), PLR_CRASH);
IS_CARRYING_W(object->carried_by) -= GET_OBJ_WEIGHT(object);
IS_CARRYING_N(object->carried_by)--;
object->carried_by = NULL;
object->next_content = NULL;
}
/* Return the effect of a piece of armor in position eq_pos */
int apply_ac(struct char_data * ch, int eq_pos)
{
int factor;
if (GET_EQ(ch, eq_pos) == NULL) {
core_dump();
return (0);
}
if (!(GET_OBJ_TYPE(GET_EQ(ch, eq_pos)) == ITEM_ARMOR))
return (0);
switch (eq_pos) {
case WEAR_BODY:
factor = 3;
break; /* 30% */
case WEAR_HEAD:
factor = 2;
break; /* 20% */
case WEAR_LEGS:
factor = 2;
break; /* 20% */
default:
factor = 1;
break; /* all others 10% */
}
return (factor * GET_OBJ_VAL(GET_EQ(ch, eq_pos), 0));
}
int invalid_align(struct char_data *ch, struct obj_data *obj)
{
if (IS_OBJ_STAT(obj, ITEM_ANTI_EVIL) && IS_EVIL(ch))
return TRUE;
if (IS_OBJ_STAT(obj, ITEM_ANTI_GOOD) && IS_GOOD(ch))
return TRUE;
if (IS_OBJ_STAT(obj, ITEM_ANTI_NEUTRAL) && IS_NEUTRAL(ch))
return TRUE;
return FALSE;
}
void equip_char(struct char_data * ch, struct obj_data * obj, int pos)
{
int j;
if (pos < 0 || pos >= NUM_WEARS) {
core_dump();
return;
}
if (GET_EQ(ch, pos)) {
log("SYSERR: Char is already equipped: %s, %s", GET_NAME(ch),
obj->short_description);
return;
}
if (obj->carried_by) {
log("SYSERR: EQUIP: Obj is carried_by when equip.");
return;
}
if (obj->in_room != NOWHERE) {
log("SYSERR: EQUIP: Obj is in_room when equip.");
return;
}
if (invalid_align(ch, obj) || invalid_class(ch, obj)) {
act("You are zapped by $p and instantly let go of it.", FALSE, ch, obj, 0, TO_CHAR);
act("$n is zapped by $p and instantly lets go of it.", FALSE, ch, obj, 0, TO_ROOM);
obj_to_room(obj, ch->in_room);
return;
}
GET_EQ(ch, pos) = obj;
obj->worn_by = ch;
obj->worn_on = pos;
if (GET_OBJ_TYPE(obj) == ITEM_ARMOR)
GET_AC(ch) -= apply_ac(ch, pos);
/* Weapon Proficiency Handling */
if ((GET_OBJ_TYPE(obj) == ITEM_WEAPON) &&
(pos == WEAR_WIELD)) {
if (prof_get(ch, 2, GET_OBJ_VNUM(obj)) != -1)
GET_CUR_PROF(ch) = prof_get_node(ch, 2, GET_OBJ_VNUM(obj));
/* Mobs are assumed to be proficient in their weapons */
if (IS_NPC(ch))
prof_set(ch, 2, GET_OBJ_VNUM(obj), 80.00);
else
if (GET_LEVEL(ch) >= LVL_IMMORT)
prof_set(ch, 2, GET_OBJ_VNUM(obj), 100.00); }
if (ch->in_room != NOWHERE) {
if (pos == WEAR_LIGHT && GET_OBJ_TYPE(obj) == ITEM_LIGHT)
if (GET_OBJ_VAL(obj, 2)) /* if light is ON */
world[ch->in_room].light++;
} else
log("SYSERR: ch->in_room = NOWHERE when equipping char %s.", GET_NAME(ch));
for (j = 0; j < MAX_OBJ_AFFECT; j++)
affect_modify(ch, obj->affected[j].location,
obj->affected[j].modifier,
obj->obj_flags.bitvector, TRUE);
affect_total(ch);
}
struct obj_data *unequip_char(struct char_data * ch, int pos)
{
int j;
struct obj_data *obj;
if ((pos < 0 || pos >= NUM_WEARS) || GET_EQ(ch, pos) == NULL) {
core_dump();
return (NULL);
}
obj = GET_EQ(ch, pos);
obj->worn_by = NULL;
obj->worn_on = -1;
if (GET_OBJ_TYPE(obj) == ITEM_ARMOR)
GET_AC(ch) += apply_ac(ch, pos);
/* Removing a weapon, get rid of current prof */
if ((GET_OBJ_TYPE(obj) == ITEM_WEAPON) &&
(pos == WEAR_WIELD) )
GET_CUR_PROF(ch) = NULL;
if (ch->in_room != NOWHERE) {
if (pos == WEAR_LIGHT && GET_OBJ_TYPE(obj) == ITEM_LIGHT)
if (GET_OBJ_VAL(obj, 2)) /* if light is ON */
world[ch->in_room].light--;
} else
log("SYSERR: ch->in_room = NOWHERE when unequipping char %s.", GET_NAME(ch));
GET_EQ(ch, pos) = NULL;
for (j = 0; j < MAX_OBJ_AFFECT; j++)
affect_modify(ch, obj->affected[j].location,
obj->affected[j].modifier,
obj->obj_flags.bitvector, FALSE);
affect_total(ch);
return (obj);
}
int get_number(char **name)
{
int i;
char *ppos;
char number[MAX_INPUT_LENGTH];
*number = '\0';
if ((ppos = strchr(*name, '.')) != NULL) {
*ppos++ = '\0';
strcpy(number, *name);
strcpy(*name, ppos);
for (i = 0; *(number + i); i++)
if (!isdigit(*(number + i)))
return (0);
return (atoi(number));
}
return (1);
}
/* Search a given list for an object number, and return a ptr to that obj */
struct obj_data *get_obj_in_list_num(int num, struct obj_data * list)
{
struct obj_data *i;
for (i = list; i; i = i->next_content)
if (GET_OBJ_RNUM(i) == num)
return (i);
return (NULL);
}
/* search the entire world for an object number, and return a pointer */
struct obj_data *get_obj_num(obj_rnum nr)
{
struct obj_data *i;
for (i = object_list; i; i = i->next)
if (GET_OBJ_RNUM(i) == nr)
return (i);
return (NULL);
}
/* search a room for a char, and return a pointer if found.. */
struct char_data *get_char_room(char *name, room_rnum room)
{
struct char_data *i;
int j = 0, number;
char tmpname[MAX_INPUT_LENGTH];
char *tmp = tmpname;
strcpy(tmp, name);
if (!(number = get_number(&tmp)))
return (NULL);
for (i = world[room].people; i && (j <= number); i = i->next_in_room)
if (isname(tmp, i->player.name))
if (++j == number)
return (i);
return (NULL);
}
/* search all over the world for a char num, and return a pointer if found */
struct char_data *get_char_num(mob_rnum nr)
{
struct char_data *i;
for (i = character_list; i; i = i->next)
if (GET_MOB_RNUM(i) == nr)
return (i);
return (NULL);
}
/* put an object in a room */
void obj_to_room(struct obj_data * object, room_rnum room)
{
if (!object || room < 0 || room > top_of_world)
log("SYSERR: Illegal value(s) passed to obj_to_room. (Room #%d/%d, obj %p)",
room, top_of_world, object);
else {
object->next_content = world[room].contents;
world[room].contents = object;
object->in_room = room;
object->carried_by = NULL;
if (ROOM_FLAGGED(room, ROOM_HOUSE))
SET_BIT(ROOM_FLAGS(room), ROOM_HOUSE_CRASH);
if (IS_OBJ_STAT(object, ITEM_MELT)) {
act("$p falls to pieces as it hits the ground.", FALSE, 0, object, 0, TO_ROOM);
extract_obj(object);
return; }
if (obj_sank_or_fell(object))
return;
/* No souls lying about */
if (CAN_WEAR(object, ITEM_WEAR_SOUL))
extract_obj(object);
}
}
/* Take an object from a room */
void obj_from_room(struct obj_data * object)
{
struct obj_data *temp;
if (!object || object->in_room == NOWHERE) {
log("SYSERR: NULL object (%p) or obj not in a room (%d) passed to obj_from_room",
object, object->in_room);
return;
}
REMOVE_FROM_LIST(object, world[object->in_room].contents, next_content);
if (ROOM_FLAGGED(object->in_room, ROOM_HOUSE))
SET_BIT(ROOM_FLAGS(object->in_room), ROOM_HOUSE_CRASH);
object->in_room = NOWHERE;
object->next_content = NULL;
}
/* put an object in an object (quaint) */
void obj_to_obj(struct obj_data * obj, struct obj_data * obj_to)
{
struct obj_data *tmp_obj;
if (!obj || !obj_to || obj == obj_to) {
log("SYSERR: NULL object (%p) or same source (%p) and target (%p) obj passed to obj_to_obj.",
obj, obj, obj_to);
return;
}
obj->next_content = obj_to->contains;
obj_to->contains = obj;
obj->in_obj = obj_to;
for (tmp_obj = obj->in_obj; tmp_obj->in_obj; tmp_obj = tmp_obj->in_obj)
GET_OBJ_WEIGHT(tmp_obj) += GET_OBJ_WEIGHT(obj);
/* top level object. Subtract weight from inventory if necessary. */
GET_OBJ_WEIGHT(tmp_obj) += GET_OBJ_WEIGHT(obj);
if (tmp_obj->carried_by)
IS_CARRYING_W(tmp_obj->carried_by) += GET_OBJ_WEIGHT(obj);
}
/* remove an object from an object */
void obj_from_obj(struct obj_data * obj)
{
struct obj_data *temp, *obj_from;
if (obj->in_obj == NULL) {
log("SYSERR: (%s): trying to illegally extract obj from obj.", __FILE__);
return;
}
obj_from = obj->in_obj;
REMOVE_FROM_LIST(obj, obj_from->contains, next_content);
/* Subtract weight from containers container */
for (temp = obj->in_obj; temp->in_obj; temp = temp->in_obj)
GET_OBJ_WEIGHT(temp) -= GET_OBJ_WEIGHT(obj);
/* Subtract weight from char that carries the object */
GET_OBJ_WEIGHT(temp) -= GET_OBJ_WEIGHT(obj);
if (temp->carried_by)
IS_CARRYING_W(temp->carried_by) -= GET_OBJ_WEIGHT(obj);
obj->in_obj = NULL;
obj->next_content = NULL;
}
/* Set all carried_by to point to new owner */
void object_list_new_owner(struct obj_data * list, struct char_data * ch)
{
if (list) {
object_list_new_owner(list->contains, ch);
object_list_new_owner(list->next_content, ch);
list->carried_by = ch;
}
}
/* Extract an object from the world */
void extract_obj(struct obj_data * obj)
{
struct obj_data *temp;
struct char_data *ch;
struct char_data *next = NULL;
if (obj->worn_by != NULL)
if (unequip_char(obj->worn_by, obj->worn_on) != obj)
log("SYSERR: Inconsistent worn_by and worn_on pointers!!");
if (obj->in_room != NOWHERE)
obj_from_room(obj);
else if (obj->carried_by)
obj_from_char(obj);
else if (obj->in_obj)
obj_from_obj(obj);
/* Seat Extraction Sanity Check */
if (OBJ_SAT_IN_BY(obj)) {
for (ch = OBJ_SAT_IN_BY(obj); OBJ_SAT_IN_BY(obj); ch = next) {
if (!NEXT_IN_SEAT(ch))
OBJ_SAT_IN_BY(obj) = NULL;
else
OBJ_SAT_IN_BY(obj) = (next = NEXT_IN_SEAT(ch));
SITTING_IN(ch) = NULL;
NEXT_IN_SEAT(ch) = NULL;
}
}
/* Removing Money from a Character */
if ( (obj->carried_by) && (GET_OBJ_TYPE(obj) == ITEM_MONEY) )
GET_GOLD(obj->carried_by) -= money_obj_value(obj);
/* Get rid of the contents of the object, as well. */
while (obj->contains)
extract_obj(obj->contains);
REMOVE_FROM_LIST(obj, object_list, next);
if (GET_OBJ_RNUM(obj) >= 0)
(obj_index[GET_OBJ_RNUM(obj)].number)--;
if (SCRIPT(obj))
extract_script(SCRIPT(obj));
free_obj(obj);
}
void update_object(struct obj_data * obj, int use)
{
/* dont update objects with a timer trigger */
if (!SCRIPT_CHECK(obj, OTRIG_TIMER) && (GET_OBJ_TIMER(obj) > 0))
GET_OBJ_TIMER(obj) -= use;
if (obj->contains)
update_object(obj->contains, use);
if (obj->next_content)
update_object(obj->next_content, use);
}
void update_char_objects(struct char_data * ch)
{
int i;
if (GET_EQ(ch, WEAR_LIGHT) != NULL)
if (GET_OBJ_TYPE(GET_EQ(ch, WEAR_LIGHT)) == ITEM_LIGHT)
if (GET_OBJ_VAL(GET_EQ(ch, WEAR_LIGHT), 2) > 0) {
i = --GET_OBJ_VAL(GET_EQ(ch, WEAR_LIGHT), 2);
if (i == 1) {
send_to_char("Your light begins to flicker and fade.\r\n", ch);
act("$n's light begins to flicker and fade.", FALSE, ch, 0, 0, TO_ROOM);
} else if (i == 0) {
send_to_char("Your light sputters out and dies.\r\n", ch);
act("$n's light sputters out and dies.", FALSE, ch, 0, 0, TO_ROOM);
world[ch->in_room].light--;
}
{ /* Decrease objet value over time */
struct obj_data *proto;
obj_rnum r_num;
if ((r_num = real_object(GET_OBJ_VNUM(GET_EQ(ch, WEAR_LIGHT)))) < 0) {
mudlog("SYSERR: In light value reduction - couldn't get object's rnum!", NRM, 32, TRUE);
return;
}
proto = read_object(r_num, REAL);
GET_OBJ_COST(GET_EQ(ch, WEAR_LIGHT)) = GET_OBJ_COST(proto) *
GET_OBJ_VAL(GET_EQ(ch, WEAR_LIGHT), 2) / GET_OBJ_VAL(proto, 2);
extract_obj(proto);
}
}
for (i = 0; i < NUM_WEARS; i++)
if (GET_EQ(ch, i))
update_object(GET_EQ(ch, i), 2);
if (ch->carrying)
update_object(ch->carrying, 1);
}
/* Extract a ch completely from the world, and leave his stuff behind */
void extract_char(struct char_data * ch)
{
struct char_data *k, *temp;
struct descriptor_data *t_desc;
struct obj_data *obj;
int i, freed = 0;
char_from_chair(ch);
/* Get rid of the mount */
if (RIDING(ch) || RIDDEN_BY(ch))
dismount_char(ch);
if (!IS_NPC(ch) && !ch->desc) {
for (t_desc = descriptor_list; t_desc; t_desc = t_desc->next)
if (t_desc->original == ch)
do_return(t_desc->character, NULL, 0, 0);
}
if (ch->in_room == NOWHERE) {
log("SYSERR: NOWHERE extracting char %s. (%s, extract_char)",
GET_NAME(ch), __FILE__);
exit(1);
}
if (ch->followers || ch->master)
die_follower(ch);
if (ch->desc) {
/* Fix a duplication bug for character extractions. */
for (t_desc = descriptor_list; t_desc; t_desc = t_desc->next) {
if (t_desc == ch->desc || !t_desc->character)
continue;
if (GET_IDNUM(ch) == GET_IDNUM(t_desc->character)) {
SEND_TO_Q("Mulitple login detected -- bye.\r\n", t_desc);
STATE(t_desc) = CON_CLOSE;
}
}
/* Forget snooping, if applicable */
if (ch->desc->snooping) {
ch->desc->snooping->snoop_by = NULL;
ch->desc->snooping = NULL;
}
if (ch->desc->snoop_by) {
SEND_TO_Q("Your victim is no longer among us.\r\n",
ch->desc->snoop_by);
ch->desc->snoop_by->snooping = NULL;
ch->desc->snoop_by = NULL;
}
}
/* transfer objects to room, if any */
while (ch->carrying) {
obj = ch->carrying;
obj_from_char(obj);
obj_to_room(obj, ch->in_room);
}
/* transfer equipment to room, if any */
for (i = 0; i < NUM_WEARS; i++)
if (GET_EQ(ch, i))
obj_to_room(unequip_char(ch, i), ch->in_room);
if (FIGHTING(ch))
stop_fighting(ch);
for (k = combat_list; k; k = temp) {
temp = k->next_fighting;
if (FIGHTING(k) == ch)
stop_fighting(k);
}
char_from_room(ch);
/* pull the char from the list */
REMOVE_FROM_LIST(ch, character_list, next);
if (ch->desc && ch->desc->original)
do_return(ch, NULL, 0, 0);
if (!IS_NPC(ch)) {
save_char(ch, NOWHERE);
Crash_delete_crashfile(ch);
} else {
if (GET_MOB_RNUM(ch) > -1) /* if mobile */
mob_index[GET_MOB_RNUM(ch)].number--;
clearMemory(ch); /* Only NPC's can have memory */
if (SCRIPT(ch))
extract_script(SCRIPT(ch));
if (SCRIPT_MEM(ch))
extract_script_mem(SCRIPT_MEM(ch));
free_char(ch);
freed = 1;
}
if (!freed && ch->desc != NULL) {
STATE(ch->desc) = CON_MENU;
SEND_TO_Q(MENU, ch->desc);
} else { /* if a player gets purged from within the game */
if (!freed)
free_char(ch);
}
}
/* ***********************************************************************
* Here follows high-level versions of some earlier routines, ie functions*
* which incorporate the actual player-data *.
*********************************************************************** */
struct char_data *get_player_vis(struct char_data * ch, char *name, int inroom)
{
struct char_data *i;
for (i = character_list; i; i = i->next) {
if (IS_NPC(i))
continue;
if (inroom == FIND_CHAR_ROOM && i->in_room != ch->in_room)
continue;
if (str_cmp(i->player.name, name)) /* If not same, continue */
continue;
if (!CAN_SEE(ch, i))
continue;
return (i);
}
return (NULL);
}
struct char_data *get_char_room_vis(struct char_data * ch, char *name)
{
struct char_data *i;
int j = 0, number;
char tmpname[MAX_INPUT_LENGTH];
char *tmp = tmpname;
/* JE 7/18/94 :-) :-) */
if (!str_cmp(name, "self") || !str_cmp(name, "me"))
return (ch);
/* 0.<name> means PC with name */
strcpy(tmp, name);
if (!(number = get_number(&tmp)))
return (get_player_vis(ch, tmp, FIND_CHAR_ROOM));
for (i = world[ch->in_room].people; i && j <= number; i = i->next_in_room)
if (isname(tmp, i->player.name))
if (CAN_SEE(ch, i))
if (++j == number)
return (i);
return (NULL);
}
struct char_data *get_char_vis(struct char_data * ch, char *name, int where)
{
struct char_data *i;
int j = 0, number;
char tmpname[MAX_INPUT_LENGTH];
char *tmp = tmpname;
/* check the room first */
if (where == FIND_CHAR_ROOM)
return get_char_room_vis(ch, name);
else if (where == FIND_CHAR_WORLD) {
if ((i = get_char_room_vis(ch, name)) != NULL)
return (i);
strcpy(tmp, name);
if (!(number = get_number(&tmp)))
return get_player_vis(ch, tmp, 0);
for (i = character_list; i && (j <= number); i = i->next)
if (isname(tmp, i->player.name) && CAN_SEE(ch, i))
if (++j == number)
return (i);
}
return (NULL);
}
struct obj_data *get_obj_in_list_vis(struct char_data * ch, char *name,
struct obj_data * list)
{
struct obj_data *i;
int j = 0, number;
char tmpname[MAX_INPUT_LENGTH];
char *tmp = tmpname;
if (!str_cmp(name, "it")) {
if (GET_OBJ_IT(ch) == NULL)
return (NULL);
for (i = list; i; i = i->next_content)
if (GET_OBJ_IT(ch) == i)
if (CAN_SEE_OBJ(ch, i)) {
GET_OBJ_IT(ch) = i;
return (i); }
return (NULL); }
strcpy(tmp, name);
if (!(number = get_number(&tmp)))
return (NULL);
for (i = list; i && (j <= number); i = i->next_content)
if (isname(tmp, i->name))
if (CAN_SEE_OBJ(ch, i))
if (++j == number) {
GET_OBJ_IT(ch) = i;
return (i); }
return (NULL);
}
/* search the entire world for an object, and return a pointer */
struct obj_data *get_obj_vis(struct char_data * ch, char *name)
{
struct obj_data *i;
int j = 0, number;
char tmpname[MAX_INPUT_LENGTH];
char *tmp = tmpname;
/* scan items carried */
if ((i = get_obj_in_list_vis(ch, name, ch->carrying)) != NULL)
return (i);
/* scan room */
if ((i = get_obj_in_list_vis(ch, name, world[ch->in_room].contents)) != NULL)
return (i);
strcpy(tmp, name);
if ((number = get_number(&tmp)) == 0)
return (NULL);
/* ok.. no luck yet. scan the entire obj list */
for (i = object_list; i && (j <= number); i = i->next)
if (isname(tmp, i->name))
if (CAN_SEE_OBJ(ch, i))
if (++j == number)
return (i);
return (NULL);
}
struct obj_data *get_object_in_equip_vis(struct char_data * ch,
char *arg, struct obj_data * equipment[], int *j)
{
if (!str_cmp(arg, "it")) {
if (GET_OBJ_IT(ch) == NULL)
return (NULL);
for ((*j) = 0; (*j) < (NUM_WEARS - 1); (*j)++)
if (equipment[(*j)])
if (CAN_SEE_OBJ(ch, equipment[(*j)]))
if (GET_OBJ_IT(ch) == equipment[(*j)]) {
GET_OBJ_IT(ch) = equipment[(*j)];
return (equipment[(*j)]); }
return (NULL); }
for ((*j) = 0; (*j) < (NUM_WEARS - 1); (*j)++)
if (equipment[(*j)])
if (CAN_SEE_OBJ(ch, equipment[(*j)]))
if (isname(arg, equipment[(*j)]->name))
return (equipment[(*j)]);
return (NULL);
}
/* Generic Find, designed to find any object/character
*
* Calling:
* *arg is the pointer containing the string to be searched for.
* This string doesn't have to be a single word, the routine
* extracts the next word itself.
* bitv.. All those bits that you want to "search through".
* Bit found will be result of the function
* *ch This is the person that is trying to "find"
* **tar_ch Will be NULL if no character was found, otherwise points
* **tar_obj Will be NULL if no object was found, otherwise points
*
* The routine used to return a pointer to the next word in *arg (just
* like the one_argument routine), but now it returns an integer that
* describes what it filled in.
*/
int generic_find(char *arg, bitvector_t bitvector, struct char_data * ch,
struct char_data ** tar_ch, struct obj_data ** tar_obj)
{
int i, found;
char name[256];
*tar_ch = NULL;
*tar_obj = NULL;
one_argument(arg, name);
if (!*name)
return (0);
if (IS_SET(bitvector, FIND_CHAR_ROOM)) { /* Find person in room */
if ((*tar_ch = get_char_vis(ch, name, FIND_CHAR_ROOM)) != NULL)
return (FIND_CHAR_ROOM);
}
if (IS_SET(bitvector, FIND_CHAR_WORLD)) {
if ((*tar_ch = get_char_vis(ch, name, FIND_CHAR_WORLD)) != NULL)
return (FIND_CHAR_WORLD);
}
if (IS_SET(bitvector, FIND_OBJ_INV)) {
if ((*tar_obj = get_obj_in_list_vis(ch, name, ch->carrying)) != NULL)
return (FIND_OBJ_INV);
}
if (IS_SET(bitvector, FIND_OBJ_EQUIP)) {
for (found = FALSE, i = 0; i < (NUM_WEARS - 1) && !found; i++)
if (GET_EQ(ch, i) && isname(name, GET_EQ(ch, i)->name)) {
*tar_obj = GET_EQ(ch, i);
found = TRUE;
}
if (found)
return (FIND_OBJ_EQUIP);
}
if (IS_SET(bitvector, FIND_OBJ_ROOM)) {
if ((*tar_obj = get_obj_in_list_vis(ch, name, world[ch->in_room].contents)) != NULL)
return (FIND_OBJ_ROOM);
}
if (IS_SET(bitvector, FIND_OBJ_WORLD)) {
if ((*tar_obj = get_obj_vis(ch, name)))
return (FIND_OBJ_WORLD);
}
return (0);
}
/* a function to scan for "all" or "all.x" */
int find_all_dots(char *arg)
{
if (!strcmp(arg, "all"))
return (FIND_ALL);
else if (!strncmp(arg, "all.", 4)) {
strcpy(arg, arg + 4);
return (FIND_ALLDOT);
} else
return (FIND_INDIV);
}
void char_from_chair(struct char_data *ch)
{
struct obj_data *chair;
struct char_data *tempch;
int i, found = 0;
if (!SITTING_IN(ch))
return;
if (!(chair = SITTING_IN(ch))){
log("SYSERR: ACK, no chair for char in char from chair");
SITTING_IN(ch) = NULL;
NEXT_IN_SEAT(ch) = NULL;
return;
}
if (!(tempch = OBJ_SAT_IN_BY(chair))){
log("SYSERR: Char from chair, but no chair!");
SITTING_IN(ch) = NULL;
NEXT_IN_SEAT(ch) = NULL;
return;
}
if (tempch == ch){
if (!NEXT_IN_SEAT(ch))
OBJ_SAT_IN_BY(chair) = NULL;
else
OBJ_SAT_IN_BY(chair) = NEXT_IN_SEAT(ch);
GET_OBJ_VAL(chair, 1) -= 1;
SITTING_IN(ch) = NULL;
NEXT_IN_SEAT(ch) = NULL;
return;
}
for (i = 0; i < GET_OBJ_VAL(chair, 1) && found == 0; i++){
if (NEXT_IN_SEAT(tempch) == ch){
NEXT_IN_SEAT(tempch) = NEXT_IN_SEAT(ch);
found = 1;
}
}
if (found == 0)
log("SYSERR: Char flagged as sitting, but not in chair");
else
GET_OBJ_VAL(chair, 1) -= 1;
SITTING_IN(ch) = NULL;
NEXT_IN_SEAT(ch) = NULL;
return;
}
/* Move passengers along who are in a vehicle */
void move_vehicle(struct obj_data *object, room_rnum room) {
struct char_data *tempch, *nextch;
for (tempch = OBJ_SAT_IN_BY(object); tempch; tempch = nextch) {
nextch = NEXT_IN_SEAT(tempch);
/* Pilot is moved in do_simple_move */
if (tempch == OBJ_SAT_IN_BY(object))
continue;
char_from_room(tempch);
char_to_room(tempch, room);
look_at_room(tempch, 0);
if (ROOM_FLAGGED(room, ROOM_DEATH) && GET_LEVEL(tempch) < LVL_IMMORT) {
if (!IS_NPC(tempch))
GET_DT_CNT(tempch)++;
send_to_char("Died in vehicle routine\r\n", tempch);
log_death_trap(tempch);
death_cry(tempch);
extract_char(tempch);
}
}
/* Move the vehicle */
obj_from_room(object);
obj_to_room(object, room);
}
/* Mount Support */
void dismount_char(struct char_data *ch) {
if (RIDING(ch)) {
RIDDEN_BY(RIDING(ch)) = NULL;
RIDING(ch) = NULL;
}
if (RIDDEN_BY(ch)) {
RIDING(RIDDEN_BY(ch)) = NULL;
RIDDEN_BY(ch) = NULL;
}
}
void mount_char(struct char_data *ch, struct char_data *mount) {
RIDING(ch) = mount;
RIDDEN_BY(mount) = ch;
}
int obj_sank_or_fell(struct obj_data *obj) {
room_rnum roomnum;
if ((SECT(obj->in_room) == SECT_FLYING) &&
(GET_OBJ_TYPE(obj) != ITEM_AIRPLANE) ) {
act("$p falls from the sky with a whistle.", FALSE, 0, obj, 0, TO_ROOM);
extract_obj(obj);
return 1; }
/* Not flying and not sinking, no need to handle it. */
if (!IS_WATER(obj->in_room))
return 0;
if ((!world[obj->in_room].dir_option[DOWN]) ||
(world[obj->in_room].dir_option[DOWN]->to_room == NOWHERE) ||
(IS_SET(world[obj->in_room].dir_option[DOWN]->exit_info, EX_CLOSED))) {
act("$p sinks through the water and comes to rest.",
FALSE, world[obj->in_room].people, obj, 0, TO_ROOM);
act("$p sinks through the water and comes to rest.",
FALSE, world[obj->in_room].people, obj, 0, TO_CHAR);
return 0;}
if ((GET_OBJ_WEIGHT(obj) > 0) && (obj->in_room != NOWHERE) &&
(GET_OBJ_TYPE(obj) != ITEM_BOAT) &&
(GET_OBJ_TYPE(obj) != ITEM_AIRPLANE) ) {
while ((world[obj->in_room].dir_option[DOWN]) &&
(world[obj->in_room].dir_option[DOWN]->to_room != NOWHERE) &&
(!IS_SET(world[obj->in_room].dir_option[DOWN]->exit_info, EX_CLOSED)) ) {
act("$p sinks into the watery depths.",
FALSE, world[obj->in_room].people, obj, 0, TO_ROOM);
act("$p sinks into the watery depths.",
FALSE, world[obj->in_room].people, obj, 0, TO_CHAR);
roomnum = world[obj->in_room].dir_option[DOWN]->to_room;
obj_from_room(obj);
obj_to_room(obj, roomnum);
}
}
return 0;
}