mirror of
https://github.com/tbamud/tbamud.git
synced 2026-03-19 18:56:33 +01:00
6780 lines
214 KiB
C
6780 lines
214 KiB
C
/**************************************************************************
|
||
* File: act.wizard.c Part of tbaMUD *
|
||
* Usage: Player-level god commands and other goodies. *
|
||
* *
|
||
* All rights reserved. See license 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 "interpreter.h"
|
||
#include "handler.h"
|
||
#include "db.h"
|
||
#include "spells.h"
|
||
#include "house.h"
|
||
#include "screen.h"
|
||
#include "constants.h"
|
||
#include "oasis.h"
|
||
#include "dg_scripts.h"
|
||
#include "shop.h"
|
||
#include "act.h"
|
||
#include "genzon.h" /* for real_zone_by_thing */
|
||
#include "class.h"
|
||
#include "species.h"
|
||
#include "genmob.h"
|
||
#include "genolc.h"
|
||
#include "genobj.h"
|
||
#include "genshp.h"
|
||
#include "fight.h"
|
||
#include "house.h"
|
||
#include "modify.h"
|
||
#include "quest.h"
|
||
#include "ban.h"
|
||
#include "screen.h"
|
||
#include "roomsave.h"
|
||
|
||
/* local utility functions with file scope */
|
||
static int perform_set(struct char_data *ch, struct char_data *vict, int mode, char *val_arg);
|
||
static void perform_immort_invis(struct char_data *ch, int level);
|
||
static void do_stat_room(struct char_data *ch, struct room_data *rm);
|
||
static void do_stat_object(struct char_data *ch, struct obj_data *j);
|
||
static void do_stat_character(struct char_data *ch, struct char_data *k);
|
||
static void do_stat_shop(struct char_data *ch, shop_rnum shop_nr);
|
||
static void stop_snooping(struct char_data *ch);
|
||
static struct obj_data *find_inventory_coin(struct char_data *ch);
|
||
static void remove_other_coins_from_list(struct obj_data *list, struct obj_data *keep);
|
||
static size_t print_zone_to_buf(char *bufptr, size_t left, zone_rnum zone, int listall);
|
||
static struct char_data *is_in_game(long idnum);
|
||
static void mob_checkload(struct char_data *ch, mob_vnum mvnum);
|
||
static void obj_checkload(struct char_data *ch, obj_vnum ovnum);
|
||
static void trg_checkload(struct char_data *ch, trig_vnum tvnum);
|
||
static void mod_llog_entry(struct last_entry *llast,int type);
|
||
static int get_max_recent(void);
|
||
static void clear_recent(struct recent_player *this);
|
||
static struct recent_player *create_recent(void);
|
||
const char *get_spec_func_name(SPECIAL(*func));
|
||
bool zedit_get_levels(struct descriptor_data *d, char *buf);
|
||
|
||
/* Modern stat table helpers */
|
||
#define STAT_LABEL_WIDTH 18
|
||
#define STAT_VALUE_WIDTH 55
|
||
|
||
static const char *stat_border_line(void);
|
||
static void stat_table_border(struct char_data *ch);
|
||
static void stat_table_row(struct char_data *ch, const char *label, const char *value);
|
||
static void stat_table_row_fmt(struct char_data *ch, const char *label, const char *fmt, ...) __attribute__((format(printf,3,4)));
|
||
static void stat_table_border_buf(char *buf, size_t buf_size, size_t *len);
|
||
static void stat_table_row_buf(char *buf, size_t buf_size, size_t *len, const char *label, const char *value);
|
||
static void stat_table_row_fmt_buf(char *buf, size_t buf_size, size_t *len, const char *label, const char *fmt, ...) __attribute__((format(printf,5,6)));
|
||
static void stat_appendf(char *buf, size_t buf_size, size_t *len, const char *fmt, ...) __attribute__((format(printf,4,5)));
|
||
static void stat_append_list_item(char *buf, size_t buf_size, size_t *len, size_t *line_len, const char *item);
|
||
static void stat_format_notrade_classes(bitvector_t flags, char *out, size_t outsz);
|
||
static void stat_format_script_triggers(struct script_data *sc, char *buf, size_t buf_size);
|
||
static void stat_format_script_globals(struct script_data *sc, char *buf, size_t buf_size);
|
||
static void stat_format_script_memory(struct script_memory *mem, char *buf, size_t buf_size);
|
||
static void stat_format_character_list(struct char_data *viewer, struct char_data *list, char *buf, size_t buf_size);
|
||
static void stat_format_object_list(struct char_data *viewer, struct obj_data *list, char *buf, size_t buf_size);
|
||
static void stat_format_exit_summary(struct room_data *rm, char *buf, size_t buf_size);
|
||
static void stat_format_char_effects(struct char_data *k, char *buf, size_t buf_size);
|
||
static void stat_format_obj_affects(struct obj_data *j, char *buf, size_t buf_size);
|
||
static void stat_format_obj_special(struct obj_data *j, char *buf, size_t buf_size);
|
||
static void stat_format_zone_cmds_room(room_vnum rvnum, char *buf, size_t buf_size);
|
||
|
||
/* Local Globals */
|
||
static struct recent_player *recent_list = NULL; /** Global list of recent players */
|
||
|
||
static const char *stat_border_line(void)
|
||
{
|
||
static char border[STAT_LABEL_WIDTH + STAT_VALUE_WIDTH + 16];
|
||
if (!*border) {
|
||
size_t pos = 0;
|
||
border[pos++] = '+';
|
||
for (int i = 0; i < STAT_LABEL_WIDTH + 2 && pos < sizeof(border) - 1; i++)
|
||
border[pos++] = '-';
|
||
border[pos++] = '+';
|
||
for (int i = 0; i < STAT_VALUE_WIDTH + 2 && pos < sizeof(border) - 1; i++)
|
||
border[pos++] = '-';
|
||
border[pos++] = '+';
|
||
border[pos++] = '\r';
|
||
border[pos++] = '\n';
|
||
border[pos] = '\0';
|
||
}
|
||
return border;
|
||
}
|
||
|
||
static void stat_table_border(struct char_data *ch)
|
||
{
|
||
send_to_char(ch, "%s", stat_border_line());
|
||
}
|
||
|
||
static const char *stat_next_chunk(const char *text, char *chunk, size_t width)
|
||
{
|
||
const char *ptr = text;
|
||
size_t chunk_len = 0;
|
||
|
||
chunk[0] = '\0';
|
||
|
||
while (*ptr == ' ')
|
||
ptr++;
|
||
|
||
while (*ptr && *ptr != '\n' && *ptr != '\r') {
|
||
const char *word_start = ptr;
|
||
size_t word_len = 0;
|
||
|
||
while (word_start[word_len] &&
|
||
word_start[word_len] != ' ' &&
|
||
word_start[word_len] != '\n' &&
|
||
word_start[word_len] != '\r')
|
||
word_len++;
|
||
|
||
if (word_len == 0)
|
||
break;
|
||
|
||
if (chunk_len == 0 && word_len > width) {
|
||
word_len = width;
|
||
memcpy(chunk, word_start, word_len);
|
||
chunk_len = word_len;
|
||
chunk[chunk_len] = '\0';
|
||
ptr = word_start + word_len;
|
||
return ptr;
|
||
}
|
||
|
||
size_t needed = word_len + (chunk_len ? 1 : 0);
|
||
if (chunk_len + needed > width)
|
||
break;
|
||
|
||
if (chunk_len)
|
||
chunk[chunk_len++] = ' ';
|
||
memcpy(chunk + chunk_len, word_start, word_len);
|
||
chunk_len += word_len;
|
||
chunk[chunk_len] = '\0';
|
||
|
||
ptr = word_start + word_len;
|
||
|
||
while (*ptr == ' ')
|
||
ptr++;
|
||
}
|
||
|
||
while (*ptr == '\r' || *ptr == '\n')
|
||
ptr++;
|
||
|
||
return ptr;
|
||
}
|
||
|
||
static void stat_table_row(struct char_data *ch, const char *label, const char *value)
|
||
{
|
||
const char *text = (value && *value) ? value : "<None>";
|
||
bool printed = FALSE;
|
||
|
||
while (*text) {
|
||
while (*text == '\r' || *text == '\n')
|
||
text++;
|
||
if (!*text)
|
||
break;
|
||
|
||
char chunk[STAT_VALUE_WIDTH + 1];
|
||
const char *next = stat_next_chunk(text, chunk, STAT_VALUE_WIDTH);
|
||
|
||
if (!*chunk) {
|
||
text = next;
|
||
continue;
|
||
}
|
||
|
||
send_to_char(ch, "| %-*s | %-*s |\r\n",
|
||
STAT_LABEL_WIDTH,
|
||
printed || !label ? "" : label,
|
||
STAT_VALUE_WIDTH,
|
||
chunk);
|
||
|
||
printed = TRUE;
|
||
text = next;
|
||
}
|
||
|
||
if (!printed)
|
||
send_to_char(ch, "| %-*s | %-*s |\r\n",
|
||
STAT_LABEL_WIDTH,
|
||
label ? label : "",
|
||
STAT_VALUE_WIDTH,
|
||
(value && *value) ? value : "<None>");
|
||
}
|
||
|
||
static void stat_table_row_fmt(struct char_data *ch, const char *label, const char *fmt, ...)
|
||
{
|
||
char buf[MAX_STRING_LENGTH];
|
||
va_list args;
|
||
|
||
va_start(args, fmt);
|
||
vsnprintf(buf, sizeof(buf), fmt, args);
|
||
va_end(args);
|
||
|
||
stat_table_row(ch, label, buf);
|
||
}
|
||
|
||
static void stat_table_border_buf(char *buf, size_t buf_size, size_t *len)
|
||
{
|
||
stat_appendf(buf, buf_size, len, "%s", stat_border_line());
|
||
}
|
||
|
||
static void stat_table_row_buf(char *buf, size_t buf_size, size_t *len, const char *label, const char *value)
|
||
{
|
||
const char *text = (value && *value) ? value : "<None>";
|
||
bool printed = FALSE;
|
||
|
||
while (*text) {
|
||
while (*text == '\r' || *text == '\n')
|
||
text++;
|
||
if (!*text)
|
||
break;
|
||
|
||
char chunk[STAT_VALUE_WIDTH + 1];
|
||
const char *next = stat_next_chunk(text, chunk, STAT_VALUE_WIDTH);
|
||
|
||
if (!*chunk) {
|
||
text = next;
|
||
continue;
|
||
}
|
||
|
||
stat_appendf(buf, buf_size, len, "| %-*s | %-*s |\r\n",
|
||
STAT_LABEL_WIDTH,
|
||
printed || !label ? "" : label,
|
||
STAT_VALUE_WIDTH,
|
||
chunk);
|
||
|
||
printed = TRUE;
|
||
text = next;
|
||
}
|
||
|
||
if (!printed)
|
||
stat_appendf(buf, buf_size, len, "| %-*s | %-*s |\r\n",
|
||
STAT_LABEL_WIDTH,
|
||
label ? label : "",
|
||
STAT_VALUE_WIDTH,
|
||
(value && *value) ? value : "<None>");
|
||
}
|
||
|
||
static void stat_table_row_fmt_buf(char *buf, size_t buf_size, size_t *len, const char *label, const char *fmt, ...)
|
||
{
|
||
char row[MAX_STRING_LENGTH];
|
||
va_list args;
|
||
|
||
va_start(args, fmt);
|
||
vsnprintf(row, sizeof(row), fmt, args);
|
||
va_end(args);
|
||
|
||
stat_table_row_buf(buf, buf_size, len, label, row);
|
||
}
|
||
|
||
static void stat_appendf(char *buf, size_t buf_size, size_t *len, const char *fmt, ...)
|
||
{
|
||
if (*len >= buf_size)
|
||
return;
|
||
|
||
va_list args;
|
||
va_start(args, fmt);
|
||
int wrote = vsnprintf(buf + *len, buf_size - *len, fmt, args);
|
||
va_end(args);
|
||
|
||
if (wrote < 0)
|
||
return;
|
||
|
||
if ((size_t)wrote >= buf_size - *len)
|
||
*len = buf_size - 1;
|
||
else
|
||
*len += wrote;
|
||
}
|
||
|
||
static void stat_append_list_item(char *buf, size_t buf_size, size_t *len, size_t *line_len, const char *item)
|
||
{
|
||
size_t item_len = strlen(item);
|
||
|
||
if (*line_len && *line_len + 2 + item_len > STAT_VALUE_WIDTH) {
|
||
stat_appendf(buf, buf_size, len, "\n");
|
||
*line_len = 0;
|
||
}
|
||
|
||
if (*line_len) {
|
||
stat_appendf(buf, buf_size, len, ", ");
|
||
*line_len += 2;
|
||
}
|
||
|
||
stat_appendf(buf, buf_size, len, "%s", item);
|
||
*line_len += item_len;
|
||
}
|
||
|
||
static void stat_format_notrade_classes(bitvector_t flags, char *out, size_t outsz)
|
||
{
|
||
size_t len = 0;
|
||
int i, found = 0;
|
||
|
||
if (!out || outsz == 0)
|
||
return;
|
||
|
||
out[0] = '\0';
|
||
|
||
for (i = TRADE_CLASS_START; i < NUM_TRADERS; i++) {
|
||
if (IS_SET(flags, 1 << i)) {
|
||
int n = snprintf(out + len, outsz - len, "%s%s", found ? " " : "", trade_letters[i]);
|
||
|
||
if (n < 0 || (size_t)n >= outsz - len) {
|
||
out[outsz - 1] = '\0';
|
||
return;
|
||
}
|
||
|
||
len += (size_t)n;
|
||
found = 1;
|
||
}
|
||
}
|
||
|
||
if (!found)
|
||
strlcpy(out, "NOBITS", outsz);
|
||
}
|
||
|
||
static void stat_format_script_triggers(struct script_data *sc, char *buf, size_t buf_size)
|
||
{
|
||
size_t len = 0;
|
||
buf[0] = '\0';
|
||
|
||
if (!sc || !TRIGGERS(sc)) {
|
||
strlcpy(buf, "None", buf_size);
|
||
return;
|
||
}
|
||
|
||
for (trig_data *t = TRIGGERS(sc); t; t = t->next) {
|
||
const char *attach = (t->attach_type == OBJ_TRIGGER) ? "obj" :
|
||
(t->attach_type == WLD_TRIGGER) ? "room" : "mob";
|
||
const char **type_names = (t->attach_type == OBJ_TRIGGER) ? otrig_types :
|
||
(t->attach_type == WLD_TRIGGER) ? wtrig_types : trig_types;
|
||
char type_buf[MAX_STRING_LENGTH];
|
||
sprintbit(GET_TRIG_TYPE(t), type_names, type_buf, sizeof(type_buf));
|
||
|
||
if (len)
|
||
stat_appendf(buf, buf_size, &len, "\n");
|
||
|
||
stat_appendf(buf, buf_size, &len, "#%d %s (%s %s) narg=%d arg=%s",
|
||
GET_TRIG_VNUM(t),
|
||
GET_TRIG_NAME(t),
|
||
attach,
|
||
type_buf,
|
||
GET_TRIG_NARG(t),
|
||
(GET_TRIG_ARG(t) && *GET_TRIG_ARG(t)) ? GET_TRIG_ARG(t) : "None");
|
||
|
||
if (GET_TRIG_WAIT(t))
|
||
stat_appendf(buf, buf_size, &len, " [wait]");
|
||
}
|
||
}
|
||
|
||
static void stat_format_script_globals(struct script_data *sc, char *buf, size_t buf_size)
|
||
{
|
||
size_t len = 0;
|
||
buf[0] = '\0';
|
||
|
||
if (!sc || !sc->global_vars) {
|
||
strlcpy(buf, "None", buf_size);
|
||
return;
|
||
}
|
||
|
||
for (struct trig_var_data *tv = sc->global_vars; tv; tv = tv->next) {
|
||
char value[MAX_INPUT_LENGTH];
|
||
|
||
if (*(tv->value) == UID_CHAR)
|
||
find_uid_name(tv->value, value, sizeof(value));
|
||
else
|
||
strlcpy(value, tv->value, sizeof(value));
|
||
|
||
if (len)
|
||
stat_appendf(buf, buf_size, &len, "\n");
|
||
|
||
if (tv->context)
|
||
stat_appendf(buf, buf_size, &len, "%s:%ld = %s", tv->name, tv->context, value);
|
||
else
|
||
stat_appendf(buf, buf_size, &len, "%s = %s", tv->name, value);
|
||
}
|
||
}
|
||
|
||
static void stat_format_script_memory(struct script_memory *mem, char *buf, size_t buf_size)
|
||
{
|
||
size_t len = 0;
|
||
buf[0] = '\0';
|
||
|
||
if (!mem) {
|
||
strlcpy(buf, "None", buf_size);
|
||
return;
|
||
}
|
||
|
||
for (struct script_memory *cur = mem; cur; cur = cur->next) {
|
||
struct char_data *mc = find_char(cur->id);
|
||
const char *name = mc ? GET_NAME(mc) : "**Corrupted**";
|
||
|
||
if (len)
|
||
stat_appendf(buf, buf_size, &len, "\n");
|
||
|
||
stat_appendf(buf, buf_size, &len, "%-15s %s",
|
||
name,
|
||
cur->cmd ? cur->cmd : "<default>");
|
||
}
|
||
}
|
||
|
||
static void stat_format_character_list(struct char_data *viewer, struct char_data *list, char *buf, size_t buf_size)
|
||
{
|
||
size_t len = 0;
|
||
buf[0] = '\0';
|
||
|
||
for (struct char_data *k = list; k; k = k->next_in_room) {
|
||
if (viewer && !CAN_SEE(viewer, k))
|
||
continue;
|
||
|
||
if (len)
|
||
stat_appendf(buf, buf_size, &len, ", ");
|
||
|
||
stat_appendf(buf, buf_size, &len, "%s (%s)",
|
||
GET_NAME(k),
|
||
!IS_NPC(k) ? "PC" : (!IS_MOB(k) ? "NPC" : "MOB"));
|
||
}
|
||
|
||
if (!len)
|
||
strlcpy(buf, "None", buf_size);
|
||
}
|
||
|
||
static void stat_format_object_list(struct char_data *viewer, struct obj_data *list, char *buf, size_t buf_size)
|
||
{
|
||
size_t len = 0;
|
||
buf[0] = '\0';
|
||
|
||
for (struct obj_data *j = list; j; j = j->next_content) {
|
||
if (viewer && !CAN_SEE_OBJ(viewer, j))
|
||
continue;
|
||
|
||
if (len)
|
||
stat_appendf(buf, buf_size, &len, ", ");
|
||
|
||
stat_appendf(buf, buf_size, &len, "%s", j->short_description ? j->short_description : "<Unnamed>");
|
||
}
|
||
|
||
if (!len)
|
||
strlcpy(buf, "None", buf_size);
|
||
}
|
||
|
||
static void stat_format_exit_summary(struct room_data *rm, char *buf, size_t buf_size)
|
||
{
|
||
size_t len = 0;
|
||
buf[0] = '\0';
|
||
|
||
for (int i = 0; i < DIR_COUNT; i++) {
|
||
if (!rm->dir_option[i])
|
||
continue;
|
||
|
||
const char *dir = dirs[i];
|
||
char exit_buf[MAX_STRING_LENGTH];
|
||
sprintbit(rm->dir_option[i]->exit_info, exit_bits, exit_buf, sizeof(exit_buf));
|
||
|
||
room_rnum to = rm->dir_option[i]->to_room;
|
||
if (len)
|
||
stat_appendf(buf, buf_size, &len, "\n");
|
||
|
||
if (to == NOWHERE)
|
||
stat_appendf(buf, buf_size, &len, "%s -> NOWHERE (flags: %s)", dir, exit_buf);
|
||
else
|
||
stat_appendf(buf, buf_size, &len, "%s -> #%d %s (flags: %s, key: %d, keywords: %s)",
|
||
dir,
|
||
GET_ROOM_VNUM(to),
|
||
world[to].name,
|
||
exit_buf,
|
||
rm->dir_option[i]->key == NOTHING ? -1 : rm->dir_option[i]->key,
|
||
rm->dir_option[i]->keyword ? rm->dir_option[i]->keyword : "None");
|
||
}
|
||
|
||
if (!len)
|
||
strlcpy(buf, "None", buf_size);
|
||
}
|
||
|
||
static void stat_format_char_effects(struct char_data *k, char *buf, size_t buf_size)
|
||
{
|
||
size_t len = 0;
|
||
buf[0] = '\0';
|
||
|
||
for (struct affected_type *aff = k->affected; aff; aff = aff->next) {
|
||
char flags[MAX_STRING_LENGTH];
|
||
bool has_flags = FALSE;
|
||
|
||
for (int i = 0; i < NUM_AFF_FLAGS; i++) {
|
||
if (IS_SET_AR(aff->bitvector, i)) {
|
||
if (!has_flags) {
|
||
flags[0] = '\0';
|
||
has_flags = TRUE;
|
||
}
|
||
size_t f_len = strlen(flags);
|
||
snprintf(flags + f_len, sizeof(flags) - f_len, "%s%s",
|
||
f_len ? " " : "",
|
||
affected_bits[i]);
|
||
}
|
||
}
|
||
|
||
if (len)
|
||
stat_appendf(buf, buf_size, &len, "\n");
|
||
|
||
const char *dur_unit = "hr";
|
||
int display_dur = aff->duration + 1;
|
||
|
||
if (aff->spell == SKILL_PERCEPTION ||
|
||
aff->spell == SPELL_SCAN_AFFECT ||
|
||
aff->spell == SPELL_LISTEN_AFFECT) {
|
||
/* convert mud-hours -> real minutes (round up) */
|
||
int total_seconds = display_dur * SECS_PER_MUD_HOUR;
|
||
display_dur = (total_seconds + SECS_PER_REAL_MIN - 1) / SECS_PER_REAL_MIN;
|
||
dur_unit = "min";
|
||
}
|
||
|
||
stat_appendf(buf, buf_size, &len, "%s (%d%s)",
|
||
skill_name(aff->spell),
|
||
display_dur,
|
||
dur_unit);
|
||
|
||
if (aff->modifier)
|
||
stat_appendf(buf, buf_size, &len, " %+d %s",
|
||
aff->modifier,
|
||
apply_types[(int)aff->location]);
|
||
|
||
if (has_flags)
|
||
stat_appendf(buf, buf_size, &len, " [sets %s]", flags);
|
||
}
|
||
|
||
if (!len)
|
||
strlcpy(buf, "None", buf_size);
|
||
}
|
||
|
||
static void stat_format_obj_affects(struct obj_data *j, char *buf, size_t buf_size)
|
||
{
|
||
size_t len = 0;
|
||
buf[0] = '\0';
|
||
|
||
for (int i = 0; i < MAX_OBJ_AFFECT; i++) {
|
||
if (!j->affected[i].modifier)
|
||
continue;
|
||
|
||
if (len)
|
||
stat_appendf(buf, buf_size, &len, "\n");
|
||
|
||
stat_appendf(buf, buf_size, &len, "%+d %s",
|
||
j->affected[i].modifier,
|
||
apply_types[j->affected[i].location]);
|
||
}
|
||
|
||
if (!len)
|
||
strlcpy(buf, "None", buf_size);
|
||
}
|
||
|
||
static void stat_format_obj_special(struct obj_data *j, char *buf, size_t buf_size)
|
||
{
|
||
size_t len = 0;
|
||
buf[0] = '\0';
|
||
struct char_data *tempch;
|
||
|
||
switch (GET_OBJ_TYPE(j)) {
|
||
case ITEM_LIGHT:
|
||
if (GET_OBJ_VAL(j, 2) == -1)
|
||
stat_appendf(buf, buf_size, &len, "Infinite light");
|
||
else
|
||
stat_appendf(buf, buf_size, &len, "Hours left: %d", GET_OBJ_VAL(j, 2));
|
||
break;
|
||
case ITEM_SCROLL:
|
||
case ITEM_POTION:
|
||
stat_appendf(buf, buf_size, &len, "Level %d spells: %s, %s, %s",
|
||
GET_OBJ_VAL(j, 0),
|
||
skill_name(GET_OBJ_VAL(j, 1)),
|
||
skill_name(GET_OBJ_VAL(j, 2)),
|
||
skill_name(GET_OBJ_VAL(j, 3)));
|
||
break;
|
||
case ITEM_WAND:
|
||
case ITEM_STAFF:
|
||
stat_appendf(buf, buf_size, &len, "%s at level %d, %d/%d charges",
|
||
skill_name(GET_OBJ_VAL(j, 3)),
|
||
GET_OBJ_VAL(j, 0),
|
||
GET_OBJ_VAL(j, 2),
|
||
GET_OBJ_VAL(j, 1));
|
||
break;
|
||
case ITEM_WEAPON:
|
||
stat_appendf(buf, buf_size, &len, "Damage %dd%d (avg %.1f), type %s",
|
||
GET_OBJ_VAL(j, 1),
|
||
GET_OBJ_VAL(j, 2),
|
||
((GET_OBJ_VAL(j, 2) + 1) / 2.0) * GET_OBJ_VAL(j, 1),
|
||
attack_hit_text[GET_OBJ_VAL(j, 3)].singular);
|
||
break;
|
||
case ITEM_ARMOR:
|
||
stat_appendf(buf, buf_size, &len, "Piece AC %d, bulk %d, magic %+d, stealth %s, durability %d, str req %d",
|
||
GET_OBJ_VAL(j, VAL_ARMOR_PIECE_AC),
|
||
GET_OBJ_VAL(j, VAL_ARMOR_BULK),
|
||
GET_OBJ_VAL(j, VAL_ARMOR_MAGIC_BONUS),
|
||
YESNO(GET_OBJ_VAL(j, VAL_ARMOR_STEALTH_DISADV)),
|
||
GET_OBJ_VAL(j, VAL_ARMOR_DURABILITY),
|
||
GET_OBJ_VAL(j, VAL_ARMOR_STR_REQ));
|
||
break;
|
||
case ITEM_CONTAINER: {
|
||
char flags[MAX_STRING_LENGTH];
|
||
sprintbit(GET_OBJ_VAL(j, 1), container_bits, flags, sizeof(flags));
|
||
stat_appendf(buf, buf_size, &len, "Capacity %d, Flags %s, Key %d, Corpse %s",
|
||
GET_OBJ_VAL(j, 0),
|
||
flags,
|
||
GET_OBJ_VAL(j, 2),
|
||
YESNO(GET_OBJ_VAL(j, 3)));
|
||
break;
|
||
}
|
||
case ITEM_DRINKCON:
|
||
case ITEM_FOUNTAIN: {
|
||
char drink[MAX_INPUT_LENGTH];
|
||
sprinttype(GET_OBJ_VAL(j, 2), drinks, drink, sizeof(drink));
|
||
stat_appendf(buf, buf_size, &len, "Capacity %d, Contains %d, Liquid %s, Poisoned %s",
|
||
GET_OBJ_VAL(j, 0),
|
||
GET_OBJ_VAL(j, 1),
|
||
drink,
|
||
YESNO(GET_OBJ_VAL(j, 3)));
|
||
break;
|
||
}
|
||
case ITEM_NOTE:
|
||
stat_appendf(buf, buf_size, &len, "Tongue %d", GET_OBJ_VAL(j, 0));
|
||
break;
|
||
case ITEM_FOOD:
|
||
stat_appendf(buf, buf_size, &len, "Bites %d/%d, Hours full %d, Poisoned %s",
|
||
GET_OBJ_VAL(j, 1),
|
||
GET_OBJ_VAL(j, 0),
|
||
GET_OBJ_VAL(j, 2),
|
||
YESNO(GET_OBJ_VAL(j, 3)));
|
||
break;
|
||
case ITEM_MONEY:
|
||
stat_appendf(buf, buf_size, &len, "Coins: %d", GET_OBJ_VAL(j, 0));
|
||
break;
|
||
case ITEM_FURNITURE:
|
||
stat_appendf(buf, buf_size, &len, "Seats %d/%d, Allowed pos %d",
|
||
GET_OBJ_VAL(j, 1),
|
||
GET_OBJ_VAL(j, 0),
|
||
GET_OBJ_VAL(j, 2));
|
||
if (OBJ_SAT_IN_BY(j)) {
|
||
stat_appendf(buf, buf_size, &len, ", Occupied by:");
|
||
for (tempch = OBJ_SAT_IN_BY(j); tempch; tempch = NEXT_SITTING(tempch))
|
||
stat_appendf(buf, buf_size, &len, " %s", GET_NAME(tempch));
|
||
}
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
|
||
if (!len)
|
||
strlcpy(buf, "None", buf_size);
|
||
}
|
||
|
||
static int purge_room(room_rnum room)
|
||
{
|
||
int j;
|
||
struct char_data *vict;
|
||
|
||
if (room == NOWHERE || room > top_of_world) return 0;
|
||
|
||
for (vict = world[room].people; vict; vict = vict->next_in_room) {
|
||
if (!IS_NPC(vict))
|
||
continue;
|
||
|
||
/* Dump inventory. */
|
||
while (vict->carrying)
|
||
extract_obj(vict->carrying);
|
||
|
||
/* Dump equipment. */
|
||
for (j = 0; j < NUM_WEARS; j++)
|
||
if (GET_EQ(vict, j))
|
||
extract_obj(GET_EQ(vict, j));
|
||
|
||
/* Dump character. */
|
||
extract_char(vict);
|
||
}
|
||
|
||
/* Clear the ground. */
|
||
while (world[room].contents)
|
||
extract_obj(world[room].contents);
|
||
|
||
return 1;
|
||
}
|
||
|
||
/* ===================== Emote engine ===================== */
|
||
|
||
/* Operators:
|
||
*
|
||
* ~ (name) / target sees "you"
|
||
* ! him/her/them / target sees "you"
|
||
* % (name)'s / target sees "your"
|
||
* ^ his/her/their / target sees "your"
|
||
* # he/she/they / target sees "you"
|
||
* & himself/herself/themself / target sees "yourself"
|
||
* = (name)'s / target sees "yours"
|
||
* + his/hers/theirs / target sees "yours"
|
||
* @ moves actor name (or actor's possessive for pemote) to that position
|
||
*/
|
||
|
||
/* --- Pronoun & string helpers --- */
|
||
static const char *pron_obj(struct char_data *tch) { /* him/her/them */
|
||
switch (GET_SEX(tch)) { case SEX_MALE: return "him"; case SEX_FEMALE: return "her"; default: return "them"; }
|
||
}
|
||
static const char *pron_pos_adj(struct char_data *tch) { /* his/her/their */
|
||
switch (GET_SEX(tch)) { case SEX_MALE: return "his"; case SEX_FEMALE: return "her"; default: return "their"; }
|
||
}
|
||
static const char *pron_pos_pron(struct char_data *tch) { /* his/hers/theirs */
|
||
switch (GET_SEX(tch)) { case SEX_MALE: return "his"; case SEX_FEMALE: return "hers"; default: return "theirs"; }
|
||
}
|
||
static const char *pron_subj(struct char_data *tch) { /* he/she/they */
|
||
switch (GET_SEX(tch)) { case SEX_MALE: return "he"; case SEX_FEMALE: return "she"; default: return "they"; }
|
||
}
|
||
static const char *pron_refl(struct char_data *tch) { /* himself/herself/themself */
|
||
switch (GET_SEX(tch)) { case SEX_MALE: return "himself"; case SEX_FEMALE: return "herself"; default: return "themself"; }
|
||
}
|
||
|
||
static void make_possessive(const char *name, char *out, size_t outsz) {
|
||
size_t n = strlcpy(out, name, outsz);
|
||
if (n > 0 && out[n-1] == 's') strlcat(out, "'", outsz);
|
||
else strlcat(out, "'s", outsz);
|
||
}
|
||
|
||
static bool is_end_punct(char c) { return (c == '.' || c == '!' || c == '?'); }
|
||
|
||
static void collapse_spaces(char *s) {
|
||
char *src = s, *dst = s; bool last_space = false;
|
||
while (*src) {
|
||
if (isspace((unsigned char)*src)) { if (!last_space) *dst++ = ' '; last_space = true; }
|
||
else { *dst++ = *src; last_space = false; }
|
||
src++;
|
||
}
|
||
*dst = '\0';
|
||
}
|
||
|
||
static void build_actor_name(struct char_data *actor,
|
||
bool possessive,
|
||
char *out, size_t outsz)
|
||
{
|
||
/* Prefer short description if present; fall back to personal name */
|
||
const char *base =
|
||
(GET_SHORT_DESC(actor) && *GET_SHORT_DESC(actor))
|
||
? GET_SHORT_DESC(actor)
|
||
: GET_NAME(actor);
|
||
|
||
if (!possessive)
|
||
strlcpy(out, base, outsz);
|
||
else
|
||
make_possessive(base, out, outsz);
|
||
}
|
||
|
||
/* Replace all occurrences of 'needle' in 'hay' with 'repl'. */
|
||
static void replace_all_tokens(char *hay, size_t haysz, const char *needle, const char *repl) {
|
||
char work[MAX_STRING_LENGTH]; work[0] = '\0';
|
||
const char *src = hay; size_t nlen = strlen(needle);
|
||
while (*src) {
|
||
const char *pos = strstr(src, needle);
|
||
if (!pos) { strlcat(work, src, sizeof(work)); break; }
|
||
size_t head = (size_t)(pos - src);
|
||
if (head) {
|
||
char chunk[2048];
|
||
if (head >= sizeof(chunk)) head = sizeof(chunk) - 1;
|
||
memcpy(chunk, src, head); chunk[head] = '\0';
|
||
strlcat(work, chunk, sizeof(work));
|
||
}
|
||
strlcat(work, repl, sizeof(work));
|
||
src = pos + nlen;
|
||
}
|
||
strlcpy(hay, work, haysz);
|
||
}
|
||
|
||
static bool is_token_operator(char c) {
|
||
switch (c) {
|
||
case '~': case '!': case '%': case '^': case '#':
|
||
case '&': case '=': case '+': case '@':
|
||
return TRUE;
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
/* Capitalize the first alphabetic character of every sentence (start and after .?!).
|
||
Skips any number of spaces and common closers (quotes/brackets) between sentences. */
|
||
static void capitalize_sentences(char *s) {
|
||
bool new_sent = true;
|
||
for (char *p = s; *p; ++p) {
|
||
unsigned char c = (unsigned char)*p;
|
||
if (new_sent) {
|
||
if (isalpha(c)) {
|
||
*p = toupper(c);
|
||
new_sent = false;
|
||
} else if (!isspace(c) && c != '"' && c != '\'' && c != ')' && c != ']' && c != '}') {
|
||
/* Non-space symbol at sentence start; don't flip flag yet unless it's a letter later. */
|
||
}
|
||
}
|
||
if (*p == '.' || *p == '!' || *p == '?')
|
||
new_sent = true;
|
||
}
|
||
}
|
||
|
||
/* --- Numbered target parsing --- */
|
||
/* Parse "2.corpse" => out_num=2, out_name="corpse". "corpse" => out_num=1, out_name="corpse". */
|
||
static void split_numbered_name(const char *raw, int *out_num, char *out_name, size_t outsz) {
|
||
char tmp[MAX_NAME_LENGTH];
|
||
strlcpy(tmp, raw, sizeof(tmp));
|
||
char *p = tmp;
|
||
int num = get_number(&p); /* advances p if leading "N." is present */
|
||
if (num <= 0) num = 1;
|
||
if (*p) strlcpy(out_name, p, outsz);
|
||
else strlcpy(out_name, tmp, outsz);
|
||
*out_num = num;
|
||
}
|
||
|
||
/* Case-insensitive strcmp helper (tiny) */
|
||
static bool ieq(const char *a, const char *b) {
|
||
while (*a && *b) {
|
||
char ca = tolower((unsigned char)*a++);
|
||
char cb = tolower((unsigned char)*b++);
|
||
if (ca != cb) return false;
|
||
}
|
||
return *a == '\0' && *b == '\0';
|
||
}
|
||
|
||
/* Resolve a char/obj with support for numbered refs, searching room chars, room objs, inventory, equipment.
|
||
Special: "me"/"self" (any operator) resolves to the actor. */
|
||
static bool resolve_reference(struct char_data *actor,
|
||
const char *raw,
|
||
struct char_data **out_ch,
|
||
struct obj_data **out_obj) {
|
||
char name[MAX_NAME_LENGTH];
|
||
int ordinal = 1;
|
||
|
||
*out_ch = NULL; *out_obj = NULL;
|
||
|
||
if (ieq(raw, "me") || ieq(raw, "self")) { *out_ch = actor; return true; }
|
||
|
||
split_numbered_name(raw, &ordinal, name, sizeof(name));
|
||
|
||
/* Characters in room (ordinal applies to this list) */
|
||
{
|
||
int num = ordinal;
|
||
struct char_data *tch = get_char_room_vis(actor, name, &num);
|
||
if (tch) { *out_ch = tch; return true; }
|
||
}
|
||
|
||
/* Objects in room */
|
||
{
|
||
int num = ordinal;
|
||
struct obj_data *obj = get_obj_in_list_vis(actor, name, &num, world[IN_ROOM(actor)].contents);
|
||
if (obj) { *out_obj = obj; return true; }
|
||
}
|
||
/* Objects carried */
|
||
{
|
||
int num = ordinal;
|
||
struct obj_data *obj = get_obj_in_list_vis(actor, name, &num, actor->carrying);
|
||
if (obj) { *out_obj = obj; return true; }
|
||
}
|
||
/* Objects equipped */
|
||
{
|
||
int num = ordinal;
|
||
struct obj_data *obj = get_obj_in_equip_vis(actor, name, &num, actor->equipment);
|
||
if (obj) { *out_obj = obj; return true; }
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/* Build replacement text for a token as seen by 'viewer'. */
|
||
static void build_replacement(const struct emote_token *tok,
|
||
struct char_data *actor,
|
||
struct char_data *viewer,
|
||
bool actor_possessive_for_at,
|
||
char *out, size_t outsz) {
|
||
out[0] = '\0';
|
||
|
||
if (tok->op == '@') {
|
||
/* Use actor's sdesc if present, otherwise their name */
|
||
const char *ref = (GET_SHORT_DESC(actor) && *GET_SHORT_DESC(actor))
|
||
? GET_SHORT_DESC(actor)
|
||
: GET_NAME(actor);
|
||
|
||
if (!actor_possessive_for_at)
|
||
strlcpy(out, ref, outsz);
|
||
else
|
||
make_possessive(ref, out, outsz);
|
||
return;
|
||
}
|
||
|
||
if (tok->tch) {
|
||
bool you = (viewer == tok->tch);
|
||
/* For non-you views, prefer sdesc over name */
|
||
const char *ref = (GET_SHORT_DESC(tok->tch) && *GET_SHORT_DESC(tok->tch))
|
||
? GET_SHORT_DESC(tok->tch)
|
||
: GET_NAME(tok->tch);
|
||
|
||
switch (tok->op) {
|
||
case '~':
|
||
if (you) strlcpy(out, "you", outsz);
|
||
else strlcpy(out, ref, outsz);
|
||
break;
|
||
|
||
case '!':
|
||
if (you) strlcpy(out, "you", outsz);
|
||
else strlcpy(out, pron_obj(tok->tch), outsz);
|
||
break;
|
||
|
||
case '%':
|
||
if (you) strlcpy(out, "your", outsz);
|
||
else make_possessive(ref, out, outsz);
|
||
break;
|
||
|
||
case '^':
|
||
if (you) strlcpy(out, "your", outsz);
|
||
else strlcpy(out, pron_pos_adj(tok->tch), outsz);
|
||
break;
|
||
|
||
case '#':
|
||
if (you) strlcpy(out, "you", outsz);
|
||
else strlcpy(out, pron_subj(tok->tch), outsz);
|
||
break;
|
||
|
||
case '&':
|
||
if (you) strlcpy(out, "yourself", outsz);
|
||
else strlcpy(out, pron_refl(tok->tch), outsz);
|
||
break;
|
||
|
||
case '=':
|
||
if (you) strlcpy(out, "yours", outsz);
|
||
else make_possessive(ref, out, outsz);
|
||
break;
|
||
|
||
case '+':
|
||
if (you) strlcpy(out, "yours", outsz);
|
||
else strlcpy(out, pron_pos_pron(tok->tch), outsz);
|
||
break;
|
||
|
||
default:
|
||
strlcpy(out, ref, outsz);
|
||
break;
|
||
}
|
||
return;
|
||
}
|
||
|
||
if (tok->tobj) {
|
||
const char *sdesc = (tok->tobj->short_description && *tok->tobj->short_description)
|
||
? tok->tobj->short_description : "something";
|
||
char posbuf[MAX_INPUT_LENGTH];
|
||
switch (tok->op) {
|
||
case '~': strlcpy(out, sdesc, outsz); break;
|
||
case '!': strlcpy(out, "it", outsz); break;
|
||
case '#': strlcpy(out, "it", outsz); break;
|
||
case '%':
|
||
case '=': make_possessive(sdesc, posbuf, sizeof(posbuf)); strlcpy(out, posbuf, outsz); break;
|
||
case '^':
|
||
case '+': strlcpy(out, "its", outsz); break;
|
||
case '&': strlcpy(out, "itself", outsz); break;
|
||
default: strlcpy(out, sdesc, outsz); break;
|
||
}
|
||
return;
|
||
}
|
||
|
||
strlcpy(out, "something", outsz);
|
||
}
|
||
|
||
bool build_targeted_phrase(struct char_data *ch, const char *input, bool allow_actor_at, struct targeted_phrase *phrase) {
|
||
struct emote_token tokens[MAX_EMOTE_TOKENS];
|
||
int tokc = 0;
|
||
char out[MAX_STRING_LENGTH];
|
||
char working[MAX_STRING_LENGTH];
|
||
const char *p;
|
||
|
||
if (!phrase)
|
||
return FALSE;
|
||
|
||
phrase->template[0] = '\0';
|
||
phrase->token_count = 0;
|
||
|
||
if (!input || !*input)
|
||
return TRUE;
|
||
|
||
strlcpy(working, input, sizeof(working));
|
||
out[0] = '\0';
|
||
p = working;
|
||
|
||
while (*p) {
|
||
if (is_token_operator(*p)) {
|
||
char op = *p++;
|
||
char name[MAX_NAME_LENGTH];
|
||
int ni = 0;
|
||
|
||
if (op == '@' && !allow_actor_at) {
|
||
send_to_char(ch, "You can't use '@' in that phrase.\r\n");
|
||
return FALSE;
|
||
}
|
||
|
||
if (op != '@') {
|
||
const char *q = p;
|
||
|
||
while (*q && isdigit((unsigned char)*q) && ni < (int)sizeof(name) - 1)
|
||
name[ni++] = *q++;
|
||
|
||
if (ni > 0 && *q == '.' && ni < (int)sizeof(name) - 1)
|
||
name[ni++] = *q++;
|
||
|
||
while (*q && (isalnum((unsigned char)*q) || *q == '_') && ni < (int)sizeof(name) - 1)
|
||
name[ni++] = *q++;
|
||
|
||
name[ni] = '\0';
|
||
p = q;
|
||
} else {
|
||
name[0] = '\0';
|
||
}
|
||
|
||
if (tokc >= MAX_EMOTE_TOKENS) {
|
||
send_to_char(ch, "That's too many references for one phrase.\r\n");
|
||
return FALSE;
|
||
}
|
||
|
||
tokens[tokc].op = op;
|
||
tokens[tokc].name[0] = '\0';
|
||
tokens[tokc].tch = NULL;
|
||
tokens[tokc].tobj = NULL;
|
||
|
||
if (op != '@') {
|
||
if (!*name) {
|
||
send_to_char(ch, "You need to specify who or what you're referencing.\r\n");
|
||
return FALSE;
|
||
}
|
||
strlcpy(tokens[tokc].name, name, sizeof(tokens[tokc].name));
|
||
if (!resolve_reference(ch, name, &tokens[tokc].tch, &tokens[tokc].tobj)) {
|
||
send_to_char(ch, "You can't find one of the references here.\r\n");
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
char ph[16];
|
||
snprintf(ph, sizeof(ph), "$T%d", tokc + 1);
|
||
strlcat(out, ph, sizeof(out));
|
||
tokc++;
|
||
continue;
|
||
}
|
||
|
||
char buf[2] = { *p++, '\0' };
|
||
strlcat(out, buf, sizeof(out));
|
||
}
|
||
|
||
strlcpy(phrase->template, out, sizeof(phrase->template));
|
||
phrase->token_count = tokc;
|
||
for (int i = 0; i < tokc; i++)
|
||
phrase->tokens[i] = tokens[i];
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
void render_targeted_phrase(struct char_data *actor,
|
||
const struct targeted_phrase *phrase,
|
||
bool actor_possessive_for_at,
|
||
struct char_data *viewer,
|
||
char *out,
|
||
size_t outsz)
|
||
{
|
||
char msg[MAX_STRING_LENGTH];
|
||
|
||
if (!out || !phrase) {
|
||
if (out && outsz > 0)
|
||
*out = '\0';
|
||
return;
|
||
}
|
||
|
||
if (!phrase->template[0]) {
|
||
if (outsz > 0)
|
||
*out = '\0';
|
||
return;
|
||
}
|
||
|
||
strlcpy(msg, phrase->template, sizeof(msg));
|
||
|
||
for (int i = 0; i < phrase->token_count; i++) {
|
||
char token[16], repl[MAX_INPUT_LENGTH];
|
||
snprintf(token, sizeof(token), "$T%d", i + 1);
|
||
build_replacement(&phrase->tokens[i], actor, viewer, actor_possessive_for_at, repl, sizeof(repl));
|
||
replace_all_tokens(msg, sizeof(msg), token, repl);
|
||
}
|
||
|
||
collapse_spaces(msg);
|
||
strlcpy(out, msg, outsz);
|
||
}
|
||
|
||
static bool hidden_emote_can_view(struct char_data *actor,
|
||
struct char_data *viewer,
|
||
int stealth_total) {
|
||
int opposed;
|
||
|
||
if (!viewer || viewer == actor)
|
||
return TRUE;
|
||
if (GET_LEVEL(viewer) >= LVL_IMMORT)
|
||
return TRUE;
|
||
if (!AWAKE(viewer))
|
||
return FALSE;
|
||
|
||
if (can_scan_for_sneak(viewer))
|
||
opposed = roll_scan_perception(viewer);
|
||
else
|
||
opposed = rand_number(1, 20);
|
||
|
||
return opposed >= stealth_total;
|
||
}
|
||
|
||
/* ===================== Main entry ===================== */
|
||
void perform_emote(struct char_data *ch, char *argument, bool possessive, bool hidden) {
|
||
char base[MAX_STRING_LENGTH];
|
||
char with_placeholders[MAX_STRING_LENGTH];
|
||
int at_count = 0;
|
||
int stealth_total = 0;
|
||
|
||
struct emote_token toks[MAX_EMOTE_TOKENS];
|
||
int tokc = 0;
|
||
|
||
skip_spaces(&argument);
|
||
if (!*argument) { send_to_char(ch, "Yes... but what?\r\n"); return; }
|
||
|
||
if (hidden)
|
||
stealth_total = roll_stealth_check(ch);
|
||
|
||
/* Only one '@' allowed (inserts actor name/possessive at that spot) */
|
||
for (const char *c = argument; *c; ++c) if (*c == '@') at_count++;
|
||
if (at_count > 1) { send_to_char(ch, "You can only use '@' once in an emote.\r\n"); return; }
|
||
bool has_at = (at_count == 1);
|
||
|
||
/* Prefix actor name unless '@' is used */
|
||
if (!has_at) {
|
||
char who[MAX_INPUT_LENGTH];
|
||
build_actor_name(ch, possessive, who, sizeof(who));
|
||
snprintf(base, sizeof(base), "%s %s", who, argument);
|
||
} else {
|
||
strlcpy(base, argument, sizeof(base));
|
||
}
|
||
|
||
/* Parse operators to placeholders ($Tn) and capture tokens in order */
|
||
{
|
||
char out[MAX_STRING_LENGTH]; out[0] = '\0';
|
||
const char *p = base;
|
||
|
||
while (*p && tokc < MAX_EMOTE_TOKENS) {
|
||
if (*p == '@' || *p == '~' || *p == '!' || *p == '%' ||
|
||
*p == '^' || *p == '#' || *p == '&' || *p == '=' || *p == '+') {
|
||
|
||
char op = *p++;
|
||
char name[MAX_NAME_LENGTH]; int ni = 0;
|
||
|
||
if (op == '@') {
|
||
name[0] = '\0';
|
||
} else {
|
||
/* Allow numbered refs like "2.corpse" but strip trailing punctuation. */
|
||
const char *q = p;
|
||
|
||
/* optional leading digits */
|
||
while (*q && isdigit((unsigned char)*q) && ni < (int)sizeof(name) - 1)
|
||
name[ni++] = *q++;
|
||
|
||
/* include a single '.' only if we had digits (for "2.corpse") */
|
||
if (ni > 0 && *q == '.' && ni < (int)sizeof(name) - 1)
|
||
name[ni++] = *q++;
|
||
|
||
/* base name (letters/digits/underscore only) */
|
||
while (*q && (isalnum((unsigned char)*q) || *q == '_') && ni < (int)sizeof(name) - 1)
|
||
name[ni++] = *q++;
|
||
|
||
name[ni] = '\0';
|
||
p = q;
|
||
}
|
||
|
||
toks[tokc].op = op;
|
||
toks[tokc].name[0] = '\0';
|
||
toks[tokc].tch = NULL;
|
||
toks[tokc].tobj = NULL;
|
||
|
||
if (op != '@') {
|
||
strlcpy(toks[tokc].name, name, sizeof(toks[tokc].name));
|
||
if (!resolve_reference(ch, name, &toks[tokc].tch, &toks[tokc].tobj)) {
|
||
send_to_char(ch, "You can't find one of the references here.\r\n");
|
||
return;
|
||
}
|
||
}
|
||
|
||
char ph[16]; snprintf(ph, sizeof(ph), "$T%d", tokc + 1);
|
||
strlcat(out, ph, sizeof(out));
|
||
tokc++;
|
||
continue;
|
||
}
|
||
|
||
char buf[2] = { *p++, '\0' };
|
||
strlcat(out, buf, sizeof(out));
|
||
}
|
||
strlcat(out, p, sizeof(out));
|
||
strlcpy(with_placeholders, out, sizeof(with_placeholders));
|
||
}
|
||
|
||
/* Replace literal '@' with a placeholder if present */
|
||
if (has_at && tokc < MAX_EMOTE_TOKENS) {
|
||
toks[tokc].op = '@'; toks[tokc].name[0] = '\0'; toks[tokc].tch = NULL; toks[tokc].tobj = NULL;
|
||
char ph[16]; snprintf(ph, sizeof(ph), "$T%d", tokc + 1);
|
||
replace_all_tokens(with_placeholders, sizeof(with_placeholders), "@", ph);
|
||
tokc++;
|
||
}
|
||
|
||
/* Polish: ensure final punctuation (only if the string lacks any .?! at the very end), collapse spaces */
|
||
{
|
||
size_t n = strlen(with_placeholders);
|
||
bool ends_with_punct = (n > 0 && is_end_punct(with_placeholders[n - 1]));
|
||
if (!ends_with_punct) strlcat(with_placeholders, ".", sizeof(with_placeholders));
|
||
collapse_spaces(with_placeholders);
|
||
}
|
||
|
||
struct targeted_phrase phrase;
|
||
strlcpy(phrase.template, with_placeholders, sizeof(phrase.template));
|
||
phrase.token_count = tokc;
|
||
for (int i = 0; i < tokc && i < MAX_EMOTE_TOKENS; i++)
|
||
phrase.tokens[i] = toks[i];
|
||
|
||
/* Deliver personalized message to everyone in the room (including actor) */
|
||
for (struct descriptor_data *d = descriptor_list; d; d = d->next) {
|
||
if (STATE(d) != CON_PLAYING || !d->character) continue;
|
||
if (IN_ROOM(d->character) != IN_ROOM(ch)) continue;
|
||
if (hidden && !hidden_emote_can_view(ch, d->character, stealth_total))
|
||
continue;
|
||
|
||
char msg[MAX_STRING_LENGTH];
|
||
render_targeted_phrase(ch, &phrase, possessive, d->character, msg, sizeof(msg));
|
||
|
||
/* Final per-viewer cleanup: spaces + multi-sentence capitalization */
|
||
collapse_spaces(msg);
|
||
capitalize_sentences(msg);
|
||
|
||
if (d->character == ch) {
|
||
act(msg, FALSE, ch, NULL, NULL, TO_CHAR);
|
||
} else if (hidden) {
|
||
send_to_char(d->character, "You notice:\r\n%s\r\n", msg);
|
||
} else {
|
||
act(msg, FALSE, ch, NULL, d->character, TO_VICT);
|
||
}
|
||
}
|
||
}
|
||
/* =================== End emote engine =================== */
|
||
|
||
ACMD(do_wizhelp)
|
||
{
|
||
extern int *cmd_sort_info;
|
||
int no = 1, i, cmd_num;
|
||
int level;
|
||
|
||
if (!ch->desc)
|
||
return;
|
||
|
||
send_to_char(ch, "The following privileged commands are available:\r\n");
|
||
|
||
for (level = LVL_IMPL; level >= LVL_IMMORT; level--) {
|
||
send_to_char(ch, "%sLevel %d%s:\r\n", CCCYN(ch, C_NRM), level, CCNRM(ch, C_NRM));
|
||
for (no = 1, cmd_num = 1; complete_cmd_info[cmd_sort_info[cmd_num]].command[0] != '\n'; cmd_num++) {
|
||
i = cmd_sort_info[cmd_num];
|
||
|
||
if (complete_cmd_info[i].minimum_level != level)
|
||
continue;
|
||
|
||
send_to_char(ch, "%-14s%s", complete_cmd_info[i].command, no++ % 7 == 0 ? "\r\n" : "");
|
||
}
|
||
if (no % 7 != 1)
|
||
send_to_char(ch, "\r\n");
|
||
if (level != LVL_IMMORT)
|
||
send_to_char(ch, "\r\n");
|
||
}
|
||
}
|
||
|
||
ACMD(do_echo)
|
||
{
|
||
skip_spaces(&argument);
|
||
|
||
if (!*argument)
|
||
send_to_char(ch, "Yes.. but what?\r\n");
|
||
else {
|
||
char buf[MAX_INPUT_LENGTH + 4];
|
||
|
||
if (subcmd == SCMD_EMOTE)
|
||
snprintf(buf, sizeof(buf), "$n %s", argument);
|
||
else {
|
||
strlcpy(buf, argument, sizeof(buf));
|
||
mudlog(CMP, MAX(LVL_BUILDER, GET_INVIS_LEV(ch)), TRUE, "(GC) %s echoed: %s", GET_NAME(ch), buf);
|
||
}
|
||
act(buf, FALSE, ch, 0, 0, TO_ROOM);
|
||
|
||
if (!IS_NPC(ch) && PRF_FLAGGED(ch, PRF_NOREPEAT))
|
||
send_to_char(ch, "%s", CONFIG_OK);
|
||
else
|
||
act(buf, FALSE, ch, 0, 0, TO_CHAR);
|
||
}
|
||
}
|
||
|
||
ACMD(do_emote)
|
||
{
|
||
perform_emote(ch, argument, FALSE, FALSE);
|
||
}
|
||
|
||
ACMD(do_pemote)
|
||
{
|
||
perform_emote(ch, argument, TRUE, FALSE);
|
||
}
|
||
|
||
ACMD(do_hemote)
|
||
{
|
||
perform_emote(ch, argument, FALSE, TRUE);
|
||
}
|
||
|
||
ACMD(do_phemote)
|
||
{
|
||
perform_emote(ch, argument, TRUE, TRUE);
|
||
}
|
||
|
||
ACMD(do_send)
|
||
{
|
||
char arg[MAX_INPUT_LENGTH], buf[MAX_INPUT_LENGTH];
|
||
struct char_data *vict;
|
||
|
||
half_chop(argument, arg, buf);
|
||
|
||
if (!*arg) {
|
||
send_to_char(ch, "Send what to who?\r\n");
|
||
return;
|
||
}
|
||
if (!(vict = get_char_vis(ch, arg, NULL, FIND_CHAR_WORLD))) {
|
||
send_to_char(ch, "%s", CONFIG_NOPERSON);
|
||
return;
|
||
}
|
||
send_to_char(vict, "%s\r\n", buf);
|
||
mudlog(CMP, MAX(LVL_GOD, GET_INVIS_LEV(ch)), TRUE, "(GC) %s sent %s: %s", GET_NAME(ch), GET_NAME(vict), buf);
|
||
|
||
if (!IS_NPC(ch) && PRF_FLAGGED(ch, PRF_NOREPEAT))
|
||
send_to_char(ch, "Sent.\r\n");
|
||
else
|
||
send_to_char(ch, "You send '%s' to %s.\r\n", buf, GET_NAME(vict));
|
||
}
|
||
|
||
/* take a string, and return an rnum.. used for goto, at, etc. -je 4/6/93 */
|
||
room_rnum find_target_room(struct char_data *ch, char *rawroomstr)
|
||
{
|
||
room_rnum location = NOWHERE;
|
||
char roomstr[MAX_INPUT_LENGTH];
|
||
|
||
one_argument(rawroomstr, roomstr);
|
||
|
||
if (!*roomstr) {
|
||
send_to_char(ch, "You must supply a room number or name.\r\n");
|
||
return (NOWHERE);
|
||
}
|
||
|
||
if (isdigit(*roomstr) && !strchr(roomstr, '.')) {
|
||
if ((location = real_room((room_vnum)atoi(roomstr))) == NOWHERE) {
|
||
send_to_char(ch, "No room exists with that number.\r\n");
|
||
return (NOWHERE);
|
||
}
|
||
} else {
|
||
struct char_data *target_mob;
|
||
struct obj_data *target_obj;
|
||
char *mobobjstr = roomstr;
|
||
int num;
|
||
|
||
num = get_number(&mobobjstr);
|
||
if ((target_mob = get_char_vis(ch, mobobjstr, &num, FIND_CHAR_WORLD)) != NULL) {
|
||
if ((location = IN_ROOM(target_mob)) == NOWHERE) {
|
||
send_to_char(ch, "That character is currently lost.\r\n");
|
||
return (NOWHERE);
|
||
}
|
||
} else if ((target_obj = get_obj_vis(ch, mobobjstr, &num)) != NULL) {
|
||
if (IN_ROOM(target_obj) != NOWHERE)
|
||
location = IN_ROOM(target_obj);
|
||
else if (target_obj->carried_by && IN_ROOM(target_obj->carried_by) != NOWHERE)
|
||
location = IN_ROOM(target_obj->carried_by);
|
||
else if (target_obj->worn_by && IN_ROOM(target_obj->worn_by) != NOWHERE)
|
||
location = IN_ROOM(target_obj->worn_by);
|
||
|
||
if (location == NOWHERE) {
|
||
send_to_char(ch, "That object is currently not in a room.\r\n");
|
||
return (NOWHERE);
|
||
}
|
||
}
|
||
|
||
if (location == NOWHERE) {
|
||
send_to_char(ch, "Nothing exists by that name.\r\n");
|
||
return (NOWHERE);
|
||
}
|
||
}
|
||
|
||
/* A location has been found -- if you're >= GRGOD, no restrictions. */
|
||
if (GET_LEVEL(ch) >= LVL_GRGOD)
|
||
return (location);
|
||
|
||
if (ROOM_FLAGGED(location, ROOM_GODROOM))
|
||
send_to_char(ch, "You are not godly enough to use that room!\r\n");
|
||
else if (ROOM_FLAGGED(location, ROOM_PRIVATE) && world[location].people && world[location].people->next_in_room)
|
||
send_to_char(ch, "There's a private conversation going on in that room.\r\n");
|
||
else if (ROOM_FLAGGED(location, ROOM_HOUSE) && !House_can_enter(ch, GET_ROOM_VNUM(location)))
|
||
send_to_char(ch, "That's private property -- no trespassing!\r\n");
|
||
else
|
||
return (location);
|
||
|
||
return (NOWHERE);
|
||
}
|
||
|
||
ACMD(do_at)
|
||
{
|
||
char command[MAX_INPUT_LENGTH], buf[MAX_INPUT_LENGTH];
|
||
room_rnum location, original_loc;
|
||
|
||
half_chop(argument, buf, command);
|
||
if (!*buf) {
|
||
send_to_char(ch, "You must supply a room number or a name.\r\n");
|
||
return;
|
||
}
|
||
|
||
if (!*command) {
|
||
send_to_char(ch, "What do you want to do there?\r\n");
|
||
return;
|
||
}
|
||
|
||
if ((location = find_target_room(ch, buf)) == NOWHERE)
|
||
return;
|
||
|
||
/* a location has been found. */
|
||
original_loc = IN_ROOM(ch);
|
||
char_from_room(ch);
|
||
char_to_room(ch, location);
|
||
command_interpreter(ch, command);
|
||
|
||
/* check if the char is still there */
|
||
if (IN_ROOM(ch) == location) {
|
||
char_from_room(ch);
|
||
char_to_room(ch, original_loc);
|
||
}
|
||
}
|
||
|
||
ACMD(do_goto)
|
||
{
|
||
char buf[MAX_STRING_LENGTH];
|
||
room_rnum location;
|
||
|
||
if ((location = find_target_room(ch, argument)) == NOWHERE)
|
||
return;
|
||
|
||
if (ZONE_FLAGGED(GET_ROOM_ZONE(location), ZONE_NOIMMORT) && (GET_LEVEL(ch) >= LVL_IMMORT) && (GET_LEVEL(ch) < LVL_GRGOD)) {
|
||
send_to_char(ch, "Sorry, that zone is off-limits for immortals!");
|
||
return;
|
||
}
|
||
|
||
snprintf(buf, sizeof(buf), "$n %s", POOFOUT(ch) ? POOFOUT(ch) : "disappears in a puff of smoke.");
|
||
act(buf, TRUE, ch, 0, 0, TO_ROOM);
|
||
|
||
char_from_room(ch);
|
||
char_to_room(ch, location);
|
||
|
||
snprintf(buf, sizeof(buf), "$n %s", POOFIN(ch) ? POOFIN(ch) : "appears with an ear-splitting bang.");
|
||
act(buf, TRUE, ch, 0, 0, TO_ROOM);
|
||
|
||
look_at_room(ch, 0);
|
||
enter_wtrigger(&world[IN_ROOM(ch)], ch, -1);
|
||
}
|
||
|
||
ACMD(do_trans)
|
||
{
|
||
char buf[MAX_INPUT_LENGTH];
|
||
struct descriptor_data *i;
|
||
struct char_data *victim;
|
||
|
||
one_argument(argument, buf);
|
||
if (!*buf)
|
||
send_to_char(ch, "Whom do you wish to transfer?\r\n");
|
||
else if (str_cmp("all", buf)) {
|
||
if (!(victim = get_char_vis(ch, buf, NULL, FIND_CHAR_WORLD)))
|
||
send_to_char(ch, "%s", CONFIG_NOPERSON);
|
||
else if (victim == ch)
|
||
send_to_char(ch, "That doesn't make much sense, does it?\r\n");
|
||
else {
|
||
if ((GET_LEVEL(ch) < GET_LEVEL(victim)) && !IS_NPC(victim)) {
|
||
send_to_char(ch, "Go transfer someone your own size.\r\n");
|
||
return;
|
||
}
|
||
act("$n disappears in a mushroom cloud.", FALSE, victim, 0, 0, TO_ROOM);
|
||
char_from_room(victim);
|
||
char_to_room(victim, IN_ROOM(ch));
|
||
act("$n arrives from a puff of smoke.", FALSE, victim, 0, 0, TO_ROOM);
|
||
act("$n has transferred you!", FALSE, ch, 0, victim, TO_VICT);
|
||
look_at_room(victim, 0);
|
||
|
||
enter_wtrigger(&world[IN_ROOM(victim)], victim, -1);
|
||
}
|
||
} else { /* Trans All */
|
||
if (GET_LEVEL(ch) < LVL_GRGOD) {
|
||
send_to_char(ch, "I think not.\r\n");
|
||
return;
|
||
}
|
||
|
||
for (i = descriptor_list; i; i = i->next)
|
||
if (STATE(i) == CON_PLAYING && i->character && i->character != ch) {
|
||
victim = i->character;
|
||
if (GET_LEVEL(victim) >= GET_LEVEL(ch))
|
||
continue;
|
||
act("$n disappears in a mushroom cloud.", FALSE, victim, 0, 0, TO_ROOM);
|
||
char_from_room(victim);
|
||
char_to_room(victim, IN_ROOM(ch));
|
||
act("$n arrives from a puff of smoke.", FALSE, victim, 0, 0, TO_ROOM);
|
||
act("$n has transferred you!", FALSE, ch, 0, victim, TO_VICT);
|
||
look_at_room(victim, 0);
|
||
enter_wtrigger(&world[IN_ROOM(victim)], victim, -1);
|
||
}
|
||
send_to_char(ch, "%s", CONFIG_OK);
|
||
}
|
||
}
|
||
|
||
ACMD(do_teleport)
|
||
{
|
||
char buf[MAX_INPUT_LENGTH], buf2[MAX_INPUT_LENGTH];
|
||
struct char_data *victim;
|
||
room_rnum target;
|
||
|
||
two_arguments(argument, buf, buf2);
|
||
|
||
if (!*buf)
|
||
send_to_char(ch, "Whom do you wish to teleport?\r\n");
|
||
else if (!(victim = get_char_vis(ch, buf, NULL, FIND_CHAR_WORLD)))
|
||
send_to_char(ch, "%s", CONFIG_NOPERSON);
|
||
else if (victim == ch)
|
||
send_to_char(ch, "Use 'goto' to teleport yourself.\r\n");
|
||
else if (GET_LEVEL(victim) >= GET_LEVEL(ch))
|
||
send_to_char(ch, "Maybe you shouldn't do that.\r\n");
|
||
else if (!*buf2)
|
||
send_to_char(ch, "Where do you wish to send this person?\r\n");
|
||
else if ((target = find_target_room(ch, buf2)) != NOWHERE) {
|
||
send_to_char(ch, "%s", CONFIG_OK);
|
||
act("$n disappears in a puff of smoke.", FALSE, victim, 0, 0, TO_ROOM);
|
||
char_from_room(victim);
|
||
char_to_room(victim, target);
|
||
act("$n arrives from a puff of smoke.", FALSE, victim, 0, 0, TO_ROOM);
|
||
act("$n has teleported you!", FALSE, ch, 0, (char *) victim, TO_VICT);
|
||
look_at_room(victim, 0);
|
||
enter_wtrigger(&world[IN_ROOM(victim)], victim, -1);
|
||
}
|
||
}
|
||
|
||
ACMD(do_vnum)
|
||
{
|
||
char buf[MAX_INPUT_LENGTH], buf2[MAX_INPUT_LENGTH];
|
||
int good_arg = 0;
|
||
|
||
half_chop(argument, buf, buf2);
|
||
|
||
if (!*buf || !*buf2) {
|
||
send_to_char(ch, "Usage: vnum { obj | mob | room | trig } <name>\r\n");
|
||
return;
|
||
}
|
||
if (is_abbrev(buf, "mob") && (good_arg = 1))
|
||
if (!vnum_mobile(buf2, ch))
|
||
send_to_char(ch, "No mobiles by that name.\r\n");
|
||
|
||
if (is_abbrev(buf, "obj") && (good_arg =1 ))
|
||
if (!vnum_object(buf2, ch))
|
||
send_to_char(ch, "No objects by that name.\r\n");
|
||
|
||
if (is_abbrev(buf, "room") && (good_arg = 1))
|
||
if (!vnum_room(buf2, ch))
|
||
send_to_char(ch, "No rooms by that name.\r\n");
|
||
|
||
if (is_abbrev(buf, "trig") && (good_arg = 1))
|
||
if (!vnum_trig(buf2, ch))
|
||
send_to_char(ch, "No triggers by that name.\r\n");
|
||
|
||
if (!good_arg)
|
||
send_to_char(ch, "Usage: vnum { obj | mob | room | trig } <name>\r\n");
|
||
}
|
||
|
||
#define ZOCMD zone_table[zrnum].cmd[subcmd]
|
||
|
||
static void stat_format_zone_cmds_room(room_vnum rvnum, char *buf, size_t buf_size)
|
||
{
|
||
zone_rnum zrnum = real_zone_by_thing(rvnum);
|
||
room_rnum rrnum = real_room(rvnum), cmd_room = NOWHERE;
|
||
int subcmd = 0, count = 0;
|
||
size_t len = 0;
|
||
|
||
buf[0] = '\0';
|
||
|
||
if (zrnum == NOWHERE || rrnum == NOWHERE) {
|
||
strlcpy(buf, "None", buf_size);
|
||
return;
|
||
}
|
||
|
||
#define ZOCMD zone_table[zrnum].cmd[subcmd]
|
||
while (ZOCMD.command != 'S') {
|
||
switch (ZOCMD.command) {
|
||
case 'M':
|
||
case 'O':
|
||
case 'T':
|
||
case 'V':
|
||
cmd_room = ZOCMD.arg3;
|
||
break;
|
||
case 'D':
|
||
case 'R':
|
||
cmd_room = ZOCMD.arg1;
|
||
break;
|
||
default:
|
||
cmd_room = NOWHERE;
|
||
break;
|
||
}
|
||
|
||
if (cmd_room == rrnum) {
|
||
if (len)
|
||
stat_appendf(buf, buf_size, &len, "\n");
|
||
|
||
count++;
|
||
switch (ZOCMD.command) {
|
||
case 'M':
|
||
stat_appendf(buf, buf_size, &len, "%sLoad mob %s (#%d) max %d",
|
||
ZOCMD.if_flag ? "then " : "",
|
||
mob_proto[ZOCMD.arg1].player.short_descr,
|
||
mob_index[ZOCMD.arg1].vnum,
|
||
ZOCMD.arg2);
|
||
break;
|
||
case 'G':
|
||
stat_appendf(buf, buf_size, &len, "%sGive %s (#%d) max %d",
|
||
ZOCMD.if_flag ? "then " : "",
|
||
obj_proto[ZOCMD.arg1].short_description,
|
||
obj_index[ZOCMD.arg1].vnum,
|
||
ZOCMD.arg2);
|
||
break;
|
||
case 'O':
|
||
stat_appendf(buf, buf_size, &len, "%sLoad obj %s (#%d) max %d",
|
||
ZOCMD.if_flag ? "then " : "",
|
||
obj_proto[ZOCMD.arg1].short_description,
|
||
obj_index[ZOCMD.arg1].vnum,
|
||
ZOCMD.arg2);
|
||
break;
|
||
case 'E':
|
||
stat_appendf(buf, buf_size, &len, "%sEquip %s (#%d) %s max %d",
|
||
ZOCMD.if_flag ? "then " : "",
|
||
obj_proto[ZOCMD.arg1].short_description,
|
||
obj_index[ZOCMD.arg1].vnum,
|
||
equipment_types[ZOCMD.arg3],
|
||
ZOCMD.arg2);
|
||
break;
|
||
case 'P':
|
||
stat_appendf(buf, buf_size, &len, "%sPut %s (#%d) in %s (#%d) max %d",
|
||
ZOCMD.if_flag ? "then " : "",
|
||
obj_proto[ZOCMD.arg1].short_description,
|
||
obj_index[ZOCMD.arg1].vnum,
|
||
obj_proto[ZOCMD.arg3].short_description,
|
||
obj_index[ZOCMD.arg3].vnum,
|
||
ZOCMD.arg2);
|
||
break;
|
||
case 'R':
|
||
stat_appendf(buf, buf_size, &len, "%sRemove %s (#%d)",
|
||
ZOCMD.if_flag ? "then " : "",
|
||
obj_proto[ZOCMD.arg2].short_description,
|
||
obj_index[ZOCMD.arg2].vnum);
|
||
break;
|
||
case 'D':
|
||
stat_appendf(buf, buf_size, &len, "%sSet door %s %s",
|
||
ZOCMD.if_flag ? "then " : "",
|
||
dirs[ZOCMD.arg2],
|
||
ZOCMD.arg3 ? ((ZOCMD.arg3 == 1) ? "closed" : "locked") : "open");
|
||
break;
|
||
case 'T':
|
||
stat_appendf(buf, buf_size, &len, "%sAttach trig %s (#%d) to %s",
|
||
ZOCMD.if_flag ? "then " : "",
|
||
trig_index[ZOCMD.arg2]->proto->name,
|
||
trig_index[ZOCMD.arg2]->vnum,
|
||
(ZOCMD.arg1 == MOB_TRIGGER) ? "mobile" :
|
||
(ZOCMD.arg1 == OBJ_TRIGGER) ? "object" :
|
||
(ZOCMD.arg1 == WLD_TRIGGER) ? "room" : "unknown");
|
||
break;
|
||
case 'V':
|
||
stat_appendf(buf, buf_size, &len, "%sAssign global %s:%d to %s = %s",
|
||
ZOCMD.if_flag ? "then " : "",
|
||
ZOCMD.sarg1,
|
||
ZOCMD.arg2,
|
||
(ZOCMD.arg1 == MOB_TRIGGER) ? "mobile" :
|
||
(ZOCMD.arg1 == OBJ_TRIGGER) ? "object" :
|
||
(ZOCMD.arg1 == WLD_TRIGGER) ? "room" : "unknown",
|
||
ZOCMD.sarg2 ? ZOCMD.sarg2 : "");
|
||
break;
|
||
default:
|
||
stat_appendf(buf, buf_size, &len, "%s<Unknown command %c>",
|
||
ZOCMD.if_flag ? "then " : "",
|
||
ZOCMD.command);
|
||
break;
|
||
}
|
||
}
|
||
subcmd++;
|
||
}
|
||
#undef ZOCMD
|
||
|
||
if (!count)
|
||
strlcpy(buf, "None", buf_size);
|
||
}
|
||
|
||
static void do_stat_room(struct char_data *ch, struct room_data *rm)
|
||
{
|
||
char buf[MAX_STRING_LENGTH];
|
||
char chars[MAX_STRING_LENGTH];
|
||
char objs[MAX_STRING_LENGTH];
|
||
char exits[MAX_STRING_LENGTH];
|
||
char triggers[MAX_STRING_LENGTH];
|
||
char globals[MAX_STRING_LENGTH];
|
||
char zone_cmds[MAX_STRING_LENGTH];
|
||
size_t len = 0;
|
||
|
||
stat_table_border(ch);
|
||
stat_table_row(ch, "Name", rm->name ? rm->name : "<None>");
|
||
|
||
stat_table_row_fmt(ch, "Identifiers", "Zone %d (%s), VNum #%d (RNum %d), ID %ld",
|
||
zone_table[rm->zone].number, zone_table[rm->zone].name,
|
||
rm->number, real_room(rm->number), room_script_id(rm));
|
||
|
||
sprinttype(rm->sector_type, sector_types, buf, sizeof(buf));
|
||
stat_table_row_fmt(ch, "Type", "Sector %s, SpecProc %s",
|
||
buf,
|
||
rm->func ? get_spec_func_name(rm->func) : "None");
|
||
|
||
sprintbitarray(rm->room_flags, room_bits, RF_ARRAY_MAX, buf);
|
||
stat_table_row(ch, "Room Flags", buf);
|
||
|
||
buf[0] = '\0';
|
||
len = 0;
|
||
for (struct extra_descr_data *desc = rm->ex_description; desc; desc = desc->next)
|
||
stat_appendf(buf, sizeof(buf), &len, "%s%s", len ? ", " : "", desc->keyword ? desc->keyword : "<None>");
|
||
if (!len)
|
||
strlcpy(buf, "None", sizeof(buf));
|
||
stat_table_row(ch, "Extra Descs", buf);
|
||
|
||
stat_format_character_list(ch, rm->people, chars, sizeof(chars));
|
||
stat_table_row(ch, "Characters", chars);
|
||
|
||
stat_format_object_list(ch, rm->contents, objs, sizeof(objs));
|
||
stat_table_row(ch, "Contents", objs);
|
||
|
||
stat_format_exit_summary(rm, exits, sizeof(exits));
|
||
stat_table_row(ch, "Exits", exits);
|
||
|
||
stat_format_script_triggers(SCRIPT(rm), triggers, sizeof(triggers));
|
||
stat_table_row(ch, "Triggers", triggers);
|
||
|
||
stat_format_script_globals(SCRIPT(rm), globals, sizeof(globals));
|
||
stat_table_row(ch, "Script Vars", globals);
|
||
|
||
stat_format_zone_cmds_room(rm->number, zone_cmds, sizeof(zone_cmds));
|
||
stat_table_row(ch, "Zone Commands", zone_cmds);
|
||
|
||
stat_table_border(ch);
|
||
}
|
||
|
||
static void do_stat_object(struct char_data *ch, struct obj_data *j)
|
||
{
|
||
char buf[MAX_STRING_LENGTH];
|
||
char values[MAX_STRING_LENGTH];
|
||
char affects[MAX_STRING_LENGTH];
|
||
char contents[MAX_STRING_LENGTH];
|
||
char triggers[MAX_STRING_LENGTH];
|
||
char globals[MAX_STRING_LENGTH];
|
||
const char *const *labels = obj_value_labels(GET_OBJ_TYPE(j));
|
||
size_t len = 0;
|
||
|
||
stat_table_border(ch);
|
||
stat_table_row(ch, "Name", j->short_description ? j->short_description : "<None>");
|
||
stat_table_row(ch, "Keywords", j->name ? j->name : "<None>");
|
||
stat_table_row(ch, "Long Desc", j->description ? j->description : "<None>");
|
||
|
||
buf[0] = '\0';
|
||
len = 0;
|
||
for (struct extra_descr_data *desc = j->ex_description; desc; desc = desc->next) {
|
||
stat_appendf(buf, sizeof(buf), &len, "%s%s", len ? ", " : "", desc->keyword ? desc->keyword : "<None>");
|
||
}
|
||
if (!len)
|
||
strlcpy(buf, "None", sizeof(buf));
|
||
stat_table_row(ch, "Extra Descs", buf);
|
||
|
||
stat_table_row_fmt(ch, "Identifiers", "VNum #%d (RNum %d) ID %ld",
|
||
GET_OBJ_VNUM(j), GET_OBJ_RNUM(j), obj_script_id(j));
|
||
|
||
sprinttype(GET_OBJ_TYPE(j), item_types, buf, sizeof(buf));
|
||
stat_table_row_fmt(ch, "Type", "%s, SpecProc %s",
|
||
buf,
|
||
GET_OBJ_SPEC(j) ? get_spec_func_name(GET_OBJ_SPEC(j)) : "None");
|
||
|
||
buf[0] = '\0';
|
||
len = 0;
|
||
if (IN_ROOM(j) != NOWHERE)
|
||
stat_appendf(buf, sizeof(buf), &len, "Room #%d %s",
|
||
GET_ROOM_VNUM(IN_ROOM(j)), world[IN_ROOM(j)].name);
|
||
else
|
||
stat_appendf(buf, sizeof(buf), &len, "Room <None>");
|
||
stat_appendf(buf, sizeof(buf), &len, ", In Obj %s",
|
||
j->in_obj ? (j->in_obj->short_description ? j->in_obj->short_description : j->in_obj->name) : "None");
|
||
stat_appendf(buf, sizeof(buf), &len, ", Carried by %s",
|
||
j->carried_by ? GET_NAME(j->carried_by) : "Nobody");
|
||
stat_appendf(buf, sizeof(buf), &len, ", Worn by %s",
|
||
j->worn_by ? GET_NAME(j->worn_by) : "Nobody");
|
||
stat_table_row(ch, "Location", buf);
|
||
|
||
stat_table_row_fmt(ch, "Stats", "Weight %d, Cost %d",
|
||
GET_OBJ_WEIGHT(j), GET_OBJ_COST(j));
|
||
|
||
sprintbitarray(GET_OBJ_WEAR(j), wear_bits, TW_ARRAY_MAX, buf);
|
||
stat_table_row(ch, "Wear Slots", buf);
|
||
|
||
sprintbitarray(GET_OBJ_EXTRA(j), extra_bits, EF_ARRAY_MAX, buf);
|
||
stat_table_row(ch, "Extra Flags", buf);
|
||
|
||
sprintbitarray(GET_OBJ_AFFECT(j), affected_bits, AF_ARRAY_MAX, buf);
|
||
stat_table_row(ch, "Affect Flags", buf);
|
||
|
||
values[0] = '\0';
|
||
len = 0;
|
||
for (int i = 0; i < NUM_OBJ_VAL_POSITIONS; i++) {
|
||
stat_appendf(values, sizeof(values), &len, "%s%s=%d",
|
||
len ? ", " : "", labels[i], GET_OBJ_VAL(j, i));
|
||
}
|
||
stat_table_row(ch, "Object Values", values);
|
||
|
||
stat_format_obj_special(j, buf, sizeof(buf));
|
||
stat_table_row(ch, "Special", buf);
|
||
|
||
if (j->contains) {
|
||
stat_format_object_list(ch, j->contains, contents, sizeof(contents));
|
||
stat_table_row(ch, "Contains", contents);
|
||
} else
|
||
stat_table_row(ch, "Contains", "None");
|
||
|
||
stat_format_obj_affects(j, affects, sizeof(affects));
|
||
stat_table_row(ch, "Apply Mods", affects);
|
||
|
||
stat_format_script_triggers(SCRIPT(j), triggers, sizeof(triggers));
|
||
stat_table_row(ch, "Triggers", triggers);
|
||
|
||
stat_format_script_globals(SCRIPT(j), globals, sizeof(globals));
|
||
stat_table_row(ch, "Script Vars", globals);
|
||
|
||
stat_table_border(ch);
|
||
}
|
||
|
||
static void do_stat_character(struct char_data *ch, struct char_data *k)
|
||
{
|
||
char buf[MAX_STRING_LENGTH];
|
||
char buf2[MAX_STRING_LENGTH];
|
||
char effects[MAX_STRING_LENGTH];
|
||
char triggers[MAX_STRING_LENGTH];
|
||
char globals[MAX_STRING_LENGTH];
|
||
struct ac_breakdown acb;
|
||
const char *sex = genders[(int) GET_SEX(k)];
|
||
const char *ctype = !IS_NPC(k) ? "PC" : (!IS_MOB(k) ? "NPC" : "MOB");
|
||
|
||
stat_table_border(ch);
|
||
stat_table_row_fmt(ch, "Name", "%s (%s %s)", GET_NAME(k), sex, ctype);
|
||
|
||
if (IS_NPC(k) && k->player.name && *k->player.name)
|
||
stat_table_row(ch, "Keywords", k->player.name);
|
||
|
||
if (k->player.short_descr && *k->player.short_descr)
|
||
stat_table_row(ch, "Short Desc", k->player.short_descr);
|
||
|
||
if (k->player.long_descr && *k->player.long_descr)
|
||
stat_table_row(ch, "Long Desc", k->player.long_descr);
|
||
|
||
if (IS_MOB(k)) {
|
||
stat_table_row_fmt(ch, "Identifiers", "VNum #%d (RNum %d) ID %ld",
|
||
GET_MOB_VNUM(k), GET_MOB_RNUM(k), char_script_id(k));
|
||
} else {
|
||
room_vnum loadroom = GET_LOADROOM(k);
|
||
if (loadroom == NOWHERE)
|
||
stat_table_row_fmt(ch, "Identifiers", "ID %ld, Loadroom <None>", GET_IDNUM(k));
|
||
else
|
||
stat_table_row_fmt(ch, "Identifiers", "ID %ld, Loadroom #%d", GET_IDNUM(k), loadroom);
|
||
}
|
||
|
||
if (IN_ROOM(k) == NOWHERE)
|
||
stat_table_row(ch, "Current Room", "Nowhere");
|
||
else
|
||
stat_table_row_fmt(ch, "Current Room", "#%d %s (Zone %d)",
|
||
GET_ROOM_VNUM(IN_ROOM(k)),
|
||
world[IN_ROOM(k)].name,
|
||
zone_table[world[IN_ROOM(k)].zone].number);
|
||
|
||
if (!IS_NPC(k)) {
|
||
char logon[64], olc[64] = "";
|
||
strftime(logon, sizeof(logon), "%b %d %Y", localtime(&(k->player.time.logon)));
|
||
|
||
if (GET_LEVEL(k) >= LVL_BUILDER) {
|
||
if (GET_OLC_ZONE(k) == AEDIT_PERMISSION)
|
||
snprintf(olc, sizeof(olc), ", OLC Aedit");
|
||
else if (GET_OLC_ZONE(k) == HEDIT_PERMISSION)
|
||
snprintf(olc, sizeof(olc), ", OLC Hedit");
|
||
else if (GET_OLC_ZONE(k) == ALL_PERMISSION)
|
||
snprintf(olc, sizeof(olc), ", OLC All");
|
||
else if (GET_OLC_ZONE(k) == NOWHERE)
|
||
snprintf(olc, sizeof(olc), ", OLC OFF");
|
||
else
|
||
snprintf(olc, sizeof(olc), ", OLC %d", GET_OLC_ZONE(k));
|
||
}
|
||
|
||
stat_table_row_fmt(ch, "Account", "Last %s%s",
|
||
logon, olc);
|
||
{
|
||
time_t played_seconds = get_total_played_seconds(k);
|
||
int played_minutes = (played_seconds / SECS_PER_REAL_MIN) % 60;
|
||
int played_hours = (played_seconds / SECS_PER_REAL_HOUR) % 24;
|
||
int played_days = played_seconds / SECS_PER_REAL_DAY;
|
||
stat_table_row_fmt(ch, "Age/Playtime", "Age %d, %dd %dh %dm",
|
||
GET_ROLEPLAY_AGE(k), played_days, played_hours, played_minutes);
|
||
}
|
||
}
|
||
|
||
stat_table_row_fmt(ch, "Class", "%s", CLASS_NAME(k));
|
||
stat_table_row_fmt(ch, "Species", "%s", get_species_name(GET_SPECIES(k)));
|
||
|
||
stat_table_row_fmt(ch, "Attributes",
|
||
"Str %d Int %d Wis %d Dex %d Con %d Cha %d",
|
||
GET_STR(k), GET_INT(k), GET_WIS(k),
|
||
GET_DEX(k), GET_CON(k), GET_CHA(k));
|
||
|
||
stat_table_row_fmt(ch, "Size", "Weight %d, Height %d",
|
||
GET_WEIGHT(k), GET_HEIGHT(k));
|
||
|
||
stat_table_row_fmt(ch, "Saving Throws",
|
||
"Str %+d Dex %+d Con %+d Int %+d Wis %+d Cha %+d",
|
||
get_save_mod(k, ABIL_STR),
|
||
get_save_mod(k, ABIL_DEX),
|
||
get_save_mod(k, ABIL_CON),
|
||
get_save_mod(k, ABIL_INT),
|
||
get_save_mod(k, ABIL_WIS),
|
||
get_save_mod(k, ABIL_CHA));
|
||
|
||
stat_table_row_fmt(ch, "Vitals",
|
||
"HP %d/%d (+%d) | Mana %d/%d (+%d) | Stamina %d/%d (+%d)",
|
||
GET_HIT(k), GET_MAX_HIT(k), hit_gain(k),
|
||
GET_MANA(k), GET_MAX_MANA(k), mana_gain(k),
|
||
GET_STAMINA(k), GET_MAX_STAMINA(k), move_gain(k));
|
||
|
||
stat_table_row_fmt(ch, "Currency", "Coins %d, Bank %d (Total %d)",
|
||
GET_COINS(k), GET_BANK_COINS(k), GET_COINS(k) + GET_BANK_COINS(k));
|
||
|
||
if (!IS_NPC(k)) {
|
||
if (GET_QUEST(k) != NOTHING)
|
||
stat_table_row_fmt(ch, "Quests", "Points %d, Completed %d, Current #%d (%d tics left)",
|
||
GET_QUESTPOINTS(k), GET_NUM_QUESTS(k), GET_QUEST(k), GET_QUEST_TIME(k));
|
||
else
|
||
stat_table_row_fmt(ch, "Quests", "Points %d, Completed %d",
|
||
GET_QUESTPOINTS(k), GET_NUM_QUESTS(k));
|
||
}
|
||
|
||
compute_ac_breakdown(k, &acb);
|
||
stat_table_row_fmt(ch, "Armor Class",
|
||
"%d (base %d, armor %d, magic %+d, Dex cap %d => %+d, situ %+d)",
|
||
acb.total, acb.base, acb.armor_piece_sum, acb.armor_magic_sum,
|
||
acb.dex_cap, acb.dex_mod_applied, acb.situational);
|
||
|
||
sprinttype(GET_POS(k), position_types, buf, sizeof(buf));
|
||
const char *fighting = FIGHTING(k) ? GET_NAME(FIGHTING(k)) : "Nobody";
|
||
buf2[0] = '\0';
|
||
size_t pos_len = 0;
|
||
stat_appendf(buf2, sizeof(buf2), &pos_len, "%s, Fighting %s", buf, fighting);
|
||
|
||
if (IS_NPC(k)) {
|
||
sprinttype(k->mob_specials.default_pos, position_types, buf, sizeof(buf));
|
||
stat_appendf(buf2, sizeof(buf2), &pos_len, ", Default %s, Attack %s",
|
||
buf, attack_hit_text[(int) k->mob_specials.attack_type].singular);
|
||
} else
|
||
stat_appendf(buf2, sizeof(buf2), &pos_len, ", Idle %d tics", k->char_specials.timer);
|
||
|
||
if (k->desc) {
|
||
sprinttype(STATE(k->desc), connected_types, buf, sizeof(buf));
|
||
stat_appendf(buf2, sizeof(buf2), &pos_len, ", Conn %s", buf);
|
||
}
|
||
|
||
stat_table_row(ch, "Position", buf2);
|
||
|
||
if (IS_MOB(k)) {
|
||
stat_table_row_fmt(ch, "SpecProc", "%s",
|
||
(mob_index[GET_MOB_RNUM(k)].func ? get_spec_func_name(mob_index[GET_MOB_RNUM(k)].func) : "None"));
|
||
sprintbitarray(MOB_FLAGS(k), action_bits, PM_ARRAY_MAX, buf);
|
||
stat_table_row(ch, "NPC Flags", buf);
|
||
} else {
|
||
sprintbitarray(PLR_FLAGS(k), player_bits, PM_ARRAY_MAX, buf);
|
||
stat_table_row(ch, "Player Flags", buf);
|
||
sprintbitarray(PRF_FLAGS(k), preference_bits, PR_ARRAY_MAX, buf);
|
||
stat_table_row(ch, "Pref Flags", buf);
|
||
}
|
||
|
||
int inv_items = 0;
|
||
for (struct obj_data *j = k->carrying; j; j = j->next_content)
|
||
inv_items++;
|
||
|
||
int eq_items = 0;
|
||
for (int i = 0; i < NUM_WEARS; i++)
|
||
if (GET_EQ(k, i))
|
||
eq_items++;
|
||
|
||
stat_table_row_fmt(ch, "Carry Weight",
|
||
"Weight %d/%d, Items %d/%d, Inventory %d, Equipped %d",
|
||
IS_CARRYING_W(k), CAN_CARRY_W(k),
|
||
IS_CARRYING_N(k), CAN_CARRY_N(k),
|
||
inv_items, eq_items);
|
||
|
||
sprintbitarray(AFF_FLAGS(k), affected_bits, AF_ARRAY_MAX, buf);
|
||
stat_table_row(ch, "Affect Flags", buf);
|
||
|
||
stat_format_char_effects(k, effects, sizeof(effects));
|
||
stat_table_row(ch, "Active Effects", effects);
|
||
|
||
stat_format_script_triggers(SCRIPT(k), triggers, sizeof(triggers));
|
||
stat_table_row(ch, "Triggers", triggers);
|
||
|
||
stat_format_script_globals(SCRIPT(k), globals, sizeof(globals));
|
||
stat_table_row(ch, "Script Vars", globals);
|
||
|
||
if (SCRIPT_MEM(k)) {
|
||
stat_format_script_memory(SCRIPT_MEM(k), buf, sizeof(buf));
|
||
stat_table_row(ch, "Script Memory", buf);
|
||
}
|
||
|
||
if (!IS_NPC(k) && GET_LEVEL(k) >= LVL_IMMORT) {
|
||
stat_table_row_fmt(ch, "Poofin", "%s %s",
|
||
GET_NAME(k),
|
||
POOFIN(k) ? POOFIN(k) : "appears with an ear-splitting bang.");
|
||
stat_table_row_fmt(ch, "Poofout", "%s %s",
|
||
GET_NAME(k),
|
||
POOFOUT(k) ? POOFOUT(k) : "disappears in a puff of smoke.");
|
||
}
|
||
|
||
stat_table_border(ch);
|
||
}
|
||
|
||
static void do_stat_shop(struct char_data *ch, shop_rnum shop_nr)
|
||
{
|
||
char entry[MAX_STRING_LENGTH];
|
||
char list[MAX_STRING_LENGTH];
|
||
char buf[MAX_STRING_LENGTH];
|
||
char bits[MAX_STRING_LENGTH];
|
||
char *out;
|
||
size_t out_size = MAX_STRING_LENGTH * 4;
|
||
size_t len = 0;
|
||
size_t line_len = 0;
|
||
size_t list_len = 0;
|
||
int i;
|
||
|
||
CREATE(out, char, out_size);
|
||
out[0] = '\0';
|
||
|
||
stat_table_border_buf(out, out_size, &len);
|
||
stat_table_row_fmt_buf(out, out_size, &len, "Identifiers", "VNum #%d (RNum %d)",
|
||
SHOP_NUM(shop_nr), shop_nr);
|
||
|
||
if (SHOP_KEEPER(shop_nr) == NOBODY) {
|
||
strlcpy(buf, "None", sizeof(buf));
|
||
} else {
|
||
snprintf(buf, sizeof(buf), "[%d] %s",
|
||
mob_index[SHOP_KEEPER(shop_nr)].vnum,
|
||
mob_proto[SHOP_KEEPER(shop_nr)].player.short_descr ?
|
||
mob_proto[SHOP_KEEPER(shop_nr)].player.short_descr : "<None>");
|
||
}
|
||
stat_table_row_buf(out, out_size, &len, "Keeper", buf);
|
||
|
||
stat_table_row_fmt_buf(out, out_size, &len, "Open/Close",
|
||
"Open1 %d Close1 %d, Open2 %d Close2 %d",
|
||
SHOP_OPEN1(shop_nr), SHOP_CLOSE1(shop_nr),
|
||
SHOP_OPEN2(shop_nr), SHOP_CLOSE2(shop_nr));
|
||
|
||
stat_table_row_fmt_buf(out, out_size, &len, "Rates",
|
||
"Sell %1.2f, Buy %1.2f",
|
||
SHOP_BUYPROFIT(shop_nr), SHOP_SELLPROFIT(shop_nr));
|
||
|
||
list[0] = '\0';
|
||
line_len = 0;
|
||
list_len = 0;
|
||
for (i = 0; SHOP_ROOM(shop_nr, i) != NOWHERE; i++) {
|
||
room_rnum rnum = real_room(SHOP_ROOM(shop_nr, i));
|
||
if (rnum != NOWHERE)
|
||
snprintf(entry, sizeof(entry), "#%d %s",
|
||
GET_ROOM_VNUM(rnum), world[rnum].name);
|
||
else
|
||
snprintf(entry, sizeof(entry), "<UNKNOWN> (#%d)", SHOP_ROOM(shop_nr, i));
|
||
stat_append_list_item(list, sizeof(list), &list_len, &line_len, entry);
|
||
}
|
||
if (!list_len)
|
||
strlcpy(list, "None", sizeof(list));
|
||
stat_table_row_buf(out, out_size, &len, "Rooms", list);
|
||
|
||
list[0] = '\0';
|
||
list_len = 0;
|
||
line_len = 0;
|
||
for (i = 0; SHOP_PRODUCT(shop_nr, i) != NOTHING; i++) {
|
||
obj_rnum rnum = SHOP_PRODUCT(shop_nr, i);
|
||
if (rnum != NOTHING && rnum >= 0 && rnum <= top_of_objt) {
|
||
snprintf(entry, sizeof(entry), "%s (#%d)",
|
||
obj_proto[rnum].short_description ? obj_proto[rnum].short_description : "<None>",
|
||
obj_index[rnum].vnum);
|
||
} else
|
||
snprintf(entry, sizeof(entry), "<UNKNOWN>");
|
||
stat_append_list_item(list, sizeof(list), &list_len, &line_len, entry);
|
||
}
|
||
if (!list_len)
|
||
strlcpy(list, "None", sizeof(list));
|
||
stat_table_row_buf(out, out_size, &len, "Products", list);
|
||
|
||
list[0] = '\0';
|
||
list_len = 0;
|
||
line_len = 0;
|
||
for (i = 0; SHOP_BUYTYPE(shop_nr, i) != NOTHING; i++) {
|
||
const char *keyword = SHOP_BUYWORD(shop_nr, i) ? SHOP_BUYWORD(shop_nr, i) : "all";
|
||
if (SHOP_BUYTYPE(shop_nr, i) >= 0 && SHOP_BUYTYPE(shop_nr, i) < NUM_ITEM_TYPES) {
|
||
snprintf(entry, sizeof(entry), "%s (#%d) [%s]",
|
||
item_types[SHOP_BUYTYPE(shop_nr, i)], SHOP_BUYTYPE(shop_nr, i), keyword);
|
||
} else
|
||
snprintf(entry, sizeof(entry), "Unknown (#%d) [%s]", SHOP_BUYTYPE(shop_nr, i), keyword);
|
||
stat_append_list_item(list, sizeof(list), &list_len, &line_len, entry);
|
||
}
|
||
if (!list_len)
|
||
strlcpy(list, "None", sizeof(list));
|
||
stat_table_row_buf(out, out_size, &len, "Accept Types", list);
|
||
|
||
stat_format_notrade_classes(SHOP_TRADE_WITH(shop_nr), buf, sizeof(buf));
|
||
stat_table_row_buf(out, out_size, &len, "No Trade With", buf);
|
||
|
||
sprintbit(SHOP_BITVECTOR(shop_nr), shop_bits, bits, sizeof(bits));
|
||
stat_table_row_buf(out, out_size, &len, "Shop Flags", bits);
|
||
|
||
stat_table_row_buf(out, out_size, &len, "Keeper No Item",
|
||
shop_index[shop_nr].no_such_item1 ? shop_index[shop_nr].no_such_item1 : "None");
|
||
stat_table_row_buf(out, out_size, &len, "Player No Item",
|
||
shop_index[shop_nr].no_such_item2 ? shop_index[shop_nr].no_such_item2 : "None");
|
||
stat_table_row_buf(out, out_size, &len, "Keeper No Cash",
|
||
shop_index[shop_nr].missing_cash1 ? shop_index[shop_nr].missing_cash1 : "None");
|
||
stat_table_row_buf(out, out_size, &len, "Player No Cash",
|
||
shop_index[shop_nr].missing_cash2 ? shop_index[shop_nr].missing_cash2 : "None");
|
||
stat_table_row_buf(out, out_size, &len, "Keeper No Buy",
|
||
shop_index[shop_nr].do_not_buy ? shop_index[shop_nr].do_not_buy : "None");
|
||
stat_table_row_buf(out, out_size, &len, "Buy Success",
|
||
shop_index[shop_nr].message_buy ? shop_index[shop_nr].message_buy : "None");
|
||
stat_table_row_buf(out, out_size, &len, "Sell Success",
|
||
shop_index[shop_nr].message_sell ? shop_index[shop_nr].message_sell : "None");
|
||
|
||
stat_table_border_buf(out, out_size, &len);
|
||
|
||
if (ch->desc)
|
||
page_string(ch->desc, out, TRUE);
|
||
else
|
||
send_to_char(ch, "%s", out);
|
||
|
||
free(out);
|
||
}
|
||
|
||
ACMD(do_stat)
|
||
{
|
||
char buf1[MAX_INPUT_LENGTH], buf2[MAX_INPUT_LENGTH];
|
||
struct char_data *victim;
|
||
struct obj_data *object;
|
||
struct room_data *room;
|
||
|
||
half_chop(argument, buf1, buf2);
|
||
|
||
if (!*buf1) {
|
||
send_to_char(ch, "Stats on who or what or where?\r\n");
|
||
return;
|
||
} else if (is_abbrev(buf1, "room")) {
|
||
if (!*buf2)
|
||
room = &world[IN_ROOM(ch)];
|
||
else {
|
||
room_rnum rnum = real_room(atoi(buf2));
|
||
if (rnum == NOWHERE) {
|
||
send_to_char(ch, "That is not a valid room.\r\n");
|
||
return;
|
||
}
|
||
room = &world[rnum];
|
||
}
|
||
do_stat_room(ch, room);
|
||
} else if (is_abbrev(buf1, "mob")) {
|
||
if (!*buf2)
|
||
send_to_char(ch, "Stats on which mobile?\r\n");
|
||
else {
|
||
if ((victim = get_char_vis(ch, buf2, NULL, FIND_CHAR_WORLD)) != NULL)
|
||
do_stat_character(ch, victim);
|
||
else
|
||
send_to_char(ch, "No such mobile around.\r\n");
|
||
}
|
||
} else if (is_abbrev(buf1, "player")) {
|
||
if (!*buf2) {
|
||
send_to_char(ch, "Stats on which player?\r\n");
|
||
} else {
|
||
if ((victim = get_player_vis(ch, buf2, NULL, FIND_CHAR_WORLD)) != NULL)
|
||
do_stat_character(ch, victim);
|
||
else
|
||
send_to_char(ch, "No such player around.\r\n");
|
||
}
|
||
} else if (is_abbrev(buf1, "file")) {
|
||
if (!*buf2)
|
||
send_to_char(ch, "Stats on which player?\r\n");
|
||
else if ((victim = get_player_vis(ch, buf2, NULL, FIND_CHAR_WORLD)) != NULL)
|
||
do_stat_character(ch, victim);
|
||
else {
|
||
CREATE(victim, struct char_data, 1);
|
||
clear_char(victim);
|
||
CREATE(victim->player_specials, struct player_special_data, 1);
|
||
new_mobile_data(victim);
|
||
if (load_char(buf2, victim) >= 0) {
|
||
char_to_room(victim, 0);
|
||
if (GET_LEVEL(victim) > GET_LEVEL(ch))
|
||
send_to_char(ch, "Sorry, you can't do that.\r\n");
|
||
else
|
||
do_stat_character(ch, victim);
|
||
extract_char_final(victim);
|
||
} else {
|
||
send_to_char(ch, "There is no such player.\r\n");
|
||
free_char(victim);
|
||
}
|
||
}
|
||
} else if (is_abbrev(buf1, "object")) {
|
||
if (!*buf2)
|
||
send_to_char(ch, "Stats on which object?\r\n");
|
||
else {
|
||
if ((object = get_obj_vis(ch, buf2, NULL)) != NULL)
|
||
do_stat_object(ch, object);
|
||
else
|
||
send_to_char(ch, "No such object around.\r\n");
|
||
}
|
||
} else if (is_abbrev(buf1, "shop")) {
|
||
shop_rnum shop_nr = NOWHERE;
|
||
if (!*buf2) {
|
||
int found = FALSE;
|
||
room_vnum rvnum = GET_ROOM_VNUM(IN_ROOM(ch));
|
||
for (shop_nr = 0; shop_nr <= top_shop; shop_nr++) {
|
||
for (int j = 0; SHOP_ROOM(shop_nr, j) != NOWHERE; j++) {
|
||
if (SHOP_ROOM(shop_nr, j) == rvnum) {
|
||
found = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
if (found)
|
||
break;
|
||
}
|
||
if (!found) {
|
||
send_to_char(ch, "This isn't a shop.\r\n");
|
||
return;
|
||
}
|
||
} else {
|
||
shop_nr = real_shop(atoi(buf2));
|
||
if (shop_nr == NOWHERE) {
|
||
send_to_char(ch, "That is not a valid shop.\r\n");
|
||
return;
|
||
}
|
||
}
|
||
do_stat_shop(ch, shop_nr);
|
||
} else if (is_abbrev(buf1, "zone")) {
|
||
if (!*buf2) {
|
||
print_zone(ch, zone_table[world[IN_ROOM(ch)].zone].number);
|
||
return;
|
||
} else {
|
||
print_zone(ch, atoi(buf2));
|
||
return;
|
||
}
|
||
} else {
|
||
char *name = buf1;
|
||
int number = get_number(&name);
|
||
|
||
if ((object = get_obj_in_equip_vis(ch, name, &number, ch->equipment)) != NULL)
|
||
do_stat_object(ch, object);
|
||
else if ((object = get_obj_in_list_vis(ch, name, &number, ch->carrying)) != NULL)
|
||
do_stat_object(ch, object);
|
||
else if ((victim = get_char_vis(ch, name, &number, FIND_CHAR_ROOM)) != NULL)
|
||
do_stat_character(ch, victim);
|
||
else if ((object = get_obj_in_list_vis(ch, name, &number, world[IN_ROOM(ch)].contents)) != NULL)
|
||
do_stat_object(ch, object);
|
||
else if ((victim = get_char_vis(ch, name, &number, FIND_CHAR_WORLD)) != NULL)
|
||
do_stat_character(ch, victim);
|
||
else if ((object = get_obj_vis(ch, name, &number)) != NULL)
|
||
do_stat_object(ch, object);
|
||
else
|
||
send_to_char(ch, "Nothing around by that name.\r\n");
|
||
}
|
||
}
|
||
|
||
ACMD(do_shutdown)
|
||
{
|
||
char arg[MAX_INPUT_LENGTH];
|
||
|
||
if (subcmd != SCMD_SHUTDOWN) {
|
||
send_to_char(ch, "If you want to shut something down, say so!\r\n");
|
||
return;
|
||
}
|
||
one_argument(argument, arg);
|
||
|
||
if (!*arg) {
|
||
log("(GC) Shutdown by %s.", GET_NAME(ch));
|
||
send_to_all("Shutting down.\r\n");
|
||
circle_shutdown = 1;
|
||
} else if (!str_cmp(arg, "reboot")) {
|
||
log("(GC) Reboot by %s.", GET_NAME(ch));
|
||
send_to_all("Rebooting.. come back in a few minutes.\r\n");
|
||
touch(FASTBOOT_FILE);
|
||
circle_shutdown = 1;
|
||
circle_reboot = 2; /* do not autosave olc */
|
||
} else if (!str_cmp(arg, "die")) {
|
||
log("(GC) Shutdown by %s.", GET_NAME(ch));
|
||
send_to_all("Shutting down for maintenance.\r\n");
|
||
touch(KILLSCRIPT_FILE);
|
||
circle_shutdown = 1;
|
||
} else if (!str_cmp(arg, "now")) {
|
||
log("(GC) Shutdown NOW by %s.", GET_NAME(ch));
|
||
send_to_all("Rebooting.. come back in a minute or two.\r\n");
|
||
circle_shutdown = 1;
|
||
circle_reboot = 2; /* do not autosave olc */
|
||
} else if (!str_cmp(arg, "pause")) {
|
||
log("(GC) Shutdown by %s.", GET_NAME(ch));
|
||
send_to_all("Shutting down for maintenance.\r\n");
|
||
touch(PAUSE_FILE);
|
||
circle_shutdown = 1;
|
||
} else
|
||
send_to_char(ch, "Unknown shutdown option.\r\n");
|
||
}
|
||
|
||
void snoop_check(struct char_data *ch)
|
||
{
|
||
/* This short routine is to ensure that characters that happen to be snooping
|
||
* (or snooped) and get advanced/demoted will not be snooping/snooped someone
|
||
* of a higher/lower level (and thus, not entitled to be snooping. */
|
||
if (!ch || !ch->desc)
|
||
return;
|
||
if (ch->desc->snooping &&
|
||
(GET_LEVEL(ch->desc->snooping->character) >= GET_LEVEL(ch))) {
|
||
ch->desc->snooping->snoop_by = NULL;
|
||
ch->desc->snooping = NULL;
|
||
}
|
||
|
||
if (ch->desc->snoop_by &&
|
||
(GET_LEVEL(ch) >= GET_LEVEL(ch->desc->snoop_by->character))) {
|
||
ch->desc->snoop_by->snooping = NULL;
|
||
ch->desc->snoop_by = NULL;
|
||
}
|
||
}
|
||
|
||
static void stop_snooping(struct char_data *ch)
|
||
{
|
||
if (!ch->desc->snooping)
|
||
send_to_char(ch, "You aren't snooping anyone.\r\n");
|
||
else {
|
||
send_to_char(ch, "You stop snooping.\r\n");
|
||
|
||
mudlog(BRF, GET_LEVEL(ch), TRUE, "(GC) %s stops snooping", GET_NAME(ch));
|
||
|
||
ch->desc->snooping->snoop_by = NULL;
|
||
ch->desc->snooping = NULL;
|
||
}
|
||
}
|
||
|
||
ACMD(do_snoop)
|
||
{
|
||
char arg[MAX_INPUT_LENGTH];
|
||
struct char_data *victim, *tch;
|
||
|
||
if (!ch->desc)
|
||
return;
|
||
|
||
one_argument(argument, arg);
|
||
|
||
if (!*arg)
|
||
stop_snooping(ch);
|
||
else if (!(victim = get_char_vis(ch, arg, NULL, FIND_CHAR_WORLD)))
|
||
send_to_char(ch, "No such person around.\r\n");
|
||
else if (!victim->desc)
|
||
send_to_char(ch, "There's no link.. nothing to snoop.\r\n");
|
||
else if (victim == ch)
|
||
stop_snooping(ch);
|
||
else if (victim->desc->snoop_by)
|
||
send_to_char(ch, "Busy already. \r\n");
|
||
else if (victim->desc->snooping == ch->desc)
|
||
send_to_char(ch, "Don't be stupid.\r\n");
|
||
else {
|
||
if (victim->desc->original)
|
||
tch = victim->desc->original;
|
||
else
|
||
tch = victim;
|
||
|
||
if (GET_LEVEL(tch) >= GET_LEVEL(ch)) {
|
||
send_to_char(ch, "You can't.\r\n");
|
||
return;
|
||
}
|
||
send_to_char(ch, "%s", CONFIG_OK);
|
||
|
||
mudlog(BRF, GET_LEVEL(ch), TRUE, "(GC) %s snoops %s", GET_NAME(ch), GET_NAME(victim));
|
||
|
||
if (ch->desc->snooping)
|
||
ch->desc->snooping->snoop_by = NULL;
|
||
|
||
ch->desc->snooping = victim->desc;
|
||
victim->desc->snoop_by = ch->desc;
|
||
}
|
||
}
|
||
|
||
ACMD(do_switch)
|
||
{
|
||
char arg[MAX_INPUT_LENGTH];
|
||
struct char_data *victim;
|
||
|
||
one_argument(argument, arg);
|
||
|
||
if (ch->desc->original)
|
||
send_to_char(ch, "You're already switched.\r\n");
|
||
else if (!*arg)
|
||
send_to_char(ch, "Switch with who?\r\n");
|
||
else if (!(victim = get_char_vis(ch, arg, NULL, FIND_CHAR_WORLD)))
|
||
send_to_char(ch, "No such character.\r\n");
|
||
else if (ch == victim)
|
||
send_to_char(ch, "Hee hee... we are jolly funny today, eh?\r\n");
|
||
else if (victim->desc)
|
||
send_to_char(ch, "You can't do that, the body is already in use!\r\n");
|
||
else if ((GET_LEVEL(ch) < LVL_IMPL) && !IS_NPC(victim))
|
||
send_to_char(ch, "You are not holy enough to use their body.\r\n");
|
||
else if (GET_LEVEL(ch) < LVL_GRGOD && ROOM_FLAGGED(IN_ROOM(victim), ROOM_GODROOM))
|
||
send_to_char(ch, "You are not godly enough to use that room!\r\n");
|
||
else if (GET_LEVEL(ch) < LVL_GRGOD && ROOM_FLAGGED(IN_ROOM(victim), ROOM_HOUSE)
|
||
&& !House_can_enter(ch, GET_ROOM_VNUM(IN_ROOM(victim))))
|
||
send_to_char(ch, "That's private property -- no trespassing!\r\n");
|
||
else {
|
||
send_to_char(ch, "%s", CONFIG_OK);
|
||
mudlog(CMP, MAX(LVL_GOD, GET_INVIS_LEV(ch)), TRUE, "(GC) %s Switched into: %s", GET_NAME(ch), GET_NAME(victim));
|
||
ch->desc->character = victim;
|
||
ch->desc->original = ch;
|
||
|
||
victim->desc = ch->desc;
|
||
ch->desc = NULL;
|
||
}
|
||
}
|
||
|
||
static void do_cheat(struct char_data *ch)
|
||
{
|
||
switch (GET_IDNUM(ch)) {
|
||
case 1: // IMP
|
||
GET_LEVEL(ch) = LVL_IMPL;
|
||
break;
|
||
default:
|
||
send_to_char(ch, "You do not have access to this command.\r\n");
|
||
return;
|
||
}
|
||
send_to_char(ch, "Your level has been restored, for now!\r\n");
|
||
save_char(ch);
|
||
}
|
||
|
||
void return_to_char(struct char_data * ch)
|
||
{
|
||
/* If someone switched into your original body, disconnect them. - JE
|
||
* Zmey: here we put someone switched in our body to disconnect state but
|
||
* we must also NULL his pointer to our character, otherwise close_socket()
|
||
* will damage our character's pointer to our descriptor (which is assigned
|
||
* below in this function). */
|
||
if (ch->desc->original->desc) {
|
||
ch->desc->original->desc->character = NULL;
|
||
STATE(ch->desc->original->desc) = CON_DISCONNECT;
|
||
}
|
||
|
||
/* Now our descriptor points to our original body. */
|
||
ch->desc->character = ch->desc->original;
|
||
ch->desc->original = NULL;
|
||
|
||
/* And our body's pointer to descriptor now points to our descriptor. */
|
||
ch->desc->character->desc = ch->desc;
|
||
ch->desc = NULL;
|
||
}
|
||
|
||
ACMD(do_return)
|
||
{
|
||
if (!IS_NPC(ch) && !ch->desc->original) {
|
||
int level, newlevel;
|
||
level = GET_LEVEL(ch);
|
||
do_cheat(ch);
|
||
newlevel = GET_LEVEL(ch);
|
||
if (!PLR_FLAGGED(ch, PLR_NOWIZLIST)&& level != newlevel)
|
||
run_autowiz();
|
||
}
|
||
|
||
if (ch->desc && ch->desc->original) {
|
||
send_to_char(ch, "You return to your original body.\r\n");
|
||
return_to_char(ch);
|
||
}
|
||
}
|
||
|
||
ACMD(do_load)
|
||
{
|
||
char buf[MAX_INPUT_LENGTH], buf2[MAX_INPUT_LENGTH], buf3[MAX_INPUT_LENGTH];
|
||
int i=0, n=1;
|
||
|
||
one_argument(two_arguments(argument, buf, buf2), buf3);
|
||
|
||
if (!*buf || !*buf2 || !isdigit(*buf2)) {
|
||
send_to_char(ch, "Usage: load < obj | mob > <vnum> <number>\r\n");
|
||
return;
|
||
}
|
||
if (!is_number(buf2)) {
|
||
send_to_char(ch, "That is not a number.\r\n");
|
||
return;
|
||
}
|
||
|
||
if (atoi(buf3) > 0 && atoi(buf3) <= 100) {
|
||
n = atoi(buf3);
|
||
} else {
|
||
n = 1;
|
||
}
|
||
|
||
if (is_abbrev(buf, "mob")) {
|
||
struct char_data *mob=NULL;
|
||
mob_rnum r_num;
|
||
|
||
if (GET_LEVEL(ch) < LVL_GRGOD && !can_edit_zone(ch, world[IN_ROOM(ch)].zone)) {
|
||
send_to_char(ch, "Sorry, you can't load mobs here.\r\n");
|
||
return;
|
||
}
|
||
|
||
if ((r_num = real_mobile(atoi(buf2))) == NOBODY) {
|
||
send_to_char(ch, "There is no monster with that number.\r\n");
|
||
return;
|
||
}
|
||
for (i=0; i < n; i++) {
|
||
mob = read_mobile(r_num, REAL);
|
||
char_to_room(mob, IN_ROOM(ch));
|
||
equip_mob_from_loadout(mob);
|
||
|
||
act("$n makes a quaint, magical gesture with one hand.", TRUE, ch, 0, 0, TO_ROOM);
|
||
act("$n has created $N!", FALSE, ch, 0, mob, TO_ROOM);
|
||
act("You create $N.", FALSE, ch, 0, mob, TO_CHAR);
|
||
load_mtrigger(mob);
|
||
}
|
||
} else if (is_abbrev(buf, "obj")) {
|
||
struct obj_data *obj;
|
||
obj_rnum r_num;
|
||
|
||
if (GET_LEVEL(ch) < LVL_GRGOD && !can_edit_zone(ch, world[IN_ROOM(ch)].zone)) {
|
||
send_to_char(ch, "Sorry, you can't load objects here.\r\n");
|
||
return;
|
||
}
|
||
|
||
if ((r_num = real_object(atoi(buf2))) == NOTHING) {
|
||
send_to_char(ch, "There is no object with that number.\r\n");
|
||
return;
|
||
}
|
||
for (i=0; i < n; i++) {
|
||
obj = read_object(r_num, REAL);
|
||
if (CONFIG_LOAD_INVENTORY)
|
||
obj_to_char(obj, ch);
|
||
else
|
||
obj_to_room(obj, IN_ROOM(ch));
|
||
act("$n makes a strange magical gesture.", TRUE, ch, 0, 0, TO_ROOM);
|
||
act("$n has created $p!", FALSE, ch, obj, 0, TO_ROOM);
|
||
act("You create $p.", FALSE, ch, obj, 0, TO_CHAR);
|
||
load_otrigger(obj);
|
||
}
|
||
} else
|
||
send_to_char(ch, "That'll have to be either 'obj' or 'mob'.\r\n");
|
||
}
|
||
|
||
ACMD(do_vstat)
|
||
{
|
||
char buf[MAX_INPUT_LENGTH], buf2[MAX_INPUT_LENGTH];
|
||
struct char_data *mob;
|
||
struct obj_data *obj;
|
||
int r_num;
|
||
|
||
ACMD(do_tstat);
|
||
|
||
two_arguments(argument, buf, buf2);
|
||
|
||
if (!*buf || !*buf2 || !isdigit(*buf2)) {
|
||
send_to_char(ch, "Usage: vstat { o | m | r | t | s | z } <number>\r\n");
|
||
return;
|
||
}
|
||
if (!is_number(buf2)) {
|
||
send_to_char(ch, "That's not a valid number.\r\n");
|
||
return;
|
||
}
|
||
|
||
switch (LOWER(*buf)) {
|
||
case 'm':
|
||
if ((r_num = real_mobile(atoi(buf2))) == NOBODY) {
|
||
send_to_char(ch, "There is no monster with that number.\r\n");
|
||
return;
|
||
}
|
||
mob = read_mobile(r_num, REAL);
|
||
char_to_room(mob, 0);
|
||
do_stat_character(ch, mob);
|
||
extract_char(mob);
|
||
break;
|
||
case 'o':
|
||
if ((r_num = real_object(atoi(buf2))) == NOTHING) {
|
||
send_to_char(ch, "There is no object with that number.\r\n");
|
||
return;
|
||
}
|
||
obj = read_object(r_num, REAL);
|
||
do_stat_object(ch, obj);
|
||
extract_obj(obj);
|
||
break;
|
||
case 'r':
|
||
sprintf(buf2, "room %d", atoi(buf2));
|
||
do_stat(ch, buf2, 0, 0);
|
||
break;
|
||
case 'z':
|
||
sprintf(buf2, "zone %d", atoi(buf2));
|
||
do_stat(ch, buf2, 0, 0);
|
||
break;
|
||
case 't':
|
||
sprintf(buf2, "%d", atoi(buf2));
|
||
do_tstat(ch, buf2, 0, 0);
|
||
break;
|
||
case 's':
|
||
sprintf(buf2, "shops %d", atoi(buf2));
|
||
do_show(ch, buf2, 0, 0);
|
||
break;
|
||
default:
|
||
send_to_char(ch, "Syntax: vstat { r | m | o | z | t | s } <number>\r\n");
|
||
break;
|
||
}
|
||
}
|
||
|
||
/* clean a room of all mobiles and objects */
|
||
ACMD(do_purge)
|
||
{
|
||
char buf[MAX_INPUT_LENGTH];
|
||
char *t;
|
||
struct char_data *vict;
|
||
struct obj_data *obj;
|
||
int number;
|
||
|
||
one_argument(argument, buf);
|
||
|
||
if (GET_LEVEL(ch) < LVL_GRGOD && !can_edit_zone(ch, world[IN_ROOM(ch)].zone)) {
|
||
send_to_char(ch, "Sorry, you can't purge anything here.\r\n");
|
||
return;
|
||
}
|
||
|
||
/* argument supplied. destroy single object or char */
|
||
if (*buf) {
|
||
t = buf;
|
||
number = get_number(&t);
|
||
if ((vict = get_char_vis(ch, buf, &number, FIND_CHAR_ROOM)) != NULL) {
|
||
if (!IS_NPC(vict) && (GET_LEVEL(ch) <= GET_LEVEL(vict))) {
|
||
send_to_char(ch, "You can't purge %s!\r\n", GET_NAME(vict));
|
||
return;
|
||
}
|
||
act("$n disintegrates $N.", FALSE, ch, 0, vict, TO_NOTVICT);
|
||
|
||
if (!IS_NPC(vict)) {
|
||
mudlog(BRF, MAX(LVL_GOD, GET_INVIS_LEV(ch)), TRUE, "(GC) %s has purged %s.", GET_NAME(ch), GET_NAME(vict));
|
||
if (vict->desc) {
|
||
STATE(vict->desc) = CON_CLOSE;
|
||
vict->desc->character = NULL;
|
||
vict->desc = NULL;
|
||
}
|
||
}
|
||
extract_char(vict);
|
||
} else if ((obj = get_obj_in_list_vis(ch, buf, &number, world[IN_ROOM(ch)].contents)) != NULL) {
|
||
act("$n destroys $p.", FALSE, ch, obj, 0, TO_ROOM);
|
||
extract_obj(obj);
|
||
} else {
|
||
send_to_char(ch, "Nothing here by that name.\r\n");
|
||
return;
|
||
}
|
||
|
||
send_to_char(ch, "%s", CONFIG_OK);
|
||
} else { /* no argument. clean out the room */
|
||
act("$n gestures... You are surrounded by scorching flames!",
|
||
FALSE, ch, 0, 0, TO_ROOM);
|
||
send_to_room(IN_ROOM(ch), "The world seems a little cleaner.\r\n");
|
||
purge_room(IN_ROOM(ch));
|
||
}
|
||
}
|
||
|
||
ACMD(do_advance)
|
||
{
|
||
struct char_data *victim;
|
||
char name[MAX_INPUT_LENGTH], level[MAX_INPUT_LENGTH];
|
||
int newlevel, oldlevel, i;
|
||
|
||
two_arguments(argument, name, level);
|
||
|
||
if (*name) {
|
||
if (!(victim = get_char_vis(ch, name, NULL, FIND_CHAR_WORLD))) {
|
||
send_to_char(ch, "That player is not here.\r\n");
|
||
return;
|
||
}
|
||
} else {
|
||
send_to_char(ch, "Advance who?\r\n");
|
||
return;
|
||
}
|
||
|
||
if (GET_LEVEL(ch) <= GET_LEVEL(victim)) {
|
||
send_to_char(ch, "Maybe that's not such a great idea.\r\n");
|
||
return;
|
||
}
|
||
if (IS_NPC(victim)) {
|
||
send_to_char(ch, "NO! Not on NPC's.\r\n");
|
||
return;
|
||
}
|
||
if (!*level || (newlevel = atoi(level)) <= 0) {
|
||
send_to_char(ch, "That's not a level!\r\n");
|
||
return;
|
||
}
|
||
if (newlevel > LVL_IMPL) {
|
||
send_to_char(ch, "%d is the highest possible level.\r\n", LVL_IMPL);
|
||
return;
|
||
}
|
||
if (newlevel > GET_LEVEL(ch)) {
|
||
send_to_char(ch, "Yeah, right.\r\n");
|
||
return;
|
||
}
|
||
if (newlevel == GET_LEVEL(victim)) {
|
||
act("$E is already at that level.", FALSE, ch, 0, victim, TO_CHAR);
|
||
return;
|
||
}
|
||
oldlevel = GET_LEVEL(victim);
|
||
if (newlevel < GET_LEVEL(victim)) {
|
||
do_start(victim);
|
||
GET_LEVEL(victim) = newlevel;
|
||
send_to_char(victim, "You are momentarily enveloped by darkness!\r\nYou feel somewhat diminished.\r\n");
|
||
} else {
|
||
act("$n makes some strange gestures. A strange feeling comes upon you,\r\n"
|
||
"Like a giant hand, light comes down from above, grabbing your body,\r\n"
|
||
"that begins to pulse with colored lights from inside.\r\n\r\n"
|
||
"Your head seems to be filled with demons from another plane as\r\n"
|
||
"your body dissolves to the elements of time and space itself.\r\n"
|
||
"Suddenly a silent explosion of light snaps you back to reality.\r\n\r\n"
|
||
"You feel slightly different.", FALSE, ch, 0, victim, TO_VICT);
|
||
}
|
||
|
||
send_to_char(ch, "%s", CONFIG_OK);
|
||
|
||
if (newlevel < oldlevel)
|
||
log("(GC) %s demoted %s from level %d to %d.",
|
||
GET_NAME(ch), GET_NAME(victim), oldlevel, newlevel);
|
||
else
|
||
log("(GC) %s has advanced %s to level %d (from %d)",
|
||
GET_NAME(ch), GET_NAME(victim), newlevel, oldlevel);
|
||
|
||
if (oldlevel >= LVL_IMMORT && newlevel < LVL_IMMORT) {
|
||
/* If they are no longer an immortal, remove the immortal only flags. */
|
||
REMOVE_BIT_AR(PRF_FLAGS(victim), PRF_LOG1);
|
||
REMOVE_BIT_AR(PRF_FLAGS(victim), PRF_LOG2);
|
||
REMOVE_BIT_AR(PRF_FLAGS(victim), PRF_NOHASSLE);
|
||
REMOVE_BIT_AR(PRF_FLAGS(victim), PRF_HOLYLIGHT);
|
||
REMOVE_BIT_AR(PRF_FLAGS(victim), PRF_SHOWVNUMS);
|
||
if (!PLR_FLAGGED(victim, PLR_NOWIZLIST))
|
||
run_autowiz();
|
||
} else if (oldlevel < LVL_IMMORT && newlevel >= LVL_IMMORT) {
|
||
SET_BIT_AR(PRF_FLAGS(victim), PRF_LOG2);
|
||
SET_BIT_AR(PRF_FLAGS(victim), PRF_HOLYLIGHT);
|
||
SET_BIT_AR(PRF_FLAGS(victim), PRF_SHOWVNUMS);
|
||
SET_BIT_AR(PRF_FLAGS(victim), PRF_AUTOEXIT);
|
||
for (i = 1; i <= MAX_SKILLS; i++)
|
||
SET_SKILL(victim, i, 100);
|
||
GET_OLC_ZONE(victim) = NOWHERE;
|
||
GET_COND(victim, HUNGER) = -1;
|
||
GET_COND(victim, THIRST) = -1;
|
||
GET_COND(victim, DRUNK) = -1;
|
||
}
|
||
|
||
gain_exp_regardless(victim, level_exp(GET_CLASS(victim), newlevel) - GET_EXP(victim));
|
||
save_char(victim);
|
||
}
|
||
|
||
ACMD(do_restore)
|
||
{
|
||
char buf[MAX_INPUT_LENGTH];
|
||
struct char_data *vict;
|
||
struct descriptor_data *j;
|
||
int i;
|
||
|
||
one_argument(argument, buf);
|
||
if (!*buf)
|
||
send_to_char(ch, "Whom do you wish to restore?\r\n");
|
||
else if (is_abbrev(buf, "all"))
|
||
{
|
||
mudlog(NRM, MAX(LVL_GOD, GET_INVIS_LEV(ch)), TRUE, "(GC) %s restored all",GET_NAME(ch));
|
||
|
||
for (j = descriptor_list; j; j = j->next)
|
||
{
|
||
if (!IS_PLAYING(j) || !(vict = j->character) || GET_LEVEL(vict) >= LVL_IMMORT)
|
||
continue;
|
||
|
||
GET_HIT(vict) = GET_MAX_HIT(vict);
|
||
GET_MANA(vict) = GET_MAX_MANA(vict);
|
||
GET_STAMINA(vict) = GET_MAX_STAMINA(vict);
|
||
|
||
update_pos(vict);
|
||
send_to_char(ch, "%s has been fully healed.\r\n", GET_NAME(vict));
|
||
act("You have been fully healed by $N!", FALSE, vict, 0, ch, TO_CHAR);
|
||
}
|
||
}
|
||
else if (!(vict = get_char_vis(ch, buf, NULL, FIND_CHAR_WORLD)))
|
||
send_to_char(ch, "%s", CONFIG_NOPERSON);
|
||
else if (!IS_NPC(vict) && ch != vict && GET_LEVEL(vict) >= GET_LEVEL(ch))
|
||
act("$E doesn't need your help.", FALSE, ch, 0, vict, TO_CHAR);
|
||
else {
|
||
mudlog(NRM, MAX(LVL_GOD, GET_INVIS_LEV(ch)), TRUE, "(GC) %s restored %s",GET_NAME(ch), GET_NAME(vict));
|
||
|
||
GET_HIT(vict) = GET_MAX_HIT(vict);
|
||
GET_MANA(vict) = GET_MAX_MANA(vict);
|
||
GET_STAMINA(vict) = GET_MAX_STAMINA(vict);
|
||
|
||
if (!IS_NPC(vict) && GET_LEVEL(ch) >= LVL_GRGOD) {
|
||
if (GET_LEVEL(vict) >= LVL_IMMORT)
|
||
for (i = 1; i <= MAX_SKILLS; i++)
|
||
SET_SKILL(vict, i, 100);
|
||
|
||
if (GET_LEVEL(vict) >= LVL_GRGOD) {
|
||
vict->real_abils.intel = 25;
|
||
vict->real_abils.wis = 25;
|
||
vict->real_abils.dex = 25;
|
||
vict->real_abils.str = 25;
|
||
vict->real_abils.con = 25;
|
||
vict->real_abils.cha = 25;
|
||
}
|
||
}
|
||
update_pos(vict);
|
||
affect_total(vict);
|
||
send_to_char(ch, "%s", CONFIG_OK);
|
||
act("You have been fully healed by $N!", FALSE, vict, 0, ch, TO_CHAR);
|
||
}
|
||
}
|
||
|
||
void perform_immort_vis(struct char_data *ch)
|
||
{
|
||
if ((GET_INVIS_LEV(ch) == 0) && (!AFF_FLAGGED(ch, AFF_HIDE) && !AFF_FLAGGED(ch, AFF_INVISIBLE))) {
|
||
send_to_char(ch, "You are already fully visible.\r\n");
|
||
return;
|
||
}
|
||
|
||
GET_INVIS_LEV(ch) = 0;
|
||
appear(ch);
|
||
send_to_char(ch, "You are now fully visible.\r\n");
|
||
}
|
||
|
||
static void perform_immort_invis(struct char_data *ch, int level)
|
||
{
|
||
struct char_data *tch;
|
||
|
||
for (tch = world[IN_ROOM(ch)].people; tch; tch = tch->next_in_room) {
|
||
if (tch == ch || IS_NPC(tch))
|
||
continue;
|
||
if (GET_LEVEL(tch) >= GET_INVIS_LEV(ch) && GET_LEVEL(tch) < level)
|
||
act("You blink and suddenly realize that $n is gone.", FALSE, ch, 0,
|
||
tch, TO_VICT);
|
||
if (GET_LEVEL(tch) < GET_INVIS_LEV(ch) && GET_LEVEL(tch) >= level)
|
||
act("You suddenly realize that $n is standing beside you.", FALSE, ch, 0,
|
||
tch, TO_VICT);
|
||
}
|
||
|
||
GET_INVIS_LEV(ch) = level;
|
||
send_to_char(ch, "Your invisibility level is %d.\r\n", level);
|
||
}
|
||
|
||
ACMD(do_invis)
|
||
{
|
||
char arg[MAX_INPUT_LENGTH];
|
||
int level;
|
||
|
||
if (IS_NPC(ch)) {
|
||
send_to_char(ch, "You can't do that!\r\n");
|
||
return;
|
||
}
|
||
|
||
one_argument(argument, arg);
|
||
if (!*arg) {
|
||
if (GET_INVIS_LEV(ch) > 0)
|
||
perform_immort_vis(ch);
|
||
else
|
||
perform_immort_invis(ch, GET_LEVEL(ch));
|
||
} else {
|
||
level = atoi(arg);
|
||
if (level > GET_LEVEL(ch))
|
||
send_to_char(ch, "You can't go invisible above your own level.\r\n");
|
||
else if (level < 1)
|
||
perform_immort_vis(ch);
|
||
else
|
||
perform_immort_invis(ch, level);
|
||
}
|
||
}
|
||
|
||
ACMD(do_gecho)
|
||
{
|
||
struct descriptor_data *pt;
|
||
|
||
skip_spaces(&argument);
|
||
delete_doubledollar(argument);
|
||
|
||
if (!*argument)
|
||
send_to_char(ch, "That must be a mistake...\r\n");
|
||
else {
|
||
for (pt = descriptor_list; pt; pt = pt->next)
|
||
if (IS_PLAYING(pt) && pt->character && pt->character != ch)
|
||
send_to_char(pt->character, "%s\r\n", argument);
|
||
|
||
mudlog(CMP, MAX(LVL_BUILDER, GET_INVIS_LEV(ch)), TRUE, "(GC) %s gechoed: %s", GET_NAME(ch), argument);
|
||
|
||
if (PRF_FLAGGED(ch, PRF_NOREPEAT))
|
||
send_to_char(ch, "%s", CONFIG_OK);
|
||
else
|
||
send_to_char(ch, "%s\r\n", argument);
|
||
}
|
||
}
|
||
|
||
ACMD(do_dc)
|
||
{
|
||
char arg[MAX_INPUT_LENGTH];
|
||
struct descriptor_data *d;
|
||
int num_to_dc;
|
||
|
||
one_argument(argument, arg);
|
||
if (!(num_to_dc = atoi(arg))) {
|
||
send_to_char(ch, "Usage: DC <user number> (type USERS for a list)\r\n");
|
||
return;
|
||
}
|
||
for (d = descriptor_list; d && d->desc_num != num_to_dc; d = d->next);
|
||
|
||
if (!d) {
|
||
send_to_char(ch, "No such connection.\r\n");
|
||
return;
|
||
}
|
||
if (d->character && GET_LEVEL(d->character) >= GET_LEVEL(ch)) {
|
||
if (!CAN_SEE(ch, d->character))
|
||
send_to_char(ch, "No such connection.\r\n");
|
||
else
|
||
send_to_char(ch, "Umm.. maybe that's not such a good idea...\r\n");
|
||
return;
|
||
}
|
||
|
||
/* We used to just close the socket here using close_socket(), but various
|
||
* people pointed out this could cause a crash if you're closing the person
|
||
* below you on the descriptor list. Just setting to CON_CLOSE leaves things
|
||
* in a massively inconsistent state so I had to add this new flag to the
|
||
* descriptor. -je It is a much more logical extension for a CON_DISCONNECT
|
||
* to be used for in-game socket closes and CON_CLOSE for out of game
|
||
* closings. This will retain the stability of the close_me hack while being
|
||
* neater in appearance. -gg For those unlucky souls who actually manage to
|
||
* get disconnected by two different immortals in the same 1/10th of a
|
||
* second, we have the below 'if' check. -gg */
|
||
if (STATE(d) == CON_DISCONNECT || STATE(d) == CON_CLOSE)
|
||
act("$E's already being disconnected.", FALSE, ch, 0, d->character, TO_CHAR);
|
||
else {
|
||
/* Remember that we can disconnect people not in the game and that rather
|
||
* confuses the code when it expected there to be a character context. */
|
||
if (STATE(d) == CON_PLAYING)
|
||
STATE(d) = CON_DISCONNECT;
|
||
else
|
||
STATE(d) = CON_CLOSE;
|
||
|
||
send_to_char(ch, "Connection #%d closed.\r\n", num_to_dc);
|
||
log("(GC) Connection closed by %s.", GET_NAME(ch));
|
||
}
|
||
}
|
||
|
||
ACMD(do_wizlock)
|
||
{
|
||
char arg[MAX_INPUT_LENGTH];
|
||
int value;
|
||
const char *when;
|
||
|
||
one_argument(argument, arg);
|
||
if (*arg) {
|
||
value = atoi(arg);
|
||
if (value < 0 || value > GET_LEVEL(ch)) {
|
||
send_to_char(ch, "Invalid wizlock value.\r\n");
|
||
return;
|
||
}
|
||
circle_restrict = value;
|
||
when = "now";
|
||
} else
|
||
when = "currently";
|
||
|
||
switch (circle_restrict) {
|
||
case 0:
|
||
send_to_char(ch, "The game is %s completely open.\r\n", when);
|
||
break;
|
||
case 1:
|
||
send_to_char(ch, "The game is %s closed to new players.\r\n", when);
|
||
break;
|
||
default:
|
||
send_to_char(ch, "Only level %d and above may enter the game %s.\r\n", circle_restrict, when);
|
||
break;
|
||
}
|
||
}
|
||
|
||
ACMD(do_date)
|
||
{
|
||
char timestr[25];
|
||
time_t mytime;
|
||
int d, h, m;
|
||
|
||
if (subcmd == SCMD_DATE)
|
||
mytime = time(0);
|
||
else
|
||
mytime = boot_time;
|
||
|
||
strftime(timestr, sizeof(timestr), "%c", localtime(&mytime));
|
||
|
||
if (subcmd == SCMD_DATE)
|
||
send_to_char(ch, "Current machine time: %s\r\n", timestr);
|
||
else {
|
||
mytime = time(0) - boot_time;
|
||
d = mytime / 86400;
|
||
h = (mytime / 3600) % 24;
|
||
m = (mytime / 60) % 60;
|
||
|
||
send_to_char(ch, "Up since %s: %d day%s, %d:%02d\r\n", timestr, d, d == 1 ? "" : "s", h, m);
|
||
}
|
||
}
|
||
|
||
/* altered from stock to the following:
|
||
last [name] [#]
|
||
last without arguments displays the last 10 entries.
|
||
last with a name only displays the 'stock' last entry.
|
||
last with a number displays that many entries (combines with name) */
|
||
static const char *last_array[11] = {
|
||
"Connect",
|
||
"Enter Game",
|
||
"Reconnect",
|
||
"Takeover",
|
||
"Quit",
|
||
"Idleout",
|
||
"Disconnect",
|
||
"Shutdown",
|
||
"Reboot",
|
||
"Crash",
|
||
"Playing"
|
||
};
|
||
|
||
struct last_entry *find_llog_entry(int punique, long idnum) {
|
||
FILE *fp;
|
||
struct last_entry mlast;
|
||
struct last_entry *llast;
|
||
int size, recs, tmp;
|
||
|
||
if(!(fp=fopen(LAST_FILE,"r"))) {
|
||
log("Error opening last_file for reading, will create.");
|
||
return NULL;
|
||
}
|
||
fseek(fp,0L,SEEK_END);
|
||
size=ftell(fp);
|
||
|
||
/* recs = number of records in the last file */
|
||
recs = size/sizeof(struct last_entry);
|
||
/* we'll search last to first, since it's faster than any thing else we can
|
||
* do (like searching for the last shutdown/etc..) */
|
||
for(tmp=recs-1; tmp > 0; tmp--) {
|
||
fseek(fp,-1*((long)sizeof(struct last_entry)),SEEK_CUR);
|
||
if (fread(&mlast,sizeof(struct last_entry),1,fp) != 1)
|
||
return NULL;
|
||
/*another one to keep that stepback */
|
||
fseek(fp,-1*((long)sizeof(struct last_entry)),SEEK_CUR);
|
||
|
||
if(mlast.idnum == idnum && mlast.punique == punique) {
|
||
/* then we've found a match */
|
||
CREATE(llast,struct last_entry,1);
|
||
memcpy(llast,&mlast,sizeof(struct last_entry));
|
||
fclose(fp);
|
||
return llast;
|
||
}
|
||
/*not the one we seek. next */
|
||
}
|
||
/*not found, no problem, quit */
|
||
fclose(fp);
|
||
return NULL;
|
||
}
|
||
|
||
/* mod_llog_entry assumes that llast is accurate */
|
||
static void mod_llog_entry(struct last_entry *llast,int type) {
|
||
FILE *fp;
|
||
struct last_entry mlast;
|
||
int size, recs, tmp;
|
||
|
||
if(!(fp=fopen(LAST_FILE,"r+"))) {
|
||
log("Error opening last_file for reading and writing.");
|
||
return;
|
||
}
|
||
fseek(fp,0L,SEEK_END);
|
||
size=ftell(fp);
|
||
|
||
/* recs = number of records in the last file */
|
||
recs = size/sizeof(struct last_entry);
|
||
|
||
/* We'll search last to first, since it's faster than any thing else we can
|
||
* do (like searching for the last shutdown/etc..) */
|
||
for(tmp=recs; tmp > 0; tmp--) {
|
||
fseek(fp,-1*((long)sizeof(struct last_entry)),SEEK_CUR);
|
||
if(fread(&mlast,sizeof(struct last_entry),1,fp) != 1) {
|
||
log("mod_llog_entry: read error or unexpected end of file.");
|
||
return;
|
||
}
|
||
/* Another one to keep that stepback. */
|
||
fseek(fp,-1*((long)sizeof(struct last_entry)),SEEK_CUR);
|
||
|
||
if(mlast.idnum == llast->idnum && mlast.punique == llast->punique) {
|
||
/* Then we've found a match, lets assume quit is inviolate, mainly
|
||
* because disconnect is called after each of these */
|
||
if(mlast.close_type != LAST_QUIT &&
|
||
mlast.close_type != LAST_IDLEOUT &&
|
||
mlast.close_type != LAST_REBOOT &&
|
||
mlast.close_type != LAST_SHUTDOWN) {
|
||
mlast.close_type=type;
|
||
}
|
||
mlast.close_time=time(0);
|
||
/*write it, and we're done!*/
|
||
fwrite(&mlast,sizeof(struct last_entry),1,fp);
|
||
fclose(fp);
|
||
return;
|
||
}
|
||
/* Not the one we seek, next. */
|
||
}
|
||
fclose(fp);
|
||
|
||
/* Not found, no problem, quit. */
|
||
return;
|
||
}
|
||
|
||
void add_llog_entry(struct char_data *ch, int type) {
|
||
FILE *fp;
|
||
struct last_entry *llast;
|
||
|
||
/* so if a char enteres a name, but bad password, otherwise loses link before
|
||
* he gets a pref assinged, we won't record it */
|
||
if(GET_PREF(ch) <= 0) {
|
||
return;
|
||
}
|
||
|
||
/* See if we have a login stored */
|
||
llast = find_llog_entry(GET_PREF(ch), GET_IDNUM(ch));
|
||
|
||
/* we didn't - make a new one */
|
||
if(llast == NULL) { /* no entry found, add ..error if close! */
|
||
CREATE(llast,struct last_entry,1);
|
||
strncpy(llast->username,GET_NAME(ch),15);
|
||
strncpy(llast->hostname,GET_HOST(ch),127);
|
||
llast->username[15]='\0';
|
||
llast->hostname[127]='\0';
|
||
llast->idnum=GET_IDNUM(ch);
|
||
llast->punique=GET_PREF(ch);
|
||
llast->time=time(0);
|
||
llast->close_time=0;
|
||
llast->close_type=type;
|
||
|
||
if(!(fp=fopen(LAST_FILE,"a"))) {
|
||
log("error opening last_file for appending");
|
||
free(llast);
|
||
return;
|
||
}
|
||
fwrite(llast,sizeof(struct last_entry),1,fp);
|
||
fclose(fp);
|
||
} else {
|
||
/* We've found a login - update it */
|
||
mod_llog_entry(llast,type);
|
||
}
|
||
free(llast);
|
||
}
|
||
|
||
void clean_llog_entries(void) {
|
||
FILE *ofp, *nfp;
|
||
struct last_entry mlast;
|
||
int recs;
|
||
|
||
if(!(ofp=fopen(LAST_FILE,"r")))
|
||
return; /* no file, no gripe */
|
||
|
||
fseek(ofp,0L,SEEK_END);
|
||
recs=ftell(ofp)/sizeof(struct last_entry);
|
||
rewind(ofp);
|
||
|
||
if (recs < MAX_LAST_ENTRIES) {
|
||
fclose(ofp);
|
||
return;
|
||
}
|
||
|
||
if (!(nfp=fopen("etc/nlast", "w"))) {
|
||
log("Error trying to open new last file.");
|
||
fclose(ofp);
|
||
return;
|
||
}
|
||
|
||
/* skip first entries */
|
||
fseek(ofp,(recs-MAX_LAST_ENTRIES)* (sizeof(struct last_entry)),SEEK_CUR);
|
||
|
||
/* copy the rest */
|
||
while (!feof(ofp)) {
|
||
if(fread(&mlast,sizeof(struct last_entry),1,ofp) != 1 ) {
|
||
log("clean_llog_entries: read error or unexpected end of file.");
|
||
return;
|
||
}
|
||
fwrite(&mlast,sizeof(struct last_entry),1,nfp);
|
||
}
|
||
fclose(ofp);
|
||
fclose(nfp);
|
||
|
||
remove(LAST_FILE);
|
||
rename("etc/nlast", LAST_FILE);
|
||
}
|
||
|
||
/* debugging stuff, if you wanna see the whole file */
|
||
static void list_llog_entries(struct char_data *ch)
|
||
{
|
||
FILE *fp;
|
||
struct last_entry llast;
|
||
char timestr[25];
|
||
|
||
if(!(fp=fopen(LAST_FILE,"r"))) {
|
||
log("llist_log_entries: could not open last log file %s.", LAST_FILE);
|
||
send_to_char(ch, "Error! - no last log");
|
||
}
|
||
send_to_char(ch, "Last log\r\n");
|
||
|
||
while(fread(&llast, sizeof(struct last_entry), 1, fp) == 1) {
|
||
strftime(timestr, sizeof(timestr), "%a %b %d %Y %H:%M:%S", localtime(&llast.time));
|
||
send_to_char(ch, "%10s %d %s %s\r\n", llast.username, llast.punique,
|
||
last_array[llast.close_type], timestr);
|
||
break;
|
||
}
|
||
|
||
if(ferror(fp)) {
|
||
log("llist_log_entries: error reading %s.", LAST_FILE);
|
||
send_to_char(ch, "Error reading last_log file.");
|
||
}
|
||
}
|
||
|
||
static struct char_data *is_in_game(long idnum) {
|
||
struct descriptor_data *i;
|
||
|
||
for (i = descriptor_list; i; i = i->next) {
|
||
if (i->character && GET_IDNUM(i->character) == idnum) {
|
||
return i->character;
|
||
}
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
ACMD(do_last)
|
||
{
|
||
char arg[MAX_INPUT_LENGTH], name[MAX_INPUT_LENGTH], timestr[25], to[6];
|
||
char deltastr[6];
|
||
time_t delta;
|
||
struct char_data *vict = NULL;
|
||
struct char_data *temp;
|
||
int recs, num = 0;
|
||
FILE *fp;
|
||
struct last_entry mlast;
|
||
|
||
*name = '\0';
|
||
|
||
if (*argument) { /* parse it */
|
||
half_chop(argument, arg, argument);
|
||
while (*arg) {
|
||
if ((*arg == '*' || !strcmp(arg, "all")) && (GET_LEVEL(ch) == LVL_IMPL)) {
|
||
list_llog_entries(ch);
|
||
return;
|
||
}
|
||
if (isdigit(*arg)) {
|
||
num = atoi(arg);
|
||
if (num < 0)
|
||
num = 0;
|
||
} else {
|
||
strncpy(name, arg, sizeof(name)-1);
|
||
name[sizeof(name) - 1] = '\0';
|
||
}
|
||
|
||
half_chop(argument, arg, argument);
|
||
}
|
||
}
|
||
|
||
if (*name && !num) {
|
||
CREATE(vict, struct char_data, 1);
|
||
clear_char(vict);
|
||
CREATE(vict->player_specials, struct player_special_data, 1);
|
||
new_mobile_data(vict);
|
||
if (load_char(name, vict) < 0) {
|
||
send_to_char(ch, "There is no such player.\r\n");
|
||
free_char(vict);
|
||
return;
|
||
}
|
||
|
||
strftime(timestr, sizeof(timestr), "%a %b %d %H:%M:%S %Y", localtime(&(vict->player.time.logon)));
|
||
|
||
send_to_char(ch, "[%5ld] [%2d %s] %-12s : %-18s : %-24s\r\n",
|
||
GET_IDNUM(vict), (int) GET_LEVEL(vict),
|
||
CLASS_ABBR(vict), GET_NAME(vict),
|
||
GET_HOST(vict) && *GET_HOST(vict) ? GET_HOST(vict) : "(NOHOST)", timestr);
|
||
free_char(vict);
|
||
return;
|
||
}
|
||
|
||
if(num <= 0 || num >= 100) {
|
||
num=10;
|
||
}
|
||
|
||
if(!(fp=fopen(LAST_FILE,"r"))) {
|
||
send_to_char(ch, "No entries found.\r\n");
|
||
return;
|
||
}
|
||
fseek(fp,0L,SEEK_END);
|
||
recs=ftell(fp)/sizeof(struct last_entry);
|
||
|
||
send_to_char(ch, "Last log\r\n");
|
||
while(num > 0 && recs > 0) {
|
||
fseek(fp,-1* ((long)sizeof(struct last_entry)),SEEK_CUR);
|
||
if(fread(&mlast,sizeof(struct last_entry),1,fp) != 1) {
|
||
send_to_char(ch, "Error reading log file.");
|
||
return;
|
||
}
|
||
fseek(fp,-1*((long)sizeof(struct last_entry)),SEEK_CUR);
|
||
if(!*name ||(*name && !str_cmp(name, mlast.username))) {
|
||
strftime(timestr, sizeof(timestr), "%a %b %d %Y %H:%M", localtime(&mlast.time));
|
||
send_to_char(ch, "%10.10s %20.20s %20.21s - ",
|
||
mlast.username, mlast.hostname, timestr);
|
||
if((temp=is_in_game(mlast.idnum)) && mlast.punique == GET_PREF(temp)) {
|
||
send_to_char(ch, "Still Playing ");
|
||
} else {
|
||
delta = mlast.close_time - mlast.time;
|
||
strftime(to, sizeof(to), "%H:%M", localtime(&mlast.close_time));
|
||
strftime(deltastr, sizeof(deltastr), "%H:%M", gmtime(&delta));
|
||
|
||
send_to_char(ch, "%5.5s (%5.5s) %s", to, deltastr,
|
||
last_array[mlast.close_type]);
|
||
}
|
||
|
||
send_to_char(ch, "\r\n");
|
||
num--;
|
||
}
|
||
recs--;
|
||
}
|
||
fclose(fp);
|
||
}
|
||
|
||
ACMD(do_force)
|
||
{
|
||
struct descriptor_data *i, *next_desc;
|
||
struct char_data *vict, *next_force;
|
||
char arg[MAX_INPUT_LENGTH], to_force[MAX_INPUT_LENGTH], buf1[MAX_INPUT_LENGTH + 32];
|
||
|
||
half_chop(argument, arg, to_force);
|
||
|
||
snprintf(buf1, sizeof(buf1), "$n has forced you to '%s'.", to_force);
|
||
|
||
if (!*arg || !*to_force)
|
||
send_to_char(ch, "Whom do you wish to force do what?\r\n");
|
||
else if ((GET_LEVEL(ch) < LVL_GRGOD) || (str_cmp("all", arg) && str_cmp("room", arg))) {
|
||
if (!(vict = get_char_vis(ch, arg, NULL, FIND_CHAR_WORLD)))
|
||
send_to_char(ch, "%s", CONFIG_NOPERSON);
|
||
else if (!IS_NPC(vict) && GET_LEVEL(ch) < LVL_GOD)
|
||
send_to_char(ch, "You cannot force players.\r\n");
|
||
else if (!IS_NPC(vict) && GET_LEVEL(ch) <= GET_LEVEL(vict))
|
||
send_to_char(ch, "No, no, no!\r\n");
|
||
else {
|
||
send_to_char(ch, "%s", CONFIG_OK);
|
||
act(buf1, TRUE, ch, NULL, vict, TO_VICT);
|
||
mudlog(CMP, MAX(LVL_GOD, GET_INVIS_LEV(ch)), TRUE, "(GC) %s forced %s to %s", GET_NAME(ch), GET_NAME(vict), to_force);
|
||
command_interpreter(vict, to_force);
|
||
}
|
||
} else if (!str_cmp("room", arg)) {
|
||
send_to_char(ch, "%s", CONFIG_OK);
|
||
mudlog(NRM, MAX(LVL_GOD, GET_INVIS_LEV(ch)), TRUE, "(GC) %s forced room %d to %s",
|
||
GET_NAME(ch), GET_ROOM_VNUM(IN_ROOM(ch)), to_force);
|
||
|
||
for (vict = world[IN_ROOM(ch)].people; vict; vict = next_force) {
|
||
next_force = vict->next_in_room;
|
||
if (!IS_NPC(vict) && GET_LEVEL(vict) >= GET_LEVEL(ch))
|
||
continue;
|
||
act(buf1, TRUE, ch, NULL, vict, TO_VICT);
|
||
command_interpreter(vict, to_force);
|
||
}
|
||
} else { /* force all */
|
||
send_to_char(ch, "%s", CONFIG_OK);
|
||
mudlog(NRM, MAX(LVL_GOD, GET_INVIS_LEV(ch)), TRUE, "(GC) %s forced all to %s", GET_NAME(ch), to_force);
|
||
|
||
for (i = descriptor_list; i; i = next_desc) {
|
||
next_desc = i->next;
|
||
|
||
if (STATE(i) != CON_PLAYING || !(vict = i->character) || (!IS_NPC(vict) && GET_LEVEL(vict) >= GET_LEVEL(ch)))
|
||
continue;
|
||
act(buf1, TRUE, ch, NULL, vict, TO_VICT);
|
||
command_interpreter(vict, to_force);
|
||
}
|
||
}
|
||
}
|
||
|
||
ACMD(do_wiznet)
|
||
{
|
||
char buf1[MAX_INPUT_LENGTH + MAX_NAME_LENGTH + 32],
|
||
buf2[MAX_INPUT_LENGTH + MAX_NAME_LENGTH + 32];
|
||
struct descriptor_data *d;
|
||
char emote = FALSE;
|
||
int level = LVL_IMMORT;
|
||
|
||
skip_spaces(&argument);
|
||
|
||
if (!*argument) {
|
||
send_to_char(ch, "Usage: wiznet [ #<level> ] [<text> | *<emotetext> | @ ]\r\n");
|
||
return;
|
||
}
|
||
switch (*argument) {
|
||
case '*':
|
||
emote = TRUE;
|
||
case '#':
|
||
one_argument(argument + 1, buf1);
|
||
if (is_number(buf1)) {
|
||
half_chop(argument+1, buf1, argument);
|
||
level = MAX(atoi(buf1), LVL_IMMORT);
|
||
if (level > GET_LEVEL(ch)) {
|
||
send_to_char(ch, "You can't wizline above your own level.\r\n");
|
||
return;
|
||
}
|
||
} else if (emote)
|
||
argument++;
|
||
break;
|
||
|
||
case '@':
|
||
send_to_char(ch, "God channel status:\r\n");
|
||
for (d = descriptor_list; d; d = d->next) {
|
||
if (STATE(d) != CON_PLAYING || GET_LEVEL(d->character) < LVL_IMMORT)
|
||
continue;
|
||
if (!CAN_SEE(ch, d->character))
|
||
continue;
|
||
|
||
send_to_char(ch, " %-*s%s%s%s\r\n", MAX_NAME_LENGTH, GET_NAME(d->character),
|
||
PLR_FLAGGED(d->character, PLR_WRITING) ? " (Writing)" : "",
|
||
PLR_FLAGGED(d->character, PLR_MAILING) ? " (Writing mail)" : "",
|
||
PRF_FLAGGED(d->character, PRF_NOWIZ) ? " (Offline)" : "");
|
||
}
|
||
return;
|
||
|
||
case '\\':
|
||
++argument;
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
if (PRF_FLAGGED(ch, PRF_NOWIZ)) {
|
||
send_to_char(ch, "You are offline!\r\n");
|
||
return;
|
||
}
|
||
skip_spaces(&argument);
|
||
|
||
if (!*argument) {
|
||
send_to_char(ch, "Don't bother the gods like that!\r\n");
|
||
return;
|
||
}
|
||
if (level > LVL_IMMORT) {
|
||
snprintf(buf1, sizeof(buf1), "\tc%s: <%d> %s%s\tn\r\n", GET_NAME(ch), level, emote ? "<--- " : "", argument);
|
||
snprintf(buf2, sizeof(buf1), "\tcSomeone: <%d> %s%s\tn\r\n", level, emote ? "<--- " : "", argument);
|
||
} else {
|
||
snprintf(buf1, sizeof(buf1), "\tc%s: %s%s\tn\r\n", GET_NAME(ch), emote ? "<--- " : "", argument);
|
||
snprintf(buf2, sizeof(buf1), "\tcSomeone: %s%s\tn\r\n", emote ? "<--- " : "", argument);
|
||
}
|
||
|
||
for (d = descriptor_list; d; d = d->next) {
|
||
if (IS_PLAYING(d) && (GET_LEVEL(d->character) >= level) &&
|
||
(!PRF_FLAGGED(d->character, PRF_NOWIZ))
|
||
&& (d != ch->desc || !(PRF_FLAGGED(d->character, PRF_NOREPEAT)))) {
|
||
if (CAN_SEE(d->character, ch)) {
|
||
parse_at(buf1);
|
||
send_to_char(d->character, "%s%s%s", CCCYN(d->character, C_NRM), buf1, CCNRM(d->character, C_NRM));
|
||
add_history(d->character, buf1, HIST_WIZNET);
|
||
} else {
|
||
parse_at(buf2);
|
||
send_to_char(d->character, "%s%s%s", CCCYN(d->character, C_NRM), buf2, CCNRM(d->character, C_NRM));
|
||
add_history(d->character, buf2, HIST_WIZNET);
|
||
}
|
||
}
|
||
}
|
||
|
||
if (PRF_FLAGGED(ch, PRF_NOREPEAT))
|
||
send_to_char(ch, "%s", CONFIG_OK);
|
||
}
|
||
|
||
ACMD(do_zreset)
|
||
{
|
||
char arg[MAX_INPUT_LENGTH];
|
||
zone_rnum i;
|
||
zone_vnum j;
|
||
|
||
one_argument(argument, arg);
|
||
|
||
if (*arg == '*') {
|
||
if (GET_LEVEL(ch) < LVL_GOD){
|
||
send_to_char(ch, "You do not have permission to reset the entire world.\r\n");
|
||
return;
|
||
} else {
|
||
for (i = 0; i <= top_of_zone_table; i++)
|
||
reset_zone(i);
|
||
|
||
/* NEW: re-apply persistent room contents across the world */
|
||
RoomSave_boot();
|
||
|
||
send_to_char(ch, "Reset world.\r\n");
|
||
mudlog(NRM, MAX(LVL_GOD, GET_INVIS_LEV(ch)), TRUE, "(GC) %s reset entire world.", GET_NAME(ch));
|
||
return;
|
||
}
|
||
} else if (*arg == '.' || !*arg)
|
||
i = world[IN_ROOM(ch)].zone;
|
||
else {
|
||
j = atoi(arg);
|
||
for (i = 0; i <= top_of_zone_table; i++)
|
||
if (zone_table[i].number == j)
|
||
break;
|
||
}
|
||
|
||
if (i <= top_of_zone_table && (can_edit_zone(ch, i) || GET_LEVEL(ch) > LVL_IMMORT)) {
|
||
reset_zone(i);
|
||
|
||
/* NEW: re-apply persistent room contents for the zone that was reset */
|
||
RoomSave_boot(); /* If you later add a zone-scoped loader, call that here instead */
|
||
|
||
send_to_char(ch, "Reset zone #%d: %s.\r\n", zone_table[i].number, zone_table[i].name);
|
||
mudlog(NRM, MAX(LVL_GOD, GET_INVIS_LEV(ch)), TRUE,
|
||
"(GC) %s reset zone %d (%s)", GET_NAME(ch), zone_table[i].number, zone_table[i].name);
|
||
} else
|
||
send_to_char(ch, "You do not have permission to reset this zone. Try %d.\r\n", GET_OLC_ZONE(ch));
|
||
}
|
||
|
||
/* General fn for wizcommands of the sort: cmd <player> */
|
||
ACMD(do_wizutil)
|
||
{
|
||
char arg[MAX_INPUT_LENGTH];
|
||
struct char_data *vict;
|
||
int taeller;
|
||
long result;
|
||
|
||
one_argument(argument, arg);
|
||
|
||
if (!*arg)
|
||
send_to_char(ch, "Yes, but for whom?!?\r\n");
|
||
else if (!(vict = get_char_vis(ch, arg, NULL, FIND_CHAR_WORLD)))
|
||
send_to_char(ch, "There is no such player.\r\n");
|
||
else if (IS_NPC(vict))
|
||
send_to_char(ch, "You can't do that to a mob!\r\n");
|
||
else if (GET_LEVEL(vict) >= GET_LEVEL(ch) && vict != ch)
|
||
send_to_char(ch, "Hmmm...you'd better not.\r\n");
|
||
else {
|
||
switch (subcmd) {
|
||
case SCMD_REROLL:
|
||
send_to_char(ch, "Rerolled...\r\n");
|
||
roll_real_abils(vict);
|
||
log("(GC) %s has rerolled %s.", GET_NAME(ch), GET_NAME(vict));
|
||
send_to_char(ch, "New stats: Str %d, Int %d, Wis %d, Dex %d, Con %d, Cha %d\r\n",
|
||
GET_STR(vict), GET_INT(vict), GET_WIS(vict),
|
||
GET_DEX(vict), GET_CON(vict), GET_CHA(vict));
|
||
break;
|
||
case SCMD_PARDON:
|
||
send_to_char(ch, "Criminal flags are currently disabled.\r\n");
|
||
return;
|
||
case SCMD_MUTE:
|
||
result = PLR_TOG_CHK(vict, PLR_NOSHOUT);
|
||
mudlog(BRF, MAX(LVL_GOD, GET_INVIS_LEV(ch)), TRUE, "(GC) Mute %s for %s by %s.",
|
||
ONOFF(result), GET_NAME(vict), GET_NAME(ch));
|
||
send_to_char(ch, "(GC) Mute %s for %s by %s.\r\n", ONOFF(result), GET_NAME(vict), GET_NAME(ch));
|
||
break;
|
||
case SCMD_FREEZE:
|
||
if (ch == vict) {
|
||
send_to_char(ch, "Oh, yeah, THAT'S real smart...\r\n");
|
||
return;
|
||
}
|
||
if (PLR_FLAGGED(vict, PLR_FROZEN)) {
|
||
send_to_char(ch, "Your victim is already pretty cold.\r\n");
|
||
return;
|
||
}
|
||
SET_BIT_AR(PLR_FLAGS(vict), PLR_FROZEN);
|
||
GET_FREEZE_LEV(vict) = GET_LEVEL(ch);
|
||
send_to_char(vict, "A bitter wind suddenly rises and drains every erg of heat from your body!\r\nYou feel frozen!\r\n");
|
||
send_to_char(ch, "Frozen.\r\n");
|
||
act("A sudden cold wind conjured from nowhere freezes $n!", FALSE, vict, 0, 0, TO_ROOM);
|
||
mudlog(BRF, MAX(LVL_GOD, GET_INVIS_LEV(ch)), TRUE, "(GC) %s frozen by %s.", GET_NAME(vict), GET_NAME(ch));
|
||
break;
|
||
case SCMD_THAW:
|
||
if (!PLR_FLAGGED(vict, PLR_FROZEN)) {
|
||
send_to_char(ch, "Sorry, your victim is not morbidly encased in ice at the moment.\r\n");
|
||
return;
|
||
}
|
||
if (GET_FREEZE_LEV(vict) > GET_LEVEL(ch)) {
|
||
send_to_char(ch, "Sorry, a level %d God froze %s... you can't unfreeze %s.\r\n",
|
||
GET_FREEZE_LEV(vict), GET_NAME(vict), HMHR(vict));
|
||
return;
|
||
}
|
||
mudlog(BRF, MAX(LVL_GOD, GET_INVIS_LEV(ch)), TRUE, "(GC) %s un-frozen by %s.", GET_NAME(vict), GET_NAME(ch));
|
||
REMOVE_BIT_AR(PLR_FLAGS(vict), PLR_FROZEN);
|
||
send_to_char(vict, "A fireball suddenly explodes in front of you, melting the ice!\r\nYou feel thawed.\r\n");
|
||
send_to_char(ch, "Thawed.\r\n");
|
||
act("A sudden fireball conjured from nowhere thaws $n!", FALSE, vict, 0, 0, TO_ROOM);
|
||
break;
|
||
case SCMD_UNAFFECT:
|
||
if (vict->affected || ANY_AFF_FLAGS(vict)) {
|
||
while (vict->affected)
|
||
affect_remove(vict, vict->affected);
|
||
for(taeller=0; taeller < AF_ARRAY_MAX; taeller++)
|
||
AFF_FLAGS(vict)[taeller] = 0;
|
||
send_to_char(vict, "There is a brief flash of light!\r\nYou feel slightly different.\r\n");
|
||
send_to_char(ch, "All spells removed.\r\n");
|
||
} else {
|
||
send_to_char(ch, "Your victim does not have any affections!\r\n");
|
||
return;
|
||
}
|
||
break;
|
||
default:
|
||
log("SYSERR: Unknown subcmd %d passed to do_wizutil (%s)", subcmd, __FILE__);
|
||
/* SYSERR_DESC: This is the same as the unhandled case in do_gen_ps(),
|
||
* but this function handles 'reroll', 'pardon', 'freeze', etc. */
|
||
break;
|
||
}
|
||
save_char(vict);
|
||
}
|
||
}
|
||
|
||
/* single zone printing fn used by "show zone" so it's not repeated in the
|
||
code 3 times ... -je, 4/6/93 FIXME: overflow possible */
|
||
static size_t print_zone_to_buf(char *bufptr, size_t left, zone_rnum zone, int listall)
|
||
{
|
||
size_t tmp;
|
||
|
||
if (listall) {
|
||
int i, j, k, l, m, n, o;
|
||
char buf[MAX_STRING_LENGTH];
|
||
|
||
sprintbitarray(zone_table[zone].zone_flags, zone_bits, ZN_ARRAY_MAX, buf);
|
||
|
||
tmp = snprintf(bufptr, left,
|
||
"%3d %-30.30s%s By: %-10.10s%s Age: %3d; Reset: %3d (%s); Range: %5d-%5d\r\n",
|
||
zone_table[zone].number, zone_table[zone].name, KNRM, zone_table[zone].builders, KNRM,
|
||
zone_table[zone].age, zone_table[zone].lifespan,
|
||
zone_table[zone].reset_mode ? ((zone_table[zone].reset_mode == 1) ? "Reset when no players are in zone" : "Normal reset") : "Never reset",
|
||
zone_table[zone].bot, zone_table[zone].top);
|
||
j = k = l = m = n = o = 0;
|
||
|
||
for (i = 0; i < top_of_world; i++)
|
||
if (world[i].number >= zone_table[zone].bot && world[i].number <= zone_table[zone].top)
|
||
j++;
|
||
|
||
for (i = 0; i < top_of_objt; i++)
|
||
if (obj_index[i].vnum >= zone_table[zone].bot && obj_index[i].vnum <= zone_table[zone].top)
|
||
k++;
|
||
|
||
for (i = 0; i < top_of_mobt; i++)
|
||
if (mob_index[i].vnum >= zone_table[zone].bot && mob_index[i].vnum <= zone_table[zone].top)
|
||
l++;
|
||
|
||
for (i = 0; i<= top_shop; i++)
|
||
if (SHOP_NUM(i) >= zone_table[zone].bot && SHOP_NUM(i) <= zone_table[zone].top)
|
||
m++;
|
||
|
||
for (i = 0; i < top_of_trigt; i++)
|
||
if (trig_index[i]->vnum >= zone_table[zone].bot && trig_index[i]->vnum <= zone_table[zone].top)
|
||
n++;
|
||
|
||
o = count_quests(zone_table[zone].bot, zone_table[zone].top);
|
||
|
||
tmp += snprintf(bufptr + tmp, left - tmp,
|
||
" Zone stats:\r\n"
|
||
" ---------------\r\n"
|
||
" Flags: %s\r\n"
|
||
" Min Lev: %2d\r\n"
|
||
" Max Lev: %2d\r\n"
|
||
" Rooms: %2d\r\n"
|
||
" Objects: %2d\r\n"
|
||
" Mobiles: %2d\r\n"
|
||
" Shops: %2d\r\n"
|
||
" Triggers: %2d\r\n"
|
||
" Quests: %2d\r\n",
|
||
buf, zone_table[zone].min_level, zone_table[zone].max_level,
|
||
j, k, l, m, n, o);
|
||
|
||
return tmp;
|
||
}
|
||
|
||
return snprintf(bufptr, left,
|
||
"%3d %-*s%s By: %-10.10s%s Range: %5d-%5d\r\n", zone_table[zone].number,
|
||
count_color_chars(zone_table[zone].name)+30, zone_table[zone].name, KNRM,
|
||
zone_table[zone].builders, KNRM, zone_table[zone].bot, zone_table[zone].top);
|
||
}
|
||
|
||
ACMD(do_show)
|
||
{
|
||
int i, j, k, l, con, builder =0; /* i, j, k to specifics? */
|
||
size_t len, nlen;
|
||
zone_rnum zrn;
|
||
zone_vnum zvn;
|
||
byte self = FALSE;
|
||
struct char_data *vict = NULL;
|
||
struct obj_data *obj;
|
||
struct descriptor_data *d;
|
||
char field[MAX_INPUT_LENGTH], value[MAX_INPUT_LENGTH],
|
||
arg[MAX_INPUT_LENGTH], buf[MAX_STRING_LENGTH];
|
||
int r, g, b;
|
||
char colour[16];
|
||
|
||
struct show_struct {
|
||
const char *cmd;
|
||
const char level;
|
||
} fields[] = {
|
||
{ "nothing", 0 }, /* 0 */
|
||
{ "zones", LVL_IMMORT }, /* 1 */
|
||
{ "player", LVL_IMMORT },
|
||
{ "stats", LVL_IMMORT },
|
||
{ "errors", LVL_IMMORT }, /* 5 */
|
||
{ "death", LVL_IMMORT },
|
||
{ "godrooms", LVL_IMMORT },
|
||
{ "shops", LVL_IMMORT },
|
||
{ "houses", LVL_IMMORT },
|
||
{ "snoop", LVL_IMMORT }, /* 10 */
|
||
{ "exp", LVL_IMMORT },
|
||
{ "colour", LVL_IMMORT },
|
||
{ "\n", 0 }
|
||
};
|
||
|
||
skip_spaces(&argument);
|
||
|
||
if (!*argument) {
|
||
send_to_char(ch, "Show options:\r\n");
|
||
for (j = 0, i = 1; fields[i].level; i++)
|
||
if (fields[i].level <= GET_LEVEL(ch))
|
||
send_to_char(ch, "%-15s%s", fields[i].cmd, (!(++j % 5) ? "\r\n" : ""));
|
||
send_to_char(ch, "\r\n");
|
||
return;
|
||
}
|
||
|
||
strcpy(arg, two_arguments(argument, field, value)); /* strcpy: OK (argument <= MAX_INPUT_LENGTH == arg) */
|
||
|
||
for (l = 0; *(fields[l].cmd) != '\n'; l++)
|
||
if (!strncmp(field, fields[l].cmd, strlen(field)))
|
||
break;
|
||
|
||
if (GET_LEVEL(ch) < fields[l].level) {
|
||
send_to_char(ch, "You are not godly enough for that!\r\n");
|
||
return;
|
||
}
|
||
if (!strcmp(value, "."))
|
||
self = TRUE;
|
||
buf[0] = '\0';
|
||
|
||
switch (l) {
|
||
/* show zone */
|
||
case 1:
|
||
/* tightened up by JE 4/6/93 */
|
||
if (self)
|
||
print_zone_to_buf(buf, sizeof(buf), world[IN_ROOM(ch)].zone, 1);
|
||
else if (*value && is_number(value)) {
|
||
for (zvn = atoi(value), zrn = 0; zone_table[zrn].number != zvn && zrn <= top_of_zone_table; zrn++);
|
||
if (zrn <= top_of_zone_table)
|
||
print_zone_to_buf(buf, sizeof(buf), zrn, 1);
|
||
else {
|
||
send_to_char(ch, "That is not a valid zone.\r\n");
|
||
return;
|
||
}
|
||
} else {
|
||
char *buf2;
|
||
if (*value)
|
||
builder = 1;
|
||
for (len = zrn = 0; zrn <= top_of_zone_table; zrn++) {
|
||
if (*value) {
|
||
buf2 = strtok(strdup(zone_table[zrn].builders), " ");
|
||
while (buf2) {
|
||
if (!str_cmp(buf2, value)) {
|
||
if (builder == 1)
|
||
builder++;
|
||
break;
|
||
}
|
||
buf2 = strtok(NULL, " ");
|
||
}
|
||
if (!buf2)
|
||
continue;
|
||
}
|
||
nlen = print_zone_to_buf(buf + len, sizeof(buf) - len, zrn, 0);
|
||
if (len + nlen >= sizeof(buf))
|
||
break;
|
||
len += nlen;
|
||
}
|
||
}
|
||
if (builder == 1)
|
||
send_to_char(ch, "%s has not built any zones here.\r\n", CAP(value));
|
||
else if (builder == 2)
|
||
send_to_char(ch, "The following zones have been built by: %s\r\n", CAP(value));
|
||
page_string(ch->desc, buf, TRUE);
|
||
break;
|
||
|
||
/* show player */
|
||
case 2: {
|
||
char buf1[64], buf2[64];
|
||
|
||
if (!*value) {
|
||
send_to_char(ch, "A name would help.\r\n");
|
||
return;
|
||
}
|
||
|
||
CREATE(vict, struct char_data, 1);
|
||
clear_char(vict);
|
||
CREATE(vict->player_specials, struct player_special_data, 1);
|
||
new_mobile_data(vict);
|
||
if (load_char(value, vict) < 0) {
|
||
send_to_char(ch, "There is no such player.\r\n");
|
||
free_char(vict);
|
||
return;
|
||
}
|
||
|
||
strftime(buf1, sizeof(buf1), "%a %b %d %H:%M:%S %Y", localtime(&(vict->player.time.birth)));
|
||
strftime(buf2, sizeof(buf2), "%a %b %d %H:%H:%S %Y", localtime(&(vict->player.time.logon)));
|
||
|
||
send_to_char(ch, "Player: %-12s (%s) [%2d %s]\r\n", GET_NAME(vict),
|
||
genders[(int) GET_SEX(vict)], GET_LEVEL(vict), CLASS_ABBR(vict));
|
||
send_to_char(ch, "Coins: %-8d Bal: %-8d Exp: %-8d\r\n",
|
||
GET_COINS(vict), GET_BANK_COINS(vict), GET_EXP(vict));
|
||
send_to_char(ch, "Started: %-25.25s Last: %-25.25s\r\n", buf1, buf2);
|
||
send_to_char(ch, "Played: %dh %dm\r\n",
|
||
(int) (vict->player.time.played / 3600),
|
||
(int) (vict->player.time.played / 60 % 60));
|
||
|
||
free_char(vict);
|
||
break;
|
||
}
|
||
/* show stats */
|
||
case 3:
|
||
i = 0;
|
||
j = 0;
|
||
k = 0;
|
||
con = 0;
|
||
for (vict = character_list; vict; vict = vict->next) {
|
||
if (IS_NPC(vict))
|
||
j++;
|
||
else if (CAN_SEE(ch, vict)) {
|
||
i++;
|
||
if (vict->desc)
|
||
con++;
|
||
}
|
||
}
|
||
for (obj = object_list; obj; obj = obj->next)
|
||
k++;
|
||
send_to_char(ch,
|
||
"Current stats:\r\n"
|
||
" %5d players in game %5d connected\r\n"
|
||
" %5d registered\r\n"
|
||
" %5d mobiles %5d prototypes\r\n"
|
||
" %5d objects %5d prototypes\r\n"
|
||
" %5d rooms %5d zones\r\n"
|
||
" %5d triggers %5d shops\r\n"
|
||
" %5d large bufs %5d autoquests\r\n"
|
||
" %5d buf switches %5d overflows\r\n"
|
||
" %5d lists\r\n",
|
||
i, con,
|
||
top_of_p_table + 1,
|
||
j, top_of_mobt + 1,
|
||
k, top_of_objt + 1,
|
||
top_of_world + 1, top_of_zone_table + 1,
|
||
top_of_trigt + 1, top_shop + 1,
|
||
buf_largecount, total_quests,
|
||
buf_switches, buf_overflows, global_lists->iSize
|
||
);
|
||
break;
|
||
|
||
/* show errors */
|
||
case 4:
|
||
len = strlcpy(buf, "Errant Rooms\r\n------------\r\n", sizeof(buf));
|
||
for (i = 0, k = 0; i <= top_of_world; i++)
|
||
for (j = 0; j < DIR_COUNT; j++) {
|
||
if (!W_EXIT(i,j))
|
||
continue;
|
||
if (W_EXIT(i,j)->to_room == 0) {
|
||
nlen = snprintf(buf + len, sizeof(buf) - len, "%2d: (void ) [%5d] %-*s%s (%s)\r\n", ++k, GET_ROOM_VNUM(i), count_color_chars(world[i].name)+40, world[i].name, QNRM, dirs[j]);
|
||
if (len + nlen >= sizeof(buf))
|
||
break;
|
||
len += nlen;
|
||
}
|
||
if (W_EXIT(i,j)->to_room == NOWHERE && !W_EXIT(i,j)->general_description) {
|
||
nlen = snprintf(buf + len, sizeof(buf) - len, "%2d: (Nowhere) [%5d] %-*s%s (%s)\r\n", ++k, GET_ROOM_VNUM(i), count_color_chars(world[i].name)+ 40, world[i].name, QNRM, dirs[j]);
|
||
if (len + nlen >= sizeof(buf))
|
||
break;
|
||
len += nlen;
|
||
}
|
||
}
|
||
page_string(ch->desc, buf, TRUE);
|
||
break;
|
||
|
||
/* show death */
|
||
case 5:
|
||
len = strlcpy(buf, "Death Traps\r\n-----------\r\n", sizeof(buf));
|
||
for (i = 0, j = 0; i <= top_of_world; i++)
|
||
if (ROOM_FLAGGED(i, ROOM_DEATH)) {
|
||
nlen = snprintf(buf + len, sizeof(buf) - len, "%2d: [%5d] %s%s\r\n", ++j, GET_ROOM_VNUM(i), world[i].name, QNRM);
|
||
if (len + nlen >= sizeof(buf))
|
||
break;
|
||
len += nlen;
|
||
}
|
||
page_string(ch->desc, buf, TRUE);
|
||
break;
|
||
|
||
/* show godrooms */
|
||
case 6:
|
||
len = strlcpy(buf, "Godrooms\r\n--------------------------\r\n", sizeof(buf));
|
||
for (i = 0, j = 0; i <= top_of_world; i++)
|
||
if (ROOM_FLAGGED(i, ROOM_GODROOM)) {
|
||
nlen = snprintf(buf + len, sizeof(buf) - len, "%2d: [%5d] %s%s\r\n", ++j, GET_ROOM_VNUM(i), world[i].name, QNRM);
|
||
if (len + nlen >= sizeof(buf))
|
||
break;
|
||
len += nlen;
|
||
}
|
||
page_string(ch->desc, buf, TRUE);
|
||
break;
|
||
|
||
/* show shops */
|
||
case 7:
|
||
show_shops(ch, value);
|
||
break;
|
||
|
||
/* show houses */
|
||
case 8:
|
||
hcontrol_list_houses(ch, value);
|
||
break;
|
||
|
||
/* show snoop */
|
||
case 9:
|
||
i = 0;
|
||
send_to_char(ch, "People currently snooping:\r\n--------------------------\r\n");
|
||
for (d = descriptor_list; d; d = d->next) {
|
||
if (d->snooping == NULL || d->character == NULL)
|
||
continue;
|
||
if (STATE(d) != CON_PLAYING || GET_LEVEL(ch) < GET_LEVEL(d->character))
|
||
continue;
|
||
if (!CAN_SEE(ch, d->character) || IN_ROOM(d->character) == NOWHERE)
|
||
continue;
|
||
i++;
|
||
send_to_char(ch, "%-10s%s - snooped by %s%s.\r\n", GET_NAME(d->snooping->character), QNRM, GET_NAME(d->character), QNRM);
|
||
}
|
||
if (i == 0)
|
||
send_to_char(ch, "No one is currently snooping.\r\n");
|
||
break;
|
||
|
||
/* show experience tables */
|
||
case 10:
|
||
len = strlcpy(buf, "LvL - Mu Cl Th Wa BA Ra Br Dr\r\n--------------------------\r\n", sizeof(buf));
|
||
|
||
for (i = 1; i < LVL_IMMORT; i++) {
|
||
nlen = snprintf(buf + len, sizeof(buf) - len, "%-3d - %-6d %-6d %-6d %-6d %-6d %-6d %-6d %-6d\r\n", i,
|
||
level_exp(CLASS_SORCEROR, i) - level_exp(CLASS_SORCEROR, i - 1),
|
||
level_exp(CLASS_CLERIC, i) - level_exp(CLASS_CLERIC, i - 1),
|
||
level_exp(CLASS_ROGUE, i) - level_exp(CLASS_ROGUE, i - 1),
|
||
level_exp(CLASS_FIGHTER, i) - level_exp(CLASS_FIGHTER, i - 1),
|
||
level_exp(CLASS_BARBARIAN, i) - level_exp(CLASS_BARBARIAN, i - 1),
|
||
level_exp(CLASS_RANGER, i) - level_exp(CLASS_RANGER, i - 1),
|
||
level_exp(CLASS_BARD, i) - level_exp(CLASS_BARD, i - 1),
|
||
level_exp(CLASS_DRUID, i) - level_exp(CLASS_DRUID, i - 1));
|
||
if (len + nlen >= sizeof(buf))
|
||
break;
|
||
len += nlen;
|
||
}
|
||
|
||
page_string(ch->desc, buf, TRUE);
|
||
break;
|
||
|
||
case 11:
|
||
len = strlcpy(buf, "Colours\r\n--------------------------\r\n", sizeof(buf));
|
||
k = 0;
|
||
for (r = 0; r < 6; r++)
|
||
for (g = 0; g < 6; g++)
|
||
for (b = 0; b < 6; b++) {
|
||
sprintf(colour, "F%d%d%d", r, g, b);
|
||
nlen = snprintf(buf + len, sizeof(buf) - len, "%s%s%s", ColourRGB(ch->desc, colour), colour, ++k % 6 == 0 ? "\tn\r\n" : " ");
|
||
if (len + nlen >= sizeof(buf))
|
||
break;
|
||
len += nlen;
|
||
}
|
||
page_string(ch->desc, buf, TRUE);
|
||
break;
|
||
|
||
/* show what? */
|
||
default:
|
||
send_to_char(ch, "Sorry, I don't understand that.\r\n");
|
||
break;
|
||
}
|
||
}
|
||
|
||
/* The do_set function */
|
||
|
||
#define PC 1
|
||
#define NPC 2
|
||
#define BOTH 3
|
||
|
||
#define MISC 0
|
||
#define BINARY 1
|
||
#define NUMBER 2
|
||
|
||
#define SET_OR_REMOVE(flagset, flags) { \
|
||
if (on) SET_BIT_AR(flagset, flags); \
|
||
else if (off) REMOVE_BIT_AR(flagset, flags); }
|
||
|
||
#define RANGE(low, high) (value = MAX((low), MIN((high), (value))))
|
||
|
||
/* The set options available */
|
||
static struct set_struct {
|
||
const char *cmd;
|
||
const char level;
|
||
const char pcnpc;
|
||
const char type;
|
||
} set_fields[] = {
|
||
{ "ac", LVL_BUILDER, BOTH, NUMBER }, /* 0 */
|
||
{ "afk", LVL_BUILDER, PC, BINARY }, /* 1 */
|
||
{ "age", LVL_GOD, BOTH, NUMBER },
|
||
{ "bank", LVL_BUILDER, PC, NUMBER },
|
||
{ "brief", LVL_GOD, PC, BINARY }, /* 4 */
|
||
{ "cha", LVL_BUILDER, BOTH, NUMBER },
|
||
{ "class", LVL_BUILDER, BOTH, MISC },
|
||
{ "color", LVL_GOD, PC, BINARY },
|
||
{ "con", LVL_BUILDER, BOTH, NUMBER },
|
||
{ "deleted", LVL_IMPL, PC, BINARY },
|
||
{ "dex", LVL_BUILDER, BOTH, NUMBER },
|
||
{ "drunk", LVL_BUILDER, BOTH, MISC },
|
||
{ "exp", LVL_GOD, BOTH, NUMBER },
|
||
{ "frozen", LVL_GRGOD, PC, BINARY }, /* 13 */
|
||
{ "coins", LVL_BUILDER, BOTH, NUMBER },
|
||
{ "height", LVL_BUILDER, BOTH, NUMBER },
|
||
{ "hitpoints", LVL_BUILDER, BOTH, NUMBER },
|
||
{ "hunger", LVL_BUILDER, BOTH, MISC }, /* 17 */
|
||
{ "int", LVL_BUILDER, BOTH, NUMBER },
|
||
{ "invis", LVL_GOD, PC, NUMBER },
|
||
{ "invstart", LVL_BUILDER, PC, BINARY },
|
||
{ "level", LVL_GRGOD, BOTH, NUMBER }, /* 21 */
|
||
{ "loadroom", LVL_BUILDER, PC, MISC },
|
||
{ "mana", LVL_BUILDER, BOTH, NUMBER },
|
||
{ "maxhit", LVL_BUILDER, BOTH, NUMBER },
|
||
{ "maxmana", LVL_BUILDER, BOTH, NUMBER },
|
||
{ "maxstam", LVL_BUILDER, BOTH, NUMBER }, /* 26 */
|
||
{ "name", LVL_IMMORT, PC, MISC },
|
||
{ "nodelete", LVL_GOD, PC, BINARY },
|
||
{ "nohassle", LVL_GOD, PC, BINARY },
|
||
{ "nosummon", LVL_BUILDER, PC, BINARY },
|
||
{ "nowizlist", LVL_GRGOD, PC, BINARY },
|
||
{ "olc", LVL_GRGOD, PC, MISC },
|
||
{ "password", LVL_GRGOD, PC, MISC },
|
||
{ "poofin", LVL_IMMORT, PC, MISC },
|
||
{ "poofout", LVL_IMMORT, PC, MISC },
|
||
{ "quest", LVL_GOD, PC, BINARY },
|
||
{ "room", LVL_BUILDER, BOTH, NUMBER },
|
||
{ "screenwidth", LVL_GOD, PC, NUMBER }, /* 38 */
|
||
{ "sex", LVL_GOD, BOTH, MISC },
|
||
{ "showvnums", LVL_BUILDER, PC, BINARY },
|
||
{ "siteok", LVL_GOD, PC, BINARY },
|
||
{ "skill", LVL_GOD, BOTH, NUMBER },
|
||
{ "stam", LVL_BUILDER, BOTH, NUMBER }, /* 43 */
|
||
{ "str", LVL_BUILDER, BOTH, NUMBER },
|
||
{ "thirst", LVL_BUILDER, BOTH, MISC },
|
||
{ "variable", LVL_GRGOD, PC, MISC },
|
||
{ "weight", LVL_BUILDER, BOTH, NUMBER },
|
||
{ "wis", LVL_BUILDER, BOTH, NUMBER },
|
||
{ "questpoints", LVL_GOD, PC, NUMBER }, /* 49 */
|
||
{ "questhistory", LVL_GOD, PC, NUMBER },
|
||
{ "species", LVL_BUILDER, BOTH, MISC },
|
||
{ "\n", 0, BOTH, MISC }
|
||
};
|
||
|
||
static int perform_set(struct char_data *ch, struct char_data *vict, int mode, char *val_arg)
|
||
{
|
||
int i, on = 0, off = 0, value = 0, qvnum;
|
||
room_rnum rnum;
|
||
room_vnum rvnum;
|
||
|
||
/* Check to make sure all the levels are correct */
|
||
if (GET_LEVEL(ch) != LVL_IMPL) {
|
||
if (!IS_NPC(vict) && GET_LEVEL(ch) <= GET_LEVEL(vict) && vict != ch) {
|
||
send_to_char(ch, "Maybe that's not such a great idea...\r\n");
|
||
return (0);
|
||
}
|
||
}
|
||
if (GET_LEVEL(ch) < set_fields[mode].level) {
|
||
send_to_char(ch, "You are not godly enough for that!\r\n");
|
||
return (0);
|
||
}
|
||
|
||
/* Make sure the PC/NPC is correct */
|
||
if (IS_NPC(vict) && !(set_fields[mode].pcnpc & NPC)) {
|
||
send_to_char(ch, "You can't do that to a beast!\r\n");
|
||
return (0);
|
||
} else if (!IS_NPC(vict) && !(set_fields[mode].pcnpc & PC)) {
|
||
send_to_char(ch, "That can only be done to a beast!\r\n");
|
||
return (0);
|
||
}
|
||
|
||
/* Find the value of the argument */
|
||
if (set_fields[mode].type == BINARY) {
|
||
if (!strcmp(val_arg, "on") || !strcmp(val_arg, "yes"))
|
||
on = 1;
|
||
else if (!strcmp(val_arg, "off") || !strcmp(val_arg, "no"))
|
||
off = 1;
|
||
if (!(on || off)) {
|
||
send_to_char(ch, "Value must be 'on' or 'off'.\r\n");
|
||
return (0);
|
||
}
|
||
} else if (set_fields[mode].type == NUMBER) {
|
||
value = atoi(val_arg);
|
||
}
|
||
switch (mode) {
|
||
case 0: /* ac */
|
||
vict->points.armor = RANGE(-100, 100);
|
||
affect_total(vict);
|
||
break;
|
||
case 1: /* afk */
|
||
SET_OR_REMOVE(PRF_FLAGS(vict), PRF_AFK);
|
||
break;
|
||
case 2: /* age */
|
||
if (value < 2 || value > 200) { /* Arbitrary limits. */
|
||
send_to_char(ch, "Ages 2 to 200 accepted.\r\n");
|
||
return (0);
|
||
}
|
||
GET_ROLEPLAY_AGE(vict) = LIMIT(value, MIN_CHAR_AGE, MAX_CHAR_AGE);
|
||
GET_ROLEPLAY_AGE_YEAR(vict) = time_info.year;
|
||
break;
|
||
case 3: /* bank */
|
||
GET_BANK_COINS(vict) = RANGE(0, 100000000);
|
||
break;
|
||
case 4: /* brief */
|
||
SET_OR_REMOVE(PRF_FLAGS(vict), PRF_BRIEF);
|
||
break;
|
||
case 5: /* cha */
|
||
if (IS_NPC(vict) || GET_LEVEL(vict) >= LVL_GRGOD)
|
||
RANGE(3, 25);
|
||
else
|
||
RANGE(3, 18);
|
||
vict->real_abils.cha = value;
|
||
affect_total(vict);
|
||
break;
|
||
case 6: /* class */
|
||
if ((i = parse_class(*val_arg)) == CLASS_UNDEFINED) {
|
||
send_to_char(ch, "That is not a class.\r\n");
|
||
return (0);
|
||
}
|
||
GET_CLASS(vict) = i;
|
||
break;
|
||
case 7: /* color */
|
||
SET_OR_REMOVE(PRF_FLAGS(vict), (PRF_COLOR_1));
|
||
SET_OR_REMOVE(PRF_FLAGS(vict), (PRF_COLOR_2));
|
||
break;
|
||
case 8: /* con */
|
||
if (IS_NPC(vict) || GET_LEVEL(vict) >= LVL_GRGOD)
|
||
RANGE(3, 25);
|
||
else
|
||
RANGE(3, 18);
|
||
vict->real_abils.con = value;
|
||
affect_total(vict);
|
||
break;
|
||
case 9: /* delete */
|
||
SET_OR_REMOVE(PLR_FLAGS(vict), PLR_DELETED);
|
||
break;
|
||
case 10: /* dex */
|
||
if (IS_NPC(vict) || GET_LEVEL(vict) >= LVL_GRGOD)
|
||
RANGE(3, 25);
|
||
else
|
||
RANGE(3, 18);
|
||
vict->real_abils.dex = value;
|
||
affect_total(vict);
|
||
break;
|
||
case 11: /* drunk */
|
||
if (!str_cmp(val_arg, "off")) {
|
||
GET_COND(vict, DRUNK) = -1;
|
||
send_to_char(ch, "%s's drunkenness is now off.\r\n", GET_NAME(vict));
|
||
} else if (is_number(val_arg)) {
|
||
value = atoi(val_arg);
|
||
RANGE(0, 24);
|
||
GET_COND(vict, DRUNK) = value;
|
||
send_to_char(ch, "%s's drunkenness set to %d.\r\n", GET_NAME(vict), value);
|
||
} else {
|
||
send_to_char(ch, "Must be 'off' or a value from 0 to 24.\r\n");
|
||
return (0);
|
||
}
|
||
break;
|
||
case 12: /* exp */
|
||
vict->points.exp = RANGE(0, 50000000);
|
||
break;
|
||
case 13: /* frozen */
|
||
if (ch == vict && on) {
|
||
send_to_char(ch, "Better not -- could be a long winter!\r\n");
|
||
return (0);
|
||
}
|
||
SET_OR_REMOVE(PLR_FLAGS(vict), PLR_FROZEN);
|
||
break;
|
||
case 14: { /* coins */
|
||
struct obj_data *coin_obj;
|
||
int i;
|
||
|
||
value = MIN(MAX(value, 0), 100000000);
|
||
coin_obj = find_inventory_coin(vict);
|
||
|
||
if (value == 0) {
|
||
remove_other_coins_from_list(vict->carrying, NULL);
|
||
for (i = 0; i < NUM_WEARS; i++)
|
||
remove_other_coins_from_list(GET_EQ(vict, i), NULL);
|
||
GET_COINS(vict) = 0;
|
||
send_to_char(ch, "Ok.\r\n");
|
||
return (1);
|
||
}
|
||
|
||
if (coin_obj) {
|
||
GET_OBJ_VAL(coin_obj, 0) = value;
|
||
update_money_obj(coin_obj);
|
||
} else {
|
||
coin_obj = create_money(value);
|
||
if (!coin_obj) {
|
||
send_to_char(ch, "Ok.\r\n");
|
||
return (1);
|
||
}
|
||
obj_to_char(coin_obj, vict);
|
||
}
|
||
|
||
remove_other_coins_from_list(vict->carrying, coin_obj);
|
||
for (i = 0; i < NUM_WEARS; i++)
|
||
remove_other_coins_from_list(GET_EQ(vict, i), coin_obj);
|
||
|
||
GET_COINS(vict) = value;
|
||
send_to_char(ch, "Ok.\r\n");
|
||
return (1);
|
||
}
|
||
case 15: /* height */
|
||
GET_HEIGHT(vict) = value;
|
||
affect_total(vict);
|
||
break;
|
||
case 16: /* hit */
|
||
vict->points.hit = RANGE(-9, vict->points.max_hit);
|
||
affect_total(vict);
|
||
break;
|
||
case 17: /* hunger */
|
||
if (!str_cmp(val_arg, "off")) {
|
||
GET_COND(vict, HUNGER) = -1;
|
||
send_to_char(ch, "%s's hunger is now off.\r\n", GET_NAME(vict));
|
||
} else if (is_number(val_arg)) {
|
||
value = atoi(val_arg);
|
||
RANGE(0, 24);
|
||
GET_COND(vict, HUNGER) = value;
|
||
send_to_char(ch, "%s's hunger set to %d.\r\n", GET_NAME(vict), value);
|
||
} else {
|
||
send_to_char(ch, "Must be 'off' or a value from 0 to 24.\r\n");
|
||
return (0);
|
||
}
|
||
break;
|
||
case 18: /* int */
|
||
if (IS_NPC(vict) || GET_LEVEL(vict) >= LVL_GRGOD)
|
||
RANGE(3, 25);
|
||
else
|
||
RANGE(3, 18);
|
||
vict->real_abils.intel = value;
|
||
affect_total(vict);
|
||
break;
|
||
case 19: /* invis */
|
||
if (GET_LEVEL(ch) < LVL_IMPL && ch != vict) {
|
||
send_to_char(ch, "You aren't godly enough for that!\r\n");
|
||
return (0);
|
||
}
|
||
GET_INVIS_LEV(vict) = RANGE(0, GET_LEVEL(vict));
|
||
break;
|
||
case 20: /* invistart */
|
||
SET_OR_REMOVE(PLR_FLAGS(vict), PLR_INVSTART);
|
||
break;
|
||
case 21: /* level */
|
||
if ((!IS_NPC(vict) && value > GET_LEVEL(ch)) || value > LVL_IMPL) {
|
||
send_to_char(ch, "You can't do that.\r\n");
|
||
return (0);
|
||
}
|
||
RANGE(1, LVL_IMPL);
|
||
vict->player.level = value;
|
||
break;
|
||
case 22: /* loadroom */
|
||
if (!str_cmp(val_arg, "off")) {
|
||
REMOVE_BIT_AR(PLR_FLAGS(vict), PLR_LOADROOM);
|
||
} else if (is_number(val_arg)) {
|
||
rvnum = atoi(val_arg);
|
||
if (real_room(rvnum) != NOWHERE) {
|
||
SET_BIT_AR(PLR_FLAGS(vict), PLR_LOADROOM);
|
||
GET_LOADROOM(vict) = rvnum;
|
||
send_to_char(ch, "%s will enter at room #%d.\r\n", GET_NAME(vict), GET_LOADROOM(vict));
|
||
} else {
|
||
send_to_char(ch, "That room does not exist!\r\n");
|
||
return (0);
|
||
}
|
||
} else {
|
||
send_to_char(ch, "Must be 'off' or a room's virtual number.\r\n");
|
||
return (0);
|
||
}
|
||
break;
|
||
case 23: /* mana */
|
||
vict->points.mana = RANGE(0, vict->points.max_mana);
|
||
affect_total(vict);
|
||
break;
|
||
case 24: /* maxhit */
|
||
vict->points.max_hit = RANGE(1, 5000);
|
||
affect_total(vict);
|
||
break;
|
||
case 25: /* maxmana */
|
||
vict->points.max_mana = RANGE(1, 5000);
|
||
affect_total(vict);
|
||
break;
|
||
case 26: /* maxstam */
|
||
vict->points.max_stamina = RANGE(1, 5000);
|
||
affect_total(vict);
|
||
break;
|
||
case 27: /* name */
|
||
if (ch != vict && GET_LEVEL(ch) < LVL_IMPL) {
|
||
send_to_char(ch, "Only Imps can change the name of other players.\r\n");
|
||
return (0);
|
||
}
|
||
if (!change_player_name(ch, vict, val_arg)) {
|
||
send_to_char(ch, "Name has not been changed!\r\n");
|
||
return (0);
|
||
}
|
||
break;
|
||
case 28: /* nodelete */
|
||
SET_OR_REMOVE(PLR_FLAGS(vict), PLR_NODELETE);
|
||
break;
|
||
case 29: /* nohassle */
|
||
if (GET_LEVEL(ch) < LVL_GOD && ch != vict) {
|
||
send_to_char(ch, "You aren't godly enough for that!\r\n");
|
||
return (0);
|
||
}
|
||
SET_OR_REMOVE(PRF_FLAGS(vict), PRF_NOHASSLE);
|
||
break;
|
||
case 30: /* nosummon */
|
||
SET_OR_REMOVE(PRF_FLAGS(vict), PRF_SUMMONABLE);
|
||
send_to_char(ch, "Nosummon %s for %s.\r\n", ONOFF(!on), GET_NAME(vict));
|
||
break;
|
||
case 31: /* nowiz */
|
||
SET_OR_REMOVE(PLR_FLAGS(vict), PLR_NOWIZLIST);
|
||
break;
|
||
case 32: /* olc */
|
||
if (is_abbrev(val_arg, "socials") || is_abbrev(val_arg, "actions") || is_abbrev(val_arg, "aedit"))
|
||
GET_OLC_ZONE(vict) = AEDIT_PERMISSION;
|
||
else if (is_abbrev(val_arg, "hedit") || is_abbrev(val_arg, "help"))
|
||
GET_OLC_ZONE(vict) = HEDIT_PERMISSION;
|
||
else if (*val_arg == '*' || is_abbrev(val_arg, "all"))
|
||
GET_OLC_ZONE(vict) = ALL_PERMISSION;
|
||
else if (is_abbrev(val_arg, "off"))
|
||
GET_OLC_ZONE(vict) = NOWHERE;
|
||
else if (!is_number(val_arg)) {
|
||
send_to_char(ch, "Value must be a zone number, 'aedit', 'hedit', 'off' or 'all'.\r\n");
|
||
return (0);
|
||
} else
|
||
GET_OLC_ZONE(vict) = atoi(val_arg);
|
||
break;
|
||
case 33: /* password */
|
||
if (GET_LEVEL(vict) >= LVL_GRGOD) {
|
||
send_to_char(ch, "You cannot change that.\r\n");
|
||
return (0);
|
||
}
|
||
strncpy(GET_PASSWD(vict), CRYPT(val_arg, GET_NAME(vict)), MAX_PWD_LENGTH); /* strncpy: OK (G_P:MAX_PWD_LENGTH) */
|
||
*(GET_PASSWD(vict) + MAX_PWD_LENGTH) = '\0';
|
||
send_to_char(ch, "Password changed to '%s'.\r\n", val_arg);
|
||
break;
|
||
case 34: /* poofin */
|
||
if ((vict == ch) || (GET_LEVEL(ch) == LVL_IMPL)) {
|
||
skip_spaces(&val_arg);
|
||
parse_at(val_arg);
|
||
|
||
if (POOFIN(vict))
|
||
free(POOFIN(vict));
|
||
|
||
if (!*val_arg)
|
||
POOFIN(vict) = NULL;
|
||
else
|
||
POOFIN(vict) = strdup(val_arg);
|
||
}
|
||
break;
|
||
case 35: /* poofout */
|
||
if ((vict == ch) || (GET_LEVEL(ch) == LVL_IMPL)) {
|
||
skip_spaces(&val_arg);
|
||
parse_at(val_arg);
|
||
|
||
if (POOFOUT(vict))
|
||
free(POOFOUT(vict));
|
||
|
||
if (!*val_arg)
|
||
POOFOUT(vict) = NULL;
|
||
else
|
||
POOFOUT(vict) = strdup(val_arg);
|
||
}
|
||
break;
|
||
case 36: /* quest */
|
||
SET_OR_REMOVE(PRF_FLAGS(vict), PRF_QUEST);
|
||
break;
|
||
case 37: /* room */
|
||
if ((rnum = real_room(value)) == NOWHERE) {
|
||
send_to_char(ch, "No room exists with that number.\r\n");
|
||
return (0);
|
||
}
|
||
if (IN_ROOM(vict) != NOWHERE)
|
||
char_from_room(vict);
|
||
char_to_room(vict, rnum);
|
||
break;
|
||
case 38: /* screenwidth */
|
||
GET_SCREEN_WIDTH(vict) = RANGE(40, 200);
|
||
break;
|
||
case 39: /* sex */
|
||
if ((i = search_block(val_arg, genders, FALSE)) < 0) {
|
||
send_to_char(ch, "Must be 'male', 'female', or 'neutral'.\r\n");
|
||
return (0);
|
||
}
|
||
GET_SEX(vict) = i;
|
||
break;
|
||
case 40: /* showvnums */
|
||
SET_OR_REMOVE(PRF_FLAGS(vict), PRF_SHOWVNUMS);
|
||
break;
|
||
case 41: /* siteok */
|
||
SET_OR_REMOVE(PLR_FLAGS(vict), PLR_SITEOK);
|
||
break;
|
||
case 42: /* skills/spells */
|
||
{
|
||
char local_buf[MAX_INPUT_LENGTH], *value_arg, *name_end;
|
||
char skill_name[MAX_INPUT_LENGTH];
|
||
int snum;
|
||
|
||
/* Make a writable copy and trim trailing spaces */
|
||
strlcpy(local_buf, val_arg, sizeof(local_buf));
|
||
{
|
||
int len = strlen(local_buf);
|
||
while (len > 0 && isspace((unsigned char)local_buf[len - 1])) {
|
||
local_buf[--len] = '\0';
|
||
}
|
||
}
|
||
|
||
if (!*local_buf) {
|
||
send_to_char(ch, "Usage: set <player> skill <skill-name> <0-100>\r\n");
|
||
return (0);
|
||
}
|
||
|
||
/* Find last word (the numeric value) by walking backwards */
|
||
name_end = local_buf + strlen(local_buf) - 1;
|
||
while (name_end > local_buf && !isspace((unsigned char)*name_end))
|
||
name_end--;
|
||
|
||
if (name_end <= local_buf) {
|
||
send_to_char(ch, "Usage: set <player> skill <skill-name> <0-100>\r\n");
|
||
return (0);
|
||
}
|
||
|
||
*name_end = '\0'; /* terminate skill name string */
|
||
value_arg = name_end + 1; /* point to numeric string */
|
||
|
||
/* Trim trailing whitespace from skill name */
|
||
while (name_end > local_buf && isspace((unsigned char)name_end[-1])) {
|
||
*--name_end = '\0';
|
||
}
|
||
|
||
char *skill_ptr = local_buf;
|
||
skip_spaces(&skill_ptr);
|
||
strlcpy(skill_name, skill_ptr, sizeof(skill_name));
|
||
|
||
if (!*skill_name || !*value_arg) {
|
||
send_to_char(ch, "Usage: set <player> skill <skill-name> <0-100>\r\n");
|
||
return (0);
|
||
}
|
||
|
||
if (IS_NPC(vict)) {
|
||
send_to_char(ch, "You can only set skills on player characters.\r\n");
|
||
return (0);
|
||
}
|
||
|
||
if (!is_number(value_arg)) {
|
||
send_to_char(ch, "The skill value must be a number from 0 to 100.\r\n");
|
||
return (0);
|
||
}
|
||
|
||
value = atoi(value_arg);
|
||
if (value < 0) value = 0;
|
||
if (value > 100) value = 100;
|
||
|
||
snum = find_skill_num(skill_name); /* handles case-insensitive, abbrev match */
|
||
if (snum <= 0) {
|
||
send_to_char(ch, "That skill or spell doesn't exist.\r\n");
|
||
return (0);
|
||
}
|
||
|
||
SET_SKILL(vict, snum, value);
|
||
|
||
send_to_char(ch, "Set %s's %s to %d%%.\r\n",
|
||
GET_NAME(vict), spell_info[snum].name, value);
|
||
|
||
if (vict != ch)
|
||
send_to_char(vict, "%s has set your %s to %d%%.\r\n",
|
||
GET_NAME(ch), spell_info[snum].name, value);
|
||
|
||
save_char(vict);
|
||
|
||
mudlog(CMP, MAX(LVL_GOD, GET_INVIS_LEV(ch)), TRUE,
|
||
"%s set %s's %s skill to %d.",
|
||
GET_NAME(ch), GET_NAME(vict), spell_info[snum].name, value);
|
||
|
||
}
|
||
break;
|
||
|
||
case 43: /* stam */
|
||
vict->points.stamina = RANGE(0, vict->points.max_stamina);
|
||
affect_total(vict);
|
||
break;
|
||
|
||
case 44: /* str */
|
||
if (IS_NPC(vict) || GET_LEVEL(vict) >= LVL_GRGOD)
|
||
RANGE(3, 25);
|
||
else
|
||
RANGE(3, 18);
|
||
vict->real_abils.str = value;
|
||
affect_total(vict);
|
||
break;
|
||
case 45: /* thirst */
|
||
if (!str_cmp(val_arg, "off")) {
|
||
GET_COND(vict, THIRST) = -1;
|
||
send_to_char(ch, "%s's thirst is now off.\r\n", GET_NAME(vict));
|
||
} else if (is_number(val_arg)) {
|
||
value = atoi(val_arg);
|
||
RANGE(0, 24);
|
||
GET_COND(vict, THIRST) = value;
|
||
send_to_char(ch, "%s's thirst set to %d.\r\n", GET_NAME(vict), value);
|
||
} else {
|
||
send_to_char(ch, "Must be 'off' or a value from 0 to 24.\r\n");
|
||
return (0);
|
||
}
|
||
break;
|
||
case 46: /* variable */
|
||
return perform_set_dg_var(ch, vict, val_arg);
|
||
case 47: /* weight */
|
||
GET_WEIGHT(vict) = value;
|
||
affect_total(vict);
|
||
break;
|
||
case 48: /* wis */
|
||
if (IS_NPC(vict) || GET_LEVEL(vict) >= LVL_GRGOD)
|
||
RANGE(3, 25);
|
||
else
|
||
RANGE(3, 18);
|
||
vict->real_abils.wis = value;
|
||
affect_total(vict);
|
||
break;
|
||
case 49: /* questpoints */
|
||
GET_QUESTPOINTS(vict) = RANGE(0, 100000000);
|
||
break;
|
||
case 50: /* questhistory */
|
||
qvnum = atoi(val_arg);
|
||
if (real_quest(qvnum) == NOTHING) {
|
||
send_to_char(ch, "That quest doesn't exist.\r\n");
|
||
return FALSE;
|
||
} else {
|
||
if (is_complete(vict, qvnum)) {
|
||
remove_completed_quest(vict, qvnum);
|
||
send_to_char(ch, "Quest %d removed from history for player %s.\r\n",
|
||
qvnum, GET_NAME(vict));
|
||
} else {
|
||
add_completed_quest(vict, qvnum);
|
||
send_to_char(ch, "Quest %d added to history for player %s.\r\n",
|
||
qvnum, GET_NAME(vict));
|
||
}
|
||
break;
|
||
}
|
||
case 51: /* species */
|
||
if ((i = parse_species(val_arg)) == SPECIES_UNDEFINED) {
|
||
send_to_char(ch, "That is not a species.\r\n");
|
||
return (0);
|
||
}
|
||
update_species(vict, i);
|
||
affect_total(vict);
|
||
send_to_char(ch, "You set %s's species to %s.\r\n",
|
||
get_char_sdesc(vict), get_species_name(GET_SPECIES(vict)));
|
||
break;
|
||
default:
|
||
send_to_char(ch, "Can't set that!\r\n");
|
||
return (0);
|
||
}
|
||
/* Show the new value of the variable */
|
||
if (set_fields[mode].type == BINARY) {
|
||
send_to_char(ch, "%s %s for %s.\r\n", set_fields[mode].cmd, ONOFF(on), GET_NAME(vict));
|
||
} else if (set_fields[mode].type == NUMBER) {
|
||
send_to_char(ch, "%s's %s set to %d.\r\n", GET_NAME(vict), set_fields[mode].cmd, value);
|
||
} else
|
||
send_to_char(ch, "%s", CONFIG_OK);
|
||
|
||
return (1);
|
||
}
|
||
|
||
static void show_set_help(struct char_data *ch)
|
||
{
|
||
const char *set_levels[] = {"Imm", "God", "GrGod", "IMP"};
|
||
const char *set_targets[] = {"PC", "NPC", "BOTH"};
|
||
const char *set_types[] = {"MISC", "BINARY", "NUMBER"};
|
||
char buf[MAX_STRING_LENGTH];
|
||
int i, len=0, add_len=0;
|
||
|
||
len = snprintf(buf, sizeof(buf), "%sCommand Lvl Who? Type%s\r\n", CCCYN(ch, C_NRM), CCNRM(ch, C_NRM));
|
||
for (i = 0; *(set_fields[i].cmd) != '\n'; i++) {
|
||
if (set_fields[i].level <= GET_LEVEL(ch)) {
|
||
add_len = snprintf(buf+len, sizeof(buf)-len, "%-20s%-5s %-4s %-6s\r\n", set_fields[i].cmd,
|
||
set_levels[((int)(set_fields[i].level) - LVL_IMMORT)],
|
||
set_targets[(int)(set_fields[i].pcnpc)-1],
|
||
set_types[(int)(set_fields[i].type)]);
|
||
len += add_len;
|
||
}
|
||
}
|
||
page_string(ch->desc, buf, TRUE);
|
||
}
|
||
|
||
static struct obj_data *find_inventory_coin(struct char_data *ch)
|
||
{
|
||
struct obj_data *obj;
|
||
|
||
if (!ch)
|
||
return NULL;
|
||
|
||
for (obj = ch->carrying; obj; obj = obj->next_content)
|
||
if (GET_OBJ_TYPE(obj) == ITEM_MONEY)
|
||
return obj;
|
||
|
||
return NULL;
|
||
}
|
||
|
||
static void remove_other_coins_from_list(struct obj_data *list, struct obj_data *keep)
|
||
{
|
||
struct obj_data *obj, *next_obj;
|
||
|
||
for (obj = list; obj; obj = next_obj) {
|
||
next_obj = obj->next_content;
|
||
|
||
if (obj->contains)
|
||
remove_other_coins_from_list(obj->contains, keep);
|
||
|
||
if (obj != keep && GET_OBJ_TYPE(obj) == ITEM_MONEY)
|
||
extract_obj(obj);
|
||
}
|
||
}
|
||
|
||
ACMD(do_set)
|
||
{
|
||
struct char_data *vict = NULL, *cbuf = NULL;
|
||
char field[MAX_INPUT_LENGTH], name[MAX_INPUT_LENGTH], buf[MAX_INPUT_LENGTH];
|
||
int mode, len, player_i = 0, retval;
|
||
char is_file = 0, is_player = 0;
|
||
|
||
half_chop(argument, name, buf);
|
||
|
||
if (!strcmp(name, "file")) {
|
||
is_file = 1;
|
||
half_chop(buf, name, buf);
|
||
} else if (!str_cmp(name, "help")) {
|
||
show_set_help(ch);
|
||
return;
|
||
} else if (!str_cmp(name, "player")) {
|
||
is_player = 1;
|
||
half_chop(buf, name, buf);
|
||
} else if (!str_cmp(name, "mob"))
|
||
half_chop(buf, name, buf);
|
||
|
||
if (!is_file && !is_player && !str_cmp(name, "species")) {
|
||
char val[MAX_INPUT_LENGTH];
|
||
char target[MAX_INPUT_LENGTH];
|
||
|
||
half_chop(buf, val, target);
|
||
if (!*val || !*target) {
|
||
send_to_char(ch, "Usage: set species <type> <target>\r\n");
|
||
return;
|
||
}
|
||
strlcpy(field, "species", sizeof(field));
|
||
strlcpy(name, target, sizeof(name));
|
||
strlcpy(buf, val, sizeof(buf));
|
||
} else {
|
||
half_chop(buf, field, buf);
|
||
}
|
||
|
||
if (!*name || !*field) {
|
||
send_to_char(ch, "Usage: set <victim> <field> <value>\r\n");
|
||
send_to_char(ch, " %sset help%s will display valid fields\r\n", CCYEL(ch, C_NRM), CCNRM(ch, C_NRM));
|
||
return;
|
||
}
|
||
|
||
/* find the target */
|
||
if (!is_file) {
|
||
if (is_player) {
|
||
if (!(vict = get_player_vis(ch, name, NULL, FIND_CHAR_WORLD))) {
|
||
send_to_char(ch, "There is no such player.\r\n");
|
||
return;
|
||
}
|
||
} else { /* is_mob */
|
||
if (!(vict = get_char_vis(ch, name, NULL, FIND_CHAR_WORLD))) {
|
||
send_to_char(ch, "There is no such creature.\r\n");
|
||
return;
|
||
}
|
||
}
|
||
} else if (is_file) {
|
||
/* try to load the player off disk */
|
||
CREATE(cbuf, struct char_data, 1);
|
||
clear_char(cbuf);
|
||
CREATE(cbuf->player_specials, struct player_special_data, 1);
|
||
new_mobile_data(cbuf);
|
||
if ((player_i = load_char(name, cbuf)) > -1) {
|
||
if (GET_LEVEL(cbuf) > GET_LEVEL(ch)) {
|
||
free_char(cbuf);
|
||
send_to_char(ch, "Sorry, you can't do that.\r\n");
|
||
return;
|
||
}
|
||
vict = cbuf;
|
||
} else {
|
||
free_char(cbuf);
|
||
send_to_char(ch, "There is no such player.\r\n");
|
||
return;
|
||
}
|
||
}
|
||
|
||
/* find the command in the list */
|
||
len = strlen(field);
|
||
for (mode = 0; *(set_fields[mode].cmd) != '\n'; mode++)
|
||
if (!strncmp(field, set_fields[mode].cmd, len))
|
||
break;
|
||
|
||
if (*(set_fields[mode].cmd) == '\n') {
|
||
retval = 0; /* skips saving below */
|
||
send_to_char(ch, "Can't set that!\r\n");
|
||
} else
|
||
/* perform the set */
|
||
retval = perform_set(ch, vict, mode, buf);
|
||
|
||
/* save the character if a change was made */
|
||
if (retval) {
|
||
if (!is_file && !IS_NPC(vict))
|
||
save_char(vict);
|
||
if (is_file) {
|
||
GET_PFILEPOS(cbuf) = player_i;
|
||
save_char(cbuf);
|
||
send_to_char(ch, "Saved in file.\r\n");
|
||
}
|
||
}
|
||
|
||
/* free the memory if we allocated it earlier */
|
||
if (is_file)
|
||
free_char(cbuf);
|
||
}
|
||
|
||
ACMD(do_saveall)
|
||
{
|
||
if (GET_LEVEL(ch) < LVL_BUILDER)
|
||
send_to_char (ch, "You are not holy enough to use this privelege.\n\r");
|
||
else {
|
||
save_all();
|
||
House_save_all();
|
||
send_to_char(ch, "World and house files saved.\n\r");
|
||
}
|
||
}
|
||
|
||
ACMD(do_links)
|
||
{
|
||
zone_rnum zrnum;
|
||
zone_vnum zvnum;
|
||
room_rnum nr, to_room;
|
||
int first, last, j;
|
||
char arg[MAX_INPUT_LENGTH];
|
||
|
||
|
||
skip_spaces(&argument);
|
||
one_argument(argument, arg);
|
||
|
||
if (!is_number(arg)) {
|
||
zrnum = world[IN_ROOM(ch)].zone;
|
||
zvnum = zone_table[zrnum].number;
|
||
} else {
|
||
zvnum = atoi(arg);
|
||
zrnum = real_zone(zvnum);
|
||
}
|
||
|
||
if (zrnum == NOWHERE || zvnum == NOWHERE) {
|
||
send_to_char(ch, "No zone was found with that number.\n\r");
|
||
return;
|
||
}
|
||
|
||
last = zone_table[zrnum].top;
|
||
first = zone_table[zrnum].bot;
|
||
|
||
send_to_char(ch, "Zone %d is linked to the following zones:\r\n", zvnum);
|
||
for (nr = 0; nr <= top_of_world && (GET_ROOM_VNUM(nr) <= last); nr++) {
|
||
if (GET_ROOM_VNUM(nr) >= first) {
|
||
for (j = 0; j < DIR_COUNT; j++) {
|
||
if (world[nr].dir_option[j]) {
|
||
to_room = world[nr].dir_option[j]->to_room;
|
||
if (to_room != NOWHERE && (zrnum != world[to_room].zone))
|
||
send_to_char(ch, "%3d %-30s at %5d (%-5s) ---> %5d\r\n",
|
||
zone_table[world[to_room].zone].number,
|
||
zone_table[world[to_room].zone].name,
|
||
GET_ROOM_VNUM(nr), dirs[j], world[to_room].number);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Zone Checker Code below */
|
||
/*mob limits*/
|
||
#define MAX_EXP_ALLOWED GET_LEVEL(mob)*GET_LEVEL(mob) * 120
|
||
#define MAX_LEVEL_ALLOWED LVL_IMPL
|
||
#define GET_OBJ_AVG_DAM(obj) (((GET_OBJ_VAL(obj, 2) + 1) / 2.0) * GET_OBJ_VAL(obj, 1))
|
||
/* arbitrary limit for per round dam */
|
||
#define MAX_MOB_DAM_ALLOWED 500
|
||
|
||
#define ZCMD2 zone_table[zone].cmd[cmd_no] /*fom DB.C*/
|
||
|
||
/*item limits*/
|
||
#define MAX_DAM_ALLOWED 50 /* for weapons - avg. dam*/
|
||
#define MAX_AFFECTS_ALLOWED 3
|
||
#define MAX_OBJ_COINS_ALLOWED 1000000
|
||
|
||
/* Armor class limits*/
|
||
#define TOTAL_WEAR_CHECKS (NUM_ITEM_WEARS-2) /*minus Wield and Take*/
|
||
static struct zcheck_armor {
|
||
bitvector_t bitvector; /* from Structs.h */
|
||
int ac_allowed; /* Max. AC allowed for this body part */
|
||
char *message; /* phrase for error message */
|
||
} zarmor[] = {
|
||
{ITEM_WEAR_FINGER, 10, "Ring"},
|
||
{ITEM_WEAR_NECK, 10, "Necklace"},
|
||
{ITEM_WEAR_BACK, 10, "Backpack"},
|
||
{ITEM_WEAR_BODY, 10, "Body armor"},
|
||
{ITEM_WEAR_HEAD, 10, "Head gear"},
|
||
{ITEM_WEAR_LEGS, 10, "Legwear"},
|
||
{ITEM_WEAR_FEET, 10, "Footwear"},
|
||
{ITEM_WEAR_HANDS, 10, "Glove"},
|
||
{ITEM_WEAR_ARMS, 10, "Armwear"},
|
||
{ITEM_WEAR_SHIELD, 10, "Shield"},
|
||
{ITEM_WEAR_ABOUT, 10, "Cloak"},
|
||
{ITEM_WEAR_WAIST, 10, "Belt"},
|
||
{ITEM_WEAR_WRIST, 10, "Wristwear"},
|
||
{ITEM_WEAR_HOLD, 10, "Held item"}
|
||
};
|
||
|
||
/* Applies limits !! Very Important: Keep these in the same order as in Structs.h.
|
||
* To ignore an apply, set max_aff to -99. These will be ignored if MAX_APPLIES_LIMIT = 0 */
|
||
static struct zcheck_affs {
|
||
int aff_type; /*from Structs.h*/
|
||
int min_aff; /*min. allowed value*/
|
||
int max_aff; /*max. allowed value*/
|
||
char *message; /*phrase for error message*/
|
||
} zaffs[] = {
|
||
{APPLY_NONE, 0, -99, "unused0"},
|
||
{APPLY_STR, -5, 3, "strength"},
|
||
{APPLY_DEX, -5, 3, "dexterity"},
|
||
{APPLY_INT, -5, 3, "intelligence"},
|
||
{APPLY_WIS, -5, 3, "wisdom"},
|
||
{APPLY_CON, -5, 3, "constitution"},
|
||
{APPLY_CHA, -5, 3, "charisma"},
|
||
{APPLY_CLASS, 0, 0, "class"},
|
||
{APPLY_LEVEL, 0, 0, "level"},
|
||
{APPLY_AGE, -10, 10, "age"},
|
||
{APPLY_CHAR_WEIGHT,-50, 50, "character weight"},
|
||
{APPLY_CHAR_HEIGHT,-50, 50, "character height"},
|
||
{APPLY_MANA, -50, 50, "mana"},
|
||
{APPLY_HIT, -50, 50, "hit points"},
|
||
{APPLY_STAMINA, -50, 50, "stamina"},
|
||
{APPLY_COINS, 0, 0, "coins"},
|
||
{APPLY_EXP, 0, 0, "experience"},
|
||
{APPLY_AC, -10, 10, "magical AC"},
|
||
{APPLY_SAVE_STR, -2, 2, "saving throw (Strength)"},
|
||
{APPLY_SAVE_DEX, -2, 2, "saving throw (Dexterity)"},
|
||
{APPLY_SAVE_CON, -2, 2, "saving throw (Constitution)"},
|
||
{APPLY_SAVE_INT, -2, 2, "saving throw (Intelligence)"},
|
||
{APPLY_SAVE_WIS, -2, 2, "saving throw (Wisdom)"},
|
||
{APPLY_SAVE_CHA, -2, 2, "saving throw (Charisma)"}
|
||
};
|
||
|
||
/*room limits*/
|
||
/* Off limit zones are any zones a player should NOT be able to walk to (ex. Limbo) */
|
||
static const int offlimit_zones[] = {0,12,13,14,-1}; /*what zones can no room connect to (virtual num) */
|
||
#define MIN_ROOM_DESC_LENGTH 80 /* at least one line - set to 0 to not care. */
|
||
#define MAX_COLOUMN_WIDTH 80 /* at most 80 chars per line */
|
||
|
||
ACMD (do_zcheck)
|
||
{
|
||
zone_rnum zrnum;
|
||
struct obj_data *obj;
|
||
struct char_data *mob = NULL;
|
||
room_vnum exroom=0;
|
||
int ac=0;
|
||
int affs=0, value;
|
||
int i = 0, j = 0, k = 0, l = 0, m = 0, found = 0; /* found is used as a 'send now' flag*/
|
||
char buf[MAX_STRING_LENGTH];
|
||
float avg_dam;
|
||
size_t len = 0;
|
||
struct extra_descr_data *ext, *ext2;
|
||
one_argument(argument, buf);
|
||
|
||
if (!is_number(buf) || !strcmp(buf, "."))
|
||
zrnum = world[IN_ROOM(ch)].zone;
|
||
else
|
||
zrnum = real_zone(atoi(buf));
|
||
|
||
if (zrnum == NOWHERE) {
|
||
send_to_char(ch, "Check what zone ?\r\n");
|
||
return;
|
||
} else
|
||
send_to_char(ch, "Checking zone %d!\r\n", zone_table[zrnum].number);
|
||
|
||
/* Check mobs */
|
||
|
||
send_to_char(ch, "Checking Mobs for limits...\r\n");
|
||
/*check mobs first*/
|
||
for (i=0; i<top_of_mobt;i++) {
|
||
if (real_zone_by_thing(mob_index[i].vnum) == zrnum) { /*is mob in this zone?*/
|
||
mob = &mob_proto[i];
|
||
if (!strcmp(mob->player.name, "mob unfinished") && (found=1))
|
||
len += snprintf(buf + len, sizeof(buf) - len,
|
||
"- Alias hasn't been set.\r\n");
|
||
|
||
if (!strcmp(mob->player.short_descr, "the unfinished mob") && (found=1))
|
||
len += snprintf(buf + len, sizeof(buf) - len,
|
||
"- Short description hasn't been set.\r\n");
|
||
|
||
if (!strncmp(mob->player.long_descr, "An unfinished mob stands here.", 30) && (found=1))
|
||
len += snprintf(buf + len, sizeof(buf) - len,
|
||
"- Long description hasn't been set.\r\n");
|
||
|
||
if (mob->player.description && *mob->player.description) {
|
||
if (!strncmp(mob->player.description, "It looks unfinished.", 20) && (found=1))
|
||
len += snprintf(buf + len, sizeof(buf) - len,
|
||
"- Description hasn't been set.\r\n");
|
||
else if (strncmp(mob->player.description, " ", 3) && (found=1))
|
||
len += snprintf(buf + len, sizeof(buf) - len,
|
||
"- Description hasn't been formatted. (/fi)\r\n");
|
||
}
|
||
|
||
if (GET_LEVEL(mob)>MAX_LEVEL_ALLOWED && (found=1))
|
||
len += snprintf(buf + len, sizeof(buf) - len,
|
||
"- Is level %d (limit: 1-%d)\r\n",
|
||
GET_LEVEL(mob), MAX_LEVEL_ALLOWED);
|
||
|
||
/* --- 5e-style average unarmed damage check --- */
|
||
{
|
||
int prof = 0;
|
||
int str_mod = GET_ABILITY_MOD(GET_STR(mob));
|
||
int die_size;
|
||
|
||
/* derive proficiency tier; mobs use their stored unarmed skill */
|
||
prof = GET_PROFICIENCY(GET_SKILL(mob, SKILL_UNARMED));
|
||
|
||
switch (prof) {
|
||
case 0: die_size = 4; break; /* initial unarmed skill die size */
|
||
case 1: die_size = 4; break;
|
||
case 2: die_size = 6; break; /* ~40 skill level */
|
||
case 3: die_size = 6; break;
|
||
case 4: die_size = 8; break; /* ~80 skill level */
|
||
case 5: die_size = 10; break; /* max skill level */
|
||
default: die_size = 12; break;
|
||
}
|
||
|
||
/* expected average damage = average roll + STR + proficiency */
|
||
avg_dam = ((die_size + 1) / 2.0) + str_mod + prof;
|
||
|
||
if (avg_dam > MAX_MOB_DAM_ALLOWED && (found=1))
|
||
len += snprintf(buf + len, sizeof(buf) - len,
|
||
"- average unarmed damage of %4.1f is too high (limit: %d)\r\n",
|
||
avg_dam, MAX_MOB_DAM_ALLOWED);
|
||
|
||
if (prof == 0 && str_mod <= 0 && (found=1))
|
||
len += snprintf(buf + len, sizeof(buf) - len,
|
||
"- No unarmed combat proficiency set (add skill or weapon)\r\n");
|
||
}
|
||
|
||
if (GET_EXP(mob)>MAX_EXP_ALLOWED && (found=1))
|
||
len += snprintf(buf + len, sizeof(buf) - len,
|
||
"- Has %d experience (limit: %d)\r\n",
|
||
GET_EXP(mob), MAX_EXP_ALLOWED);
|
||
if ((AFF_FLAGGED(mob, AFF_CHARM) || AFF_FLAGGED(mob, AFF_POISON)) && (found = 1))
|
||
len += snprintf(buf + len, sizeof(buf) - len,
|
||
"- Has illegal affection bits set (%s %s)\r\n",
|
||
AFF_FLAGGED(mob, AFF_CHARM) ? "CHARM" : "",
|
||
AFF_FLAGGED(mob, AFF_POISON) ? "POISON" : "");
|
||
|
||
|
||
if (!MOB_FLAGGED(mob, MOB_SENTINEL) && !MOB_FLAGGED(mob, MOB_STAY_ZONE) && (found = 1))
|
||
len += snprintf(buf + len, sizeof(buf) - len,
|
||
"- Neither SENTINEL nor STAY_ZONE bits set.\r\n");
|
||
|
||
if (MOB_FLAGGED(mob, MOB_SPEC) && (found = 1))
|
||
snprintf(buf + len, sizeof(buf) - len,
|
||
"- SPEC flag needs to be removed.\r\n");
|
||
|
||
/* Additional mob checks.*/
|
||
if (found) {
|
||
send_to_char(ch,
|
||
"%s[%5d]%s %-30s: %s\r\n",
|
||
CCCYN(ch, C_NRM), GET_MOB_VNUM(mob),
|
||
CCYEL(ch, C_NRM), GET_NAME(mob),
|
||
CCNRM(ch, C_NRM));
|
||
send_to_char(ch, "%s", buf);
|
||
}
|
||
/* reset buffers and found flag */
|
||
strcpy(buf, "");
|
||
found = 0;
|
||
len = 0;
|
||
} /* mob is in zone */
|
||
} /* check mobs */
|
||
|
||
/* Check objects */
|
||
send_to_char(ch, "\r\nChecking Objects for limits...\r\n");
|
||
for (i=0; i<top_of_objt; i++) {
|
||
if (real_zone_by_thing(obj_index[i].vnum) == zrnum) { /*is object in this zone?*/
|
||
obj = &obj_proto[i];
|
||
switch (GET_OBJ_TYPE(obj)) {
|
||
case ITEM_MONEY:
|
||
if ((value = GET_OBJ_VAL(obj, 0))>MAX_OBJ_COINS_ALLOWED && (found=1))
|
||
len += snprintf(buf + len, sizeof(buf) - len,
|
||
"- Is worth %d (money limit %d coins).\r\n",
|
||
value, MAX_OBJ_COINS_ALLOWED);
|
||
break;
|
||
case ITEM_WEAPON:
|
||
if (GET_OBJ_VAL(obj, 3) >= NUM_ATTACK_TYPES && (found=1))
|
||
len += snprintf(buf + len, sizeof(buf) - len,
|
||
"- has out of range attack type %d.\r\n",
|
||
GET_OBJ_VAL(obj, 3));
|
||
|
||
if (GET_OBJ_AVG_DAM(obj)>MAX_DAM_ALLOWED && (found=1))
|
||
len += snprintf(buf + len, sizeof(buf) - len,
|
||
"- Damroll is %2.1f (limit %d)\r\n",
|
||
GET_OBJ_AVG_DAM(obj), MAX_DAM_ALLOWED);
|
||
break;
|
||
case ITEM_ARMOR:
|
||
ac=GET_OBJ_VAL(obj,0);
|
||
for (j=0; j<TOTAL_WEAR_CHECKS;j++) {
|
||
if (CAN_WEAR(obj,zarmor[j].bitvector) && (ac>zarmor[j].ac_allowed) && (found=1))
|
||
len += snprintf(buf + len, sizeof(buf) - len,
|
||
"- Has AC %d (%s limit is %d)\r\n",
|
||
ac, zarmor[j].message, zarmor[j].ac_allowed);
|
||
}
|
||
break;
|
||
|
||
} /*switch on Item_Type*/
|
||
|
||
if (!CAN_WEAR(obj, ITEM_WEAR_TAKE)) {
|
||
if ((GET_OBJ_COST(obj) || (GET_OBJ_WEIGHT(obj) && GET_OBJ_TYPE(obj) != ITEM_FOUNTAIN)) &&
|
||
(found = 1))
|
||
len += snprintf(buf + len, sizeof(buf) - len,
|
||
"- is NO_TAKE, but has cost (%d) or weight (%d) set.\r\n",
|
||
GET_OBJ_COST(obj), GET_OBJ_WEIGHT(obj));
|
||
} else {
|
||
if (GET_OBJ_COST(obj) == 0 && (found=1) && GET_OBJ_TYPE(obj) != ITEM_TRASH)
|
||
len += snprintf(buf + len, sizeof(buf) - len,
|
||
"- has 0 cost (min. 1).\r\n");
|
||
|
||
if (GET_OBJ_WEIGHT(obj) == 0 && (found=1))
|
||
len += snprintf(buf + len, sizeof(buf) - len,
|
||
"- has 0 weight (min. 1).\r\n");
|
||
|
||
if (GET_OBJ_WEIGHT(obj) > MAX_OBJ_WEIGHT && (found=1))
|
||
len += snprintf(buf + len, sizeof(buf) - len,
|
||
" Weight is too high: %d (limit %d).\r\n",
|
||
GET_OBJ_WEIGHT(obj), MAX_OBJ_WEIGHT);
|
||
|
||
|
||
if (GET_OBJ_COST(obj) > MAX_OBJ_COST && (found=1))
|
||
len += snprintf(buf + len, sizeof(buf) - len,
|
||
"- has %d cost (max %d).\r\n",
|
||
GET_OBJ_COST(obj), MAX_OBJ_COST);
|
||
}
|
||
|
||
if (GET_OBJ_LEVEL(obj) > LVL_IMMORT-1 && (found=1))
|
||
len += snprintf(buf + len, sizeof(buf) - len,
|
||
"- has min level set to %d (max %d).\r\n",
|
||
GET_OBJ_LEVEL(obj), LVL_IMMORT-1);
|
||
|
||
if (obj->main_description && *obj->main_description &&
|
||
GET_OBJ_TYPE(obj) != ITEM_STAFF &&
|
||
GET_OBJ_TYPE(obj) != ITEM_WAND &&
|
||
GET_OBJ_TYPE(obj) != ITEM_SCROLL &&
|
||
GET_OBJ_TYPE(obj) != ITEM_NOTE && (found=1))
|
||
len += snprintf(buf + len, sizeof(buf) - len,
|
||
"- has main_description set, but is inappropriate type.\r\n");
|
||
|
||
/*first check for over-all affections*/
|
||
for (affs=0, j = 0; j < MAX_OBJ_AFFECT; j++)
|
||
if (obj->affected[j].modifier) affs++;
|
||
|
||
if (affs>MAX_AFFECTS_ALLOWED && (found=1))
|
||
len += snprintf(buf + len, sizeof(buf) - len,
|
||
"- has %d affects (limit %d).\r\n",
|
||
affs, MAX_AFFECTS_ALLOWED);
|
||
|
||
/*check for out of range affections. */
|
||
for (j=0;j<MAX_OBJ_AFFECT;j++)
|
||
if (zaffs[(int)obj->affected[j].location].max_aff != -99 && /* only care if a range is set */
|
||
(obj->affected[j].modifier > zaffs[(int)obj->affected[j].location].max_aff ||
|
||
obj->affected[j].modifier < zaffs[(int)obj->affected[j].location].min_aff ||
|
||
zaffs[(int)obj->affected[j].location].min_aff == zaffs[(int)obj->affected[j].location].max_aff) && (found=1))
|
||
len += snprintf(buf + len, sizeof(buf) - len,
|
||
"- apply to %s is %d (limit %d - %d).\r\n",
|
||
zaffs[(int)obj->affected[j].location].message,
|
||
obj->affected[j].modifier,
|
||
zaffs[(int)obj->affected[j].location].min_aff,
|
||
zaffs[(int)obj->affected[j].location].max_aff);
|
||
|
||
|
||
for (ext2 = NULL, ext = obj->ex_description; ext; ext = ext->next)
|
||
if (strncmp(ext->description, " ", 3))
|
||
ext2 = ext;
|
||
|
||
if (ext2 && (found = 1))
|
||
snprintf(buf + len, sizeof(buf) - len,
|
||
"- has unformatted extra description\r\n");
|
||
/* Additional object checks. */
|
||
if (found) {
|
||
send_to_char(ch, "[%5d] %-30s: \r\n", GET_OBJ_VNUM(obj), obj->short_description);
|
||
send_to_char(ch, "%s", buf);
|
||
}
|
||
strcpy(buf, "");
|
||
len = 0;
|
||
found = 0;
|
||
} /*object is in zone*/
|
||
} /*check objects*/
|
||
|
||
/* Check rooms */
|
||
send_to_char(ch, "\r\nChecking Rooms for limits...\r\n");
|
||
for (i=0; i<top_of_world;i++) {
|
||
if (world[i].zone==zrnum) {
|
||
for (j = 0; j < DIR_COUNT; j++) {
|
||
/*check for exit, but ignore off limits if you're in an offlimit zone*/
|
||
if (!world[i].dir_option[j])
|
||
continue;
|
||
exroom=world[i].dir_option[j]->to_room;
|
||
if (exroom==NOWHERE)
|
||
continue;
|
||
if (world[exroom].zone == zrnum)
|
||
continue;
|
||
if (world[exroom].zone == world[i].zone)
|
||
continue;
|
||
|
||
for (k=0;offlimit_zones[k] != -1;k++) {
|
||
if (world[exroom].zone == real_zone(offlimit_zones[k]) && (found = 1))
|
||
len += snprintf(buf + len, sizeof(buf) - len,
|
||
"- Exit %s cannot connect to %d (zone off limits).\r\n",
|
||
dirs[j], world[exroom].number);
|
||
} /* for (k.. */
|
||
} /* cycle directions */
|
||
|
||
if (ROOM_FLAGGED(i, ROOM_ATRIUM) || ROOM_FLAGGED(i, ROOM_HOUSE) || ROOM_FLAGGED(i, ROOM_HOUSE_CRASH) || ROOM_FLAGGED(i, ROOM_OLC) || ROOM_FLAGGED(i, ROOM_BFS_MARK))
|
||
len += snprintf(buf + len, sizeof(buf) - len,
|
||
"- Has illegal affection bits set (%s %s %s %s %s)\r\n",
|
||
ROOM_FLAGGED(i, ROOM_ATRIUM) ? "ATRIUM" : "",
|
||
ROOM_FLAGGED(i, ROOM_HOUSE) ? "HOUSE" : "",
|
||
ROOM_FLAGGED(i, ROOM_HOUSE_CRASH) ? "HCRSH" : "",
|
||
ROOM_FLAGGED(i, ROOM_OLC) ? "OLC" : "",
|
||
ROOM_FLAGGED(i, ROOM_BFS_MARK) ? "*" : "");
|
||
|
||
if ((MIN_ROOM_DESC_LENGTH) && strlen(world[i].description)<MIN_ROOM_DESC_LENGTH && (found=1))
|
||
len += snprintf(buf + len, sizeof(buf) - len,
|
||
"- Room description is too short. (%4.4d of min. %d characters).\r\n",
|
||
(int)strlen(world[i].description), MIN_ROOM_DESC_LENGTH);
|
||
|
||
if (strncmp(world[i].description, " ", 3) && (found=1))
|
||
len += snprintf(buf + len, sizeof(buf) - len,
|
||
"- Room description not formatted with indent (/fi in the editor).\r\n");
|
||
|
||
/* strcspan = size of text in first arg before any character in second arg */
|
||
if ((strcspn(world[i].description, "\r\n")>MAX_COLOUMN_WIDTH) && (found=1))
|
||
len += snprintf(buf + len, sizeof(buf) - len,
|
||
"- Room description not wrapped at %d chars (/fi in the editor).\r\n",
|
||
MAX_COLOUMN_WIDTH);
|
||
|
||
for (ext2 = NULL, ext = world[i].ex_description; ext; ext = ext->next)
|
||
if (strncmp(ext->description, " ", 3))
|
||
ext2 = ext;
|
||
|
||
if (ext2 && (found = 1))
|
||
len += snprintf(buf + len, sizeof(buf) - len,
|
||
"- has unformatted extra description\r\n");
|
||
|
||
if (found) {
|
||
send_to_char(ch, "[%5d] %-30s: \r\n",
|
||
world[i].number, world[i].name ? world[i].name : "An unnamed room");
|
||
send_to_char(ch, "%s", buf);
|
||
strcpy(buf, "");
|
||
len = 0;
|
||
found = 0;
|
||
}
|
||
} /*is room in this zone?*/
|
||
} /*checking rooms*/
|
||
|
||
for (i=0; i<top_of_world;i++) {
|
||
if (world[i].zone==zrnum) {
|
||
m++;
|
||
for (j = 0, k = 0; j < DIR_COUNT; j++)
|
||
if (!world[i].dir_option[j])
|
||
k++;
|
||
|
||
if (k == DIR_COUNT)
|
||
l++;
|
||
}
|
||
}
|
||
if (l * 3 > m)
|
||
send_to_char(ch, "More than 1/3 of the rooms are not linked.\r\n");
|
||
|
||
}
|
||
|
||
static void mob_checkload(struct char_data *ch, mob_vnum mvnum)
|
||
{
|
||
int cmd_no;
|
||
zone_rnum zone;
|
||
mob_rnum mrnum = real_mobile(mvnum);
|
||
|
||
if (mrnum == NOBODY) {
|
||
send_to_char(ch, "That mob does not exist.\r\n");
|
||
return;
|
||
}
|
||
|
||
send_to_char(ch, "Checking load info for the mob %s...\r\n",
|
||
mob_proto[mrnum].player.short_descr);
|
||
|
||
for (zone=0; zone <= top_of_zone_table; zone++) {
|
||
for (cmd_no = 0; ZCMD2.command != 'S'; cmd_no++) {
|
||
if (ZCMD2.command != 'M')
|
||
continue;
|
||
|
||
/* read a mobile */
|
||
if (ZCMD2.arg1 == mrnum) {
|
||
send_to_char(ch, " [%5d] %s (%d MAX)\r\n",
|
||
world[ZCMD2.arg3].number,
|
||
world[ZCMD2.arg3].name,
|
||
ZCMD2.arg2);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
static void obj_checkload(struct char_data *ch, obj_vnum ovnum)
|
||
{
|
||
int cmd_no;
|
||
zone_rnum zone;
|
||
obj_rnum ornum = real_object(ovnum);
|
||
room_vnum lastroom_v = 0;
|
||
room_rnum lastroom_r = 0;
|
||
mob_rnum lastmob_r = 0;
|
||
|
||
if (ornum ==NOTHING) {
|
||
send_to_char(ch, "That object does not exist.\r\n");
|
||
return;
|
||
}
|
||
|
||
send_to_char(ch, "Checking load info for the obj %s...\r\n",
|
||
obj_proto[ornum].short_description);
|
||
|
||
for (zone=0; zone <= top_of_zone_table; zone++) {
|
||
for (cmd_no = 0; ZCMD2.command != 'S'; cmd_no++) {
|
||
switch (ZCMD2.command) {
|
||
case 'M':
|
||
lastroom_v = world[ZCMD2.arg3].number;
|
||
lastroom_r = ZCMD2.arg3;
|
||
lastmob_r = ZCMD2.arg1;
|
||
break;
|
||
case 'O': /* read an object */
|
||
lastroom_v = world[ZCMD2.arg3].number;
|
||
lastroom_r = ZCMD2.arg3;
|
||
if (ZCMD2.arg1 == ornum)
|
||
send_to_char(ch, " [%5d] %s (%d Max)\r\n",
|
||
lastroom_v,
|
||
world[lastroom_r].name,
|
||
ZCMD2.arg2);
|
||
break;
|
||
case 'P': /* object to object */
|
||
if (ZCMD2.arg1 == ornum)
|
||
send_to_char(ch, " [%5d] %s (Put in another object [%d Max])\r\n",
|
||
lastroom_v,
|
||
world[lastroom_r].name,
|
||
ZCMD2.arg2);
|
||
break;
|
||
case 'G': /* obj_to_char */
|
||
if (ZCMD2.arg1 == ornum)
|
||
send_to_char(ch, " [%5d] %s (Given to %s [%d][%d Max])\r\n",
|
||
lastroom_v,
|
||
world[lastroom_r].name,
|
||
mob_proto[lastmob_r].player.short_descr,
|
||
mob_index[lastmob_r].vnum,
|
||
ZCMD2.arg2);
|
||
break;
|
||
case 'E': /* object to equipment list */
|
||
if (ZCMD2.arg1 == ornum)
|
||
send_to_char(ch, " [%5d] %s (Equipped to %s [%d][%d Max])\r\n",
|
||
lastroom_v,
|
||
world[lastroom_r].name,
|
||
mob_proto[lastmob_r].player.short_descr,
|
||
mob_index[lastmob_r].vnum,
|
||
ZCMD2.arg2);
|
||
break;
|
||
case 'R': /* rem obj from room */
|
||
lastroom_v = world[ZCMD2.arg1].number;
|
||
lastroom_r = ZCMD2.arg1;
|
||
if (ZCMD2.arg2 == ornum)
|
||
send_to_char(ch, " [%5d] %s (Removed from room)\r\n",
|
||
lastroom_v,
|
||
world[lastroom_r].name);
|
||
break;
|
||
}/* switch */
|
||
} /*for cmd_no......*/
|
||
} /*for zone...*/
|
||
}
|
||
|
||
static void trg_checkload(struct char_data *ch, trig_vnum tvnum)
|
||
{
|
||
int cmd_no, found = 0;
|
||
zone_rnum zone;
|
||
trig_rnum trnum = real_trigger(tvnum);
|
||
room_vnum lastroom_v = 0;
|
||
room_rnum lastroom_r = 0, k;
|
||
mob_rnum lastmob_r = 0, i;
|
||
obj_rnum lastobj_r = 0, j;
|
||
struct trig_proto_list *tpl;
|
||
|
||
if (trnum == NOTHING) {
|
||
send_to_char(ch, "That trigger does not exist.\r\n");
|
||
return;
|
||
}
|
||
|
||
send_to_char(ch, "Checking load info for the %s trigger '%s':\r\n",
|
||
trig_index[trnum]->proto->attach_type == MOB_TRIGGER ? "mobile" :
|
||
(trig_index[trnum]->proto->attach_type == OBJ_TRIGGER ? "object" : "room"),
|
||
trig_index[trnum]->proto->name);
|
||
|
||
for (zone=0; zone <= top_of_zone_table; zone++) {
|
||
for (cmd_no = 0; ZCMD2.command != 'S'; cmd_no++) {
|
||
switch (ZCMD2.command) {
|
||
case 'M':
|
||
lastroom_v = world[ZCMD2.arg3].number;
|
||
lastroom_r = ZCMD2.arg3;
|
||
lastmob_r = ZCMD2.arg1;
|
||
break;
|
||
case 'O': /* read an object */
|
||
lastroom_v = world[ZCMD2.arg3].number;
|
||
lastroom_r = ZCMD2.arg3;
|
||
lastobj_r = ZCMD2.arg1;
|
||
break;
|
||
case 'P': /* object to object */
|
||
lastobj_r = ZCMD2.arg1;
|
||
break;
|
||
case 'G': /* obj_to_char */
|
||
lastobj_r = ZCMD2.arg1;
|
||
break;
|
||
case 'E': /* object to equipment list */
|
||
lastobj_r = ZCMD2.arg1;
|
||
break;
|
||
case 'R': /* rem obj from room */
|
||
lastroom_v = 0;
|
||
lastroom_r = 0;
|
||
lastobj_r = 0;
|
||
lastmob_r = 0;
|
||
case 'T': /* trigger to something */
|
||
if (ZCMD2.arg2 != trnum)
|
||
break;
|
||
if (ZCMD2.arg1 == MOB_TRIGGER) {
|
||
send_to_char(ch, "mob [%5d] %-60s (zedit room %5d)\r\n",
|
||
mob_index[lastmob_r].vnum,
|
||
mob_proto[lastmob_r].player.short_descr,
|
||
lastroom_v);
|
||
found = 1;
|
||
} else if (ZCMD2.arg1 == OBJ_TRIGGER) {
|
||
send_to_char(ch, "obj [%5d] %-60s (zedit room %d)\r\n",
|
||
obj_index[lastobj_r].vnum,
|
||
obj_proto[lastobj_r].short_description,
|
||
lastroom_v);
|
||
found = 1;
|
||
} else if (ZCMD2.arg1==WLD_TRIGGER) {
|
||
send_to_char(ch, "room [%5d] %-60s (zedit)\r\n",
|
||
lastroom_v,
|
||
world[lastroom_r].name);
|
||
found = 1;
|
||
}
|
||
break;
|
||
} /* switch */
|
||
} /*for cmd_no......*/
|
||
} /*for zone...*/
|
||
|
||
for (i = 0; i < top_of_mobt; i++) {
|
||
if (!mob_proto[i].proto_script)
|
||
continue;
|
||
|
||
for (tpl = mob_proto[i].proto_script;tpl;tpl = tpl->next)
|
||
if (tpl->vnum == tvnum) {
|
||
send_to_char(ch, "mob [%5d] %s\r\n",
|
||
mob_index[i].vnum,
|
||
mob_proto[i].player.short_descr);
|
||
found = 1;
|
||
}
|
||
}
|
||
|
||
for (j = 0; j < top_of_objt; j++) {
|
||
if (!obj_proto[j].proto_script)
|
||
continue;
|
||
|
||
for (tpl = obj_proto[j].proto_script;tpl;tpl = tpl->next)
|
||
if (tpl->vnum == tvnum) {
|
||
send_to_char(ch, "obj [%5d] %s\r\n",
|
||
obj_index[j].vnum,
|
||
obj_proto[j].short_description);
|
||
found = 1;
|
||
}
|
||
}
|
||
|
||
for (k = 0;k < top_of_world; k++) {
|
||
if (!world[k].proto_script)
|
||
continue;
|
||
|
||
for (tpl = world[k].proto_script;tpl;tpl = tpl->next)
|
||
if (tpl->vnum == tvnum) {
|
||
send_to_char(ch, "room[%5d] %s\r\n",
|
||
world[k].number,
|
||
world[k].name);
|
||
found = 1;
|
||
}
|
||
}
|
||
|
||
if (!found)
|
||
send_to_char(ch, "This trigger is not attached to anything.\r\n");
|
||
}
|
||
|
||
ACMD(do_checkloadstatus)
|
||
{
|
||
char buf1[MAX_INPUT_LENGTH], buf2[MAX_INPUT_LENGTH];
|
||
|
||
two_arguments(argument, buf1, buf2);
|
||
|
||
if ((!*buf1) || (!*buf2) || (!isdigit(*buf2))) {
|
||
send_to_char(ch, "Checkload <M | O | T> <vnum>\r\n");
|
||
return;
|
||
}
|
||
|
||
if (LOWER(*buf1) == 'm') {
|
||
mob_checkload(ch, atoi(buf2));
|
||
return;
|
||
}
|
||
|
||
if (LOWER(*buf1) == 'o') {
|
||
obj_checkload(ch, atoi(buf2));
|
||
return;
|
||
}
|
||
|
||
if (LOWER(*buf1) == 't') {
|
||
trg_checkload(ch, atoi(buf2));
|
||
return;
|
||
}
|
||
}
|
||
/* Zone Checker code above. */
|
||
|
||
/* (c) 1996-97 Erwin S. Andreasen. */
|
||
ACMD(do_copyover)
|
||
{
|
||
FILE *fp;
|
||
struct descriptor_data *d, *d_next;
|
||
char buf [100], buf2[100];
|
||
|
||
fp = fopen (COPYOVER_FILE, "w");
|
||
if (!fp) {
|
||
send_to_char (ch, "Copyover file not writeable, aborted.\n\r");
|
||
return;
|
||
}
|
||
|
||
sprintf (buf, "\n\r *** COPYOVER by %s - please remain seated!\n\r", GET_NAME(ch));
|
||
|
||
/* write boot_time as first line in file */
|
||
fprintf(fp, "%ld\n", (long)boot_time);
|
||
|
||
/* For each playing descriptor, save its state */
|
||
for (d = descriptor_list; d ; d = d_next) {
|
||
struct char_data * och = d->character;
|
||
|
||
/* If d is currently in someone else's body, return them. */
|
||
if (och && d->original)
|
||
return_to_char(och);
|
||
|
||
/* We delete from the list , so need to save this */
|
||
d_next = d->next;
|
||
|
||
/* drop those logging on */
|
||
if (!d->character || d->connected > CON_PLAYING) {
|
||
write_to_descriptor (d->descriptor, "\n\rSorry, we are rebooting. Come back in a few minutes.\n\r");
|
||
close_socket (d); /* throw'em out */
|
||
} else {
|
||
fprintf (fp, "%d %ld %s %s %s\n", d->descriptor, GET_PREF(och), GET_NAME(och), d->host, CopyoverGet(d));
|
||
/* save och */
|
||
GET_LOADROOM(och) = GET_ROOM_VNUM(IN_ROOM(och));
|
||
Crash_rentsave(och,0);
|
||
save_char(och);
|
||
write_to_descriptor (d->descriptor, buf);
|
||
}
|
||
}
|
||
|
||
fprintf (fp, "-1\n");
|
||
fclose (fp);
|
||
|
||
/* exec - descriptors are inherited */
|
||
sprintf (buf, "%d", port);
|
||
sprintf (buf2, "-C%d", mother_desc);
|
||
|
||
/* Ugh, seems it is expected we are 1 step above lib - this may be dangerous! */
|
||
if(chdir ("..") != 0) {
|
||
log("Error changing working directory: %s", strerror(errno));
|
||
send_to_char(ch, "Error changing working directory: %s.", strerror(errno));
|
||
exit(1);
|
||
}
|
||
|
||
/* Close reserve and other always-open files and release other resources */
|
||
execl (EXE_FILE, "circle", buf2, buf, (char *) NULL);
|
||
|
||
/* Failed - successful exec will not return */
|
||
perror ("do_copyover: execl");
|
||
send_to_char (ch, "Copyover FAILED!\n\r");
|
||
|
||
exit (1); /* too much trouble to try to recover! */
|
||
}
|
||
|
||
ACMD(do_peace)
|
||
{
|
||
struct char_data *vict, *next_v;
|
||
|
||
act ("As $n makes a strange arcane gesture, a golden light descends\r\n"
|
||
"from the heavens stopping all the fighting.\r\n",FALSE, ch, 0, 0, TO_ROOM);
|
||
send_to_room(IN_ROOM(ch), "Everything is quite peaceful now.\r\n");
|
||
for(vict=world[IN_ROOM(ch)].people; vict; vict=next_v) {
|
||
next_v = vict->next_in_room;
|
||
if (FIGHTING(vict))
|
||
stop_fighting(vict);
|
||
if (IS_NPC(vict))
|
||
clearMemory(vict);
|
||
}
|
||
}
|
||
|
||
ACMD(do_zpurge)
|
||
{
|
||
int vroom, room, zone = 0;
|
||
char arg[MAX_INPUT_LENGTH];
|
||
int purge_all = FALSE;
|
||
one_argument(argument, arg);
|
||
if (*arg == '.' || !*arg) {
|
||
zone = world[IN_ROOM(ch)].zone;
|
||
}
|
||
else if (is_number(arg)) {
|
||
zone = real_zone(atoi(arg));
|
||
if (zone == NOWHERE || zone > top_of_zone_table) {
|
||
send_to_char(ch, "That zone doesn't exist!\r\n");
|
||
return;
|
||
}
|
||
}
|
||
else if (*arg == '*') {
|
||
purge_all = TRUE;
|
||
}
|
||
else {
|
||
send_to_char(ch, "That isn't a valid zone number!\r\n");
|
||
return;
|
||
}
|
||
if (GET_LEVEL(ch) < LVL_GOD && !can_edit_zone(ch, zone)) {
|
||
send_to_char(ch, "You can only purge your own zone!\r\n");
|
||
return;
|
||
}
|
||
if (!purge_all) {
|
||
for (vroom = zone_table[zone].bot; vroom <= zone_table[zone].top; vroom++) {
|
||
purge_room(real_room(vroom));
|
||
}
|
||
send_to_char(ch, "Purged zone #%d: %s.\r\n", zone_table[zone].number, zone_table[zone].name);
|
||
mudlog(NRM, MAX(LVL_GRGOD, GET_INVIS_LEV(ch)), TRUE, "(GC) %s purged zone %d (%s)", GET_NAME(ch), zone_table[zone].number, zone_table[zone].name);
|
||
}
|
||
else {
|
||
for (room = 0; room <= top_of_world; room++) {
|
||
purge_room(room);
|
||
}
|
||
send_to_char(ch, "Purged world.\r\n");
|
||
mudlog(NRM, MAX(LVL_GRGOD, GET_INVIS_LEV(ch)), TRUE, "(GC) %s purged entire world.", GET_NAME(ch));
|
||
}
|
||
}
|
||
|
||
/** Used to read and gather a bit of information about external log files while
|
||
* in game.
|
||
* Makes use of the '\t' color codes in the file status information.
|
||
* Some of the methods used are a bit wasteful (reading through the file
|
||
* multiple times to gather diagnostic information), but it is
|
||
* assumed that the files read with this function will never be very large.
|
||
* Files to be read are assumed to exist and be readable and if they aren't,
|
||
* log the name of the missing file.
|
||
*/
|
||
ACMD(do_file)
|
||
{
|
||
/* Local variables */
|
||
int def_lines_to_read = 15; /* Set the default num lines to be read. */
|
||
int max_lines_to_read = 300; /* Maximum number of lines to read. */
|
||
FILE *req_file; /* Pointer to file to be read. */
|
||
size_t req_file_size = 0; /* Size of file to be read. */
|
||
int req_file_lines = 0; /* Number of total lines in file to be read. */
|
||
int lines_read = 0; /* Counts total number of lines read from the file. */
|
||
int req_lines = 0; /* Number of lines requested to be displayed. */
|
||
int i; /* Generic loop counter. */
|
||
int l; /* Marks choice of file in fields array. */
|
||
char field[MAX_INPUT_LENGTH]; /* Holds users choice of file to be read. */
|
||
char value[MAX_INPUT_LENGTH]; /* Holds # lines to be read, if requested. */
|
||
char buf[MAX_STRING_LENGTH]; /* Display buffer for req_file. */
|
||
|
||
/* Defines which files are available to read. */
|
||
struct file_struct {
|
||
char *cmd; /* The 'name' of the file to view */
|
||
char level; /* Minimum level needed to view. */
|
||
char *file; /* The file location, relative to the working dir. */
|
||
int read_backwards; /* Should the file be read backwards by default? */
|
||
} fields[] = {
|
||
{ "xnames", LVL_GOD, XNAME_FILE, TRUE},
|
||
{ "levels", LVL_GOD, LEVELS_LOGFILE, TRUE},
|
||
{ "rip", LVL_GOD, RIP_LOGFILE, TRUE},
|
||
{ "players", LVL_GOD, NEWPLAYERS_LOGFILE, TRUE},
|
||
{ "errors", LVL_GOD, ERRORS_LOGFILE, TRUE},
|
||
{ "godcmds", LVL_GOD, GODCMDS_LOGFILE, TRUE},
|
||
{ "syslog", LVL_GOD, SYSLOG_LOGFILE, TRUE},
|
||
{ "crash", LVL_GOD, CRASH_LOGFILE, TRUE},
|
||
{ "help", LVL_GOD, HELP_LOGFILE, TRUE},
|
||
{ "changelog", LVL_GOD, CHANGE_LOG_FILE, FALSE},
|
||
{ "deletes", LVL_GOD, DELETES_LOGFILE, TRUE},
|
||
{ "restarts", LVL_GOD, RESTARTS_LOGFILE, TRUE},
|
||
{ "usage", LVL_GOD, USAGE_LOGFILE, TRUE},
|
||
{ "badpws", LVL_GOD, BADPWS_LOGFILE, TRUE},
|
||
{ "olc", LVL_GOD, OLC_LOGFILE, TRUE},
|
||
{ "trigger", LVL_GOD, TRIGGER_LOGFILE, TRUE},
|
||
{ "\n", 0, "\n", FALSE } /* This must be the last entry */
|
||
};
|
||
|
||
/* Initialize buffer */
|
||
buf[0] = '\0';
|
||
|
||
/**/
|
||
/* End function variable set-up and initialization. */
|
||
|
||
skip_spaces(&argument);
|
||
|
||
/* Display usage if no argument. */
|
||
if (!*argument) {
|
||
send_to_char(ch, "USAGE: file <filename> <num lines>\r\n\r\nFile options:\r\n");
|
||
for (i = 0; fields[i].level; i++)
|
||
if (fields[i].level <= GET_LEVEL(ch))
|
||
send_to_char(ch, "%-15s%s\r\n", fields[i].cmd, fields[i].file);
|
||
return;
|
||
}
|
||
|
||
/* Begin validity checks. Is the file choice valid and accessible? */
|
||
/**/
|
||
/* There are some arguments, deal with them. */
|
||
two_arguments(argument, field, value);
|
||
|
||
for (l = 0; *(fields[l].cmd) != '\n'; l++)
|
||
{
|
||
if (!strncmp(field, fields[l].cmd, strlen(field)))
|
||
break;
|
||
}
|
||
|
||
if(*(fields[l].cmd) == '\n') {
|
||
send_to_char(ch, "'%s' is not a valid file.\r\n", field);
|
||
return;
|
||
}
|
||
|
||
if (GET_LEVEL(ch) < fields[l].level) {
|
||
send_to_char(ch, "You have not achieved a high enough level to view '%s'.\r\n",
|
||
fields[l].cmd);
|
||
return;
|
||
}
|
||
|
||
/* Number of lines to view. Default is 15. */
|
||
if(!*value)
|
||
req_lines = def_lines_to_read;
|
||
else if (!isdigit(*value))
|
||
{
|
||
/* This check forces the requisite positive digit and prevents negative
|
||
* numbers of lines from being read. */
|
||
send_to_char(ch, "'%s' is not a valid number of lines to view.\r\n", value);
|
||
return;
|
||
}
|
||
else
|
||
{
|
||
req_lines = atoi(value);
|
||
/* Limit the maximum number of lines */
|
||
req_lines = MIN( req_lines, max_lines_to_read );
|
||
}
|
||
|
||
/* Must be able to access the file on disk. */
|
||
if (!(req_file=fopen(fields[l].file,"r"))) {
|
||
send_to_char(ch, "The file %s can not be opened.\r\n", fields[l].file);
|
||
mudlog(BRF, LVL_IMPL, TRUE, "SYSERR: Error opening file %s using 'file' command.", fields[l].file);
|
||
return;
|
||
}
|
||
/**/
|
||
/* End validity checks. From here on, the file should be viewable. */
|
||
|
||
/* Diagnostic information about the file */
|
||
req_file_size = file_sizeof(req_file);
|
||
req_file_lines = file_numlines(req_file);
|
||
|
||
snprintf( buf, sizeof(buf),
|
||
"\tgFile:\tn %s\tg; Min. Level to read:\tn %d\tg; File Location:\tn %s\tg\r\n"
|
||
"File size (bytes):\tn %ld\tg; Total num lines:\tn %d\r\n",
|
||
fields[l].cmd, fields[l].level, fields[l].file, (long) req_file_size,
|
||
req_file_lines);
|
||
|
||
/* Should the file be 'headed' or 'tailed'? */
|
||
if ( (fields[l].read_backwards == TRUE) && (req_lines < req_file_lines) )
|
||
{
|
||
snprintf( buf + strlen(buf), sizeof(buf) - strlen(buf),
|
||
"\tgReading from the tail of the file.\tn\r\n\r\n" );
|
||
lines_read = file_tail( req_file, buf, sizeof(buf), req_lines );
|
||
}
|
||
else
|
||
{
|
||
snprintf( buf + strlen(buf), sizeof(buf) - strlen(buf),
|
||
"\tgReading from the head of the file.\tn\r\n\r\n" );
|
||
lines_read = file_head( req_file, buf, sizeof(buf), req_lines );
|
||
}
|
||
|
||
/* Since file_head and file_tail will add the overflow message, we
|
||
* don't check for status here. */
|
||
if ( lines_read == req_file_lines )
|
||
{
|
||
/* We're reading the entire file */
|
||
snprintf( buf + strlen(buf), sizeof(buf) - strlen(buf),
|
||
"\r\n\tgEntire file returned (\tn%d \tglines).\tn\r\n",
|
||
lines_read );
|
||
}
|
||
else if ( lines_read == max_lines_to_read )
|
||
{
|
||
snprintf( buf + strlen(buf), sizeof(buf) - strlen(buf),
|
||
"\r\n\tgMaximum number of \tn%d \tglines returned.\tn\r\n",
|
||
lines_read );
|
||
}
|
||
else
|
||
{
|
||
snprintf( buf + strlen(buf), sizeof(buf) - strlen(buf),
|
||
"\r\n%d \tglines returned.\tn\r\n",
|
||
lines_read );
|
||
}
|
||
|
||
/* Clean up before return */
|
||
fclose(req_file);
|
||
|
||
page_string(ch->desc, buf, 1);
|
||
}
|
||
|
||
ACMD(do_changelog)
|
||
{
|
||
time_t rawtime;
|
||
char timestr[12], line[READ_SIZE], last_buf[READ_SIZE],
|
||
buf[READ_SIZE];
|
||
FILE *fl, *new;
|
||
|
||
skip_spaces(&argument);
|
||
|
||
if (!*argument) {
|
||
send_to_char(ch, "Usage: changelog <change>\r\n");
|
||
return;
|
||
}
|
||
|
||
sprintf(buf, "%s.bak", CHANGE_LOG_FILE);
|
||
if (rename(CHANGE_LOG_FILE, buf)) {
|
||
mudlog(BRF, LVL_IMPL, TRUE,
|
||
"SYSERR: Error making backup changelog file (%s)", buf);
|
||
return;
|
||
}
|
||
|
||
if (!(fl = fopen(buf, "r"))) {
|
||
mudlog(BRF, LVL_IMPL, TRUE,
|
||
"SYSERR: Error opening backup changelog file (%s)", buf);
|
||
return;
|
||
}
|
||
|
||
if (!(new = fopen(CHANGE_LOG_FILE, "w"))) {
|
||
mudlog(BRF, LVL_IMPL, TRUE,
|
||
"SYSERR: Error opening new changelog file (%s)", CHANGE_LOG_FILE);
|
||
return;
|
||
}
|
||
|
||
while (get_line(fl, line)) {
|
||
if (*line != '[')
|
||
fprintf(new, "%s\n", line);
|
||
else {
|
||
strcpy(last_buf, line);
|
||
break;
|
||
}
|
||
}
|
||
|
||
rawtime = time(0);
|
||
strftime(timestr, sizeof(timestr), "%b %d %Y", localtime(&rawtime));
|
||
|
||
sprintf(buf, "[%s] - %s", timestr, GET_NAME(ch));
|
||
|
||
fprintf(new, "%s\n", buf);
|
||
fprintf(new, " %s\n", argument);
|
||
|
||
if (strcmp(buf, last_buf))
|
||
fprintf(new, "%s\n", line);
|
||
|
||
while (get_line(fl, line))
|
||
fprintf(new, "%s\n", line);
|
||
|
||
fclose(fl);
|
||
fclose(new);
|
||
send_to_char(ch, "Change added.\r\n");
|
||
}
|
||
|
||
#define PLIST_FORMAT \
|
||
"Usage: plist [minlev[-maxlev]] [-n name] [-d days] [-h hours] [-i] [-m]"
|
||
|
||
ACMD(do_plist)
|
||
{
|
||
int i, len = 0, count = 0;
|
||
char mode, buf[MAX_STRING_LENGTH * 20], name_search[MAX_NAME_LENGTH], timestr[MAX_STRING_LENGTH];
|
||
struct time_info_data time_away;
|
||
int low = 0, high = LVL_IMPL, low_day = 0, high_day = 10000, low_hr = 0, high_hr = 24;
|
||
|
||
skip_spaces(&argument);
|
||
strcpy(buf, argument); /* strcpy: OK (sizeof: argument == buf) */
|
||
name_search[0] = '\0';
|
||
|
||
while (*buf) {
|
||
char arg[MAX_INPUT_LENGTH], buf1[MAX_INPUT_LENGTH];
|
||
|
||
half_chop(buf, arg, buf1);
|
||
if (isdigit(*arg)) {
|
||
if (sscanf(arg, "%d-%d", &low, &high) == 1)
|
||
high = low;
|
||
strcpy(buf, buf1); /* strcpy: OK (sizeof: buf1 == buf) */
|
||
} else if (*arg == '-') {
|
||
mode = *(arg + 1); /* just in case; we destroy arg in the switch */
|
||
switch (mode) {
|
||
case 'l':
|
||
half_chop(buf1, arg, buf);
|
||
sscanf(arg, "%d-%d", &low, &high);
|
||
break;
|
||
case 'n':
|
||
half_chop(buf1, name_search, buf);
|
||
break;
|
||
case 'i':
|
||
strcpy(buf, buf1);
|
||
low = LVL_IMMORT;
|
||
break;
|
||
case 'm':
|
||
strcpy(buf, buf1);
|
||
high = LVL_IMMORT - 1;
|
||
break;
|
||
case 'd':
|
||
half_chop(buf1, arg, buf);
|
||
if (sscanf(arg, "%d-%d", &low_day, &high_day) == 1)
|
||
high_day = low_day;
|
||
break;
|
||
case 'h':
|
||
half_chop(buf1, arg, buf);
|
||
if (sscanf(arg, "%d-%d", &low_hr, &high_hr) == 1)
|
||
high_hr = low_hr;
|
||
break;
|
||
default:
|
||
send_to_char(ch, "%s\r\n", PLIST_FORMAT);
|
||
return;
|
||
}
|
||
} else {
|
||
send_to_char(ch, "%s\r\n", PLIST_FORMAT);
|
||
return;
|
||
}
|
||
}
|
||
|
||
len = 0;
|
||
len += snprintf(buf + len, sizeof(buf) - len, "\tW[ Id] (Lv) Name Last\tn\r\n"
|
||
"%s-------------------------------------%s\r\n", CCCYN(ch, C_NRM),
|
||
CCNRM(ch, C_NRM));
|
||
|
||
for (i = 0; i <= top_of_p_table; i++) {
|
||
if (player_table[i].level < low || player_table[i].level > high)
|
||
continue;
|
||
|
||
time_away = *real_time_passed(time(0), player_table[i].last);
|
||
|
||
if (*name_search && str_cmp(name_search, player_table[i].name))
|
||
continue;
|
||
|
||
if (time_away.day > high_day || time_away.day < low_day)
|
||
continue;
|
||
if (time_away.hours > high_hr || time_away.hours < low_hr)
|
||
continue;
|
||
|
||
strftime(timestr, sizeof(timestr), "%c", localtime(&player_table[i].last));
|
||
|
||
len += snprintf(buf + len, sizeof(buf) - len, "[%3ld] (%2d) %c%-15s %s\r\n",
|
||
player_table[i].id, player_table[i].level,
|
||
UPPER(*player_table[i].name), player_table[i].name + 1, timestr);
|
||
count++;
|
||
}
|
||
snprintf(buf + len, sizeof(buf) - len, "%s-------------------------------------%s\r\n"
|
||
"%d players listed.\r\n", CCCYN(ch, C_NRM), CCNRM(ch, C_NRM), count);
|
||
page_string(ch->desc, buf, TRUE);
|
||
}
|
||
|
||
ACMD(do_wizupdate)
|
||
{
|
||
run_autowiz();
|
||
send_to_char(ch, "Wizlists updated.\n\r");
|
||
}
|
||
|
||
/* NOTE: This is called from perform_set */
|
||
bool change_player_name(struct char_data *ch, struct char_data *vict, char *new_name)
|
||
{
|
||
struct char_data *temp_ch=NULL;
|
||
int plr_i = 0, i, k;
|
||
char old_name[MAX_NAME_LENGTH], old_pfile[50], new_pfile[50], buf[MAX_STRING_LENGTH];
|
||
|
||
if (!ch)
|
||
{
|
||
log("SYSERR: No char passed to change_player_name.");
|
||
return FALSE;
|
||
}
|
||
|
||
if (!vict)
|
||
{
|
||
log("SYSERR: No victim passed to change_player_name.");
|
||
send_to_char(ch, "Invalid victim.\r\n");
|
||
return FALSE;
|
||
}
|
||
|
||
if (!new_name || !(*new_name) || strlen(new_name) < 2 ||
|
||
strlen(new_name) > MAX_NAME_LENGTH || !valid_name(new_name) ||
|
||
fill_word(new_name) || reserved_word(new_name) ) {
|
||
send_to_char(ch, "Invalid new name.\r\n");
|
||
return FALSE;
|
||
}
|
||
|
||
/* Check that someone with new_name isn't already logged in */
|
||
if ((temp_ch = get_player_vis(ch, new_name, NULL, FIND_CHAR_WORLD)) != NULL) {
|
||
send_to_char(ch, "Sorry, the new name already exists.\r\n");
|
||
return FALSE;
|
||
} else {
|
||
/* try to load the player off disk */
|
||
CREATE(temp_ch, struct char_data, 1);
|
||
clear_char(temp_ch);
|
||
CREATE(temp_ch->player_specials, struct player_special_data, 1);
|
||
new_mobile_data(temp_ch);
|
||
if ((plr_i = load_char(new_name, temp_ch)) > -1) {
|
||
free_char(temp_ch);
|
||
send_to_char(ch, "Sorry, the new name already exists.\r\n");
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
/* New playername is OK - find the entry in the index */
|
||
for (i = 0; i <= top_of_p_table; i++)
|
||
if (player_table[i].id == GET_IDNUM(vict))
|
||
break;
|
||
|
||
if (player_table[i].id != GET_IDNUM(vict))
|
||
{
|
||
send_to_char(ch, "Your target was not found in the player index.\r\n");
|
||
log("SYSERR: Player %s, with ID %ld, could not be found in the player index.", GET_NAME(vict), GET_IDNUM(vict));
|
||
return FALSE;
|
||
}
|
||
|
||
/* Set up a few variables that will be needed */
|
||
sprintf(old_name, "%s", GET_NAME(vict));
|
||
if (!get_filename(old_pfile, sizeof(old_pfile), PLR_FILE, old_name))
|
||
{
|
||
send_to_char(ch, "Unable to ascertain player's old pfile name.\r\n");
|
||
return FALSE;
|
||
}
|
||
if (!get_filename(new_pfile, sizeof(new_pfile), PLR_FILE, new_name))
|
||
{
|
||
send_to_char(ch, "Unable to ascertain player's new pfile name.\r\n");
|
||
return FALSE;
|
||
}
|
||
|
||
/* Now start changing the name over - all checks and setup have passed */
|
||
free(player_table[i].name); // Free the old name in the index
|
||
player_table[i].name = strdup(new_name); // Insert the new name into the index
|
||
for (k=0; (*(player_table[i].name+k) = LOWER(*(player_table[i].name+k))); k++);
|
||
|
||
free(GET_PC_NAME(vict));
|
||
GET_PC_NAME(vict) = strdup(CAP(new_name)); // Change the name in the victims char struct
|
||
|
||
/* Rename the player's pfile */
|
||
sprintf(buf, "mv %s %s", old_pfile, new_pfile);
|
||
|
||
/* Save the changed player index - the pfile is saved by perform_set */
|
||
save_player_index();
|
||
|
||
mudlog(BRF, LVL_IMMORT, TRUE, "(GC) %s changed the name of %s to %s", GET_NAME(ch), old_name, new_name);
|
||
|
||
if (vict->desc) /* Descriptor is set if the victim is logged in */
|
||
send_to_char(vict, "Your login name has changed from %s%s%s to %s%s%s.\r\n", CCYEL(vict, C_NRM), old_name, CCNRM(vict, C_NRM),
|
||
CCYEL(vict, C_NRM), new_name, CCNRM(vict, C_NRM));
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
ACMD(do_zlock)
|
||
{
|
||
zone_vnum znvnum;
|
||
zone_rnum zn;
|
||
char arg[MAX_INPUT_LENGTH], arg2[MAX_INPUT_LENGTH];
|
||
int counter = 0;
|
||
bool fail = FALSE;
|
||
|
||
two_arguments(argument, arg, arg2);
|
||
|
||
if (!*arg) {
|
||
send_to_char(ch, "Usage: %szlock <zone number>%s\r\n", QYEL, QNRM);
|
||
send_to_char(ch, "%s zlock list%s\r\n\r\n", QYEL, QNRM);
|
||
send_to_char(ch, "Locks a zone so that building or editing is not possible.\r\n");
|
||
send_to_char(ch, "The 'list' shows all currently locked zones.\r\n");
|
||
send_to_char(ch, "'zlock all' will lock every zone with the GRID flag set.\r\n");
|
||
send_to_char(ch, "'zlock all all' will lock every zone in the MUD.\r\n");
|
||
return;
|
||
}
|
||
if (is_abbrev(arg, "all")) {
|
||
if (GET_LEVEL(ch) < LVL_GRGOD) {
|
||
send_to_char(ch, "You do not have sufficient access to lock all zones.\r\n");
|
||
return;
|
||
}
|
||
if (!*arg2) {
|
||
for (zn = 0; zn <= top_of_zone_table; zn++) {
|
||
if (!ZONE_FLAGGED(zn, ZONE_NOBUILD) && ZONE_FLAGGED(zn, ZONE_GRID)) {
|
||
counter++;
|
||
SET_BIT_AR(ZONE_FLAGS(zn), ZONE_NOBUILD);
|
||
if (save_zone(zn)) {
|
||
log("(GC) %s has locked zone %d", GET_NAME(ch), zone_table[zn].number);
|
||
} else {
|
||
fail = TRUE;
|
||
}
|
||
}
|
||
}
|
||
} else if (is_abbrev(arg2, "all")) {
|
||
for (zn = 0; zn <= top_of_zone_table; zn++) {
|
||
if (!ZONE_FLAGGED(zn, ZONE_NOBUILD)) {
|
||
counter++;
|
||
SET_BIT_AR(ZONE_FLAGS(zn), ZONE_NOBUILD);
|
||
if (save_zone(zn)) {
|
||
log("(GC) %s has locked zone %d", GET_NAME(ch), zone_table[zn].number);
|
||
} else {
|
||
fail = TRUE;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if (counter == 0) {
|
||
send_to_char(ch, "There are no unlocked zones to lock!\r\n");
|
||
return;
|
||
}
|
||
if (fail) {
|
||
send_to_char(ch, "Unable to save zone changes. Check syslog!\r\n");
|
||
return;
|
||
}
|
||
send_to_char(ch, "%d zones have now been locked.\r\n", counter);
|
||
mudlog(BRF, MAX(LVL_GOD, GET_INVIS_LEV(ch)), TRUE, "(GC) %s has locked ALL zones!", GET_NAME(ch));
|
||
return;
|
||
}
|
||
if (is_abbrev(arg, "list")) {
|
||
/* Show all locked zones */
|
||
for (zn = 0; zn <= top_of_zone_table; zn++) {
|
||
if (ZONE_FLAGGED(zn, ZONE_NOBUILD)) {
|
||
if (!counter) send_to_char(ch, "Locked Zones\r\n");
|
||
|
||
send_to_char(ch, "[%s%3d%s] %s%-*s %s%-1s%s\r\n",
|
||
QGRN, zone_table[zn].number, QNRM, QCYN, count_color_chars(zone_table[zn].name)+30, zone_table[zn].name,
|
||
QYEL, zone_table[zn].builders ? zone_table[zn].builders : "None.", QNRM);
|
||
counter++;
|
||
}
|
||
}
|
||
if (counter == 0) {
|
||
send_to_char(ch, "There are currently no locked zones!\r\n");
|
||
}
|
||
return;
|
||
}
|
||
else if ((znvnum = atoi(arg)) == 0) {
|
||
send_to_char(ch, "Usage: %szlock <zone number>%s\r\n", QYEL, QNRM);
|
||
return;
|
||
}
|
||
|
||
if ((zn = real_zone(znvnum)) == NOWHERE) {
|
||
send_to_char(ch, "That zone does not exist!\r\n");
|
||
return;
|
||
}
|
||
|
||
/* Check the builder list */
|
||
if (GET_LEVEL(ch) < LVL_GRGOD && !is_name(GET_NAME(ch), zone_table[zn].builders) && GET_OLC_ZONE(ch) != znvnum) {
|
||
send_to_char(ch, "You do not have sufficient access to lock that zone!\r\n");
|
||
return;
|
||
}
|
||
|
||
/* If we get here, player has typed 'zlock <num>' */
|
||
if (ZONE_FLAGGED(zn, ZONE_NOBUILD)) {
|
||
send_to_char(ch, "Zone %d is already locked!\r\n", znvnum);
|
||
return;
|
||
}
|
||
SET_BIT_AR(ZONE_FLAGS(zn), ZONE_NOBUILD);
|
||
if (save_zone(zn)) {
|
||
mudlog(NRM, MAX(LVL_GRGOD, GET_INVIS_LEV(ch)), TRUE, "(GC) %s has locked zone %d", GET_NAME(ch), znvnum);
|
||
}
|
||
else
|
||
{
|
||
send_to_char(ch, "Unable to save zone changes. Check syslog!\r\n");
|
||
}
|
||
}
|
||
|
||
ACMD(do_zunlock)
|
||
{
|
||
zone_vnum znvnum;
|
||
zone_rnum zn;
|
||
char arg[MAX_INPUT_LENGTH];
|
||
int counter = 0;
|
||
bool fail = FALSE;
|
||
|
||
one_argument(argument, arg);
|
||
|
||
if (!*arg) {
|
||
send_to_char(ch, "Usage: %szunlock <zone number>%s\r\n", QYEL, QNRM);
|
||
send_to_char(ch, "%s zunlock list%s\r\n\r\n", QYEL, QNRM);
|
||
send_to_char(ch, "Unlocks a 'locked' zone to allow building or editing.\r\n");
|
||
send_to_char(ch, "The 'list' shows all currently unlocked zones.\r\n");
|
||
send_to_char(ch, "'zunlock all' will unlock every zone in the MUD.\r\n");
|
||
return;
|
||
}
|
||
if (is_abbrev(arg, "all")) {
|
||
if (GET_LEVEL(ch) < LVL_GRGOD) {
|
||
send_to_char(ch, "You do not have sufficient access to lock zones.\r\n");
|
||
return;
|
||
}
|
||
for (zn = 0; zn <= top_of_zone_table; zn++) {
|
||
if (ZONE_FLAGGED(zn, ZONE_NOBUILD)) {
|
||
counter++;
|
||
REMOVE_BIT_AR(ZONE_FLAGS(zn), ZONE_NOBUILD);
|
||
if (save_zone(zn)) {
|
||
log("(GC) %s has unlocked zone %d", GET_NAME(ch), zone_table[zn].number);
|
||
} else {
|
||
fail = TRUE;
|
||
}
|
||
}
|
||
}
|
||
if (counter == 0) {
|
||
send_to_char(ch, "There are no locked zones to unlock!\r\n");
|
||
return;
|
||
}
|
||
if (fail) {
|
||
send_to_char(ch, "Unable to save zone changes. Check syslog!\r\n");
|
||
return;
|
||
}
|
||
send_to_char(ch, "%d zones have now been unlocked.\r\n", counter);
|
||
mudlog(BRF, MAX(LVL_GOD, GET_INVIS_LEV(ch)), TRUE, "(GC) %s has unlocked ALL zones!", GET_NAME(ch));
|
||
return;
|
||
}
|
||
if (is_abbrev(arg, "list")) {
|
||
/* Show all unlocked zones */
|
||
for (zn = 0; zn <= top_of_zone_table; zn++) {
|
||
if (!ZONE_FLAGGED(zn, ZONE_NOBUILD)) {
|
||
if (!counter) send_to_char(ch, "Unlocked Zones\r\n");
|
||
|
||
send_to_char(ch, "[%s%3d%s] %s%-*s %s%-1s%s\r\n",
|
||
QGRN, zone_table[zn].number, QNRM, QCYN, count_color_chars(zone_table[zn].name)+30, zone_table[zn].name,
|
||
QYEL, zone_table[zn].builders ? zone_table[zn].builders : "None.", QNRM);
|
||
counter++;
|
||
}
|
||
}
|
||
if (counter == 0) {
|
||
send_to_char(ch, "There are currently no unlocked zones!\r\n");
|
||
}
|
||
return;
|
||
}
|
||
else if ((znvnum = atoi(arg)) == 0) {
|
||
send_to_char(ch, "Usage: %szunlock <zone number>%s\r\n", QYEL, QNRM);
|
||
return;
|
||
}
|
||
|
||
if ((zn = real_zone(znvnum)) == NOWHERE) {
|
||
send_to_char(ch, "That zone does not exist!\r\n");
|
||
return;
|
||
}
|
||
|
||
/* Check the builder list */
|
||
if (GET_LEVEL(ch) < LVL_GRGOD && !is_name(GET_NAME(ch), zone_table[zn].builders) && GET_OLC_ZONE(ch) != znvnum) {
|
||
send_to_char(ch, "You do not have sufficient access to unlock that zone!\r\n");
|
||
return;
|
||
}
|
||
|
||
/* If we get here, player has typed 'zunlock <num>' */
|
||
if (!ZONE_FLAGGED(zn, ZONE_NOBUILD)) {
|
||
send_to_char(ch, "Zone %d is already unlocked!\r\n", znvnum);
|
||
return;
|
||
}
|
||
REMOVE_BIT_AR(ZONE_FLAGS(zn), ZONE_NOBUILD);
|
||
if (save_zone(zn)) {
|
||
mudlog(NRM, MAX(LVL_GRGOD, GET_INVIS_LEV(ch)), TRUE, "(GC) %s has unlocked zone %d", GET_NAME(ch), znvnum);
|
||
}
|
||
else
|
||
{
|
||
send_to_char(ch, "Unable to save zone changes. Check syslog!\r\n");
|
||
}
|
||
}
|
||
|
||
/* get highest vnum in recent player list */
|
||
static int get_max_recent(void)
|
||
{
|
||
struct recent_player *this;
|
||
int iRet=0;
|
||
|
||
this = recent_list;
|
||
|
||
while (this)
|
||
{
|
||
if (this->vnum > iRet) iRet = this->vnum;
|
||
this = this->next;
|
||
}
|
||
|
||
return iRet;
|
||
}
|
||
|
||
/* clear an item in recent player list */
|
||
static void clear_recent(struct recent_player *this)
|
||
{
|
||
this->vnum = 0;
|
||
this->time = 0;
|
||
strcpy(this->name, "");
|
||
strcpy(this->host, "");
|
||
this->next = NULL;
|
||
}
|
||
|
||
/* create new blank player in recent players list */
|
||
static struct recent_player *create_recent(void)
|
||
{
|
||
struct recent_player *newrecent;
|
||
|
||
CREATE(newrecent, struct recent_player, 1);
|
||
clear_recent(newrecent);
|
||
newrecent->next = recent_list;
|
||
recent_list = newrecent;
|
||
|
||
newrecent->vnum = get_max_recent();
|
||
newrecent->vnum++;
|
||
return newrecent;
|
||
}
|
||
|
||
/* Add player to recent player list */
|
||
bool AddRecentPlayer(char *chname, char *chhost, bool newplr, bool cpyplr)
|
||
{
|
||
struct recent_player *this;
|
||
time_t ct;
|
||
int max_vnum;
|
||
|
||
if (!chname || !*chname) // dropped connection with no name given
|
||
return FALSE;
|
||
|
||
ct = time(0); /* Grab the current time */
|
||
|
||
this = create_recent();
|
||
|
||
if (!this) return FALSE;
|
||
|
||
this->time = ct;
|
||
this->new_player = newplr;
|
||
this->copyover_player = cpyplr;
|
||
strcpy(this->host, chhost);
|
||
strcpy(this->name, chname);
|
||
max_vnum = get_max_recent();
|
||
this->vnum = max_vnum; /* Possibly should be +1 ? */
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
void free_recent_players(void)
|
||
{
|
||
struct recent_player *this;
|
||
struct recent_player *temp;
|
||
|
||
this = recent_list;
|
||
|
||
while((temp = this) != NULL)
|
||
{
|
||
this = this->next;
|
||
free(temp);
|
||
}
|
||
}
|
||
|
||
ACMD(do_recent)
|
||
{
|
||
time_t ct;
|
||
char timestr[MAX_INPUT_LENGTH], arg[MAX_INPUT_LENGTH];
|
||
int hits = 0, limit = 0, count = 0;
|
||
struct recent_player *this;
|
||
bool loc;
|
||
|
||
one_argument(argument, arg);
|
||
if (!*arg) {
|
||
limit = 0;
|
||
} else {
|
||
limit = atoi(arg);
|
||
}
|
||
|
||
if (GET_LEVEL(ch) >= LVL_GRGOD) { /* If High-Level Imm, then show Host IP */
|
||
send_to_char(ch, " ID | DATE/TIME | HOST IP | Player Name\r\n");
|
||
} else {
|
||
send_to_char(ch, " ID | DATE/TIME | Player Name\r\n");
|
||
}
|
||
|
||
this = recent_list;
|
||
while(this)
|
||
{
|
||
loc = FALSE;
|
||
hits++;
|
||
ct = this->time;
|
||
strftime(timestr, sizeof(timestr), "%a %b %d %H:%M:%S %Y", localtime(&ct));
|
||
|
||
if (*(this->host)) {
|
||
if (!strcmp(this->host, "localhost")) loc = TRUE;
|
||
}
|
||
|
||
if ((limit == 0) || (count < limit))
|
||
{
|
||
if (GET_LEVEL(ch) >= LVL_GRGOD) /* If High-Level Imm, then show Host IP */
|
||
{
|
||
if (this->new_player == TRUE) {
|
||
send_to_char(ch, "%3d | %-24.24s | %s%-32s%s | %s %s(New Player)%s\r\n", this->vnum, timestr, loc ? QRED : "", this->host, QNRM, this->name, QYEL, QNRM);
|
||
} else if (this->copyover_player == TRUE) {
|
||
send_to_char(ch, "%3d | %-24.24s | %s%-32s%s | %s %s(Copyover)%s\r\n", this->vnum, timestr, loc ? QRED : "", this->host, QNRM, this->name, QCYN, QNRM);
|
||
} else {
|
||
send_to_char(ch, "%3d | %-24.24s | %s%-32s%s | %s\r\n", this->vnum, timestr, loc ? QRED : "", this->host, QNRM, this->name);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (this->new_player == TRUE) {
|
||
send_to_char(ch, "%3d | %-24.24s | %s %s(New Player)%s\r\n", this->vnum, timestr, this->name, QYEL, QNRM);
|
||
} else if (this->copyover_player == TRUE) {
|
||
send_to_char(ch, "%3d | %-24.24s | %s %s(Copyover)%s\r\n", this->vnum, timestr, this->name, QCYN, QNRM);
|
||
} else {
|
||
send_to_char(ch, "%3d | %-24.24s | %s\r\n", this->vnum, timestr, this->name);
|
||
}
|
||
}
|
||
count++;
|
||
|
||
this = this->next;
|
||
}
|
||
else
|
||
{
|
||
this = NULL;
|
||
}
|
||
}
|
||
|
||
ct = time(0); /* Grab the current time */
|
||
strftime(timestr, sizeof(timestr), "%c", localtime(&ct));
|
||
send_to_char(ch, "Current Server Time: %s\r\nShowing %d players since last copyover/reboot\r\n", timestr, hits);
|
||
}
|
||
|
||
|
||
/* 5e system helpers */
|
||
|
||
/* Helper: map wear flags to our armor_slots[] index (-1 if not an armor slot) */
|
||
static int armor_slot_index_from_wear(const struct obj_data *obj) {
|
||
if (!obj) return -1;
|
||
|
||
/* IMPORTANT: use your project's wear flag macros.
|
||
Typical tbaMUD macros: CAN_WEAR(obj, ITEM_WEAR_*) */
|
||
if (CAN_WEAR(obj, ITEM_WEAR_HEAD)) return 0; /* "head" */
|
||
if (CAN_WEAR(obj, ITEM_WEAR_BODY)) return 1; /* "body" */
|
||
if (CAN_WEAR(obj, ITEM_WEAR_LEGS)) return 2; /* "legs" */
|
||
if (CAN_WEAR(obj, ITEM_WEAR_ARMS)) return 3; /* "arms" */
|
||
if (CAN_WEAR(obj, ITEM_WEAR_HANDS)) return 4; /* "hands" */
|
||
if (CAN_WEAR(obj, ITEM_WEAR_FEET)) return 5; /* "feet" */
|
||
|
||
/* Shield is audited separately in AC compute; skip it here */
|
||
if (CAN_WEAR(obj, ITEM_WEAR_SHIELD)) return -2; /* special */
|
||
|
||
return -1;
|
||
}
|
||
|
||
/* Pretty: slot name (matches armor_slots[] order) */
|
||
static const char *slot_name_from_index(int idx) {
|
||
switch (idx) {
|
||
case 0: return "head";
|
||
case 1: return "body";
|
||
case 2: return "legs";
|
||
case 3: return "arms";
|
||
case 4: return "hands";
|
||
case 5: return "feet";
|
||
default: return "unknown";
|
||
}
|
||
}
|
||
|
||
/* Wizard command: scan armor prototypes, validate per-piece fields (compact, paged, 25 lines) */
|
||
ACMD(do_audit)
|
||
{
|
||
int found = 0, warned = 0;
|
||
char arg[MAX_INPUT_LENGTH];
|
||
bool do_armor = FALSE;
|
||
bool do_weapons = FALSE;
|
||
|
||
one_argument(argument, arg);
|
||
if (!*arg) {
|
||
send_to_char(ch, "Audit what?\r\n");
|
||
return;
|
||
}
|
||
if (is_abbrev(arg, "armor"))
|
||
do_armor = TRUE;
|
||
else if (is_abbrev(arg, "melee"))
|
||
do_weapons = TRUE;
|
||
else {
|
||
send_to_char(ch, "Usage: audit armor | audit melee\r\n");
|
||
return;
|
||
}
|
||
|
||
if (IS_NPC(ch) || GET_LEVEL(ch) < LVL_IMMORT) {
|
||
send_to_char(ch, "You lack the authority to use this.\r\n");
|
||
return;
|
||
}
|
||
|
||
/* --- dynamic buffer builder --- */
|
||
size_t cap = 8192, len = 0;
|
||
char *out = (char *)malloc(cap);
|
||
if (!out) { send_to_char(ch, "Memory error.\r\n"); return; }
|
||
out[0] = '\0';
|
||
|
||
#define APPEND_FMT(...) do { \
|
||
int need = snprintf(NULL, 0, __VA_ARGS__); \
|
||
if (need < 0) need = 0; \
|
||
if (len + (size_t)need + 1 > cap) { \
|
||
size_t ncap = cap * 2; \
|
||
if (ncap < len + (size_t)need + 1) ncap = len + (size_t)need + 1; \
|
||
char *tmp = (char *)realloc(out, ncap); \
|
||
if (!tmp) { free(out); send_to_char(ch, "Memory error.\r\n"); return; } \
|
||
out = tmp; cap = ncap; \
|
||
} \
|
||
len += (size_t)snprintf(out + len, cap - len, __VA_ARGS__); \
|
||
} while (0)
|
||
|
||
if (do_armor) {
|
||
/* Header (short so it won’t wrap) */
|
||
APPEND_FMT("\r\n\tY[Armor Audit]\tn ITEM_ARMOR scan\r\n");
|
||
APPEND_FMT("Legend: \tR!\tn over-cap, \tY?\tn warn, S stealth-disadv\r\n");
|
||
|
||
for (obj_rnum r = 0; r <= top_of_objt; r++) {
|
||
struct obj_data *obj = &obj_proto[r];
|
||
char namebuf[128] = {0};
|
||
int idx, vnum, piece_ac, bulk, magic, stealth, strreq;
|
||
|
||
if (GET_OBJ_TYPE(obj) != ITEM_ARMOR)
|
||
continue;
|
||
|
||
/* Identify slot (skip shields here) */
|
||
idx = armor_slot_index_from_wear(obj);
|
||
if (idx == -2) continue; /* shield handled in AC; skip */
|
||
if (idx < 0) continue; /* not a supported armor slot */
|
||
|
||
vnum = GET_OBJ_VNUM(obj);
|
||
piece_ac = GET_OBJ_VAL(obj, VAL_ARMOR_PIECE_AC);
|
||
bulk = GET_OBJ_VAL(obj, VAL_ARMOR_BULK);
|
||
magic = GET_OBJ_VAL(obj, VAL_ARMOR_MAGIC_BONUS);
|
||
stealth = GET_OBJ_VAL(obj, VAL_ARMOR_STEALTH_DISADV); /* 1/0, yes or no */
|
||
strreq = GET_OBJ_VAL(obj, VAL_ARMOR_STR_REQ); /* 0 or 13/15/16 typically */
|
||
|
||
/* Display name (trim to keep line width < ~78 cols) */
|
||
if (obj->short_description)
|
||
snprintf(namebuf, sizeof(namebuf), "%s", obj->short_description);
|
||
else if (obj->name)
|
||
snprintf(namebuf, sizeof(namebuf), "%s", obj->name);
|
||
else
|
||
snprintf(namebuf, sizeof(namebuf), "object");
|
||
|
||
/* Slot caps */
|
||
const int max_piece_ac = armor_slots[idx].max_piece_ac;
|
||
const int max_magic = armor_slots[idx].max_magic;
|
||
|
||
/* Validations */
|
||
bool over_ac = (piece_ac > max_piece_ac);
|
||
bool over_magic = (magic > max_magic);
|
||
bool bad_ac = (piece_ac < 0 || piece_ac > 3);
|
||
bool bad_bulk = (bulk < 0 || bulk > 3);
|
||
bool bad_magic = (magic < 0 || magic > 3);
|
||
|
||
found++;
|
||
|
||
/* Compact, non-wrapping row (~70 cols worst case) */
|
||
APPEND_FMT("\tc[#%5d]\tn %-24.24s sl=%-5.5s ac=%2d%s b=%d%s m=%+d%s sd=%d str=%d\r\n",
|
||
vnum,
|
||
namebuf,
|
||
slot_name_from_index(idx),
|
||
piece_ac, over_ac ? " \tR!\tn" : (bad_ac ? " \tY?\tn" : ""),
|
||
bulk, bad_bulk ? " \tY?\tn" : "",
|
||
magic, over_magic ? " \tR!\tn" : (bad_magic? " \tY?\tn" : ""),
|
||
stealth, strreq);
|
||
|
||
if (over_ac || over_magic || bad_ac || bad_bulk || bad_magic)
|
||
warned++;
|
||
}
|
||
|
||
if (!found) {
|
||
free(out);
|
||
send_to_char(ch, "No ITEM_ARMOR prototypes found for the audited slots.\r\n");
|
||
return;
|
||
}
|
||
|
||
/* Footer */
|
||
APPEND_FMT("\r\nScanned: %d items, %d with issues. Armor magic cap +%d (shield separate).\r\n",
|
||
found, warned, MAX_TOTAL_ARMOR_MAGIC);
|
||
} else if (do_weapons) {
|
||
APPEND_FMT("\r\n\tY[Weapon Audit]\tn ITEM_WEAPON scan\r\n");
|
||
APPEND_FMT("Legend: \tR!\tn error, \tY?\tn warn, dmg=1d4/1d6/1d8/1d10/1d12\r\n");
|
||
|
||
for (obj_rnum r = 0; r <= top_of_objt; r++) {
|
||
struct obj_data *obj = &obj_proto[r];
|
||
char namebuf[128] = {0};
|
||
int vnum, ndice, sdice, atype, weight;
|
||
bool bad_type, bad_dmg, bad_weight;
|
||
const char *atype_name;
|
||
|
||
if (GET_OBJ_TYPE(obj) != ITEM_WEAPON)
|
||
continue;
|
||
|
||
vnum = GET_OBJ_VNUM(obj);
|
||
ndice = GET_OBJ_VAL(obj, 0);
|
||
sdice = GET_OBJ_VAL(obj, 1);
|
||
atype = GET_OBJ_VAL(obj, 2);
|
||
weight = GET_OBJ_WEIGHT(obj);
|
||
|
||
/* Display name (trim to keep line width < ~78 cols) */
|
||
if (obj->short_description)
|
||
snprintf(namebuf, sizeof(namebuf), "%s", obj->short_description);
|
||
else if (obj->name)
|
||
snprintf(namebuf, sizeof(namebuf), "%s", obj->name);
|
||
else
|
||
snprintf(namebuf, sizeof(namebuf), "object");
|
||
|
||
bad_type = (atype < 0 || atype >= NUM_ATTACK_TYPES);
|
||
bad_dmg = !(ndice == 1 &&
|
||
(sdice == 4 || sdice == 6 || sdice == 8 || sdice == 10 || sdice == 12));
|
||
bad_weight = (weight <= 0);
|
||
|
||
if (bad_type)
|
||
atype_name = "invalid";
|
||
else
|
||
atype_name = attack_hit_text[atype].singular;
|
||
|
||
found++;
|
||
|
||
APPEND_FMT("\tc[#%5d]\tn %-24.24s at=%-7.7s%s dmg=%dd%d%s wt=%d%s\r\n",
|
||
vnum,
|
||
namebuf,
|
||
atype_name, bad_type ? " \tR!\tn" : "",
|
||
ndice, sdice, bad_dmg ? " \tR!\tn" : "",
|
||
weight, bad_weight ? " \tY?\tn" : "");
|
||
|
||
if (bad_type || bad_dmg || bad_weight)
|
||
warned++;
|
||
}
|
||
|
||
if (!found) {
|
||
free(out);
|
||
send_to_char(ch, "No ITEM_WEAPON prototypes found.\r\n");
|
||
return;
|
||
}
|
||
|
||
APPEND_FMT("\r\nScanned: %d items, %d with issues.\r\n", found, warned);
|
||
}
|
||
|
||
/* Page it (copy mode) and try to force 25-line pages */
|
||
if (ch->desc) {
|
||
int old_len = 0; bool changed = false;
|
||
#if defined(GET_SCREEN_HEIGHT)
|
||
old_len = GET_SCREEN_HEIGHT(ch); GET_SCREEN_HEIGHT(ch) = 25; changed = true;
|
||
#elif defined(GET_PAGE_LENGTH)
|
||
old_len = GET_PAGE_LENGTH(ch); GET_PAGE_LENGTH(ch) = 25; changed = true;
|
||
#endif
|
||
page_string(ch->desc, out, 0); /* copy; we free out */
|
||
free(out);
|
||
if (changed) {
|
||
#if defined(GET_SCREEN_HEIGHT)
|
||
GET_SCREEN_HEIGHT(ch) = old_len;
|
||
#elif defined(GET_PAGE_LENGTH)
|
||
GET_PAGE_LENGTH(ch) = old_len;
|
||
#endif
|
||
}
|
||
} else {
|
||
send_to_char(ch, "%s", out);
|
||
free(out);
|
||
}
|
||
|
||
#undef APPEND_FMT
|
||
}
|
||
|
||
/* ====== Builder snapshot: save a staged mob's gear as its prototype loadout ====== */
|
||
/* Put these helpers near the top of act.wizard.c (or a shared .c) */
|
||
struct inv_count { obj_vnum vnum; int qty; struct inv_count *next; };
|
||
|
||
static void inv_add(struct inv_count **head, obj_vnum v, int q) {
|
||
struct inv_count *p;
|
||
if (q < 1) q = 1;
|
||
for (p = *head; p; p = p->next)
|
||
if (p->vnum == v) { p->qty += q; return; }
|
||
CREATE(p, struct inv_count, 1);
|
||
p->vnum = v; p->qty = q; p->next = *head; *head = p;
|
||
}
|
||
|
||
static void inv_free_all(struct inv_count **head) {
|
||
struct inv_count *n, *p = *head;
|
||
while (p) { n = p->next; free(p); p = n; }
|
||
*head = NULL;
|
||
}
|
||
|
||
/* Add ACMD prototype to interpreter.h: ACMD(do_msave); */
|
||
|
||
ACMD(do_msave)
|
||
{
|
||
char a1[MAX_INPUT_LENGTH], a2[MAX_INPUT_LENGTH];
|
||
char target[MAX_INPUT_LENGTH] = {0}, flags[MAX_INPUT_LENGTH] = {0};
|
||
struct char_data *vict = NULL, *tmp = NULL;
|
||
mob_rnum rnum;
|
||
int include_inv = 0; /* -all */
|
||
int clear_first = 1; /* default replace; -append flips this to 0 */
|
||
int equips_added = 0, inv_entries = 0;
|
||
struct inv_count *inv = NULL;
|
||
int pos;
|
||
struct obj_data *o;
|
||
|
||
two_arguments(argument, a1, a2);
|
||
if (*a1 && *a1 == '-') {
|
||
/* user wrote: msave -flags <mob> */
|
||
strcpy(flags, a1);
|
||
strcpy(target, a2);
|
||
} else {
|
||
/* user wrote: msave <mob> [-flags] */
|
||
strcpy(target, a1);
|
||
strcpy(flags, a2);
|
||
}
|
||
|
||
/* Parse flags (space-separated, any order) */
|
||
if (*flags) {
|
||
char buf[MAX_INPUT_LENGTH], *p = flags;
|
||
while (*p) {
|
||
p = one_argument(p, buf);
|
||
if (!*buf) break;
|
||
if (!str_cmp(buf, "-all")) include_inv = 1;
|
||
else if (!str_cmp(buf, "-append")) clear_first = 0;
|
||
else if (!str_cmp(buf, "-clear")) clear_first = 1;
|
||
else {
|
||
send_to_char(ch, "Unknown flag '%s'. Try -all, -append, or -clear.\r\n", buf);
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Find target mob in the room */
|
||
if (*target)
|
||
vict = get_char_vis(ch, target, NULL, FIND_CHAR_ROOM);
|
||
else {
|
||
/* No name: pick the first NPC only if exactly one exists */
|
||
for (tmp = world[IN_ROOM(ch)].people; tmp; tmp = tmp->next_in_room) {
|
||
if (IS_NPC(tmp)) {
|
||
if (vict) { vict = NULL; break; } /* more than one — force explicit name */
|
||
vict = tmp;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (!vict || !IS_NPC(vict)) {
|
||
send_to_char(ch, "Target an NPC in this room: msave <mob> [-all] [-append|-clear]\r\n");
|
||
return;
|
||
}
|
||
|
||
/* Resolve prototype and permission to edit its zone */
|
||
rnum = GET_MOB_RNUM(vict);
|
||
if (rnum < 0) {
|
||
send_to_char(ch, "I can’t resolve that mob's prototype.\r\n");
|
||
return;
|
||
}
|
||
|
||
#ifdef CAN_EDIT_ZONE
|
||
if (!can_edit_zone(ch, real_zone_by_thing(GET_MOB_VNUM(vict)))) {
|
||
send_to_char(ch, "You don’t have permission to modify that mob’s zone.\r\n");
|
||
return;
|
||
}
|
||
#endif
|
||
|
||
/* Build the new loadout into the PROTOTYPE */
|
||
if (clear_first)
|
||
loadout_free_list(&mob_proto[rnum].proto_loadout);
|
||
|
||
/* Capture equipment: one entry per worn slot */
|
||
for (pos = 0; pos < NUM_WEARS; pos++) {
|
||
o = GET_EQ(vict, pos);
|
||
if (!o) continue;
|
||
if (GET_OBJ_VNUM(o) <= 0) continue;
|
||
loadout_add_entry(&mob_proto[rnum].proto_loadout, GET_OBJ_VNUM(o), (int)pos, 1);
|
||
equips_added++;
|
||
}
|
||
|
||
/* Capture inventory (compressed by vnum) if requested */
|
||
if (include_inv) {
|
||
for (o = vict->carrying; o; o = o->next_content) {
|
||
if (GET_OBJ_VNUM(o) <= 0) continue;
|
||
inv_add(&inv, GET_OBJ_VNUM(o), 1);
|
||
}
|
||
{
|
||
struct inv_count *p;
|
||
for (p = inv; p; p = p->next) {
|
||
loadout_add_entry(&mob_proto[rnum].proto_loadout, p->vnum, -1, MAX(1, p->qty));
|
||
inv_entries++;
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Persist to disk: save the zone owning this mob vnum */
|
||
{
|
||
zone_rnum zr = real_zone_by_thing(GET_MOB_VNUM(vict));
|
||
if (zr == NOWHERE) {
|
||
mudlog(CMP, MAX(LVL_GOD, GET_INVIS_LEV(ch)), TRUE,
|
||
"msave: could not resolve zone for mob %d", GET_MOB_VNUM(vict));
|
||
send_to_char(ch, "Saved in memory, but couldn’t resolve zone to write disk.\r\n");
|
||
} else {
|
||
save_mobiles(zr);
|
||
send_to_char(ch,
|
||
"Loadout saved for mob [%d]. Equipped: %d, Inventory lines: %d%s\r\n",
|
||
GET_MOB_VNUM(vict), equips_added, inv_entries, include_inv ? "" : " (use -all to include inventory)");
|
||
mudlog(CMP, MAX(LVL_GOD, GET_INVIS_LEV(ch)), TRUE,
|
||
"msave: %s saved loadout for mob %d (eq=%d, inv=%d) in zone %d",
|
||
GET_NAME(ch), GET_MOB_VNUM(vict), equips_added, inv_entries,
|
||
zone_table[zr].number);
|
||
}
|
||
}
|
||
|
||
inv_free_all(&inv);
|
||
}
|
||
|
||
ACMD(do_rsave)
|
||
{
|
||
room_rnum rnum;
|
||
zone_rnum znum;
|
||
int ok;
|
||
|
||
if (IS_NPC(ch)) {
|
||
send_to_char(ch, "Mobiles can’t use this.\r\n");
|
||
return;
|
||
}
|
||
|
||
/* IN_ROOM(ch) is already a room_rnum (index into world[]). Do NOT pass it to real_room(). */
|
||
rnum = IN_ROOM(ch);
|
||
|
||
if (rnum == NOWHERE || rnum < 0 || rnum > top_of_world) {
|
||
send_to_char(ch, "You are not in a valid room.\r\n");
|
||
return;
|
||
}
|
||
|
||
znum = world[rnum].zone;
|
||
if (znum < 0 || znum > top_of_zone_table) {
|
||
send_to_char(ch, "This room is not attached to a valid zone.\r\n");
|
||
return;
|
||
}
|
||
|
||
/* Optional: permission check */
|
||
if (!can_edit_zone(ch, znum)) {
|
||
send_to_char(ch, "You don’t have permission to modify zone %d.\r\n",
|
||
zone_table[znum].number);
|
||
return;
|
||
}
|
||
|
||
/* Save just this room into the correct zone’s .rsv file */
|
||
ok = RoomSave_now(rnum);
|
||
|
||
if (!ok) {
|
||
send_to_char(ch, "rsave: failed.\r\n");
|
||
mudlog(BRF, GET_LEVEL(ch), TRUE,
|
||
"RSAVE FAIL: %s room %d (rnum=%d) zone %d (znum=%d)",
|
||
GET_NAME(ch), GET_ROOM_VNUM(rnum), rnum,
|
||
zone_table[znum].number, znum);
|
||
return;
|
||
}
|
||
|
||
send_to_char(ch, "rsave: room %d saved to roomsave file for zone %d.\r\n",
|
||
GET_ROOM_VNUM(rnum), zone_table[znum].number);
|
||
|
||
mudlog(CMP, GET_LEVEL(ch), TRUE,
|
||
"RSAVE OK: %s room %d (rnum=%d) -> world/rsv/%d.rsv",
|
||
GET_NAME(ch), GET_ROOM_VNUM(rnum), rnum, zone_table[znum].number);
|
||
}
|