/* ************************************************************************
* File: db.c EmpireMUD AD 1.0 *
* Usage: Loading/saving chars, booting/resetting world, internal funcs *
* *
* All rights reserved. See license.doc for complete information. *
* *
* Code base by Paul Clarke. EmpireMUD Project, a tbgMUD Production. *
* Based upon CircleMUD 3.0, beta patch level 17, by Jeremy Elson. *
* *
* Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University *
* CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991. *
************************************************************************ */
#define __DB_C__
#include "conf.h"
#include "sysdep.h"
#include "structs.h"
#include "utils.h"
#include "db.h"
#include "comm.h"
#include "handler.h"
#include "mail.h"
#include "interpreter.h"
#include "empire.h"
/**************************************************************************
* declarations of most of the 'global' variables *
**************************************************************************/
Room world = NULL; /* array of rooms */
room_rnum top_of_world = 0; /* ref to top element of world */
int num_of_start_locs = -1; /* maximum start locations */
int *start_locs = NULL; /* list of start locations */
Creature character_list = NULL; /* global linked list of chars */
struct index_data *mob_index; /* index table for mobile file */
Creature mob_proto; /* prototypes for mobs */
mob_rnum top_of_mobt = 0; /* top of mobile index table */
Object object_list = NULL; /* global linked list of objs */
struct index_data *obj_index; /* index table for object file */
Object obj_proto; /* prototypes for objs */
obj_rnum top_of_objt = 0; /* top of object index table */
struct zone_data *zone_table; /* zone table */
zone_rnum top_of_zone_table = 0; /* top element of zone tab */
struct message_list fight_messages[MAX_MESSAGES]; /* fighting messages */
struct player_index_element *player_table = NULL; /* index to plr file */
FILE *player_fl = NULL; /* file desc of player file */
int top_of_p_table = 0; /* ref to top of table */
int top_of_p_file = 0; /* ref of size of p file */
long top_idnum = 0; /* highest idnum in use */
int no_mail = 0; /* mail disabled? */
int no_rent_check = 0; /* skip rent check on boot? */
time_t boot_time = 0; /* time of mud boot */
int wizlock_level = 0; /* level of game restriction */
char *wizlock_message = NULL; /* Message sent to people trying to connect */
char *credits = NULL; /* game credits */
char *motd = NULL; /* message of the day - mortals */
char *imotd = NULL; /* message of the day - immorts */
char *GREETINGS = NULL; /* introduction screen */
char *MENU = NULL; /* main menu */
char *CREDIT_MESSG; /* short credits */
char *help = NULL; /* help screen */
char *info = NULL; /* info page */
char *wizlist = NULL; /* list of higher gods */
char *godlist = NULL; /* list of peon gods */
char *background = NULL; /* background story */
char *handbook = NULL; /* handbook for new immortals */
char *policies = NULL; /* policies page */
int new_rotation = 0; /* Zone saving rotation, to save time */
int exp_cycle = 0; /* Experience cycle for exp-per-day */
time_t last_exp_cycle; /* Last time the cycle updated */
struct help_index_element *help_table = 0; /* the help table */
int top_of_helpt = 0; /* top of help index table */
struct time_info_data time_info;/* the infomation about the time */
struct weather_data weather_info; /* the infomation about the weather */
struct player_special_data dummy_mob; /* dummy spec area for mobs */
int Global_ignore_dark = 0; /* For use in public channels */
/* external functions */
int find_name(char *name);
void prune_crlf(char *txt);
#define READ_SIZE 256
void strip_string(char *buffer) {
register char *ptr, *str;
ptr = buffer;
str = ptr;
while((*str = *ptr)) {
str++;
ptr++;
if (*ptr == '\r')
ptr++;
}
}
bitvector_t asciiflag_conv(char *flag) {
bitvector_t flags = 0;
int is_number = 1;
register char *p;
for (p = flag; *p; p++) {
if (islower(*p))
flags |= 1 << (*p - 'a');
else if (isupper(*p))
flags |= 1 << (26 + (*p - 'A'));
if (!isdigit(*p))
is_number = 0;
}
if (is_number)
flags = atol(flag);
return (flags);
}
/*
* Steps:
* 1: Make sure no one is using the pointer in paging.
* 2: Read contents of a text file.
* 3: Allocate space.
* 4: Point 'buf' to it.
*
* We don't want to free() the string that someone may be
* viewing in the pager. page_string() keeps the internal
* str_dup()'d copy on ->showstr_head and it won't care
* if we delete the original. Otherwise, strings are kept
* on ->showstr_vector but we'll only match if the pointer
* is to the string we're interested in and not a copy.
*/
int file_to_string_alloc(const char *name, char **buf) {
extern int file_to_string(const char *name, char *buf);
char temp[MAX_STRING_LENGTH];
Descr in_use;
for (in_use = descriptor_list; in_use; in_use = in_use->next)
if (in_use->showstr_vector && *in_use->showstr_vector == *buf)
return (-1);
/* Lets not free() what used to be there unless we succeeded. */
if (file_to_string(name, temp) < 0)
return (-1);
if (*buf)
free(*buf);
*buf = str_dup(temp);
return (0);
}
/* read contents of a text file, and place in buf */
int file_to_string(const char *name, char *buf) {
FILE *fl;
char tmp[READ_SIZE+3];
*buf = '\0';
if (!(fl = fopen(name, "r"))) {
log("SYSERR: reading %s: %s", name, strerror(errno));
return (-1);
}
do {
fgets(tmp, READ_SIZE, fl);
tmp[strlen(tmp) - 1] = '\0'; /* take off the trailing \n */
strcat(tmp, "\r\n");
if (!feof(fl)) {
if (strlen(buf) + strlen(tmp) + 1 > MAX_STRING_LENGTH) {
log("SYSERR: %s: string too big (%d max)", name, MAX_STRING_LENGTH);
*buf = '\0';
return (-1);
}
strcat(buf, tmp);
}
} while (!feof(fl));
fclose(fl);
return (0);
}
int check_object(Object obj) {
extern const char *affected_bits[];
extern const char *wear_bits[];
extern const char *extra_bits[];
int error = FALSE;
if (GET_OBJ_WEIGHT(obj) < 0 && (error = TRUE))
log("SYSERR: Object #%d (%s) has negative weight (%d).", GET_OBJ_VNUM(obj), obj->short_description, GET_OBJ_WEIGHT(obj));
sprintbit(GET_OBJ_WEAR(obj), wear_bits, buf, TRUE);
if (strstr(buf, "UNDEFINED") && (error = TRUE))
log("SYSERR: Object #%d (%s) has unknown wear flags.", GET_OBJ_VNUM(obj), obj->short_description);
sprintbit(GET_OBJ_EXTRA(obj), extra_bits, buf, TRUE);
if (strstr(buf, "UNDEFINED") && (error = TRUE))
log("SYSERR: Object #%d (%s) has unknown extra flags.", GET_OBJ_VNUM(obj), obj->short_description);
sprintbit(obj->obj_flags.bitvector, affected_bits, buf, TRUE);
if (strstr(buf, "UNDEFINED") && (error = TRUE))
log("SYSERR: Object #%d (%s) has unknown affection flags.", GET_OBJ_VNUM(obj), obj->short_description);
switch (GET_OBJ_TYPE(obj)) {
case ITEM_DRINKCON:
if (GET_OBJ_VAL(obj, 1) > GET_OBJ_VAL(obj, 0) && (error = TRUE))
log("SYSERR: Object #%d (%s) contains (%d) more than maximum (%d).",
GET_OBJ_VNUM(obj), obj->short_description,
GET_OBJ_VAL(obj, 1), GET_OBJ_VAL(obj, 0));
break;
}
return (error);
}
/* read direction data */
void setup_dir(FILE * fl, int room, int dir) {
int t[5];
char line[256];
sprintf(buf2, "room #%d, direction D%d", GET_ROOM_VNUM(room), dir);
CREATE(world[room].dir_option[dir], struct room_direction_data, 1);
world[room].dir_option[dir]->keyword = fread_string(fl, buf2);
if (!get_line(fl, line)) {
log("SYSERR: Format error, %s", buf2);
exit(1);
}
if (sscanf(line, " %d %d ", t, t + 1) != 2) {
log("SYSERR: Format error, %s", buf2);
exit(1);
}
if (t[0] == 1)
world[room].dir_option[dir]->exit_info = EX_ISDOOR;
else
world[room].dir_option[dir]->exit_info = 0;
world[room].dir_option[dir]->to_room = t[1];
}
/* load the rooms */
void parse_room(FILE *fl, int virtual_nr) {
static int room_nr = 0, zone = 0;
int t[10], i, j;
char line[256], line2[256];
sprintf(buf2, "room #%d", virtual_nr);
if (virtual_nr <= (zone ? zone_table[zone - 1].top : -1)) {
log("SYSERR: Room #%d is below zone %d.", virtual_nr, zone);
exit(1);
}
while (virtual_nr > zone_table[zone].top)
if (++zone > top_of_zone_table) {
log("SYSERR: Room %d is outside of any zone.", virtual_nr);
exit(1);
}
world[room_nr].zone = zone;
world[room_nr].number = virtual_nr;
if (!get_line(fl, line)) {
log("SYSERR: Expecting sector type of room #%d but file ended!", virtual_nr);
exit(1);
}
if (sscanf(line, "%d", t) != 1) {
log("SYSERR: Format error in sector type of room #%d", virtual_nr);
exit(1);
}
world[room_nr].sector_type = t[0];
world[room_nr].contents = NULL;
world[room_nr].people = NULL;
world[room_nr].light = 0; /* Zero light sources */
for (i = 0; i < NUM_OF_DIRS; i++)
world[room_nr].dir_option[i] = NULL;
sprintf(buf,"SYSERR: Format error in room #%d (expecting D/E/S)", virtual_nr);
/* In case it's not assigned */
world[room_nr].home_room = NOWHERE;
world[room_nr].name = NULL;
world[room_nr].description = NULL;
world[room_nr].icon = NULL;
for (;;) {
if (!get_line(fl, line)) {
log(buf);
exit(1);
}
switch (*line) {
case 'A': /* type2 */
j = atoi(line+1);
world[room_nr].type2 = j;
break;
case 'B': /* build_value */
j = atoi(line+1);
world[room_nr].build_value = j;
break;
case 'C': /* type */
j = atoi(line+1);
world[room_nr].type = j;
break;
case 'D': /* dir_option */
setup_dir(fl, room_nr, atoi(line + 1));
break;
case 'E': /* affects */
if (!get_line(fl, line2))
break;
world[room_nr].base_affects = asciiflag_conv(line2);
SET_BIT(world[room_nr].affects, world[room_nr].base_affects);
break;
case 'G': /* spare */
j = atoi(line+1);
world[room_nr].spare = j;
break;
case 'H': /* home_room */
j = atoi(line+1);
world[room_nr].home_room = j;
break;
case 'I': /* icon */
sprintf(buf2, "room vnum %d", virtual_nr);
world[room_nr].icon = fread_string(fl, buf2);
break;
case 'M': /* description */
sprintf(buf2, "room vnum %d", virtual_nr);
world[room_nr].description = fread_string(fl, buf2);
break;
case 'N': /* name */
sprintf(buf2, "room vnum %d", virtual_nr);
world[room_nr].name = fread_string(fl, buf2);
break;
case 'O': /* owner (idnum) */
j = atol(line+1);
world[room_nr].owner = j;
break;
case 'R': /* resources */
if (!get_line(fl, line2)) {
log("SYSERR: Format in resource line of room #%d", virtual_nr);
exit(1);
}
if ((sscanf(line2, "%d %d %d %d", t, t+1, t+2, t+3)) != 4) {
log("SYSERR: Format in resource line of room #%d", virtual_nr);
exit(1);
}
world[room_nr].res.logs = t[0];
world[room_nr].res.sticks = t[1];
world[room_nr].res.rocks = t[2];
world[room_nr].res.iron = t[3];
break;
case 'X': /* building_entrance (SECT_BUILDING) */
j = atoi(line+1);
world[room_nr].building_entrance = j;
break;
case 'Z': /* burning, damage, dismantling */
if (!get_line(fl, line2)) {
log("SYSERR: Format in damage line Z of room #%d", virtual_nr);
exit(1);
}
if ((sscanf(line2, "%d %d %d", t, t+1, t+2)) != 3) {
log("SYSERR: Format in damage line Z of room #%d", virtual_nr);
exit(1);
}
world[room_nr].burning = t[0];
world[room_nr].damage = t[1];
world[room_nr].dismantling = t[2];
break;
case 'S': /* end of room */
top_of_world = room_nr++;
return;
default:
log(buf);
exit(1);
}
}
}
void parse_mobile(FILE *mob_f, int nr) {
static int i = 0;
int j, t[10];
char line[256], *tmpptr;
char f1[128], f2[128], f3[128];
mob_index[i].vnum = nr;
mob_index[i].number = 0;
clear_char(mob_proto + i);
/*
* Mobiles should NEVER use anything in the 'player_specials' structure.
* The only reason we have every mob in the game share this copy of the
* structure is to save newbie coders from themselves. -gg 2/25/98
*/
mob_proto[i].player_specials = &dummy_mob;
sprintf(buf2, "mob vnum %d", nr);
/***** String data *****/
mob_proto[i].player.name = fread_string(mob_f, buf2);
tmpptr = mob_proto[i].player.short_descr = fread_string(mob_f, buf2);
if (tmpptr && *tmpptr)
if (!str_cmp(fname(tmpptr), "a") || !str_cmp(fname(tmpptr), "an") || !str_cmp(fname(tmpptr), "the"))
*tmpptr = LOWER(*tmpptr);
mob_proto[i].player.long_descr = fread_string(mob_f, buf2);
mob_proto[i].player.title = NULL;
/* *** Numeric data *** */
if (!get_line(mob_f, line)) {
log("SYSERR: Format error after string section of mob #%d\n"
"...expecting line of form '# # # # #', but file ended!", nr);
exit(1);
}
if (sscanf(line, "%s %s %d %d %s", f1, f2, t + 1, t + 2, f3) != 5) {
log("SYSERR: Format error after string section of mob #%d\n"
"...expecting line of form '# # # # #'", nr);
exit(1);
}
MOB_FLAGS(mob_proto + i) = asciiflag_conv(f1);
SET_BIT(MOB_FLAGS(mob_proto + i), MOB_ISNPC);
AFF_FLAGS(mob_proto + i) = asciiflag_conv(f2);
mob_proto[i].mob_specials.type = t[1];
mob_proto[i].player.sex = t[2];
MOB_SECTS(mob_proto + i) = asciiflag_conv(f3);
/* *** Attack Data *** */
if (!get_line(mob_f, line)) {
log("SYSERR: Format error after first numeric line of mob #%d\n"
"...expecting line of form '# # # #', but file ended!", nr);
exit(1);
}
if (sscanf(line, "%d %d %d %d %d", t, t + 1, t + 2, t + 3, t + 4) != 5) {
log("SYSERR: Format error after first numeric line of mob #%d\n"
"...expecting line of form '# # # #'", nr);
exit(1);
}
mob_proto[i].mob_specials.to_hit = t[0];
mob_proto[i].mob_specials.to_dodge = t[1];
mob_proto[i].mob_specials.damage = t[2];
mob_proto[i].mob_specials.attack_type = t[3];
mob_proto[i].mob_specials.skin = t[4];
/* *** Physical Stats *** */
if (!get_line(mob_f, line)) {
log("SYSERR: Format error in attribute line 1 of mob #%d\n"
"...expecting line of form '# # #', but file ended!", nr);
exit(1);
}
if (sscanf(line, "%d %d %d", t, t + 1, t + 2) != 3) {
log("SYSERR: Format error in attribute line 1 of mob #%d\n"
"...expecting line of form '# # #'", nr);
exit(1);
}
mob_proto[i].real_abils.strength = t[0];
mob_proto[i].real_abils.dexterity = t[1];
mob_proto[i].real_abils.stamina = t[2];
/* *** Social Stats *** */
if (!get_line(mob_f, line)) {
log("SYSERR: Format error in attribute line 2 of mob #%d\n"
"...expecting line of form '# # #', but file ended!", nr);
exit(1);
}
if (sscanf(line, "%d %d %d", t, t + 1, t + 2) != 3) {
log("SYSERR: Format error in attribute line 2 of mob #%d\n"
"...expecting line of form '# # #'", nr);
exit(1);
}
mob_proto[i].real_abils.charisma = t[0];
mob_proto[i].real_abils.manipulation = t[1];
mob_proto[i].real_abils.appearance = t[2];
/* *** Mental Stats *** */
if (!get_line(mob_f, line)) {
log("SYSERR: Format error in attribute line 3 of mob #%d\n"
"...expecting line of form '# # #', but file ended!", nr);
exit(1);
}
if (sscanf(line, "%d %d %d", t, t + 1, t + 2) != 3) {
log("SYSERR: Format error in attribute line 3 of mob #%d\n"
"...expecting line of form '# # #'", nr);
exit(1);
}
mob_proto[i].real_abils.perception = t[0];
mob_proto[i].real_abils.intelligence = t[1];
mob_proto[i].real_abils.wits = t[2];
mob_proto[i].points.humanity = 3;
mob_proto[i].points.willpower = 3;
mob_proto[i].points.max_willpower = 3;
mob_proto[i].points.conscience = 3;
mob_proto[i].points.self_control = 3;
mob_proto[i].points.courage = 3;
mob_proto[i].points.damage = 0;
mob_proto[i].points.max_move = 100;
mob_proto[i].player.weight = 200;
mob_proto[i].player.height = 198;
mob_proto[i].char_specials.position = POS_STANDING;
mob_proto[i].aff_abils = mob_proto[i].real_abils;
for (j = 0; j < NUM_WEARS; j++)
mob_proto[i].equipment[j] = NULL;
mob_proto[i].nr = i;
mob_proto[i].desc = NULL;
sprintf(buf2, "mob %d, after numeric constants\n...expecting alphabetic flags", nr);
j = 0;
for (;;) {
if (!get_line(mob_f, line)) {
log("SYSERR: Format error in %s", buf2);
exit(1);
}
switch (*line) {
case 'F':
if (!get_line(mob_f, line)) {
log("SYSERR: Format error in 'F' field, %s\n...expecting spec number but file ended!", buf2);
exit(1);
}
if (sscanf(line, " %d %d ", t, t + 1) != 2) {
log("SYSERR: Unable to read 'F' value, %s", buf2);
exit(1);
}
if ((t[0] = find_mob_special_by_number(t[0])) != -1)
mob_index[i].spec_proc = mob_spec[t[0]].spec_proc;
if ((t[1] = find_mob_special_by_number(t[1])) != -1)
mob_index[i].look_spec = mob_spec[t[1]].look_spec;
break;
case 'S':
top_of_mobt = i++;
return;
default:
log("SYSERR: Format error in %s", buf2);
exit(1);
}
}
}
/* read all objects from obj file; generate index and prototypes */
void parse_object(FILE * obj_f, int nr) {
static int i = 0;
static char line[256];
int t[10], j = 0, retval;
char *tmpptr;
char f1[256], f2[256];
struct extra_descr_data *new_descr;
obj_index[i].vnum = nr;
obj_index[i].number = 0;
clear_object(obj_proto + i);
obj_proto[i].item_number = i;
sprintf(buf2, "object #%d", nr);
/* *** string data *** */
if ((obj_proto[i].name = fread_string(obj_f, buf2)) == NULL) {
log("SYSERR: Null obj name or format error at or near %s", buf2);
exit(1);
}
tmpptr = obj_proto[i].short_description = fread_string(obj_f, buf2);
if (tmpptr && *tmpptr)
if (!str_cmp(fname(tmpptr), "a") || !str_cmp(fname(tmpptr), "an") || !str_cmp(fname(tmpptr), "the"))
*tmpptr = LOWER(*tmpptr);
tmpptr = obj_proto[i].description = fread_string(obj_f, buf2);
if (tmpptr && *tmpptr)
CAP(tmpptr);
obj_proto[i].action_description = fread_string(obj_f, buf2);
/* *** numeric data *** */
if (!get_line(obj_f, line)) {
log("SYSERR: Expecting first numeric line of %s, but file ended!", buf2);
exit(1);
}
if ((retval = sscanf(line, " %d %s %s", t, f1, f2)) != 3) {
log("SYSERR: Format error in first numeric line (expecting 3 args, got %d), %s", retval, buf2);
exit(1);
}
obj_proto[i].obj_flags.type_flag = t[0];
obj_proto[i].obj_flags.extra_flags = asciiflag_conv(f1);
obj_proto[i].obj_flags.wear_flags = asciiflag_conv(f2);
if (!get_line(obj_f, line)) {
log("SYSERR: Expecting second numeric line of %s, but file ended!", buf2);
exit(1);
}
if ((retval = sscanf(line, "%d %d %d", t, t + 1, t + 2)) != 3) {
log("SYSERR: Format error in second numeric line (expecting 3 args, got %d), %s", retval, buf2);
exit(1);
}
obj_proto[i].obj_flags.value[0] = t[0];
obj_proto[i].obj_flags.value[1] = t[1];
obj_proto[i].obj_flags.value[2] = t[2];
/* Initialized to zero here, but modified later */
obj_proto[i].obj_flags.bitvector = 0;
if (!get_line(obj_f, line)) {
log("SYSERR: Expecting third numeric line of %s, but file ended!", buf2);
exit(1);
}
if ((retval = sscanf(line, "%d %d %d", t, t + 1, t + 2)) != 3) {
log("SYSERR: Format error in third numeric line (expecting 3 args, got %d), %s", retval, buf2);
exit(1);
}
obj_proto[i].obj_flags.weight = t[0];
obj_proto[i].obj_flags.material = t[1];
obj_proto[i].obj_flags.timer = t[2];
/* check to make sure that weight of containers exceeds curr. quantity */
if (obj_proto[i].obj_flags.type_flag == ITEM_DRINKCON) {
if (obj_proto[i].obj_flags.weight < obj_proto[i].obj_flags.value[1])
obj_proto[i].obj_flags.weight = obj_proto[i].obj_flags.value[1] + 5;
}
/* *** extra descriptions and affect fields *** */
for (j = 0; j < MAX_OBJ_AFFECT; j++) {
obj_proto[i].affected[j].location = APPLY_NONE;
obj_proto[i].affected[j].modifier = 0;
}
strcat(buf2, ", after numeric constants\n...expecting alphabetic flags");
j = 0;
for (;;) {
if (!get_line(obj_f, line)) {
log("SYSERR: Format error in %s", buf2);
exit(1);
}
switch (*line) {
case 'A':
if (j >= MAX_OBJ_AFFECT) {
log("SYSERR: Too many A fields (%d max), %s", MAX_OBJ_AFFECT, buf2);
exit(1);
}
if (!get_line(obj_f, line)) {
log("SYSERR: Format error in 'A' field, %s\n...expecting 2 numeric constants but file ended!", buf2);
exit(1);
}
if ((retval = sscanf(line, " %d %d ", t, t + 1)) != 2) {
log("SYSERR: Format error in 'A' field, %s\n...expecting 2 numeric arguments, got %d\n...offending line: '%s'", buf2, retval, line);
exit(1);
}
obj_proto[i].affected[j].location = t[0];
obj_proto[i].affected[j].modifier = t[1];
j++;
break;
case 'B':
if (!get_line(obj_f, line)) {
log("SYSERR: Format error in 'B' field, %s\n...expecting bitvectors but file ended!", buf2);
exit(1);
}
if (sscanf(line, " %s ", f1) != 1) {
log("SYSERR: Unable to read 'B' value, %s", buf2);
exit(1);
}
obj_proto[i].obj_flags.bitvector |= asciiflag_conv(f1);
break;
case 'E':
CREATE(new_descr, struct extra_descr_data, 1);
new_descr->keyword = fread_string(obj_f, buf2);
new_descr->description = fread_string(obj_f, buf2);
new_descr->next = obj_proto[i].ex_description;
obj_proto[i].ex_description = new_descr;
break;
case 'F':
if (!get_line(obj_f, line)) {
log("SYSERR: Format error in 'F' field, %s\n...expecting spec number but file ended!", buf2);
exit(1);
}
if (sscanf(line, " %d %d ", t, t + 1) != 2) {
log("SYSERR: Unable to read 'F' value, %s", buf2);
exit(1);
}
if ((t[0] = find_obj_special_by_number(t[0])) != -1)
obj_index[i].spec_proc = obj_spec[t[0]].spec_proc;
if ((t[1] = find_obj_special_by_number(t[1])) != -1)
obj_index[i].look_spec = obj_spec[t[1]].look_spec;
break;
case 'S':
check_object(&obj_proto[i]);
top_of_objt = i++;
return;
default:
log("SYSERR: Format error in %s", buf2);
exit(1);
}
}
}
void discrete_load(FILE *fl, int mode, char *filename) {
void parse_empire(FILE *fl, int nr);
int nr = -1, last;
char line[256];
const char *modes[] = {"world", "mob", "obj", "zone", "empire" };
for (;;) {
if (!get_line(fl, line)) {
if (nr == -1)
log("SYSERR: %s file %s is empty!", modes[mode], filename);
else {
log("SYSERR: Format error in %s after %s #%d\n"
"...expecting a new %s, but file ended!\n"
"(maybe the file is not terminated with '$'?)", filename,
modes[mode], nr, modes[mode]);
}
exit(1);
}
if (*line == '$')
return;
if (*line == '#') {
last = nr;
if (sscanf(line, "#%d", &nr) != 1) {
log("SYSERR: Format error after %s #%d", modes[mode], last);
exit(1);
}
switch (mode) {
case DB_BOOT_WLD:
parse_room(fl, nr);
break;
case DB_BOOT_MOB:
parse_mobile(fl, nr);
break;
case DB_BOOT_EMP:
parse_empire(fl, nr);
break;
case DB_BOOT_OBJ:
parse_object(fl, nr);
break;
}
}
else {
log("SYSERR: Format error in %s file %s near %s #%d", modes[mode], filename, modes[mode], nr);
log("SYSERR: ... offending line: '%s'", line);
exit(1);
}
}
}
/* function to count how many hash-mark delimited records exist in a file */
int count_hash_records(FILE * fl) {
char buf[128];
int count = 0;
while (fgets(buf, 128, fl))
if (*buf == '#')
count++;
return (count);
}
void index_boot(int mode) {
const char *index_filename, *prefix = NULL; /* NULL or egcs 1.1 complains */
FILE *index, *db_file;
int rec_count = 0, size[2];
switch (mode) {
case DB_BOOT_MOB:
prefix = MOB_PREFIX;
break;
case DB_BOOT_OBJ:
prefix = OBJ_PREFIX;
break;
case DB_BOOT_EMP:
prefix = LIB_EMPIRE;
break;
default:
log("SYSERR: Unknown subcommand %d to index_boot!", mode);
exit(1);
}
index_filename = INDEX_FILE;
sprintf(buf2, "%s%s", prefix, index_filename);
if (!(index = fopen(buf2, "r"))) {
log("SYSERR: opening index file '%s': %s", buf2, strerror(errno));
exit(1);
}
/* first, count the number of records in the file so we can malloc */
fscanf(index, "%s\n", buf1);
while (*buf1 != '$') {
sprintf(buf2, "%s%s", prefix, buf1);
if (!(db_file = fopen(buf2, "r"))) {
log("SYSERR: File '%s' listed in '%s/%s': %s", buf2, prefix, index_filename, strerror(errno));
fscanf(index, "%s\n", buf1);
continue;
}
else {
rec_count += count_hash_records(db_file);
}
fclose(db_file);
fscanf(index, "%s\n", buf1);
}
if (!rec_count) {
if (mode == DB_BOOT_EMP)
return;
log("SYSERR: boot error - 0 records counted in %s/%s.", prefix, index_filename);
exit(1);
}
/* Any idea why you put this here Jeremy? */
rec_count++;
/*
* NOTE: "bytes" does _not_ include strings or other later malloc'd things.
*/
switch (mode) {
case DB_BOOT_MOB:
CREATE(mob_proto, struct char_data, rec_count);
CREATE(mob_index, struct index_data, rec_count);
size[0] = sizeof(struct index_data) * rec_count;
size[1] = sizeof(struct char_data) * rec_count;
log(" %d mobs, %d bytes in index, %d bytes in prototypes.", rec_count, size[0], size[1]);
break;
case DB_BOOT_OBJ:
CREATE(obj_proto, struct obj_data, rec_count);
CREATE(obj_index, struct index_data, rec_count);
size[0] = sizeof(struct index_data) * rec_count;
size[1] = sizeof(struct obj_data) * rec_count;
log(" %d objs, %d bytes in index, %d bytes in prototypes.", rec_count, size[0], size[1]);
break;
case DB_BOOT_EMP:
CREATE(empire, struct empire_data, rec_count);
size[0] = sizeof(struct empire_data) * rec_count;
log(" %d empires, %d bytes.", rec_count, size[0]);
break;
}
rewind(index);
fscanf(index, "%s\n", buf1);
while (*buf1 != '$') {
sprintf(buf2, "%s%s", prefix, buf1);
if (!(db_file = fopen(buf2, "r"))) {
log("SYSERR: %s: %s", buf2, strerror(errno));
exit(1);
}
switch (mode) {
case DB_BOOT_OBJ:
case DB_BOOT_MOB:
case DB_BOOT_EMP:
discrete_load(db_file, mode, buf2);
break;
}
fclose(db_file);
fscanf(index, "%s\n", buf1);
}
fclose(index);
}
#define Z zone_table[zone]
#define ZCMD zone_table[zone].cmd[cmd_no]
/* load the zone table and command tables */
void load_zones(FILE * fl, char *zonename) {
static zone_rnum zone = 0;
int cmd_no, num_of_cmds = 0, line_num = 0, tmp, error;
char *ptr, buf[256], zname[256];
new_rotation++;
if (new_rotation > NUM_ZONE_UPDATES)
new_rotation = 0;
strcpy(zname, zonename);
while (get_line(fl, buf))
num_of_cmds++; /* this should be correct within 3 or so */
rewind(fl);
if (num_of_cmds == 0) {
log("SYSERR: %s is empty!", zname);
exit(1);
}
else
CREATE(Z.cmd, struct reset_com, num_of_cmds);
line_num += get_line(fl, buf);
if (sscanf(buf, "#%d", &Z.number) != 1) {
log("SYSERR: Format error in %s, line %d", zname, line_num);
exit(1);
}
sprintf(buf2, "beginning of zone #%d", Z.number);
Z.top = Z.number * SIZE_MAP_ZONES + (SIZE_MAP_ZONES - 1);
if (Z.top > MAP_SIZE)
Z.top = 999999999;
Z.rotation = new_rotation;
cmd_no = 0;
for (;;) {
if ((tmp = get_line(fl, buf)) == 0) {
log("SYSERR: Format error in %s - premature end of file", zname);
exit(1);
}
line_num += tmp;
ptr = buf;
skip_spaces(&ptr);
if ((ZCMD.command = *ptr) == '*')
continue;
ptr++;
if (ZCMD.command == 'S' || ZCMD.command == '$') {
ZCMD.command = 'S';
break;
}
error = 0;
if (strchr("MD", ZCMD.command) != NULL) { /* a 2-arg command */
if (sscanf(ptr, " %d %d ", &ZCMD.arg1, &ZCMD.arg2) != 2)
error = 1;
}
else if (!strchr("T", ZCMD.command)) {
if (sscanf(ptr, " %d ", &ZCMD.arg1) != 1)
error = 1;
}
if (error) {
log("SYSERR: Format error in %s, line %d: '%s'", zname, line_num, buf);
exit(1);
}
cmd_no++;
}
top_of_zone_table = zone++;
}
#undef Z
void index_boot_zones(void) {
void design_world();
FILE *db_file;
int count = 0;
sprintf(buf2, "%s0.zon", ZON_PREFIX);
if (!(db_file = fopen(buf2, "r")))
design_world();
fclose(db_file);
CREATE(zone_table, struct zone_data, 101);
for (count = 0; count <= NUM_MAP_ZONES; count++) {
sprintf(buf2, "%s%d.zon", ZON_PREFIX, count);
if (!(db_file = fopen(buf2, "r"))) {
log("SYSERR: %s: %s", buf2, strerror(errno));
exit(1);
}
load_zones(db_file, buf2);
fclose(db_file);
}
}
void index_boot_world(void) {
FILE *db_file;
int count, rec_count;
/*
* All "zones" in the over-map have SIZE_MAP_ZONES rooms, but the last is
* unlimited because it's for building use only. We need to count its
* records to see how big a world to allot.
*/
sprintf(buf2, "%s%d.wld", WLD_PREFIX, NUM_MAP_ZONES);
if (!(db_file = fopen(buf2, "r"))) {
log("SYSERR: %s: %s", buf2, strerror(errno));
exit(1);
}
rec_count = count_hash_records(db_file) + 1;
fclose(db_file);
/* Create the world */
CREATE(world, struct room_data, MAP_SIZE + rec_count);
/* Read the world */
for (count = 0; count <= NUM_MAP_ZONES; count++) {
sprintf(buf2, "%s%d.wld", WLD_PREFIX, count);
if (!(db_file = fopen(buf2, "r"))) {
log("SYSERR: %s: %s", buf2, strerror(errno));
exit(1);
}
discrete_load(db_file, DB_BOOT_WLD, buf2);
fclose(db_file);
}
}
void get_one_line(FILE *fl, char *buf) {
if (fgets(buf, READ_SIZE, fl) == NULL) {
log("SYSERR: error reading help file: not terminated with $?");
exit(1);
}
buf[strlen(buf) - 1] = '\0'; /* take off the trailing \n */
}
void load_help(FILE *fl) {
char key[READ_SIZE+1], next_key[READ_SIZE+1], entry[32384];
char line[READ_SIZE+1], *scan;
struct help_index_element el;
/* get the first keyword line */
get_one_line(fl, key);
while (*key != '$') {
/* read in the corresponding help entry */
strcpy(entry, strcat(key, "\r\n"));
get_one_line(fl, line);
while (*line != '#') {
strcat(entry, strcat(line, "\r\n"));
get_one_line(fl, line);
}
el.level = 0;
if (*line == '#' && *(line + 1))
switch (*(line + 1)) {
case 'a': el.level = LVL_IMPL; break;
case 'b': el.level = LVL_CIMPL; break;
case 'c': el.level = LVL_ASST; break;
case 'd': el.level = LVL_START_IMM; break;
case 'e': el.level = LVL_APPROVED; break;
}
/* now, add the entry to the index with each keyword on the keyword line */
el.duplicate = 0;
el.entry = str_dup(entry);
scan = one_word(key, next_key);
while (*next_key) {
el.keyword = str_dup(next_key);
help_table[top_of_helpt++] = el;
el.duplicate++;
scan = one_word(scan, next_key);
}
/* get next keyword line (or $) */
get_one_line(fl, key);
}
}
/*
* Thanks to Andrey (andrey@alex-ua.com) for this bit of code, although I
* did add the 'goto' and changed some "while()" into "do { } while()".
* -gg 6/24/98 (technically 6/25/98, but I care not.)
*/
int count_alias_records(FILE *fl) {
char key[READ_SIZE], next_key[READ_SIZE];
char line[READ_SIZE], *scan;
int total_keywords = 0;
/* get the first keyword line */
get_one_line(fl, key);
while (*key != '$') {
/* skip the text */
do {
get_one_line(fl, line);
if (feof(fl))
goto ackeof;
} while (*line != '#');
/* now count keywords */
scan = key;
do {
scan = one_word(scan, next_key);
if (*next_key)
++total_keywords;
} while (*next_key);
/* get next keyword line (or $) */
get_one_line(fl, key);
if (feof(fl))
goto ackeof;
}
return (total_keywords);
/* No, they are not evil. -gg 6/24/98 */
ackeof:
log("SYSERR: Unexpected end of help file.");
exit(1); /* Some day we hope to handle these things better... */
}
int hsort(const void *a, const void *b) {
const struct help_index_element *a1, *b1;
a1 = (const struct help_index_element *) a;
b1 = (const struct help_index_element *) b;
return (str_cmp(a1->keyword, b1->keyword));
}
void index_boot_help(void) {
const char *index_filename, *prefix = NULL; /* NULL or egcs 1.1 complains */
FILE *index, *db_file;
int rec_count = 0, size[2];
prefix = HLP_PREFIX;
index_filename = INDEX_FILE;
sprintf(buf2, "%s%s", prefix, index_filename);
if (!(index = fopen(buf2, "r"))) {
log("SYSERR: opening index file '%s': %s", buf2, strerror(errno));
exit(1);
}
/* first, count the number of records in the file so we can malloc */
fscanf(index, "%s\n", buf1);
while (*buf1 != '$') {
sprintf(buf2, "%s%s", prefix, buf1);
if (!(db_file = fopen(buf2, "r"))) {
log("SYSERR: File '%s' listed in '%s/%s': %s", buf2, prefix, index_filename, strerror(errno));
fscanf(index, "%s\n", buf1);
continue;
}
else
rec_count += count_alias_records(db_file);
fclose(db_file);
fscanf(index, "%s\n", buf1);
}
/* Exit if 0 records, unless this is shops */
if (!rec_count) {
log("SYSERR: boot error - 0 records counted in %s/%s.", prefix, index_filename);
exit(1);
}
/* Any idea why you put this here Jeremy? */
rec_count++;
/*
* NOTE: "bytes" does _not_ include strings or other later malloc'd things.
*/
CREATE(help_table, struct help_index_element, rec_count);
size[0] = sizeof(struct help_index_element) * rec_count;
log(" %d entries, %d bytes.", rec_count, size[0]);
rewind(index);
fscanf(index, "%s\n", buf1);
while (*buf1 != '$') {
sprintf(buf2, "%s%s", prefix, buf1);
if (!(db_file = fopen(buf2, "r"))) {
log("SYSERR: %s: %s", buf2, strerror(errno));
exit(1);
}
/*
* If you think about it, we have a race here. Although, this is the
* "point-the-gun-at-your-own-foot" type of race.
*/
load_help(db_file);
fclose(db_file);
fscanf(index, "%s\n", buf1);
}
fclose(index);
qsort(help_table, top_of_helpt, sizeof(struct help_index_element), hsort);
top_of_helpt--;
}
/*************************************************************************
* routines for booting the system *
*************************************************************************/
/* this is necessary for the autowiz system */
void reload_wizlists(void) {
file_to_string_alloc(WIZLIST_FILE, &wizlist);
file_to_string_alloc(GODLIST_FILE, &godlist);
}
/*
* Too bad it doesn't check the return values to let the user
* know about -1 values. This will result in an 'Okay.' to a
* 'reload' command even when the string was not replaced.
* To fix later, if desired. -gg 6/24/99
*/
ACMD(do_reload) {
one_argument(argument, arg);
if (!str_cmp(arg, "all") || *arg == '*') {
if (file_to_string_alloc(GREETINGS_FILE, &GREETINGS) == 0)
prune_crlf(GREETINGS);
if (file_to_string_alloc(MENU_FILE, &MENU) == 0)
prune_crlf(MENU);
file_to_string_alloc(SCREDITS_FILE, &CREDIT_MESSG);
file_to_string_alloc(WIZLIST_FILE, &wizlist);
file_to_string_alloc(GODLIST_FILE, &godlist);
file_to_string_alloc(CREDITS_FILE, &credits);
file_to_string_alloc(MOTD_FILE, &motd);
file_to_string_alloc(IMOTD_FILE, &imotd);
file_to_string_alloc(HELP_PAGE_FILE, &help);
file_to_string_alloc(INFO_FILE, &info);
file_to_string_alloc(POLICIES_FILE, &policies);
file_to_string_alloc(HANDBOOK_FILE, &handbook);
file_to_string_alloc(BACKGROUND_FILE, &background);
}
else if (!str_cmp(arg, "wizlist"))
file_to_string_alloc(WIZLIST_FILE, &wizlist);
else if (!str_cmp(arg, "godlist"))
file_to_string_alloc(GODLIST_FILE, &godlist);
else if (!str_cmp(arg, "credits"))
file_to_string_alloc(CREDITS_FILE, &credits);
else if (!str_cmp(arg, "motd"))
file_to_string_alloc(MOTD_FILE, &motd);
else if (!str_cmp(arg, "imotd"))
file_to_string_alloc(IMOTD_FILE, &imotd);
else if (!str_cmp(arg, "help"))
file_to_string_alloc(HELP_PAGE_FILE, &help);
else if (!str_cmp(arg, "info"))
file_to_string_alloc(INFO_FILE, &info);
else if (!str_cmp(arg, "policy"))
file_to_string_alloc(POLICIES_FILE, &policies);
else if (!str_cmp(arg, "handbook"))
file_to_string_alloc(HANDBOOK_FILE, &handbook);
else if (!str_cmp(arg, "background"))
file_to_string_alloc(BACKGROUND_FILE, &background);
else if (!str_cmp(arg, "shortcredits"))
file_to_string_alloc(SCREDITS_FILE, &CREDIT_MESSG);
else if (!str_cmp(arg, "greetings")) {
if (file_to_string_alloc(GREETINGS_FILE, &GREETINGS) == 0)
prune_crlf(GREETINGS);
}
else if (!str_cmp(arg, "menu")) {
if (file_to_string_alloc(MENU_FILE, &MENU) == 0)
prune_crlf(MENU);
}
else {
send_to_char("Unknown reload option.\r\n", ch);
return;
}
send_to_char(OK, ch);
}
/* resolve all vnums into rnums in the world */
void renum_world(void) {
register int room, door;
for (room = 0; room <= top_of_world; room++) {
for (door = 0; door < NUM_OF_DIRS; door++) {
if (world[room].dir_option[door])
if (world[room].dir_option[door]->to_room != NOWHERE)
world[room].dir_option[door]->to_room = real_room(world[room].dir_option[door]->to_room);
if (world[room].dir_option[door] && world[room].dir_option[door]->to_room == NOWHERE) {
if (world[room].dir_option[door]->keyword)
free(world[room].dir_option[door]);
free (world[room].dir_option[door]);
world[room].dir_option[door] = NULL;
}
}
if (world[room].home_room != NOWHERE)
world[real_room(world[room].home_room)].inside_rooms++;
}
}
void setup_start_locations(void) {
room_rnum r;
for (r = 0; r <= top_of_world; r++)
if (SECT(r) == SECT_TOWER_OF_SOULS) {
num_of_start_locs++;
if (start_locs)
RECREATE(start_locs, int, num_of_start_locs + 1);
else
CREATE(start_locs, int, num_of_start_locs + 1);
start_locs[num_of_start_locs] = world[r].number;
}
}
void boot_world(void) {
log("Loading zone table.");
index_boot_zones();
log("Loading rooms.");
index_boot_world();
log("Renumbering rooms.");
renum_world();
log(" Initializing start locations.");
setup_start_locations();
log("Loading mobs and generating index.");
index_boot(DB_BOOT_MOB);
log("Loading objs and generating index.");
index_boot(DB_BOOT_OBJ);
}
/* generate index table for the player file */
void build_player_index(void) {
int nr = -1, i;
long size, recs;
struct char_file_u dummy;
if (!(player_fl = fopen(PLAYER_FILE, "r+b"))) {
if (errno != ENOENT) {
perror("SYSERR: fatal error opening playerfile");
exit(1);
}
else {
log("No playerfile. Creating a new one.");
touch(PLAYER_FILE);
if (!(player_fl = fopen(PLAYER_FILE, "r+b"))) {
perror("SYSERR: fatal error opening playerfile");
exit(1);
}
}
}
fseek(player_fl, 0L, SEEK_END);
size = ftell(player_fl);
rewind(player_fl);
if (size % sizeof(struct char_file_u))
log("\aWARNING: PLAYERFILE IS PROBABLY CORRUPT!");
recs = size / sizeof(struct char_file_u);
if (recs) {
log(" %ld players in database.", recs);
CREATE(player_table, struct player_index_element, recs);
}
else {
player_table = NULL;
top_of_p_file = top_of_p_table = -1;
return;
}
for (; !feof(player_fl);) {
fread(&dummy, sizeof(struct char_file_u), 1, player_fl);
if (!feof(player_fl)) { /* new record */
nr++;
CREATE(player_table[nr].name, char, strlen(dummy.name) + 1);
for (i = 0; (*(player_table[nr].name + i) = LOWER(*(dummy.name + i))); i++);
player_table[nr].id = dummy.char_specials_saved.idnum;
top_idnum = MAX(top_idnum, dummy.char_specials_saved.idnum);
}
}
top_of_p_file = top_of_p_table = nr;
}
/* execute the reset command table of a given zone */
void reset_zone(zone_rnum zone) {
void objpack_load_room(int rnum);
int cmd_no;
Creature mob = NULL;
for (cmd_no = 0; ZCMD.command != 'S'; cmd_no++)
switch (ZCMD.command) {
case '*': /* ignore command */
break;
case 'M': /* read a mobile */
char_to_room((mob = read_mobile(ZCMD.arg1, VIRTUAL)), real_room(ZCMD.arg2));
break;
case 'T': /* tie up a mob */
if (mob)
SET_BIT(MOB_FLAGS(mob), MOB_TIED);
break;
case 'O': /* load an obj pack */
objpack_load_room(real_room(ZCMD.arg1));
break;
case 'D': /* set state of door */
if (ZCMD.arg2 < 0 || ZCMD.arg2 >= NUM_OF_DIRS || (world[real_room(ZCMD.arg1)].dir_option[ZCMD.arg2] == NULL))
ZCMD.command = '*';
else
SET_BIT(world[real_room(ZCMD.arg1)].dir_option[ZCMD.arg2]->exit_info, EX_CLOSED);
break;
default:
ZCMD.command = '*';
break;
}
}
/* reset the time in the game from file */
void reset_time(void) {
extern long load_time();
extern struct time_info_data *mud_time_passed(time_t t2, time_t t1);
long beginning_of_time;
beginning_of_time = load_time();
time_info = *mud_time_passed(time(0), beginning_of_time);
if (time_info.hours <= 6)
weather_info.sunlight = SUN_DARK;
else if (time_info.hours == 7)
weather_info.sunlight = SUN_RISE;
else if (time_info.hours <= 18)
weather_info.sunlight = SUN_LIGHT;
else if (time_info.hours == 19)
weather_info.sunlight = SUN_SET;
else
weather_info.sunlight = SUN_DARK;
log(" Current Gametime: %dH %dD %dM %dY.", time_info.hours, time_info.day, time_info.month, time_info.year);
weather_info.pressure = 960;
if ((time_info.month >= 5) && (time_info.month <= 8))
weather_info.pressure += dice(1, 50);
else
weather_info.pressure += dice(1, 80);
weather_info.change = 0;
if (weather_info.pressure <= 980)
weather_info.sky = SKY_LIGHTNING;
else if (weather_info.pressure <= 1000)
weather_info.sky = SKY_RAINING;
else if (weather_info.pressure <= 1020)
weather_info.sky = SKY_CLOUDY;
else
weather_info.sky = SKY_CLOUDLESS;
}
void update_ships(void) {
void delete_room(room_rnum rnum);
Object o;
room_rnum room, room2;
for (o = object_list; o; o = o->next)
if (GET_OBJ_TYPE(o) == ITEM_SHIP)
world[real_room(GET_OBJ_VAL(o, 2))].boat = o;
for (room = 0; room <= top_of_world; room++)
if (ROOM_TYPE(room) == RTYPE_B_ONDECK && HOME_ROOM(room) == room && !world[room].boat) {
for (room2 = 0; room2 <= top_of_world; room2++)
if (HOME_ROOM(room2) == room) {
delete_room(room2);
room2--;
}
room--;
}
}
void load_exp_cycle(void) {
FILE *fl;
if (!(fl = fopen(EXP_FILE, "r"))) {
exp_cycle = 0;
return;
}
fscanf(fl, "%d\n", &exp_cycle);
/* We don't have to save this, it won't matter */
last_exp_cycle = time(0);
fclose(fl);
}
void save_exp_cycle(void) {
FILE *fl;
if (!(fl = fopen(EXP_FILE, "w"))) {
log("Error opening exp cycle file!");
return;
}
fprintf(fl, "%d\n", exp_cycle);
fclose(fl);
}
/* body of the booting system */
void boot_db(void) {
void Read_Invalid_List();
void load_banned();
void sort_commands();
void update_obj_file();
void boot_social_messages();
void load_messages();
void read_empire_territory();
void read_empire_members();
zone_rnum i;
log("Boot db -- BEGIN.");
log("Resetting the game time:");
reset_time();
log("Reading credits, help, bground, info & motds.");
file_to_string_alloc(CREDITS_FILE, &credits);
file_to_string_alloc(MOTD_FILE, &motd);
file_to_string_alloc(IMOTD_FILE, &imotd);
file_to_string_alloc(HELP_PAGE_FILE, &help);
file_to_string_alloc(INFO_FILE, &info);
file_to_string_alloc(WIZLIST_FILE, &wizlist);
file_to_string_alloc(GODLIST_FILE, &godlist);
file_to_string_alloc(POLICIES_FILE, &policies);
file_to_string_alloc(HANDBOOK_FILE, &handbook);
file_to_string_alloc(BACKGROUND_FILE, &background);
file_to_string_alloc(SCREDITS_FILE, &CREDIT_MESSG);
if (file_to_string_alloc(GREETINGS_FILE, &GREETINGS) == 0)
prune_crlf(GREETINGS);
if (file_to_string_alloc(MENU_FILE, &MENU) == 0)
prune_crlf(MENU);
boot_world();
log("Loading help entries.");
index_boot_help();
log("Generating player index.");
build_player_index();
log("Loading empires.");
index_boot(DB_BOOT_EMP);
log(" Calculating territory and members...");
read_empire_members();
read_empire_territory();
log("Loading fight messages.");
load_messages();
log("Loading social messages.");
boot_social_messages();
log("Sorting command list.");
sort_commands();
log("Booting mail system.");
if (!scan_file()) {
log(" Mail boot failed -- Mail system disabled");
no_mail = 1;
}
log("Reading banned site and invalid-name list.");
load_banned();
Read_Invalid_List();
if (!no_rent_check) {
log("Deleting timed-out crash and rent files:");
update_obj_file();
log(" Done.");
}
for (i = 0; i <= top_of_zone_table; i++)
reset_zone(i);
update_ships();
load_exp_cycle();
log("Beginning experience cycle at %d.", exp_cycle);
boot_time = time(0);
log("Boot db -- DONE.");
}
long load_time(void) {
long t;
FILE *fp;
if (!(fp = fopen(TIME_FILE, "r"))) {
if (!(fp = fopen(TIME_FILE, "w"))) {
log("SYSERR: Unable to create a beginning_of_time file!");
return 650336715;
}
fprintf(fp, "%ld\n", (long) time(0));
fclose(fp);
return (long) time(0);
}
fscanf(fp, "%ld\n", &t);
fclose(fp);
return t;
}
void design_world(void) {
FILE *fl;
int i, j;
for (i = 0; i <= NUM_MAP_ZONES; i++) {
sprintf(buf2, "%s%d.zon", ZON_PREFIX, i);
if (!(fl = fopen(buf2, "w+"))) {
log("Unable to open: %s", buf2);
exit(1);
}
fprintf(fl, "#%d\nS\n$~", i);
fclose(fl);
}
/* ONLY do this if they haven't generated a map */
sprintf(buf2, "%s0.wld", WLD_PREFIX);
if (!(fl = fopen(buf2, "r"))) {
for (i = 0; i < NUM_MAP_ZONES; i++) {
sprintf(buf2, "%s%d.wld", WLD_PREFIX, i);
if (!(fl = fopen(buf2, "w+"))) {
log("Unable to open: %s", buf2);
exit(1);
}
for (j = 0; j < SIZE_MAP_ZONES; j++) {
fprintf(fl, "#%d\n"
"0\n"
"S\n",
(i * SIZE_MAP_ZONES) + j);
}
fprintf(fl, "$~\n");
fclose(fl);
}
sprintf(buf2, "%s%d.wld", WLD_PREFIX, NUM_MAP_ZONES);
fl = fopen(buf2, "w+");
fprintf(fl, "#%d\n8\nS\n$~\n", MAP_SIZE);
fclose(fl);
}
else
fclose(fl);
}
/*************************************************************************
* procedures for resetting, both play-time and boot-time *
*************************************************************************/
int vnum_mobile(char *searchname, Creature ch) {
int nr, found = 0;
for (nr = 0; nr <= top_of_mobt; nr++) {
if (isname(searchname, mob_proto[nr].player.name)) {
sprintf(buf, "%3d. [%5d] %s\r\n", ++found, mob_index[nr].vnum, mob_proto[nr].player.short_descr);
send_to_char(buf, ch);
}
}
return (found);
}
int vnum_object(char *searchname, Creature ch) {
int nr, found = 0;
for (nr = 0; nr <= top_of_objt; nr++) {
if (isname(searchname, obj_proto[nr].name)) {
sprintf(buf, "%3d. [%5d] %s\r\n", ++found, obj_index[nr].vnum, obj_proto[nr].short_description);
send_to_char(buf, ch);
}
}
return (found);
}
/* create a character, and add it to the char list */
Creature create_char(void) {
Creature ch;
CREATE(ch, struct char_data, 1);
clear_char(ch);
ch->next = character_list;
character_list = ch;
return (ch);
}
/* create a new mobile from a prototype */
Creature read_mobile(mob_vnum nr, int type) /* and mob_rnum */ {
mob_rnum i;
Creature mob;
if (type == VIRTUAL) {
if ((i = real_mobile(nr)) < 0) {
log("WARNING: Mobile vnum %d does not exist in database.", nr);
return (NULL);
}
}
else
i = nr;
CREATE(mob, struct char_data, 1);
clear_char(mob);
*mob = mob_proto[i];
mob->next = character_list;
character_list = mob;
mob->points.damage = 0;
mob->points.move = mob->points.max_move;
mob->player.time.birth = time(0);
mob->player.time.played = 0;
mob->player.time.logon = time(0);
GET_BLOOD(mob) = GET_MAX_BLOOD(mob);
mob_index[i].number++;
return (mob);
}
/* create an object, and add it to the object list */
Object create_obj(void) {
Object obj;
CREATE(obj, struct obj_data, 1);
clear_object(obj);
obj->next = object_list;
object_list = obj;
return (obj);
}
/* create a new object from a prototype */
Object read_object(obj_vnum nr, int type) /* and obj_rnum */ {
Object obj;
obj_rnum i;
if (nr < 0) {
log("SYSERR: Trying to create obj with negative (%d) num!", nr);
return (NULL);
}
if (type == VIRTUAL) {
if ((i = real_object(nr)) < 0) {
log("Object (V) %d does not exist in database.", nr);
return (NULL);
}
}
else
i = nr;
CREATE(obj, struct obj_data, 1);
clear_object(obj);
*obj = obj_proto[i];
obj->next = object_list;
object_list = obj;
obj_index[i].number++;
if (obj->obj_flags.timer == 0)
obj->obj_flags.timer = -1;
return (obj);
}
/* Removes the \r\n to prevent Windows clients from seeing extra linebreaks in descs */
void strip_crlf(char *buffer) {
register char *ptr, *str;
ptr = buffer;
str = ptr;
while ((*str = *ptr)) {
str++;
ptr++;
if (*ptr == '\r')
ptr++;
}
}
int last_zone_rotation = 0;
/* update zone ages, queue for reset if necessary, and dequeue when possible */
void zone_update(bool all) {
extern int objpack_save_room(int rnum);
FILE *fl;
int i, j, c, rnum, vnum, dir, r;
char temp[MAX_STRING_LENGTH];
Creature mob;
last_zone_rotation++;
if (last_zone_rotation > NUM_ZONE_UPDATES)
last_zone_rotation = 0;
for (i = 0; i <= NUM_MAP_ZONES; i++) {
if (zone_table[i].rotation != last_zone_rotation && !all)
continue;
/* World */
sprintf(buf2, "%s%d.wld", WLD_PREFIX, i);
if (!(fl = fopen(buf2, "w+"))) {
log("Unable to open: %s", buf2);
exit(1);
}
for (j = 0; j < (i == NUM_MAP_ZONES ? 1000000 : SIZE_MAP_ZONES); j++) {
r = i * SIZE_MAP_ZONES + j;
if (r > world[top_of_world].number)
break;
if (real_room(r) == NOWHERE)
continue;
fprintf(fl, "#%d\n"
"%d\n",
r, world[real_room(r)].sector_type);
if (world[real_room(r)].type2)
fprintf(fl, "A%d\n", world[real_room(r)].type2);
if (world[real_room(r)].build_value)
fprintf(fl, "B%d\n", world[real_room(r)].build_value);
if (world[real_room(r)].type)
fprintf(fl, "C%d\n", world[real_room(r)].type);
if (world[real_room(r)].base_affects)
fprintf(fl, "E\n%d\n", world[real_room(r)].base_affects);
if (world[real_room(r)].spare)
fprintf(fl, "G%d\n", world[real_room(r)].spare);
if (world[real_room(r)].home_room != NOWHERE)
fprintf(fl, "H%d\n", world[real_room(r)].home_room);
if (world[real_room(r)].icon)
fprintf(fl, "I\n%s~\n", world[real_room(r)].icon);
if (world[real_room(r)].description) {
strcpy(temp, world[real_room(r)].description);
strip_crlf(temp);
fprintf(fl, "M\n%s~\n", temp);
}
if (world[real_room(r)].name)
fprintf(fl, "N\n%s~\n", world[real_room(r)].name);
if (world[real_room(r)].owner)
fprintf(fl, "O%ld\n", world[real_room(r)].owner);
if (world[real_room(r)].res.logs || world[real_room(r)].res.sticks || world[real_room(r)].res.rocks || world[real_room(r)].res.iron)
fprintf(fl, "R\n%d %d %d %d\n", world[real_room(r)].res.logs, world[real_room(r)].res.sticks, world[real_room(r)].res.rocks, world[real_room(r)].res.iron);
if (world[real_room(r)].building_entrance)
fprintf(fl, "X%d\n", world[real_room(r)].building_entrance);
if (world[real_room(r)].burning || world[real_room(r)].damage || world[real_room(r)].dismantling)
fprintf(fl, "Z\n%d %d %d\n", world[real_room(r)].burning, world[real_room(r)].damage, world[real_room(r)].dismantling);
for (c = 0; c < NUM_OF_DIRS; c++)
if (world[real_room(r)].dir_option[c]) {
if (world[real_room(r)].dir_option[c]->keyword)
strcpy(buf2, world[real_room(r)].dir_option[c]->keyword);
else
*buf2 = 0;
fprintf(fl, "D%d\n%s~\n%d %d\n", c, buf2, IS_SET(world[real_room(r)].dir_option[c]->exit_info, EX_ISDOOR) ? 1 : 0, world[world[real_room(r)].dir_option[c]->to_room].number);
}
fprintf(fl, "S\n");
}
fprintf(fl, "$~\n");
fclose(fl);
/* Zone */
sprintf(buf2, "%s%d.zon", ZON_PREFIX, i);
if (!(fl = fopen(buf2, "w+"))) {
log("Unable to open: %s", buf2);
exit(1);
}
fprintf(fl, "#%d\n", i);
for (j = 0; j < (i == NUM_MAP_ZONES ? 1000000 : SIZE_MAP_ZONES); j++) {
rnum = real_room((vnum = (i * SIZE_MAP_ZONES + j)));
if (vnum > world[top_of_world].number)
break;
if (rnum == NOWHERE)
continue;
for (dir = 0; dir < NUM_OF_DIRS; dir++)
if (world[rnum].dir_option[dir])
if (IS_SET(world[rnum].dir_option[dir]->exit_info, EX_CLOSED))
fprintf(fl, "D %d %d\n", vnum, dir);
if (world[rnum].people)
for (mob = world[rnum].people; mob; mob = mob->next_in_room)
if (mob && IS_NPC(mob) && !MOB_FLAGGED(mob, MOB_UNDEAD)) {
fprintf(fl, "M %d %d\n", GET_MOB_VNUM(mob), vnum);
if (MOB_FLAGGED(mob, MOB_TIED) || GET_PULLING(mob))
fprintf(fl, "T\n");
}
if (world[rnum].contents)
if (objpack_save_room(rnum))
fprintf(fl, "O %d\n", vnum);
}
fprintf(fl, "S\n$~\n");
fclose(fl);
}
}
long get_ptable_by_name(char *name) {
int i;
one_argument(name, arg);
for (i = 0; i <= top_of_p_table; i++)
if (!strcmp(player_table[i].name, arg))
return (i);
return (-1);
}
long get_id_by_name(char *name) {
int i;
one_argument(name, arg);
for (i = 0; i <= top_of_p_table; i++)
if (!str_cmp(player_table[i].name, arg))
return (player_table[i].id);
return (-1);
}
char *get_name_by_id(long id)
{
int i;
for (i = 0; i <= top_of_p_table; i++)
if (player_table[i].id == id)
return (player_table[i].name);
return (NULL);
}
/* Load a char, TRUE if loaded, FALSE if not */
int load_char(char *name, struct char_file_u * char_element)
{
int player_i;
if ((player_i = find_name(name)) >= 0) {
fseek(player_fl, (long) (player_i * sizeof(struct char_file_u)), SEEK_SET);
fread(char_element, sizeof(struct char_file_u), 1, player_fl);
return (player_i);
} else
return (-1);
}
/*
* write the vital data of a player to the player file
*
* NOTE: load_room should be an *RNUM* now. It is converted to a vnum here.
*/
void save_char(Creature ch, room_rnum load_room) {
struct char_file_u st;
if (IS_NPC(ch) || !ch->desc || GET_PFILEPOS(ch) < 0)
return;
char_to_store(ch, &st);
strncpy(st.host, ch->desc->host, HOST_LENGTH);
st.host[HOST_LENGTH] = '\0';
if (!PLR_FLAGGED(ch, PLR_LOADROOM)) {
if (load_room != NOWHERE)
st.player_specials_saved.load_room = GET_ROOM_VNUM(load_room);
else
st.player_specials_saved.load_room = NOWHERE;
}
GET_LOADROOM(ch) = st.player_specials_saved.load_room;
fseek(player_fl, GET_PFILEPOS(ch) * sizeof(struct char_file_u), SEEK_SET);
fwrite(&st, sizeof(struct char_file_u), 1, player_fl);
}
void save_char_file_u(struct char_file_u st) {
int player_i;
int find_name(char *name);
if ((player_i = find_name(st.name)) >= 0) {
fseek(player_fl, player_i * sizeof(struct char_file_u), SEEK_SET);
fwrite(&st, sizeof(struct char_file_u), 1, player_fl);
}
}
/* copy data from the file structure to a char struct */
void store_to_char(struct char_file_u * st, Creature ch) {
int i;
/* to save memory, only PC's -- not MOB's -- have player_specials */
if (ch->player_specials == NULL)
CREATE(ch->player_specials, struct player_special_data, 1);
GET_SEX(ch) = st->sex;
GET_LEVEL(ch) = st->level;
ch->player.short_descr = NULL;
ch->player.long_descr = NULL;
ch->player.title = str_dup(st->title);
if (*ch->player.title == '\0')
ch->player.title = NULL;
ch->player.prompt = str_dup(st->prompt);
if (*ch->player.prompt == '\0')
ch->player.prompt = NULL;
ch->player.poofin = str_dup(st->poofin);
if (*ch->player.poofin == '\0')
ch->player.poofin = NULL;
ch->player.poofout = str_dup(st->poofout);
if (*ch->player.poofout == '\0')
ch->player.poofout = NULL;
ch->player.email = str_dup(st->email);
if (!*ch->player.email)
ch->player.email = NULL;
ch->player.lastname = str_dup(st->lastname);
if (*ch->player.lastname == '\0')
ch->player.lastname = NULL;
/* Get last logon info */
strcpy(ch->prev_host, st->host);
ch->prev_logon = st->last_logon;
ch->player.time.birth = st->birth;
ch->player.time.played = st->played;
ch->player.time.logon = time(0);
ch->player.weight = st->weight;
ch->player.height = st->height;
ch->real_abils = st->abilities;
ch->aff_abils = st->abilities;
ch->points = st->points;
ch->char_specials.saved = st->char_specials_saved;
ch->player_specials->saved = st->player_specials_saved;
GET_LAST_TELL(ch) = NOBODY;
ch->char_specials.carry_weight = 0;
ch->char_specials.carry_items = 0;
if (ch->player.name == NULL)
CREATE(ch->player.name, char, strlen(st->name) + 1);
strcpy(ch->player.name, st->name);
strcpy(ch->player.passwd, st->pwd);
/* Add all spell effects */
for (i = 0; i < MAX_AFFECT; i++)
if (st->affected[i].type)
affect_to_char(ch, &st->affected[i]);
/* Players who have been out for 6 hours get a free restore */
if (((long) (time(0) - st->last_logon)) >= 6 * SECS_PER_REAL_HOUR) {
GET_DAYS_SINCE_BATHING(ch) = 0;
GET_DAMAGE(ch) = MAX(0, GET_AGG_DAMAGE(ch));
GET_MOVE(ch) = GET_MAX_MOVE(ch);
GET_COND(ch, FULL) = MIN(0, GET_COND(ch, FULL));
GET_COND(ch, THIRST) = MIN(0, GET_COND(ch, THIRST));
GET_COND(ch, DRUNK) = MIN(0, GET_COND(ch, DRUNK));
GET_COND(ch, TIRED) = MIN(0, GET_COND(ch, TIRED));
if (!IS_INJURED(ch, INJ_TORPOR))
GET_BLOOD(ch) = GET_MAX_BLOOD(ch);
}
} /* store_to_char */
/* copy vital data from a players char-structure to the file structure */
void char_to_store(Creature ch, struct char_file_u * st) {
int i;
struct affected_type *af;
Object char_eq[NUM_WEARS];
/* Unaffect everything a character can be affected by */
for (i = 0; i < NUM_WEARS; i++) {
if (GET_EQ(ch, i))
char_eq[i] = unequip_char(ch, i);
else
char_eq[i] = NULL;
}
for (af = ch->affected, i = 0; i < MAX_AFFECT; i++) {
if (af) {
st->affected[i] = *af;
st->affected[i].next = 0;
af = af->next;
}
else {
st->affected[i].type = 0; /* Zero signifies not used */
st->affected[i].duration = 0;
st->affected[i].modifier = 0;
st->affected[i].location = 0;
st->affected[i].bitvector = 0;
st->affected[i].disc_bit = 0;
st->affected[i].next = 0;
}
}
/*
* remove the affections so that the raw values are stored; otherwise the
* effects are doubled when the char logs back in.
*/
while (ch->affected)
affect_remove(ch, ch->affected);
if ((i >= MAX_AFFECT) && af && af->next)
log("SYSERR: WARNING: OUT OF STORE ROOM FOR AFFECTED TYPES!!!");
ch->aff_abils = ch->real_abils;
st->birth = ch->player.time.birth;
st->played = ch->player.time.played;
st->played += (long) (time(0) - ch->player.time.logon);
st->last_logon = time(0);
ch->player.time.played = st->played;
ch->player.time.logon = time(0);
st->weight = GET_WEIGHT(ch);
st->height = GET_HEIGHT(ch);
st->sex = GET_SEX(ch);
st->level = GET_LEVEL(ch);
st->abilities = ch->real_abils;
st->points = ch->points;
st->char_specials_saved = ch->char_specials.saved;
st->player_specials_saved = ch->player_specials->saved;
if (GET_TITLE(ch))
strcpy(st->title, GET_TITLE(ch));
else
*st->title = '\0';
if (ch->player.prompt)
strcpy(st->prompt, ch->player.prompt);
else
*st->prompt = '\0';
if (ch->player.poofin)
strcpy(st->poofin, ch->player.poofin);
else
*st->poofin = '\0';
if (ch->player.poofout)
strcpy(st->poofout, ch->player.poofout);
else
*st->poofout = '\0';
if (ch->player.email)
strcpy(st->email, ch->player.email);
else
*st->email = '\0';
if (ch->player.lastname)
strcpy(st->lastname, ch->player.lastname);
else
*st->lastname = '\0';
strcpy(st->name, GET_NAME(ch));
strcpy(st->pwd, GET_PASSWD(ch));
/* add spell and eq affections back in now */
for (i = 0; i < MAX_AFFECT; i++)
if (st->affected[i].type)
affect_to_char(ch, &st->affected[i]);
for (i = 0; i < NUM_WEARS; i++)
if (char_eq[i])
equip_char(ch, char_eq[i], i);
/* affect_total(ch); unnecessary, I think !?! */
} /* Char to store */
/*
* Create a new entry in the in-memory index table for the player file.
* If the name already exists, by overwriting a deleted character, then
* we re-use the old position.
*/
int create_entry(char *name) {
int i, pos;
if (top_of_p_table == -1) { /* no table */
CREATE(player_table, struct player_index_element, 1);
pos = top_of_p_table = 0;
}
else if ((pos = get_ptable_by_name(name)) == -1) { /* new name */
i = ++top_of_p_table + 1;
RECREATE(player_table, struct player_index_element, i);
pos = top_of_p_table;
}
CREATE(player_table[pos].name, char, strlen(name) + 1);
/* copy lowercase equivalent of name to table field */
for (i = 0; (player_table[pos].name[i] = LOWER(name[i])); i++);
return (pos);
}
/************************************************************************
* funcs of a (more or less) general utility nature *
************************************************************************/
/* read and allocate space for a '~'-terminated string from a given file */
char *fread_string(FILE * fl, char *error)
{
char buf[MAX_STRING_LENGTH], tmp[512], *rslt;
register char *point;
int done = 0, length = 0, templength;
*buf = '\0';
do {
if (!fgets(tmp, 512, fl)) {
log("SYSERR: fread_string: format error at or near %s", error);
exit(1);
}
/* If there is a '~', end the string; else put an "\r\n" over the '\n'. */
if ((point = strchr(tmp, '~')) != NULL) {
*point = '\0';
done = 1;
} else {
point = tmp + strlen(tmp) - 1;
*(point++) = '\r';
*(point++) = '\n';
*point = '\0';
}
templength = strlen(tmp);
if (length + templength >= MAX_STRING_LENGTH) {
log("SYSERR: fread_string: string too large (db.c)");
log(error);
exit(1);
} else {
strcat(buf + length, tmp);
length += templength;
}
} while (!done);
/* allocate space for the new string and copy it */
if (strlen(buf) > 0) {
CREATE(rslt, char, length + 1);
strcpy(rslt, buf);
} else
rslt = NULL;
return (rslt);
}
/* release memory allocated for a char struct */
void free_char(Creature ch) {
void free_alias(struct alias_data *a);
int i;
struct alias_data *a;
if (ch->player_specials != NULL && ch->player_specials != &dummy_mob) {
while ((a = GET_ALIASES(ch)) != NULL) {
GET_ALIASES(ch) = (GET_ALIASES(ch))->next;
free_alias(a);
}
free(ch->player_specials);
if (IS_NPC(ch))
log("SYSERR: Mob %s (#%d) had player_specials allocated!", GET_NAME(ch), GET_MOB_VNUM(ch));
}
if (!IS_NPC(ch) || (IS_NPC(ch) && GET_MOB_RNUM(ch) == -1)) {
/* if this is a player, or a non-prototyped non-player, free all */
if (GET_NAME(ch))
free(GET_NAME(ch));
if (POOFIN(ch))
free(POOFIN(ch));
if (POOFOUT(ch))
free(POOFOUT(ch));
if (GET_EMAIL(ch))
free(GET_EMAIL(ch));
if (ch->player.title)
free(ch->player.title);
if (ch->player.lastname)
free(ch->player.lastname);
if (ch->player.prompt);
free(ch->player.prompt);
if (ch->player.short_descr)
free(ch->player.short_descr);
if (ch->player.long_descr)
free(ch->player.long_descr);
}
else if ((i = GET_MOB_RNUM(ch)) >= 0) {
/* otherwise, free strings only if the string is not pointing at proto */
if (ch->player.name && ch->player.name != mob_proto[i].player.name)
free(ch->player.name);
if (ch->player.title && ch->player.title != mob_proto[i].player.title)
free(ch->player.title);
if (ch->player.short_descr && ch->player.short_descr != mob_proto[i].player.short_descr)
free(ch->player.short_descr);
if (ch->player.long_descr && ch->player.long_descr != mob_proto[i].player.long_descr)
free(ch->player.long_descr);
if (ch->player.prompt && ch->player.prompt != mob_proto[i].player.prompt)
free(ch->player.prompt);
if (ch->player.poofin && ch->player.poofin != mob_proto[i].player.poofin)
free(ch->player.poofin);
if (ch->player.poofout && ch->player.poofout != mob_proto[i].player.poofout)
free(ch->player.poofout);
if (ch->player.email && ch->player.email != mob_proto[i].player.email)
free(ch->player.email);
}
while (ch->affected)
affect_remove(ch, ch->affected);
if (ch->desc)
ch->desc->character = NULL;
free(ch);
}
/* release memory allocated for an obj struct */
void free_obj(Object obj) {
int nr;
struct extra_descr_data *thisd, *next_one;
if ((nr = GET_OBJ_RNUM(obj)) == -1) {
if (obj->name)
free(obj->name);
if (obj->description)
free(obj->description);
if (obj->short_description)
free(obj->short_description);
if (obj->action_description)
free(obj->action_description);
if (obj->ex_description)
for (thisd = obj->ex_description; thisd; thisd = next_one) {
next_one = thisd->next;
if (thisd->keyword)
free(thisd->keyword);
if (thisd->description)
free(thisd->description);
free(thisd);
}
}
else {
if (obj->name && obj->name != obj_proto[nr].name)
free(obj->name);
if (obj->description && obj->description != obj_proto[nr].description)
free(obj->description);
if (obj->short_description && obj->short_description != obj_proto[nr].short_description)
free(obj->short_description);
if (obj->action_description && obj->action_description != obj_proto[nr].action_description)
free(obj->action_description);
if (obj->ex_description && obj->ex_description != obj_proto[nr].ex_description)
for (thisd = obj->ex_description; thisd; thisd = next_one) {
next_one = thisd->next;
if (thisd->keyword)
free(thisd->keyword);
if (thisd->description)
free(thisd->description);
free(thisd);
}
}
free(obj);
}
/* clear some of the the working variables of a char */
void reset_char(Creature ch) {
int i;
for (i = 0; i < NUM_WEARS; i++)
GET_EQ(ch, i) = NULL;
ch->followers = NULL;
ch->master = NULL;
ch->in_room = NOWHERE;
ch->carrying = NULL;
ch->next = NULL;
ch->next_fighting = NULL;
ch->next_in_room = NULL;
ON_CHAIR(ch) = NULL;
FIGHTING(ch) = NULL;
ch->char_specials.position = POS_STANDING;
ch->char_specials.carry_weight = 0;
ch->char_specials.carry_items = 0;
if (GET_MOVE(ch) <= 0)
GET_MOVE(ch) = 1;
GET_LAST_TELL(ch) = NOBODY;
}
/* clear ALL the working variables of a char; do NOT free any space alloc'ed */
void clear_char(Creature ch) {
memset((char *) ch, 0, sizeof(struct char_data));
ch->in_room = NOWHERE;
GET_PFILEPOS(ch) = -1;
GET_MOB_RNUM(ch) = NOBODY;
GET_WAS_IN(ch) = NOWHERE;
GET_POS(ch) = POS_STANDING;
}
void clear_object(Object obj) {
memset((char *) obj, 0, sizeof(struct obj_data));
obj->item_number = NOTHING;
obj->in_room = NOWHERE;
obj->worn_on = NOWHERE;
IN_CHAIR(obj) = NULL;
}
/* initialize a new character only if class is set */
void init_char(Creature ch) {
void set_title(Creature ch, char *title);
char fn[MAX_INPUT_LENGTH];
int i;
/* create a player_special structure */
if (ch->player_specials == NULL)
CREATE(ch->player_specials, struct player_special_data, 1);
GET_IMM_LEV(ch) = -1; /* Not an immortal */
/* *** if this is our first player --- he be God *** */
if (top_of_p_table == 0) {
GET_LEVEL(ch) = LVL_TOP;
GET_IMM_LEV(ch) = 0; /* Initialize it to 0, meaning Implementor */
ch->real_abils.strength = att_max(ch);
ch->real_abils.dexterity = att_max(ch);
ch->real_abils.stamina = att_max(ch);
ch->real_abils.charisma = att_max(ch);
ch->real_abils.manipulation = att_max(ch);
ch->real_abils.appearance = att_max(ch);
ch->real_abils.perception = att_max(ch);
ch->real_abils.intelligence = att_max(ch);
ch->real_abils.wits = att_max(ch);
}
get_filename(GET_NAME(ch), fn, LORE_FILE);
sprintf(buf, "rm -f %s", fn);
system(buf);
ch->points.damage = 0;
ch->points.max_move = 100;
ch->points.move = GET_MAX_MOVE(ch);
set_title(ch, NULL);
ch->player.short_descr = NULL;
ch->player.long_descr = NULL;
ch->player.prompt = NULL;
ch->player.poofin = NULL;
ch->player.poofout = NULL;
if (GET_LEVEL(ch) < LVL_APPROVED)
ch->player.email = NULL;
ch->player.time.birth = time(0);
ch->player.time.played = 0;
ch->player.time.logon = time(0);
ch->points.blood = GET_MAX_BLOOD(ch);
ch->points.willpower = ch->points.max_willpower;
if ((i = get_ptable_by_name(GET_NAME(ch))) != -1)
player_table[i].id = GET_IDNUM(ch) = ++top_idnum;
else
log("SYSERR: init_char: Character '%s' not found in player table.", GET_NAME(ch));
ch->char_specials.saved.affected_by = 0;
for (i = 0; i < NUM_CONDS; i++)
GET_COND(ch, i) = (GET_LEVEL(ch) == LVL_IMPL ? -1 : 0);
GET_LOADROOM(ch) = NOWHERE;
}
/* returns the real number of the room with given virtual number */
room_rnum real_room(room_vnum vnum)
{
room_rnum bot, top, mid;
bot = 0;
top = top_of_world;
/* perform binary search on world-table */
for (;;) {
mid = (bot + top) / 2;
if ((world + mid)->number == vnum)
return (mid);
if (bot >= top)
return (NOWHERE);
if ((world + mid)->number > vnum)
top = mid - 1;
else
bot = mid + 1;
}
}
/* returns the real number of the monster with given virtual number */
mob_rnum real_mobile(mob_vnum vnum) {
mob_rnum bot, top, mid;
bot = 0;
top = top_of_mobt;
/* perform binary search on mob-table */
for (;;) {
mid = (bot + top) / 2;
if ((mob_index + mid)->vnum == vnum)
return (mid);
if (bot >= top)
return (-1);
if ((mob_index + mid)->vnum > vnum)
top = mid - 1;
else
bot = mid + 1;
}
}
/* returns the real number of the object with given virtual number */
obj_rnum real_object(obj_vnum vnum) {
obj_rnum bot, top, mid;
bot = 0;
top = top_of_objt;
/* perform binary search on obj-table */
for (;;) {
mid = (bot + top) / 2;
if ((obj_index + mid)->vnum == vnum)
return (mid);
if (bot >= top)
return (-1);
if ((obj_index + mid)->vnum > vnum)
top = mid - 1;
else
bot = mid + 1;
}
}
int real_zone(int number) {
int i;
for (i = 0; i <= NUM_MAP_ZONES; i++)
if (number < zone_table[i].top)
return i;
return NUM_MAP_ZONES;
}
void write_lore(Creature ch) {
FILE *file;
char fn[MAX_STRING_LENGTH];
struct lore_data *temp;
if (!ch || IS_NPC(ch))
return;
get_filename(GET_NAME(ch), fn, LORE_FILE);
if (GET_LORE(ch) == NULL)
return;
if (!(file = fopen(fn, "w"))) {
log("SYSERR: Couldn't save lore for %s in '%s'.", GET_NAME(ch), fn);
perror("SYSERR: write_lore");
return;
}
for (temp = GET_LORE(ch); temp; temp = temp->next)
fprintf(file, "%d %ld %ld\n", temp->type, temp->value, temp->date);
fprintf(file, "$\n");
fclose(file);
}
void read_lore(Creature ch) {
FILE *file;
char fn[MAX_STRING_LENGTH], line[MAX_STRING_LENGTH];
struct lore_data *temp, *last = NULL;
int a;
long b, c;
if (!ch || IS_NPC(ch))
return;
get_filename(GET_NAME(ch), fn, LORE_FILE);
if (!(file = fopen(fn, "r"))) {
if (errno != ENOENT) {
log("SYSERR: Couldn't load lore for %s from '%s'.", GET_NAME(ch), fn);
perror("SYSERR: read_lore");
}
return;
}
for (;;) {
get_line(file, line);
if (!*line) {
log("SYSERR: Unexpected EOF in '%s'.", fn);
break;
}
if (*line == '$')
break;
if (sscanf(line, "%d %ld %ld", &a, &b, &c) != 3) {
log("SYSERR: Error reading data from '%s'.", fn);
break;
}
CREATE(temp, struct lore_data, 1);
temp->type = a;
temp->value = b;
temp->date = c;
if (last)
last->next = temp;
else
GET_LORE(ch) = temp;
temp->next = NULL;
last = temp;
}
fclose(file);
}