/*
* file: handler.c , Handler module. Part of DIKUMUD
* Usage: Various routines for moving about objects/players
* Copyright (C) 1990, 1991 - see 'license.doc' for complete information.
*/
#include <stdio.h>
#include <stdlib.h>
/* #include <unistd.h> */
#include <sys/types.h>
#include <string.h>
#include <ctype.h>
#include <signal.h>
#include "global.h"
#include "bug.h"
#include "utils.h"
#include "comm.h"
#include "db.h"
#include "interpreter.h"
#include "spells.h"
#include "spell_parser.h"
#include "constants.h"
#include "fight.h"
#include "modify.h"
#include "multiclass.h"
#include "opinion.h"
#include "act_wiz.h"
#define _HANDLER_C
#include "handler.h"
char *fname(const char *namelist)
{
static char holder[30] = "\0\0\0\0\0\0\0";
char *point = NULL;
if (DEBUG > 2)
log_info("called %s with %s", __PRETTY_FUNCTION__, VNULL(namelist));
for (point = holder; isalpha(*namelist); namelist++, point++)
*point = *namelist;
*point = '\0';
return (holder);
}
/*
* str must be writable
*/
int split_string(char *str, const char *sep, char **argv)
{
char *s = NULL;
int argc = 0;
if (DEBUG > 2)
log_info("called %s with %s, %s, %08zx", __PRETTY_FUNCTION__, VNULL(str), VNULL(sep),
(size_t) argv);
s = strtok(str, sep);
if (s)
argv[argc++] = s;
else {
*argv = str;
return 1;
}
while ((s = strtok(NULL, sep))) {
argv[argc++] = s;
}
return argc;
}
int isname(const char *str, const char *namelist)
{
char *argv[30];
char *xargv[30];
int argc = 0;
int xargc = 0;
int i = 0;
int j = 0;
int exact = FALSE;
char buf[MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0";
char names[MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0";
char *s = NULL;
if (DEBUG > 2)
log_info("called %s with %s, %s", __PRETTY_FUNCTION__, VNULL(str), VNULL(namelist));
strcpy(buf, str);
argc = split_string(buf, "- \t\r\n,", argv);
strcpy(names, namelist);
xargc = split_string(names, "- \t\r\n,", xargv);
s = argv[argc - 1];
s += strlen(s);
if (*(--s) == '.') {
exact = 1;
*s = 0;
} else {
exact = 0;
}
/*
* the string has now been split into separate words with the '-' replaced by string terminators. pointers to the
* beginning of each word are in argv
*/
if (exact && argc != xargc)
return 0;
for (i = 0; i < argc; i++) {
for (j = 0; j < xargc; j++) {
if (0 == str_cmp(argv[i], xargv[j])) {
xargv[j] = NULL;
break;
}
}
if (j >= xargc)
return 0;
}
return 1;
}
void init_string_block(struct string_block *sb)
{
if (DEBUG > 2)
log_info("called %s with %08zx", __PRETTY_FUNCTION__, (size_t) sb);
CREATE(sb->data, char, sb->size = 128);
/*
* Quixadhal: WHY send yourslef a SIG_ALARM if you're out of memory???
*/
#if 0
if ((sb->data = (char *)malloc(sb->size = *128)))
*sb->data = '\0';
else {
log_error("Malloc call to init_string_block failed. Exiting.");
kill(getpid(), 14);
}
#endif
}
void append_to_string_block(struct string_block *sb, char *str)
{
int len = 0;
if (DEBUG > 2)
log_info("called %s with %08zx, %s", __PRETTY_FUNCTION__, (size_t) sb, VNULL(str));
len = strlen(sb->data) + strlen(str) + 1;
if (len > sb->size) {
if (len > (sb->size *= 2))
sb->size = len;
RECREATE(sb->data, char, sb->size);
}
strcat(sb->data, str);
}
void page_string_block(struct string_block *sb, struct char_data *ch)
{
if (DEBUG > 2)
log_info("called %s with %08zx, %s", __PRETTY_FUNCTION__, (size_t) sb, SAFE_NAME(ch));
page_string(ch->desc, sb->data, 1);
}
void destroy_string_block(struct string_block *sb)
{
if (DEBUG > 2)
log_info("called %s with %08zx", __PRETTY_FUNCTION__, (size_t) sb);
DESTROY(sb->data);
sb->data = NULL;
}
void affect_modify(struct char_data *ch, char loc, char mod, long bitv, char add)
{
int i = 0;
if (DEBUG > 2)
log_info("called %s with %s, %d, %d, %ld, %d", __PRETTY_FUNCTION__, SAFE_NAME(ch),
(int)loc, (int)mod, bitv, (int)add);
if (loc == APPLY_IMMUNE) {
if (add) {
SET_BIT(ch->immune, mod);
} else {
REMOVE_BIT(ch->immune, mod);
}
} else if (loc == APPLY_SUSC) {
if (add) {
SET_BIT(ch->susc, mod);
} else {
REMOVE_BIT(ch->susc, mod);
}
} else if (loc == APPLY_M_IMMUNE) {
if (add) {
SET_BIT(ch->M_immune, mod);
} else {
REMOVE_BIT(ch->M_immune, mod);
}
} else if (loc == APPLY_SPELL) {
if (add) {
SET_BIT(ch->specials.affected_by, mod);
} else {
REMOVE_BIT(ch->specials.affected_by, mod);
}
} else if (loc == APPLY_WEAPON_SPELL) {
return;
} else {
if (add) {
SET_BIT(ch->specials.affected_by, bitv);
} else {
REMOVE_BIT(ch->specials.affected_by, 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_SEX:
/*
* ??? GET_SEX(ch) += mod;
*/
break;
case APPLY_CLASS:
break;
case APPLY_LEVEL:
break;
case APPLY_AGE:
/*
* ch->player.time.birth += mod;
*/
break;
case APPLY_CHAR_WEIGHT:
GET_WEIGHT(ch) += mod;
break;
case APPLY_CHAR_HEIGHT:
GET_HEIGHT(ch) += mod;
break;
case APPLY_MANA:
ch->points.max_mana += mod;
break;
case APPLY_HIT:
ch->points.max_hit += mod;
break;
case APPLY_MOVE:
ch->points.max_move += 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:
ch->specials.apply_saving_throw[0] += mod;
break;
case APPLY_SAVING_ROD:
ch->specials.apply_saving_throw[1] += mod;
break;
case APPLY_SAVING_PETRI:
ch->specials.apply_saving_throw[2] += mod;
break;
case APPLY_SAVING_BREATH:
ch->specials.apply_saving_throw[3] += mod;
break;
case APPLY_SAVING_SPELL:
ch->specials.apply_saving_throw[4] += mod;
break;
case APPLY_SAVE_ALL:
{
for (i = 0; i < 5; i++)
ch->specials.apply_saving_throw[i] += mod;
}
break;
case APPLY_IMMUNE:
break;
case APPLY_SUSC:
break;
case APPLY_M_IMMUNE:
break;
case APPLY_SPELL:
break;
case APPLY_HITNDAM:
GET_HITROLL(ch) += mod;
GET_DAMROLL(ch) += mod;
break;
case APPLY_WEAPON_SPELL:
case APPLY_EAT_SPELL:
break;
case APPLY_BACKSTAB:
ch->skills[SKILL_BACKSTAB].learned += mod;
break;
case APPLY_KICK:
ch->skills[SKILL_KICK].learned += mod;
break;
case APPLY_SNEAK:
ch->skills[SKILL_SNEAK].learned += mod;
break;
case APPLY_HIDE:
ch->skills[SKILL_HIDE].learned += mod;
break;
case APPLY_BASH:
ch->skills[SKILL_BASH].learned += mod;
break;
case APPLY_PICK:
ch->skills[SKILL_PICK_LOCK].learned += mod;
break;
case APPLY_STEAL:
ch->skills[SKILL_STEAL].learned += mod;
break;
case APPLY_TRACK:
ch->skills[SKILL_TRACK].learned += mod;
break;
default:
log_error("Unknown apply adjust attempt by %s.", ch->player.name);
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 = NULL;
int i = 0;
int j = 0;
if (DEBUG > 2)
log_info("called %s with %s", __PRETTY_FUNCTION__, SAFE_NAME(ch));
for (i = 0; i < MAX_WEAR; i++) {
if (ch->equipment[i])
for (j = 0; j < MAX_OBJ_AFFECT; j++)
affect_modify(ch, ch->equipment[i]->affected[j].location,
ch->equipment[i]->affected[j].modifier,
ch->equipment[i]->obj_flags.bitvector, FALSE);
}
for (af = ch->affected; af; af = af->next)
affect_modify(ch, af->location, af->modifier, af->bitvector, FALSE);
ch->tmpabilities = ch->abilities;
for (i = 0; i < MAX_WEAR; i++) {
if (ch->equipment[i])
for (j = 0; j < MAX_OBJ_AFFECT; j++)
affect_modify(ch, ch->equipment[i]->affected[j].location,
ch->equipment[i]->affected[j].modifier,
ch->equipment[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, MIN(GET_STR(ch), i));
}
/* 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 = NULL;
if (DEBUG > 1)
log_info("called %s with %s, %08zx", __PRETTY_FUNCTION__, SAFE_NAME(ch), (size_t) af);
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 *hjp = NULL;
if (DEBUG > 2)
log_info("called %s with %s, %08zx", __PRETTY_FUNCTION__, SAFE_NAME(ch), (size_t) af);
if (!ch->affected)
return;
affect_modify(ch, af->location, af->modifier, af->bitvector, FALSE);
/*
* remove structure *af from linked list
*/
if (ch->affected == af) {
/*
* remove head of list
*/
ch->affected = af->next;
} else {
for (hjp = ch->affected; (hjp->next) && (hjp->next != af); hjp = hjp->next);
if (hjp->next != af) {
log_error("Could not locate affected_type in ch->affected.");
return;
}
hjp->next = af->next; /* skip the af element */
}
DESTROY(af);
affect_total(ch);
}
/* Call affect_remove with every spell of spelltype "skill" */
void affect_from_char(struct char_data *ch, short skill)
{
struct affected_type *hjp = NULL;
if (DEBUG > 1)
log_info("called %s with %s, %hd", __PRETTY_FUNCTION__, SAFE_NAME(ch), skill);
for (hjp = ch->affected; hjp; hjp = hjp->next)
if (hjp->type == skill)
affect_remove(ch, hjp);
}
/* Return if a char is affected by a spell (SPELL_XXX), NULL indicates
* not affected */
char affected_by_spell(struct char_data *ch, short skill)
{
struct affected_type *hjp = NULL;
if (DEBUG > 2)
log_info("called %s with %s, %hd", __PRETTY_FUNCTION__, SAFE_NAME(ch), skill);
for (hjp = ch->affected; hjp; hjp = hjp->next)
if (hjp->type == skill)
return (TRUE);
return (FALSE);
}
void affect_join(struct char_data *ch, struct affected_type *af, char avg_dur, char avg_mod)
{
struct affected_type *hjp = NULL;
char found = FALSE;
if (DEBUG > 2)
log_info("called %s with %s, %08zx, %d, %d", __PRETTY_FUNCTION__, SAFE_NAME(ch),
(size_t) af, (int)avg_dur, (int)avg_mod);
for (hjp = ch->affected; !found && hjp; hjp = hjp->next) {
if (hjp->type == af->type) {
af->duration += hjp->duration;
if (avg_dur)
af->duration /= 2;
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 *i = NULL;
struct room_data *rp = NULL;
if (DEBUG > 1)
log_info("called %s with %s", __PRETTY_FUNCTION__, SAFE_NAME(ch));
if (ch->in_room == NOWHERE) {
log_error("NOWHERE extracting char from room");
return;
}
if (ch->equipment[WEAR_LIGHT])
if (ch->equipment[WEAR_LIGHT]->obj_flags.type_flag == ITEM_LIGHT)
if (ch->equipment[WEAR_LIGHT]->obj_flags.value[2]) { /* Light is ON */
real_roomp(ch->in_room)->light--;
if (real_roomp(ch->in_room)->light < 1)
reprintf(ch->in_room, ch, "A source of light leaves the room....\r\n");
}
rp = real_roomp(ch->in_room);
if (rp == NULL) {
log_info("ERROR: char_from_room: %s was not in a valid room (%d)",
(!IS_NPC(ch) ? (ch)->player.name : (ch)->player.short_descr), ch->in_room);
return;
}
if (ch == rp->people) /* head of list */
rp->people = ch->next_in_room;
else { /* locate the previous element */
for (i = rp->people; i && i->next_in_room != ch; i = i->next_in_room);
if (i)
i->next_in_room = ch->next_in_room;
else {
log_error("SHIT, %s was not in people list of his room %d!",
(!IS_NPC(ch) ? (ch)->player.name : (ch)->player.short_descr),
ch->in_room);
}
}
ch->in_room = NOWHERE;
ch->next_in_room = 0;
}
/* place a character in a room */
void char_to_room(struct char_data *ch, int room)
{
struct room_data *rp = NULL;
if (DEBUG > 1)
log_info("called %s with %s, %d", __PRETTY_FUNCTION__, SAFE_NAME(ch), room);
rp = real_roomp(room);
if (!rp) {
room = 0;
rp = real_roomp(room);
if (!rp) {
log_fatal("Cannot lookup room %d!", room);
proper_exit(MUD_HALT);
}
}
ch->next_in_room = rp->people;
rp->people = ch;
ch->in_room = room;
if (ch->equipment[WEAR_LIGHT])
if (ch->equipment[WEAR_LIGHT]->obj_flags.type_flag == ITEM_LIGHT)
if (ch->equipment[WEAR_LIGHT]->obj_flags.value[2]) { /* Light is ON */
if ((rp->light < 1) && (ch->in_room))
reprintf(ch->in_room, ch, "A source of light enters the room...\r\n");
rp->light++;
}
}
/* give an object to a char */
void obj_to_char(struct obj_data *object, struct char_data *ch)
{
if (DEBUG > 1)
log_info("called %s with %s, %s", __PRETTY_FUNCTION__, SAFE_ONAME(object),
SAFE_NAME(ch));
if (ch->carrying)
object->next_content = ch->carrying;
else
object->next_content = 0;
ch->carrying = object;
object->carried_by = ch;
object->in_room = NOWHERE;
IS_CARRYING_W(ch) += GET_OBJ_WEIGHT(object);
IS_CARRYING_N(ch)++;
}
/* take an object from a char */
void obj_from_char(struct obj_data *object)
{
struct obj_data *tmp = NULL;
if (DEBUG > 1)
log_info("called %s with %s", __PRETTY_FUNCTION__, SAFE_ONAME(object));
if (!object) {
object = 0;
return;
}
if (!object->carried_by) {
object = 0;
return;
}
if (!object->carried_by->carrying) {
object = 0;
return;
}
if (object->carried_by->carrying == object) /* head of list */
object->carried_by->carrying = object->next_content;
else {
for (tmp = object->carried_by->carrying; tmp && (tmp->next_content != object); tmp = tmp->next_content); /* locate
* previous
*/
if (!tmp) {
object = 0;
return;
}
tmp->next_content = object->next_content;
}
IS_CARRYING_W(object->carried_by) -= GET_OBJ_WEIGHT(object);
IS_CARRYING_N(object->carried_by)--;
object->carried_by = 0;
object->equipped_by = 0; /* should be unnecessary, but, why risk it */
object->next_content = 0;
}
/* Return the effect of a piece of armor in position eq_pos */
int apply_ac(struct char_data *ch, int eq_pos)
{
if (DEBUG > 2)
log_info("called %s with %s, %d", __PRETTY_FUNCTION__, SAFE_NAME(ch), eq_pos);
if (!ch->equipment[eq_pos])
return 0;
if (DEBUG)
log_info("apply_ac");
if (!(GET_ITEM_TYPE(ch->equipment[eq_pos]) == ITEM_ARMOR))
return 0;
switch (eq_pos) {
case WEAR_BODY:
return (3 * ch->equipment[eq_pos]->obj_flags.value[0]); /* 30% */
case WEAR_HEAD:
return (2 * ch->equipment[eq_pos]->obj_flags.value[0]); /* 20% */
case WEAR_LEGS:
return (2 * ch->equipment[eq_pos]->obj_flags.value[0]); /* 20% */
case WEAR_FEET:
return (ch->equipment[eq_pos]->obj_flags.value[0]); /* 10% */
case WEAR_HANDS:
return (ch->equipment[eq_pos]->obj_flags.value[0]); /* 10% */
case WEAR_ARMS:
return (ch->equipment[eq_pos]->obj_flags.value[0]); /* 10% */
case WEAR_SHIELD:
return (ch->equipment[eq_pos]->obj_flags.value[0]); /* 10% */
}
return 0;
}
void equip_char(struct char_data *ch, struct obj_data *obj, int pos)
{
int j = 0;
if (DEBUG > 2)
log_info("called %s with %s, %s, %d", __PRETTY_FUNCTION__, SAFE_NAME(ch),
SAFE_ONAME(obj), pos);
if (pos < 0 || pos >= MAX_WEAR)
return;
if (DEBUG)
log_info("equip_char");
if (obj->carried_by) {
log_info("EQUIP: Obj is carried_by when equip.");
return;
}
if (obj->in_room != NOWHERE) {
log_info("EQUIP: Obj is in_room when equip.");
return;
}
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))) {
if (ch->in_room != NOWHERE) {
act("You are zapped by $p and instantly drop it.", FALSE, ch, obj, 0, TO_CHAR);
act("$n is zapped by $p and instantly drop it.", FALSE, ch, obj, 0, TO_ROOM);
obj_to_room(obj, ch->in_room);
return;
} else {
log_info("ch->in_room = NOWHERE when equipping char.");
}
}
ch->equipment[pos] = obj;
obj->equipped_by = ch;
obj->eq_pos = pos;
if (GET_ITEM_TYPE(obj) == ITEM_ARMOR)
GET_AC(ch) -= apply_ac(ch, pos);
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 = 0;
struct obj_data *obj = NULL;
if (DEBUG > 2)
log_info("called %s with %s, %d", __PRETTY_FUNCTION__, SAFE_NAME(ch), pos);
if (pos < 0 || pos >= MAX_WEAR)
return NULL;
if (!ch->equipment[pos])
return NULL;
if (DEBUG)
log_info("unequip_char");
obj = ch->equipment[pos];
if (GET_ITEM_TYPE(obj) == ITEM_ARMOR)
GET_AC(ch) += apply_ac(ch, pos);
ch->equipment[pos] = 0;
obj->equipped_by = NULL;
obj->eq_pos = -1;
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 = 0;
char *ppos = NULL;
char anumber[MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0";
char spare[MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0";
if (DEBUG > 2)
log_info("called %s with %08zx", __PRETTY_FUNCTION__, (size_t) name);
if ((ppos = (char *)index(*name, '.')) && ppos[1]) {
*ppos++ = '\0';
strcpy(anumber, *name); /* bleed off digits */
strcpy(spare, ppos); /* move name to a tmp space, in case of overlap, thanks
* valgrind */
strcpy(*name, spare);
for (i = 0; *(anumber + i); i++)
if (!isdigit(*(anumber + i)))
return (0);
return (atoi(anumber));
}
return (1);
}
/* Search a given list for an object, and return a pointer to that object */
struct obj_data *get_obj_in_list(const char *name, struct obj_data *list)
{
struct obj_data *i = NULL;
int j = 0;
int anumber = 0;
char tmpname[MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0";
char *tmp = NULL;
if (DEBUG > 2)
log_info("called %s with %s, %08zx", __PRETTY_FUNCTION__, VNULL(name), (size_t) list);
strcpy(tmpname, name);
tmp = tmpname;
/*
* need ---
* special handlers for 2*thing, all.thing
*
* should be built into each command (get, put, buy)
*
* if (getall(name) == tRUE) {
* while *(i = getobj_in_list()) != NULL) {
* blah
* blah
* blah
* }
* } else if ((p = getabunch(name)) != NULL) {
* while (p > 0) {
* i = get_obj_in_list();
* blah
* blah
* blah
* p--;
* }
* }
*/
if (!(anumber = get_number(&tmp)))
return (0);
for (i = list, j = 1; i && (j <= anumber); i = i->next_content)
if (isname(tmp, i->name)) {
if (j == anumber)
return (i);
j++;
}
return (0);
}
/* 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 = NULL;
if (DEBUG > 2)
log_info("called %s with %d, %08zx", __PRETTY_FUNCTION__, num, (size_t) list);
for (i = list; i; i = i->next_content)
if (i->item_number == num)
return (i);
return (0);
}
/*search the entire world for an object, and return a pointer */
struct obj_data *get_obj(const char *name)
{
struct obj_data *i = NULL;
int j = 0;
int anumber = 0;
char tmpname[MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0";
char *tmp = NULL;
if (DEBUG > 2)
log_info("called %s with %s", __PRETTY_FUNCTION__, VNULL(name));
strcpy(tmpname, name);
tmp = tmpname;
if (!(anumber = get_number(&tmp)))
return (0);
for (i = object_list, j = 1; i && (j <= anumber); i = i->next)
if (isname(tmp, i->name)) {
if (j == anumber)
return (i);
j++;
}
return (0);
}
/*search the entire world for an object number, and return a pointer */
struct obj_data *get_obj_num(int nr)
{
struct obj_data *i = NULL;
if (DEBUG > 2)
log_info("called %s with %d", __PRETTY_FUNCTION__, nr);
for (i = object_list; i; i = i->next)
if (i->item_number == nr)
return (i);
return (0);
}
/* search a room for a char, and return a pointer if found.. */
struct char_data *get_char_room(const char *name, int room)
{
struct char_data *i = NULL;
int j = 0;
int anumber = 0;
char tmpname[MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0";
char *tmp = NULL;
if (DEBUG > 2)
log_info("called %s with %s, %d", __PRETTY_FUNCTION__, VNULL(name), room);
strcpy(tmpname, name);
tmp = tmpname;
if (!(anumber = get_number(&tmp)))
return (0);
for (i = real_roomp(room)->people, j = 1; i && (j <= anumber); i = i->next_in_room)
if (isname(tmp, GET_NAME(i))) {
if (j == anumber)
return (i);
j++;
}
return (0);
}
/* search all over the world for a char, and return a pointer if found */
struct char_data *get_char(const char *name)
{
struct char_data *i = NULL;
int j = 0;
int anumber = 0;
char tmpname[MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0";
char *tmp = NULL;
if (DEBUG > 2)
log_info("called %s with %s", __PRETTY_FUNCTION__, VNULL(name));
strcpy(tmpname, name);
tmp = tmpname;
if (!(anumber = get_number(&tmp)))
return (0);
for (i = character_list, j = 1; i && (j <= anumber); i = i->next)
if (isname(tmp, GET_NAME(i))) {
if (j == anumber)
return (i);
j++;
}
return (0);
}
/* search all over the world for a char num, and return a pointer if found */
struct char_data *get_char_num(int nr)
{
struct char_data *i = NULL;
if (DEBUG > 2)
log_info("called %s with %d", __PRETTY_FUNCTION__, nr);
for (i = character_list; i; i = i->next)
if (i->nr == nr)
return (i);
return (0);
}
/* put an object in a room */
void obj_to_room(struct obj_data *object, int room)
{
if (DEBUG > 1)
log_info("called %s with %s, %d", __PRETTY_FUNCTION__, SAFE_ONAME(object), room);
if (room == -1)
room = 4;
object->next_content = real_roomp(room)->contents;
real_roomp(room)->contents = object;
object->in_room = room;
object->carried_by = 0;
object->equipped_by = 0; /* should be unnecessary */
}
/* Take an object from a room */
void obj_from_room(struct obj_data *object)
{
struct obj_data *i = NULL;
if (DEBUG > 1)
log_info("called %s with %s", __PRETTY_FUNCTION__, SAFE_ONAME(object));
/*
* remove object from room
*/
if (object == real_roomp(object->in_room)->contents) /* head of list */
real_roomp(object->in_room)->contents = object->next_content;
else { /* locate previous element in list */
for (i = real_roomp(object->in_room)->contents; i &&
(i->next_content != object); i = i->next_content);
i->next_content = object->next_content;
}
object->in_room = NOWHERE;
object->next_content = 0;
}
/* 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 = NULL;
if (DEBUG > 1)
log_info("called %s with %s, %s", __PRETTY_FUNCTION__, SAFE_ONAME(obj),
SAFE_ONAME(obj_to));
obj->next_content = obj_to->contains;
obj_to->contains = obj;
obj->in_obj = obj_to;
/*
* (jdb) hopefully this will fix the object problem
*/
obj->carried_by = 0;
for (tmp_obj = obj->in_obj; tmp_obj;
GET_OBJ_WEIGHT(tmp_obj) += GET_OBJ_WEIGHT(obj), tmp_obj = tmp_obj->in_obj);
}
/* remove an object from an object */
void obj_from_obj(struct obj_data *obj)
{
struct obj_data *tmp = NULL;
struct obj_data *obj_from = NULL;
if (DEBUG > 1)
log_info("called %s with %s", __PRETTY_FUNCTION__, SAFE_ONAME(obj));
if (obj->in_obj) {
obj_from = obj->in_obj;
if (obj == obj_from->contains) /* head of list */
obj_from->contains = obj->next_content;
else {
for (tmp = obj_from->contains; tmp && (tmp->next_content != obj); tmp = tmp->next_content); /* locate
* previous */
if (!tmp) {
log_fatal("Fatal error in object structures.");
proper_exit(MUD_HALT);
}
tmp->next_content = obj->next_content;
}
/*
* Subtract weight from containers container
*/
for (tmp = obj->in_obj; tmp->in_obj; tmp = tmp->in_obj)
GET_OBJ_WEIGHT(tmp) -= GET_OBJ_WEIGHT(obj);
GET_OBJ_WEIGHT(tmp) -= GET_OBJ_WEIGHT(obj);
/*
* Subtract weight from char that carries the object
*/
if (tmp->carried_by)
IS_CARRYING_W(tmp->carried_by) -= GET_OBJ_WEIGHT(obj);
obj->in_obj = 0;
obj->next_content = 0;
} else {
log_fatal("Trying to object from object when in no object.");
proper_exit(MUD_HALT);
}
}
/* Set all carried_by to point to new owner */
void object_list_new_owner(struct obj_data *list, struct char_data *ch)
{
if (DEBUG > 2)
log_info("called %s with %08zx, %s", __PRETTY_FUNCTION__, (size_t) list, SAFE_NAME(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 *temp1 = NULL;
struct obj_data *temp2 = NULL;
if (DEBUG > 2)
log_info("called %s with %s", __PRETTY_FUNCTION__, SAFE_ONAME(obj));
if (obj->in_room != NOWHERE)
obj_from_room(obj);
else if (obj->carried_by)
obj_from_char(obj);
else if (obj->equipped_by) {
if (obj->eq_pos > -1) {
/*
** set players equipment slot to 0; that will avoid the garbage items.
*/
obj->equipped_by->equipment[(int)obj->eq_pos] = 0;
} else {
log_error("Extract on equipped item in slot -1 on: %s %s",
obj->equipped_by->player.name, obj->name);
return;
}
} else if (obj->in_obj) {
temp1 = obj->in_obj;
if (temp1->contains == obj) /* head of list */
temp1->contains = obj->next_content;
else {
for (temp2 = temp1->contains;
temp2 && (temp2->next_content != obj); temp2 = temp2->next_content);
if (temp2) {
temp2->next_content = obj->next_content;
}
}
}
for (; obj->contains; extract_obj(obj->contains));
/*
* leaves nothing !
*/
if (object_list == obj) /* head of list */
object_list = obj->next;
else {
for (temp1 = object_list; temp1 && (temp1->next != obj); temp1 = temp1->next);
if (temp1)
temp1->next = obj->next;
}
if (obj->item_number >= 0)
(obj_index[obj->item_number].number)--;
free_obj(obj);
}
void update_object(struct obj_data *obj, int use)
{
if (DEBUG > 2)
log_info("called %s with %s, %d", __PRETTY_FUNCTION__, SAFE_ONAME(obj), use);
if (obj->obj_flags.timer > 0)
obj->obj_flags.timer -= use;
if (obj->contains)
update_object(obj->contains, use);
if (obj->next_content)
if (obj->next_content != obj)
update_object(obj->next_content, use);
}
void update_char_objects(struct char_data *ch)
{
int i = 0;
if (DEBUG > 2)
log_info("called %s with %s", __PRETTY_FUNCTION__, SAFE_NAME(ch));
if (ch->equipment[WEAR_LIGHT])
if (ch->equipment[WEAR_LIGHT]->obj_flags.type_flag == ITEM_LIGHT)
if (ch->equipment[WEAR_LIGHT]->obj_flags.value[2] > 0)
(ch->equipment[WEAR_LIGHT]->obj_flags.value[2])--;
for (i = 0; i < MAX_WEAR; i++)
if (ch->equipment[i])
update_object(ch->equipment[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 obj_data *i = NULL;
struct obj_data *o = NULL;
struct char_data *k = NULL;
struct char_data *next_char = NULL;
struct descriptor_data *t_desc = NULL;
int l = 0;
int was_in = FALSE;
int j = 0;
if (DEBUG > 2)
log_info("called %s with %s", __PRETTY_FUNCTION__, SAFE_NAME(ch));
if (IS_PC(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, "", 0);
}
if (ch->in_room == NOWHERE) {
log_error("NOWHERE extracting char.");
/*
** problem from linkdeath
*/
char_to_room(ch, 0); /* 0 == all purpose store */
}
if (ch->followers || ch->master)
die_follower(ch);
if (ch->desc) {
/*
* Forget snooping
*/
if (ch->desc->snoop.snooping)
ch->desc->snoop.snooping->desc->snoop.snoop_by = 0;
if (ch->desc->snoop.snoop_by) {
cprintf(ch->desc->snoop.snoop_by, "Your victim is no longer among us.\r\n");
ch->desc->snoop.snoop_by->desc->snoop.snooping = 0;
}
ch->desc->snoop.snooping = ch->desc->snoop.snoop_by = 0;
}
if (ch->carrying) {
/*
* transfer ch's objects to room
*/
if (!IS_IMMORTAL(ch)) {
if (real_roomp(ch->in_room)->contents) { /* room nonempty */
/*
* locate tail of room-contents
*/
for (i = real_roomp(ch->in_room)->contents; i->next_content;
i = i->next_content);
/*
* append ch's stuff to room-contents
*/
i->next_content = ch->carrying;
} else
real_roomp(ch->in_room)->contents = ch->carrying;
/*
* connect the stuff to the room
*/
for (i = ch->carrying; i; i = i->next_content) {
i->carried_by = 0;
i->in_room = ch->in_room;
}
} else {
cprintf(ch, "Here, you dropped some stuff, let me help you get rid of that.\r\n");
for (i = ch->carrying; i; i = o) {
o = i->next_content;
extract_obj(i);
}
/*
* equipment too
*/
for (j = 0; j < MAX_WEAR; j++)
if (ch->equipment[j])
extract_obj(unequip_char(ch, j));
}
}
if (ch->specials.fighting)
stop_fighting(ch);
for (k = combat_list; k; k = next_char) {
next_char = k->next_fighting;
if (k->specials.fighting == ch)
stop_fighting(k);
}
/*
* Must remove from room before removing the equipment!
*/
was_in = ch->in_room;
char_from_room(ch);
/*
* clear equipment_list
*/
for (l = 0; l < MAX_WEAR; l++)
if (ch->equipment[l])
obj_to_room(unequip_char(ch, l), was_in);
if (IS_NPC(ch)) {
for (k = character_list; k; k = k->next) {
if (k->specials.hunting)
if (k->specials.hunting == ch) {
k->specials.hunting = 0;
}
if (DoesHate(k, ch)) {
RemHated(k, ch);
}
if (DoesFear(k, ch)) {
RemFeared(k, ch);
}
}
} else {
for (k = character_list; k; k = k->next) {
if (k->specials.hunting)
if (k->specials.hunting == ch) {
k->specials.hunting = 0;
}
if (DoesHate(k, ch)) {
ZeroHatred(k, ch);
}
if (DoesFear(k, ch)) {
ZeroFeared(k, ch);
}
}
}
/*
* pull the char from the list
*/
if (ch == character_list)
character_list = ch->next;
else {
for (k = character_list; (k) && (k->next != ch); k = k->next);
if (k)
k->next = ch->next;
else {
log_error("Trying to remove NULL from character_list.");
/*
* proper_exit(MUD_HALT);
*/
}
}
if (ch->desc) {
if (ch->desc->original)
do_return(ch, "", 0);
save_char(ch, NOWHERE);
}
if (IS_NPC(ch)) {
if (ch->nr > -1) /* if mobile */
mob_index[ch->nr].number--;
FreeHates(ch);
FreeFears(ch);
free_char(ch);
} else if (ch->desc) { /* Moved the following into an else block since */
/*
* valgrind pointed out that ch won't be valid for NPC's
*/
ch->desc->connected = CON_MENU_SELECT;
SEND_TO_Q(login_menu, ch->desc);
}
}
/* ***********************************************************************
* Here follows high-level versions of some earlier routines, ie functionst
* which incorporate the actual player-data.
* *********************************************************************** */
struct char_data *get_char_room_vis(struct char_data *ch,
const char *name)
{
struct char_data *i = NULL;
int j = 0;
int anumber = 0;
char tmpname[MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0";
char *tmp = NULL;
if (DEBUG > 2)
log_info("called %s with %s, %s", __PRETTY_FUNCTION__, SAFE_NAME(ch), VNULL(name));
if ((!strcasecmp(name, "me") || !strcasecmp(name, "myself")) && CAN_SEE(ch, ch))
return ch;
strcpy(tmpname, name);
tmp = tmpname;
if (!(anumber = get_number(&tmp)))
return (0);
for (i = real_roomp(ch->in_room)->people, j = 1; i && (j <= anumber); i = i->next_in_room)
if (isname(tmp, GET_NAME(i)))
if (CAN_SEE(ch, i)) {
if (j == anumber)
return (i);
j++;
}
return (0);
}
/* get a character from anywhere in the world, doesn't care much about
* being in the same room... */
struct char_data *get_char_vis_world(struct char_data *ch,
const char *name, int *count)
{
struct char_data *i = NULL;
int j = 0;
int anumber = 0;
char tmpname[MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0";
char *tmp = NULL;
if (DEBUG > 2)
log_info("called %s with %s, %s, %08zx", __PRETTY_FUNCTION__, SAFE_NAME(ch),
VNULL(name), (size_t) count);
if ((!strcasecmp(name, "me") || !strcasecmp(name, "myself")) && CAN_SEE(ch, ch))
return ch;
strcpy(tmpname, name);
tmp = tmpname;
if (!(anumber = get_number(&tmp)))
return (0);
j = count ? *count : 1;
for (i = character_list; i && (j <= anumber); i = i->next)
if (isname(tmp, GET_NAME(i)))
if (CAN_SEE(ch, i)) {
if (j == anumber)
return (i);
j++;
}
if (count)
*count = j;
return 0;
}
struct char_data *get_char_vis(struct char_data *ch, const char *name)
{
struct char_data *i = NULL;
if (DEBUG > 2)
log_info("called %s with %s, %s", __PRETTY_FUNCTION__, SAFE_NAME(ch), VNULL(name));
/*
* check location
*/
if ((i = get_char_room_vis(ch, name)))
return (i);
return get_char_vis_world(ch, name, NULL);
}
struct obj_data *get_obj_in_list_vis(struct char_data *ch,
const char *name,
struct obj_data *list)
{
struct obj_data *i = NULL;
int j = 0;
int anumber = 0;
char tmpname[MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0";
char *tmp = NULL;
if (DEBUG > 2)
log_info("called %s with %s, %s, %08zx", __PRETTY_FUNCTION__, SAFE_NAME(ch),
VNULL(name), (size_t) list);
strcpy(tmpname, name);
tmp = tmpname;
if (!(anumber = get_number(&tmp)))
return (0);
for (i = list, j = 1; i && (j <= anumber); i = i->next_content)
if (isname(tmp, i->name))
if (CAN_SEE_OBJ(ch, i)) {
if (j == anumber)
return (i);
j++;
}
return (0);
}
struct obj_data *get_obj_vis_world(struct char_data *ch,
const char *name, int *count)
{
struct obj_data *i = NULL;
int j = 0;
int anumber = 0;
char tmpname[MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0";
char *tmp = NULL;
if (DEBUG > 2)
log_info("called %s with %s, %s, %08zx", __PRETTY_FUNCTION__, SAFE_NAME(ch),
VNULL(name), (size_t) count);
strcpy(tmpname, name);
tmp = tmpname;
if (!(anumber = get_number(&tmp)))
return (0);
j = count ? *count : 1;
/*
* ok.. no luck yet. scan the entire obj list
*/
for (i = object_list; i && (j <= anumber); i = i->next)
if (isname(tmp, i->name))
if (CAN_SEE_OBJ(ch, i)) {
if (j == anumber)
return (i);
j++;
}
if (count)
*count = j;
return (0);
}
/*search the entire world for an object, and return a pointer */
struct obj_data *get_obj_vis(struct char_data *ch, const char *name)
{
struct obj_data *i = NULL;
if (DEBUG > 2)
log_info("called %s with %s, %s", __PRETTY_FUNCTION__, SAFE_NAME(ch), VNULL(name));
/*
* scan items carried
*/
if ((i = get_obj_in_list_vis(ch, name, ch->carrying)))
return (i);
/*
* scan room
*/
if ((i = get_obj_in_list_vis(ch, name, real_roomp(ch->in_room)->contents)))
return (i);
return get_obj_vis_world(ch, name, NULL);
}
struct obj_data *get_obj_vis_accessible(struct char_data *ch,
const char *name)
{
struct obj_data *i = NULL;
int j = 0;
int anumber = 0;
char tmpname[MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0";
char *tmp = NULL;
if (DEBUG > 2)
log_info("called %s with %s, %s", __PRETTY_FUNCTION__, SAFE_NAME(ch), VNULL(name));
strcpy(tmpname, name);
tmp = tmpname;
if (!(anumber = get_number(&tmp)))
return (0);
/*
* scan items carried
*/
for (i = ch->carrying, j = 1; i && j <= anumber; i = i->next_content)
if (isname(tmp, i->name) && CAN_SEE_OBJ(ch, i)) {
if (j == anumber)
return (i);
else
j++;
}
for (i = real_roomp(ch->in_room)->contents; i && j <= anumber; i = i->next_content)
if (isname(tmp, i->name) && CAN_SEE_OBJ(ch, i)) {
if (j == anumber)
return (i);
else
j++;
}
return 0;
}
struct obj_data *create_money(int amount)
{
struct obj_data *obj = NULL;
struct extra_descr_data *new_descr = NULL;
char buf[80] = "\0\0\0\0\0\0\0";
if (DEBUG > 2)
log_info("called %s with %d", __PRETTY_FUNCTION__, amount);
if (amount <= 0) {
log_fatal("Trying to create negative money.");
proper_exit(MUD_HALT);
}
CREATE(obj, struct obj_data, 1);
CREATE(new_descr, struct extra_descr_data, 1);
clear_object(obj);
if (amount == 1) {
obj->name = strdup("coin gold");
obj->short_description = strdup("a gold coin");
obj->description = strdup("One miserable gold coin.");
new_descr->keyword = strdup("coin gold");
new_descr->description = strdup("One miserable gold coin.");
} else {
obj->name = strdup("coins gold");
obj->short_description = strdup("gold coins");
obj->description = strdup("A pile of gold coins.");
new_descr->keyword = strdup("coins gold");
if (amount < 10) {
sprintf(buf, "There is %d coins.", amount);
new_descr->description = strdup(buf);
} else if (amount < 100) {
sprintf(buf, "There is about %d coins", 10 * (amount / 10));
new_descr->description = strdup(buf);
} else if (amount < 1000) {
sprintf(buf, "It looks like something round %d coins", 100 * (amount / 100));
new_descr->description = strdup(buf);
} else if (amount < 100000) {
sprintf(buf, "You guess there is %d coins",
1000 * ((amount / 1000) + number(0, (amount / 1000))));
new_descr->description = strdup(buf);
} else
new_descr->description = strdup("There is A LOT of coins");
}
new_descr->next = 0;
obj->ex_description = new_descr;
obj->obj_flags.type_flag = ITEM_MONEY;
obj->obj_flags.wear_flags = ITEM_TAKE;
obj->obj_flags.value[0] = amount;
obj->obj_flags.cost = amount;
obj->item_number = -1;
obj->next = object_list;
object_list = obj;
return (obj);
}
/* Generic Find, designed to find any object/character */
/* Calling : */
/* *arg is the sting 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 returns a pointer to the next word in *arg (just like the */
/* one_argument routine). */
int generic_find(const char *arg, int bitvector, struct char_data *ch,
struct char_data **tar_ch, struct obj_data **tar_obj)
{
char name[MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0";
int i = 0;
int found = FALSE;
static const char *ignore[] = {
"the",
"in",
"on",
"at",
"\n"
};
if (DEBUG > 2)
log_info("called %s with %d, %s, %08zx, %08zx", __PRETTY_FUNCTION__, bitvector,
SAFE_NAME(ch), (size_t) tar_ch, (size_t) tar_obj);
/*
* Eliminate spaces and "ignore" words
*/
while (*arg && !found) {
for (; *arg == ' '; arg++);
for (i = 0; (name[i] = *(arg + i)) && (name[i] != ' '); i++);
name[i] = 0;
arg += i;
if (search_block(name, ignore, TRUE) > -1)
found = TRUE;
}
if (!name[0])
return (0);
*tar_ch = 0;
*tar_obj = 0;
if (IS_SET(bitvector, FIND_CHAR_ROOM)) { /* Find person in room */
if ((*tar_ch = get_char_room_vis(ch, name))) {
return (FIND_CHAR_ROOM);
}
}
if (IS_SET(bitvector, FIND_CHAR_WORLD)) {
if ((*tar_ch = get_char_vis(ch, name))) {
return (FIND_CHAR_WORLD);
}
}
if (IS_SET(bitvector, FIND_OBJ_EQUIP)) {
for (found = FALSE, i = 0; i < MAX_WEAR && !found; i++)
if (ch->equipment[i] && str_cmp(name, ch->equipment[i]->name) == 0) {
*tar_obj = ch->equipment[i];
found = TRUE;
}
if (found) {
return (FIND_OBJ_EQUIP);
}
}
if (IS_SET(bitvector, FIND_OBJ_INV)) {
if (IS_SET(bitvector, FIND_OBJ_ROOM)) {
if ((*tar_obj = get_obj_vis_accessible(ch, name))) {
return (FIND_OBJ_INV);
}
} else {
if ((*tar_obj = get_obj_in_list_vis(ch, name, ch->carrying))) {
return (FIND_OBJ_INV);
}
}
}
if (IS_SET(bitvector, FIND_OBJ_ROOM)) {
if ((*tar_obj = get_obj_in_list_vis(ch, name, real_roomp(ch->in_room)->contents))) {
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);
}