/***************************************************************************
* file: db.c , Database module. Part of DIKUMUD *
* Usage: Loading/Saving chars, booting world, resetting etc. *
* Copyright (C) 1990, 1991 - see 'license.doc' for complete information. *
* *
* Copyright (C) 1992, 1993 Michael Chastain, Michael Quan, Mitchell Tse *
* Performance optimization and bug fixes by MERC Industries. *
* You can use our stuff in any way you like whatsoever so long as this *
* copyright notice remains intact. If you like it please drop a line *
* to mec@garnet.berkeley.edu. *
* *
* This is free software and you are benefitting. We hope that you *
* share your changes too. What goes around, comes around. *
***************************************************************************/
#include <stdlib.h>
#include <stdio.h>
extern int _filbuf(FILE *);
#include <string.h>
#include <memory.h>
#include <ctype.h>
#include <time.h>
#include "structs.h"
#include "mob.h"
#include "obj.h"
#include "utils.h"
#include "db.h"
#include "handler.h"
#include "limits.h"
#include "spells.h"
#define NEW_ZONE_SYSTEM
/*
* Sizes.
*/
#define MAX_ZONE 96
#define MAX_INDEX 1024
#define MAX_ROOM 3072
#define MAX_RESET 4096
/**************************************************************************
* declarations of most of the 'global' variables *
************************************************************************ */
struct room_data world_array[MAX_ROOM]; /* array of rooms */
struct room_data *world = world_array;
#define world world_array
int top_of_world = 0; /* ref to the top element of world */
struct obj_data *object_list = 0; /* the global linked list of obj's */
struct char_data *character_list = 0; /* global l-list of chars */
struct ban_t *ban_list=0; /* list of banned site--sigh */
struct zone_data zone_table_array[MAX_ZONE];
struct zone_data *zone_table = zone_table_array;
#define zone_table zone_table_array
/* table of reset data */
int top_of_zone_table = 0;
struct message_list fight_messages[MAX_MESSAGES]; /* fighting messages */
char greetings[MAX_STRING_LENGTH]; /* the greeting screen */
char credits[MAX_STRING_LENGTH]; /* the Credits List */
char news[MAX_STRING_LENGTH]; /* the news */
char motd[MAX_STRING_LENGTH]; /* the messages of today */
char story[MAX_STRING_LENGTH]; /* the game story */
char help[MAX_STRING_LENGTH]; /* the main help page */
char info[MAX_STRING_LENGTH]; /* the info text */
char wizlist[MAX_STRING_LENGTH]; /* the wizlist */
FILE *mob_f, /* file containing mob prototypes */
*obj_f, /* obj prototypes */
*help_fl; /* file for help texts (HELP <kwd>)*/
struct index_data mob_index_array[MAX_INDEX];
struct index_data *mob_index = mob_index_array;
#define mob_index mob_index_array
/* index table for mobile file */
struct index_data obj_index_array[MAX_INDEX];
struct index_data *obj_index = obj_index_array;
/* index table for object file */
#define obj_index obj_index_array
struct help_index_element *help_index = 0;
int top_of_mobt = 0; /* top of mobile index table */
int top_of_objt = 0; /* top of object index 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 */
/* local procedures */
void boot_zones(void);
void setup_dir(FILE *fl, int room, int dir);
void boot_world(void);
struct index_data *generate_indices(FILE *fl, int *top,
struct index_data *index);
int is_empty(int zone_nr);
void reset_zone(int zone);
int file_to_string(char *name, char *buf);
void renum_world(void);
void renum_zone_table(void);
void reset_time(void);
void clear_char(struct char_data *ch);
/* external refs */
extern struct descriptor_data *descriptor_list;
void load_messages(void);
void weather_and_time ( int mode );
void assign_spell_pointers ( void );
int dice(int number, int size);
int number(int from, int to);
void boot_social_messages(void);
void boot_pose_messages(void);
struct help_index_element *build_help_index(FILE *fl, int *num);
/*************************************************************************
* routines for booting the system *
*********************************************************************** */
/* body of the booting system */
void boot_db(void)
{
int i;
reset_time();
log( "Reading aux files." );
file_to_string(GREETINGS_FILE, greetings);
file_to_string(NEWS_FILE, news);
file_to_string(CREDITS_FILE, credits);
file_to_string(MOTD_FILE, motd);
strcat( motd, "\n\rPress RETURN to continue: " );
file_to_string(STORY_FILE, story);
file_to_string(HELP_PAGE_FILE, help);
file_to_string(INFO_FILE, info);
file_to_string(WIZLIST_FILE, wizlist);
log("Opening mobile, object and help files.");
if (!(mob_f = fopen(MOB_FILE, "r")))
{
perror( MOB_FILE );
exit( 1 );
}
if (!(obj_f = fopen(OBJ_FILE, "r")))
{
perror( OBJ_FILE );
exit( 1 );
}
if (!(help_fl = fopen(HELP_KWRD_FILE, "r")))
{
perror( HELP_KWRD_FILE );
exit( 1 );
}
help_index = build_help_index(help_fl, &top_of_helpt);
log( "Loading tinyworld." );
boot_zones();
boot_world();
renum_world();
generate_indices(mob_f, &top_of_mobt, mob_index);
generate_indices(obj_f, &top_of_objt, obj_index);
renum_zone_table();
log("Loading messages.");
load_messages();
boot_social_messages();
boot_pose_messages();
log( "Assigning function pointers." );
assign_mobiles();
assign_objects();
assign_rooms();
assign_spell_pointers();
fprintf( stderr, "\n[ Room Room]\t{Level}\t Author\tZone\n" );
for (i = 0; i <= top_of_zone_table; i++)
{
fprintf(stderr, "[%5d %5d]\t%s.\n",
(i ? (zone_table[i - 1].top + 1) : 0),
zone_table[i].top,
zone_table[i].name);
reset_zone(i);
}
fprintf( stderr, "\n" );
}
/* reset the time in the game from file */
void reset_time(void)
{
long beginning_of_time = 650336715;
struct time_info_data mud_time_passed(time_t t2, time_t t1);
time_info = mud_time_passed(time(0), beginning_of_time);
switch(time_info.hours){
case 0 :
case 1 :
case 2 :
case 3 :
case 4 :
{
weather_info.sunlight = SUN_DARK;
break;
}
case 5 :
{
weather_info.sunlight = SUN_RISE;
break;
}
case 6 :
case 7 :
case 8 :
case 9 :
case 10 :
case 11 :
case 12 :
case 13 :
case 14 :
case 15 :
case 16 :
case 17 :
case 18 :
case 19 :
case 20 :
{
weather_info.sunlight = SUN_LIGHT;
break;
}
case 21 :
{
weather_info.sunlight = SUN_SET;
break;
}
case 22 :
case 23 :
default :
{
weather_info.sunlight = SUN_DARK;
break;
}
}
sprintf(log_buf, "Current Gametime: %dH %dD %dM %dY.",
time_info.hours, time_info.day,
time_info.month, time_info.year);
log(log_buf);
weather_info.pressure = 960;
if ((time_info.month>=7)&&(time_info.month<=12))
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;
}
/* generate index table for object or monster file */
struct index_data *generate_indices(FILE *fl, int *top,
struct index_data *index)
{
int i = 0;
char buf[82];
rewind(fl);
for (;;)
{
if (fgets(buf, 81, fl))
{
if (*buf == '#')
{
/* allocate new cell */
if ( i >= MAX_INDEX )
{
perror( "Too many indexes" );
exit( 1 );
}
sscanf(buf, "#%d", &index[i].virtual);
index[i].pos = ftell(fl);
index[i].number = 0;
index[i].func = 0;
i++;
}
else
if (*buf == '$') /* EOF */
break;
}
else
{
perror("generate indices");
exit( 1 );
}
}
*top = i - 2;
return(index);
}
/* load the rooms */
void boot_world(void)
{
FILE *fl;
int room_nr = 0, zone = 0, virtual_nr, flag, tmp;
char *temp, chk[50];
struct extra_descr_data *new_descr;
character_list = 0;
object_list = 0;
if (!(fl = fopen(WORLD_FILE, "r")))
{
perror("fopen");
log("boot_world: could not open world file.");
exit( 1 );
}
do
{
fscanf(fl, " #%d\n", &virtual_nr);
temp = fread_string(fl);
if ( ( flag = (*temp != '$') ) != 0 ) /* a new record to be read */
{
if (room_nr >= MAX_ROOM)
{
perror( "Too many rooms" );
exit( 1 );
}
world[room_nr].number = virtual_nr;
world[room_nr].name = temp;
world[room_nr].description = fread_string(fl);
if (top_of_zone_table >= 0)
{
fscanf(fl, " %*d ");
/* OBS: Assumes ordering of input rooms */
if (world[room_nr].number <=
(zone ? zone_table[zone-1].top : -1))
{
fprintf(stderr, "Room nr %d is below zone %d.\n",
room_nr, zone);
exit( 1 );
}
while (world[room_nr].number > zone_table[zone].top)
if (++zone > top_of_zone_table)
{
fprintf(stderr, "Room %d is outside of any zone.\n",
virtual_nr);
exit( 1 );
}
world[room_nr].zone = zone;
}
fscanf(fl, " %d ", &tmp);
world[room_nr].room_flags = tmp;
fscanf(fl, " %d ", &tmp);
world[room_nr].sector_type = tmp;
world[room_nr].funct = 0;
world[room_nr].contents = 0;
world[room_nr].people = 0;
world[room_nr].light = 0; /* Zero light sources */
for (tmp = 0; tmp <= 5; tmp++)
world[room_nr].dir_option[tmp] = 0;
world[room_nr].ex_description = 0;
for (;;)
{
fscanf(fl, " %s \n", chk);
if (*chk == 'D') /* direction field */
setup_dir(fl, room_nr, atoi(chk + 1));
else if (*chk == 'E') /* extra description field */
{
CREATE(new_descr, struct extra_descr_data, 1);
new_descr->keyword = fread_string(fl);
new_descr->description = fread_string(fl);
new_descr->next = world[room_nr].ex_description;
world[room_nr].ex_description = new_descr;
}
else if (*chk == 'S') /* end of current room */
break;
}
room_nr++;
}
}
while (flag);
free(temp); /* cleanup the area containing the terminal $ */
fclose(fl);
top_of_world = --room_nr;
}
/* read direction data */
void setup_dir(FILE *fl, int room, int dir)
{
int tmp;
CREATE(world[room].dir_option[dir],
struct room_direction_data, 1);
world[room].dir_option[dir]->general_description =
fread_string(fl);
world[room].dir_option[dir]->keyword = fread_string(fl);
fscanf(fl, " %d ", &tmp);
if (tmp == 1)
world[room].dir_option[dir]->exit_info = EX_ISDOOR;
else if (tmp == 2)
world[room].dir_option[dir]->exit_info = EX_ISDOOR | EX_PICKPROOF;
else
world[room].dir_option[dir]->exit_info = 0;
fscanf(fl, " %d ", &tmp);
world[room].dir_option[dir]->key = tmp;
fscanf(fl, " %d ", &tmp);
world[room].dir_option[dir]->to_room = tmp;
}
void renum_world(void)
{
register int room, door;
for (room = 0; room <= top_of_world; room++)
for (door = 0; door <= 5; 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);
}
#ifdef NEW_ZONE_SYSTEM
void renum_zone_table(void)
{
int zone, comm;
for (zone = 0; zone <= top_of_zone_table; zone++)
for (comm = 0; zone_table[zone].cmd[comm].command != 'S'; comm++)
switch(zone_table[zone].cmd[comm].command)
{
case 'M':
zone_table[zone].cmd[comm].arg1 =
real_mobile(zone_table[zone].cmd[comm].arg1);
zone_table[zone].cmd[comm].arg3 =
real_room(zone_table[zone].cmd[comm].arg3);
break;
case 'O':
zone_table[zone].cmd[comm].arg1 =
real_object(zone_table[zone].cmd[comm].arg1);
if (zone_table[zone].cmd[comm].arg3 != NOWHERE)
zone_table[zone].cmd[comm].arg3 =
real_room(zone_table[zone].cmd[comm].arg3);
break;
case 'G':
zone_table[zone].cmd[comm].arg1 =
real_object(zone_table[zone].cmd[comm].arg1);
break;
case 'E':
zone_table[zone].cmd[comm].arg1 =
real_object(zone_table[zone].cmd[comm].arg1);
break;
case 'P':
zone_table[zone].cmd[comm].arg1 =
real_object(zone_table[zone].cmd[comm].arg1);
zone_table[zone].cmd[comm].arg3 =
real_object(zone_table[zone].cmd[comm].arg3);
break;
case 'D':
zone_table[zone].cmd[comm].arg1 =
real_room(zone_table[zone].cmd[comm].arg1);
break;
}
}
#endif
#ifdef NEW_ZONE_SYSTEM
/* load the zone table and command tables */
void boot_zones(void)
{
FILE *fl;
int zon = 0, tmp;
char *check, buf[81];
static struct reset_com reset_tab[MAX_RESET];
static int reset_top = 0;
if (!(fl = fopen(ZONE_FILE, "r")))
{
perror( ZONE_FILE );
exit( 1 );
}
for (;;)
{
fscanf(fl, " #%*d\n");
check = fread_string(fl);
if (*check == '$')
break; /* end of file */
/* alloc a new zone */
if ( zon >= MAX_ZONE )
{
perror( "Too many zones" );
exit( 1 );
}
zone_table[zon].name = check;
fscanf(fl, " %d ", &zone_table[zon].top);
fscanf(fl, " %d ", &zone_table[zon].lifespan);
fscanf(fl, " %d ", &zone_table[zon].reset_mode);
/* read the command table */
zone_table[zon].cmd = &reset_tab[reset_top];
for ( ;; )
{
if ( reset_top >= MAX_RESET )
{
perror( "Too many zone resets" );
exit( 1 );
}
fscanf(fl, " "); /* skip blanks */
fscanf(fl, "%c",
&reset_tab[reset_top].command);
if (reset_tab[reset_top].command == 'S')
{
reset_top++;
break;
}
if (reset_tab[reset_top].command == '*')
{
fgets(buf, 80, fl); /* skip command */
continue;
}
fscanf(fl, " %d %d %d",
&tmp,
&reset_tab[reset_top].arg1,
&reset_tab[reset_top].arg2);
reset_tab[reset_top].if_flag = tmp;
if (reset_tab[reset_top].command == 'M' ||
reset_tab[reset_top].command == 'O' ||
reset_tab[reset_top].command == 'E' ||
reset_tab[reset_top].command == 'P' ||
reset_tab[reset_top].command == 'D')
fscanf(fl, " %d", &reset_tab[reset_top].arg3);
fgets(buf, 80, fl); /* read comment */
reset_top++;
}
zon++;
}
top_of_zone_table = --zon;
free(check);
fclose(fl);
}
#endif
/*************************************************************************
* procedures for resetting, both play-time and boot-time *
*********************************************************************** */
/* read a mobile from MOB_FILE */
struct char_data *read_mobile(int nr, int type)
{
int i;
long tmp, tmp2, tmp3;
struct char_data *mob;
char buf[100];
char letter;
i = nr;
if (type == VIRTUAL)
if ((nr = real_mobile(nr)) < 0)
{
sprintf(buf, "Mobile (V) %d does not exist in database.", i);
return(0);
}
fseek(mob_f, mob_index[nr].pos, 0);
CREATE(mob, struct char_data, 1);
clear_char(mob);
/***** String data *** */
mob->player.name = fread_string(mob_f);
mob->player.short_descr = fread_string(mob_f);
mob->player.long_descr = fread_string(mob_f);
mob->player.description = fread_string(mob_f);
mob->player.title = 0;
/* *** Numeric data *** */
fscanf(mob_f, "%ld ", &tmp);
mob->specials.act = tmp;
SET_BIT(mob->specials.act, ACT_ISNPC);
fscanf(mob_f, " %ld ", &tmp);
mob->specials.affected_by = tmp;
fscanf(mob_f, " %ld ", &tmp);
mob->specials.alignment = tmp;
fscanf(mob_f, " %c \n", &letter);
if (letter == 'S') {
/* The new easy monsters */
mob->abilities.str = 11;
mob->abilities.intel = 11;
mob->abilities.wis = 11;
mob->abilities.dex = 11;
mob->abilities.con = 11;
fscanf(mob_f, " %ld ", &tmp);
GET_LEVEL(mob) = tmp;
fscanf(mob_f, " %ld ", &tmp);
mob->points.hitroll = 20-tmp;
fscanf(mob_f, " %ld ", &tmp);
mob->points.armor = 10*tmp;
fscanf(mob_f, " %ldd%ld+%ld ", &tmp, &tmp2, &tmp3);
mob->points.max_hit = dice(tmp, tmp2)+tmp3;
mob->points.hit = mob->points.max_hit;
fscanf(mob_f, " %ldd%ld+%ld \n", &tmp, &tmp2, &tmp3);
mob->points.damroll = tmp3;
mob->specials.damnodice = tmp;
mob->specials.damsizedice = tmp2;
mob->points.mana = 100;
mob->points.max_mana = 100;
mob->points.move = 82;
mob->points.max_move = 82;
fscanf(mob_f, " %ld ", &tmp);
mob->points.gold = tmp;
fscanf(mob_f, " %ld \n", &tmp);
GET_EXP(mob) = tmp;
fscanf(mob_f, " %ld ", &tmp);
mob->specials.position = tmp;
fscanf(mob_f, " %ld ", &tmp);
mob->specials.default_pos = tmp;
fscanf(mob_f, " %ld \n", &tmp);
mob->player.sex = tmp;
mob->player.class = 0;
mob->player.time.birth = time(0);
mob->player.time.played = 0;
mob->player.time.logon = time(0);
mob->player.weight = 200;
mob->player.height = 198;
for (i = 0; i < 3; i++)
GET_COND(mob, i) = -1;
for (i = 0; i < 5; i++)
mob->specials.apply_saving_throw[i] = MAX(20-GET_LEVEL(mob), 2);
} else { /* The old monsters are down below here */
fscanf(mob_f, " %ld ", &tmp);
mob->abilities.str = tmp;
fscanf(mob_f, " %ld ", &tmp);
mob->abilities.intel = tmp;
fscanf(mob_f, " %ld ", &tmp);
mob->abilities.wis = tmp;
fscanf(mob_f, " %ld ", &tmp);
mob->abilities.dex = tmp;
fscanf(mob_f, " %ld \n", &tmp);
mob->abilities.con = tmp;
fscanf(mob_f, " %ld ", &tmp);
fscanf(mob_f, " %ld ", &tmp2);
mob->points.max_hit = number(tmp, tmp2);
mob->points.hit = mob->points.max_hit;
fscanf(mob_f, " %ld ", &tmp);
mob->points.armor = 10*tmp;
fscanf(mob_f, " %ld ", &tmp);
mob->points.mana = tmp;
mob->points.max_mana = tmp;
fscanf(mob_f, " %ld ", &tmp);
mob->points.move = tmp;
mob->points.max_move = tmp;
fscanf(mob_f, " %ld ", &tmp);
mob->points.gold = tmp;
fscanf(mob_f, " %ld \n", &tmp);
GET_EXP(mob) = tmp;
fscanf(mob_f, " %ld ", &tmp);
mob->specials.position = tmp;
fscanf(mob_f, " %ld ", &tmp);
mob->specials.default_pos = tmp;
fscanf(mob_f, " %ld ", &tmp);
mob->player.sex = tmp;
fscanf(mob_f, " %ld ", &tmp);
mob->player.class = tmp;
fscanf(mob_f, " %ld ", &tmp);
GET_LEVEL(mob) = tmp;
fscanf(mob_f, " %ld ", &tmp);
mob->player.time.birth = time(0);
mob->player.time.played = 0;
mob->player.time.logon = time(0);
fscanf(mob_f, " %ld ", &tmp);
mob->player.weight = tmp;
fscanf(mob_f, " %ld \n", &tmp);
mob->player.height = tmp;
for (i = 0; i < 3; i++)
{
fscanf(mob_f, " %ld ", &tmp);
GET_COND(mob, i) = tmp;
}
fscanf(mob_f, " \n ");
for (i = 0; i < 5; i++)
{
fscanf(mob_f, " %ld ", &tmp);
mob->specials.apply_saving_throw[i] = tmp;
}
fscanf(mob_f, " \n ");
/* Set the damage as some standard 1d4 */
mob->points.damroll = 0;
mob->specials.damnodice = 1;
mob->specials.damsizedice = 6;
/* Calculate THAC0 as a formula of Level */
mob->points.hitroll = MAX(1, GET_LEVEL(mob)-3);
}
mob->tmpabilities = mob->abilities;
for (i = 0; i < MAX_WEAR; i++) /* Initialisering Ok */
mob->equipment[i] = 0;
mob->nr = nr;
mob->desc = 0;
/* insert in list */
mob->next = character_list;
character_list = mob;
mob_index[nr].number++;
return(mob);
}
/* read an object from OBJ_FILE */
struct obj_data *read_object(int nr, int eq_level)
{
struct obj_data *obj;
int tmp, i;
char chk[MAX_INPUT_LENGTH];
struct extra_descr_data *new_descr;
fseek(obj_f, obj_index[nr].pos, 0);
CREATE(obj, struct obj_data, 1);
clear_object(obj);
/* *** string data *** */
obj->name = fread_string(obj_f);
obj->short_description = fread_string(obj_f);
obj->description = fread_string(obj_f);
obj->action_description = fread_string(obj_f);
/* *** numeric data *** */
fscanf(obj_f, " %d ", &tmp); obj->obj_flags.type_flag = tmp;
fscanf(obj_f, " %d ", &tmp); obj->obj_flags.extra_flags = tmp;
fscanf(obj_f, " %d ", &tmp); obj->obj_flags.wear_flags = tmp;
fscanf(obj_f, " %d ", &tmp); obj->obj_flags.value[0] = tmp;
fscanf(obj_f, " %d ", &tmp); obj->obj_flags.value[1] = tmp;
fscanf(obj_f, " %d ", &tmp); obj->obj_flags.value[2] = tmp;
fscanf(obj_f, " %d ", &tmp); obj->obj_flags.value[3] = tmp;
fscanf(obj_f, " %d ", &tmp); obj->obj_flags.weight = tmp;
fscanf(obj_f, " %d \n", &tmp); obj->obj_flags.cost = tmp;
fscanf(obj_f, " %d \n", &tmp); obj->obj_flags.cost_per_day = tmp;
/* *** extra descriptions *** */
obj->ex_description = 0;
while (fscanf(obj_f, " %s \n", chk), *chk == 'E')
{
CREATE(new_descr, struct extra_descr_data, 1);
new_descr->keyword = fread_string(obj_f);
new_descr->description = fread_string(obj_f);
new_descr->next = obj->ex_description;
obj->ex_description = new_descr;
}
for( i = 0 ; (i < MAX_OBJ_AFFECT) && (*chk == 'A') ; i++)
{
fscanf(obj_f, " %d ", &tmp); obj->affected[i].location = tmp;
fscanf(obj_f, " %d \n", &tmp); obj->affected[i].modifier = tmp;
fscanf(obj_f, " %s \n", chk);
}
for (;(i < MAX_OBJ_AFFECT);i++)
{
obj->affected[i].location = APPLY_NONE;
obj->affected[i].modifier = 0;
}
obj->in_room = NOWHERE;
obj->next_content = 0;
obj->carried_by = 0;
obj->in_obj = 0;
obj->contains = 0;
obj->item_number = nr;
obj->obj_flags.eq_level = eq_level;
obj->next = object_list;
object_list = obj;
obj_index[nr].number++;
return (obj);
}
void zone_update(void)
{
int i;
for ( i = 0; i <= top_of_zone_table; i++ )
{
if ( zone_table[i].reset_mode == 0 )
continue;
if ( zone_table[i].age < zone_table[i].lifespan )
{
zone_table[i].age++;
continue;
}
if ( zone_table[i].reset_mode == 1 && !is_empty(i) )
continue;
reset_zone( i );
}
}
#define ZCMD zone_table[zone].cmd[cmd_no]
/* execute the reset command table of a given zone */
void reset_zone(int zone)
{
int cmd_no, last_cmd = 1;
struct char_data *mob = NULL;
struct obj_data *obj, *obj_to;
for (cmd_no = 0;;cmd_no++)
{
if (ZCMD.command == 'S')
break;
if ( last_cmd || ZCMD.if_flag == 0 )
switch(ZCMD.command)
{
case 'M': /* read a mobile */
if (mob_index[ZCMD.arg1].number <
ZCMD.arg2)
{
mob = read_mobile(ZCMD.arg1, REAL);
char_to_room(mob, ZCMD.arg3);
last_cmd = 1;
}
else
last_cmd = 0;
break;
case 'O': /* read an object */
if (obj_index[ZCMD.arg1].number < ZCMD.arg2)
if (ZCMD.arg3 >= 0)
{
if (!get_obj_in_list_num(
ZCMD.arg1,world[ZCMD.arg3].contents))
{
obj = read_object(ZCMD.arg1, 0);
obj_to_room(obj, ZCMD.arg3);
last_cmd = 1;
}
else
last_cmd = 0;
}
else
{
obj = read_object(ZCMD.arg1, 0);
obj->in_room = NOWHERE;
last_cmd = 1;
}
else
last_cmd = 0;
break;
case 'P': /* object to object */
if (obj_index[ZCMD.arg1].number < ZCMD.arg2)
{
obj_to = get_obj_num(ZCMD.arg3);
obj = read_object(ZCMD.arg1, obj_to->obj_flags.eq_level);
obj_to_obj(obj, obj_to);
last_cmd = 1;
}
else
last_cmd = 0;
break;
case 'G': /* obj_to_char */
if ( mob == NULL )
{
log( "Null mob in G" );
last_cmd = 0;
break;
}
if (obj_index[ZCMD.arg1].number < ZCMD.arg2)
{
obj = read_object(ZCMD.arg1, map_eq_level(mob) );
obj_to_char(obj, mob);
last_cmd = 1;
}
else
last_cmd = 0;
break;
case 'E': /* object to equipment list */
if ( mob == NULL )
{
log( "Null mob in E" );
last_cmd = 0;
break;
}
if (obj_index[ZCMD.arg1].number < ZCMD.arg2)
{
obj = read_object(ZCMD.arg1, map_eq_level(mob) );
equip_char(mob, obj, ZCMD.arg3);
last_cmd = 1;
}
else
last_cmd = 0;
break;
case 'D': /* set state of door */
switch (ZCMD.arg3)
{
case 0:
REMOVE_BIT(
world[ZCMD.arg1].dir_option[ZCMD.arg2]->exit_info,
EX_LOCKED);
REMOVE_BIT(
world[ZCMD.arg1].dir_option[ZCMD.arg2]->exit_info,
EX_CLOSED);
break;
case 1:
SET_BIT(
world[ZCMD.arg1].dir_option[ZCMD.arg2]->exit_info,
EX_CLOSED);
REMOVE_BIT(
world[ZCMD.arg1].dir_option[ZCMD.arg2]->exit_info,
EX_LOCKED);
break;
case 2:
SET_BIT(
world[ZCMD.arg1].dir_option[ZCMD.arg2]->exit_info,
EX_LOCKED);
SET_BIT(
world[ZCMD.arg1].dir_option[ZCMD.arg2]->exit_info,
EX_CLOSED);
break;
}
last_cmd = 1;
break;
default:
sprintf(log_buf, "Undef command: zone %d cmd %d.",
zone, cmd_no);
log(log_buf);
exit( 1 );
break;
}
else
last_cmd = 0;
}
zone_table[zone].age = 0;
}
#undef ZCMD
/* for use in reset_zone; return TRUE if zone 'nr' is free of PC's */
int is_empty(int zone_nr)
{
struct descriptor_data *i;
for (i = descriptor_list; i; i = i->next)
if (!i->connected)
if (world[i->character->in_room].zone == zone_nr)
return(0);
return(1);
}
/************************************************************************
* procs 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 buf[MAX_STRING_LENGTH];
char * pAlloc;
char * pBufLast;
for ( pBufLast = buf; pBufLast < &buf[sizeof(buf)-2]; )
{
switch( *pBufLast = getc( fl ) )
{
default:
pBufLast++;
break;
case EOF:
perror( "fread_string: EOF" );
exit( 1 );
break;
case '\n':
while ( pBufLast > buf && isspace(pBufLast[-1]) )
pBufLast--;
*pBufLast++ = '\n';
*pBufLast++ = '\r';
break;
case '~':
getc( fl );
if ( pBufLast == buf )
pAlloc = "";
else
{
*pBufLast++ = '\0';
CREATE( pAlloc, char, pBufLast-buf );
memcpy( pAlloc, buf, pBufLast-buf );
}
return pAlloc;
}
}
perror( "fread_string: string too long" );
exit( 1 );
return( NULL );
}
/* release memory allocated for a char struct */
void free_char( CHAR_DATA *ch )
{
int iWear;
struct affected_type *af;
FREE( GET_NAME(ch) );
FREE( ch->player.title );
FREE( ch->player.short_descr );
FREE( ch->player.long_descr );
FREE( ch->player.description );
for ( iWear = 0; iWear < MAX_WEAR; iWear++ )
{
if ( ch->equipment[iWear] )
obj_to_char( unequip_char( ch, iWear ), ch );
}
while ( ch->carrying )
extract_obj( ch->carrying );
for ( af = ch->affected; af; af = af->next )
affect_remove( ch, af );
FREE( ch );
}
/* release memory allocated for an obj struct */
void free_obj(struct obj_data *obj)
{
struct extra_descr_data *this, *next_one;
FREE( obj->name );
FREE( obj->description );
FREE( obj->short_description );
FREE( obj->action_description );
for ( this = obj->ex_description; this != NULL; this = next_one )
{
next_one = this->next;
FREE( this->keyword );
FREE( this->description );
FREE( this );
}
FREE(obj);
}
/* read contents of a text file, and place in buf */
int file_to_string(char *name, char *buf)
{
FILE *fl;
char tmp[100];
*buf = '\0';
if (!(fl = fopen(name, "r")))
{
perror("file-to-string");
*buf = '\0';
return(-1);
}
do
{
fgets(tmp, 99, fl);
if (!feof(fl))
{
if (strlen(buf) + strlen(tmp) + 2 > MAX_STRING_LENGTH)
{
log("fl->strng: string too big (db.c, file_to_string)");
*buf = '\0';
return(-1);
}
strcat(buf, tmp);
*(buf + strlen(buf) + 1) = '\0';
*(buf + strlen(buf)) = '\r';
}
}
while (!feof(fl));
fclose(fl);
return(0);
}
/* clear some of the the working variables of a char */
void reset_char(struct char_data *ch)
{
int i;
for (i = 0; i < MAX_WEAR; i++) /* Intializing */
ch->equipment[i] = 0;
ch->followers = 0;
ch->master = 0;
ch->carrying = 0;
ch->next = 0;
ch->next_fighting = 0;
ch->next_in_room = 0;
ch->specials.fighting = 0;
ch->specials.position = POSITION_STANDING;
ch->specials.default_pos = POSITION_STANDING;
ch->specials.carry_weight = 0;
ch->specials.carry_items = 0;
GET_AC(ch) = 100;
ch->specials.wizInvis = FALSE;
ch->specials.holyLite = FALSE;
if (GET_HIT(ch) <= 0)
GET_HIT(ch) = 1;
if (GET_MOVE(ch) <= 0)
GET_MOVE(ch) = 1;
if (GET_MANA(ch) <= 0)
GET_MANA(ch) = 1;
}
/*
* Clear but do not de-alloc.
*/
void clear_char(struct char_data *ch)
{
memset((char *)ch, (char)'\0', (int)sizeof(struct char_data));
ch->in_room = NOWHERE;
ch->specials.was_in_room = NOWHERE;
ch->specials.position = POSITION_STANDING;
ch->specials.default_pos = POSITION_STANDING;
ch->specials.wizInvis = FALSE;
ch->specials.holyLite = FALSE;
GET_AC(ch) = 100; /* Basic Armor */
if (ch->points.max_mana < 100) {
ch->points.max_mana = 100;
} /* if */
}
void clear_object(struct obj_data *obj)
{
memset((char *)obj, (char)'\0', (int)sizeof(struct obj_data));
obj->item_number = -1;
obj->in_room = NOWHERE;
}
/* initialize a new character only if class is set */
void init_char(struct char_data *ch)
{
int i;
extern int god;
/*
* Boot with -g to make gods.
*/
if ( god )
{
GET_EXP(ch) = 90000000;
GET_LEVEL(ch) = 35;
}
set_title(ch);
ch->player.short_descr = 0;
ch->player.long_descr = 0;
ch->player.description = 0;
ch->player.hometown = number(1,4);
ch->player.time.birth = time(0);
ch->player.time.played = 0;
ch->player.time.logon = time(0);
for (i = 0; i < MAX_TONGUE; i++)
ch->player.talks[i] = 0;
GET_STR(ch) = 9;
GET_INT(ch) = 9;
GET_WIS(ch) = 9;
GET_DEX(ch) = 9;
GET_CON(ch) = 9;
/* make favors for sex */
if (ch->player.sex == SEX_MALE) {
ch->player.weight = number(120,180);
ch->player.height = number(160,200);
} else {
ch->player.weight = number(100,160);
ch->player.height = number(150,180);
}
ch->points.max_mana = 100;
ch->points.mana = GET_MAX_MANA(ch);
ch->points.hit = GET_MAX_HIT(ch);
ch->points.move = GET_MAX_MOVE(ch);
ch->points.armor = 100;
for (i = 0; i < MAX_SKILLS; i++)
{
if (GET_LEVEL(ch) <35) {
ch->skills[i].learned = 0;
ch->skills[i].recognise = FALSE;
} else {
ch->skills[i].learned = 100;
ch->skills[i].recognise = FALSE;
}
}
ch->specials.affected_by = 0;
ch->specials.practices = 0;
for (i = 0; i < 5; i++)
ch->specials.apply_saving_throw[i] = 0;
for (i = 0; i < 3; i++)
GET_COND(ch, i) = (GET_LEVEL(ch) == 35 ? -1 : 35);
reset_char(ch);
}
/* returns the real number of the room with given virtual number */
int real_room(int virtual)
{
int bot, top, mid;
bot = 0;
top = top_of_world;
/* perform binary search on world-table */
for (;;)
{
mid = (bot + top) / 2;
if ((world + mid)->number == virtual)
return(mid);
if (bot >= top)
{
fprintf(stderr, "Room %d does not exist in database\n", virtual);
return(-1);
}
if ((world + mid)->number > virtual)
top = mid - 1;
else
bot = mid + 1;
}
}
/* returns the real number of the monster with given virtual number */
int real_mobile(int virtual)
{
int bot, top, mid;
bot = 0;
top = top_of_mobt;
/* perform binary search on mob-table */
for (;;)
{
mid = (bot + top) / 2;
if ((mob_index + mid)->virtual == virtual)
return(mid);
if (bot >= top)
return(-1);
if ((mob_index + mid)->virtual > virtual)
top = mid - 1;
else
bot = mid + 1;
}
}
/* returns the real number of the object with given virtual number */
int real_object(int virtual)
{
int bot, top, mid;
bot = 0;
top = top_of_objt;
/* perform binary search on obj-table */
for (;;)
{
mid = (bot + top) / 2;
if ((obj_index + mid)->virtual == virtual)
return(mid);
if (bot >= top)
return(-1);
if ((obj_index + mid)->virtual > virtual)
top = mid - 1;
else
bot = mid + 1;
}
}