/**************************************************************************
* file: SYNTAX_CHECKER.c , Check syntax of all files Part of DIKUMUD *
* Usage: QUICK AND DIRTY!! *
* Copyright (C) 1990, 1991 - see 'license.doc' for complete information. *
***************************************************************************/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include "../structs.h"
#include "../utils.h"
#include "../comm.h"
#include "../handler.h"
#include "../limits.h"
/* structure for the reset commands */
struct reset_com {
char command; /* current command */
bool if_flag; /* if TRUE: exe only if preceding exe'd */
int arg1; /* */
int arg2; /* Arguments to the command */
int arg3; /* */
/*
* Commands: *
* 'M': Read a mobile *
* 'O': Read an object *
* 'G': Give obj to mob *
* 'P': Put obj in obj *
* 'G': Obj to char *
* 'E': Obj to char equip *
* 'D': Set state of door *
*/
};
/* zone definition structure. for the 'zone-table' */
struct zone_data {
char *name; /* name of this zone */
int lifespan; /* how long between resets (minutes) */
int age; /* current age of this zone (minutes) */
int top; /* upper limit for rooms in this zone */
int reset_mode; /* conditions for reset (see below) */
int number; /* virtual number of this zone */
struct reset_com *cmd; /* command table for reset */
/*
* Reset mode: *
* 0: Don't reset, and don't update age. *
* 1: Reset if no PC's are located in zone. *
* 2: Just reset. *
*/
};
/* element in monster and object index-tables */
struct index_data {
int virtual; /* virtual number of this mob/obj */
int number; /* number of existing units of this mob/obj */
long pos; /* pos in file */
int (*func)(); /* special procedure for this mob/obj */
};
/* for queueing zones for update */
struct reset_q_element {
int zone_to_reset; /* ref to zone_data */
struct reset_q_element *next;
};
/* structure for the update queue */
struct reset_q_type {
struct reset_q_element *head;
struct reset_q_element *tail;
} reset_q;
struct player_index_element {
char *name;
int nr;
};
struct help_index_element {
char *keyword;
long pos;
};
char *fread_string(FILE *fl);
/**************************************************************************
* declarations of most of the 'global' variables *
************************************************************************ */
struct room_data *world; /* dyn alloc'ed array of rooms */
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 zone_data *zone_table; /* table of reset data */
int top_of_zone_table = 0;
struct message_list fight_messages[MAX_MESSAGES]; /* fighting messages */
struct player_index_element *player_table = 0; /* index to player file */
int top_of_p_table = 0; /* ref to top of table */
int top_of_p_file = 0;
FILE *mob_f, /* file containing mob prototypes */
*obj_f, /* obj prototypes */
*wld_f, /* World file */
*zon_f;
struct index_data *mob_index; /* index table for mobile file */
struct index_data *obj_index; /* index table for object file */
struct index_data *wld_index;
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_wldt = 0;
extern struct time_data time_info; /* the infomation about the time */
/* local procedures */
void boot_zones(void);
void setup_dir(FILE *fl, int room, int dir);
void allocate_room(int new_top);
void boot_world(void);
struct index_data *generate_indices(FILE *fl, int *top);
void build_player_index(void);
void char_to_store(struct char_data *ch, struct char_file_u *st);
void store_to_char(struct char_file_u *st, struct char_data *ch);
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);
/*************************************************************************
* routines for booting the system *
*********************************************************************** */
void assume(int faktisk, int antal, int place, char *errmsg)
{
if (antal != faktisk) {
printf("Error has occured at #%d.\n\r", place);
printf("Message is: %s\n\r", errmsg);
printf("Actual number read is %d\n\r", faktisk);
exit();
}
}
/* generate index table for object, monster or world file*/
struct index_data *generate_indices(FILE *fl, int *top)
{
int i = 0, antal;
struct index_data *index;
long pos;
char buf[82];
rewind(fl);
for (; ; ) {
if (fgets(buf, 81, fl)) {
if (*buf == '#') {
/* allocate new cell */
if (!i) /* first cell */
CREATE(index, struct index_data, 1);
else if (!(index =
(struct index_data *) realloc(index,
(i + 1) * sizeof(struct index_data )))) {
printf("load indices");
exit();
}
antal = sscanf(buf, "#%d", &index[i].virtual);
assume(antal, 1, index[i].virtual, "Next string with E/A/$");
index[i].pos = ftell(fl);
index[i].number = index[i].virtual;
index[i].func = 0;
i++;
} else if (*buf == '$') /* EOF */
break;
} else {
printf("Error when generating index, based upon #xxxx numbers.\n\r");
printf(" Probably error at end of file.\n\r");
exit();
}
}
index[i-1].number = -1;
*top = i - 1;
return(index);
}
int exist_index(struct index_data *index_list, int top, int num)
{
int i, found;
found = FALSE;
for (i = 0; (i <= top) && !(found); i++)
if (index_list[i].number == num)
found = TRUE;
if (!found) {
printf("Reference to non-existent number #%d\n\r", num);
}
return (found);
}
/* check the rooms */
void check_world(FILE *fl)
{
int room_nr = 0, zone = 0, dir_nr, virtual_nr, flag, tmp, old_virtual;
char *temp, chk[50];
struct extra_descr_data *new_descr;
int antal;
char *temp2;
world = 0;
character_list = 0;
object_list = 0;
rewind(fl);
old_virtual = -1;
do {
antal = fscanf(fl, " #%d\n", &virtual_nr);
assume(antal, 1, virtual_nr, "Reading #xxx");
if (old_virtual > virtual_nr)
assume(0, 1, virtual_nr, "Error - #'s not in order.");
old_virtual = virtual_nr;
temp = fread_string(fl);
if (flag = (*temp != '$')) /* a new record to be read */ {
temp2 = fread_string(fl);
antal = fscanf(fl, " %d ", &tmp);
assume(antal, 1, virtual_nr, "In room basic 3 numbers");
antal = fscanf(fl, " %d ", &tmp);
assume(antal, 1, virtual_nr, "In room basic 3 numbers");
antal = fscanf(fl, " %d ", &tmp);
assume(antal, 1, virtual_nr, "In room basic 3 numbers");
for (; ; ) {
antal = fscanf(fl, " %s \n", chk);
assume(antal, 1, virtual_nr, "Reading D/E/S string");
if (*chk == 'D') /* direction field */
setup_dir(fl, virtual_nr, atoi(chk + 1));
else if (*chk == 'E') /* extra description field */ {
temp2 = fread_string(fl); /* Description */
temp2 = fread_string(fl); /* Keywords */
} else if (*chk == 'S') /* end of current room */
break;
else
assume(FALSE, 0, virtual_nr, "MISSING D/E or S");
}
}
} while (flag);
}
/* read direction data */
void setup_dir(FILE *fl, int room, int dir)
{
int tmp, antal;
char *temp;
temp = fread_string(fl);
temp = fread_string(fl);
antal = fscanf(fl, " %d ", &tmp);
assume(antal, 1, room, "One of three Direction data");
antal = fscanf(fl, " %d ", &tmp);
assume(antal, 1, room, "One of three Direction data");
antal = fscanf(fl, " %d ", &tmp);
assume(antal, 1, room, "One of three Direction data");
exist_index(wld_index, top_of_wldt, tmp);
}
#define NEW_ZONE_SYSTEM xxx
/* load the zone table and command tables */
void check_zones(FILE *fl)
{
int line_no;
int antal, tmp1, tmp2, tmp3, tmp4;
int zon = 0, cmd_no = 0, ch, expand;
char *check, buf[81];
char cmd_type;
rewind(fl);
line_no = 1;
for (; ; ) {
antal = fscanf(fl, " #%*d\n");
assume(antal, 0, line_no++, "Zone number not found");
check = fread_string(fl);
line_no++;
if (*check == '$')
break; /* end of file */
/* alloc a new zone */
#ifdef NEW_ZONE_SYSTEM
antal = fscanf(fl, " %d ", &zon);
assume(antal, 1, line_no, "Zone Room < number not found");
#endif
antal = fscanf(fl, " %d ", &zon);
assume(antal, 1, line_no, "Life Span");
antal = fscanf(fl, " %d ", &zon);
assume(antal, 1, line_no++, "Reset Mode");
/* read the command table */
cmd_no = 0;
for (expand = 1; ; ) {
fscanf(fl, " "); /* skip blanks */
antal = fscanf(fl, "%c", &cmd_type);
assume(antal, 1, line_no, "Command type M/*/O/G/E/S missing");
if (cmd_type == 'S')
break;
if (cmd_type == '*') {
expand = 0;
fgets(buf, 80, fl); /* skip command */
line_no++;
continue;
}
antal = fscanf(fl, " %d %d %d", &tmp1, &tmp2, &tmp3);
assume(antal, 3, line_no, "Three values after command missing");
if (cmd_type == 'M' || cmd_type == 'O' ||
cmd_type == 'D' || cmd_type == 'P') {
antal = fscanf(fl, " %d", &tmp4);
assume(antal, 1, line_no, "Fourth value after command missing");
}
switch (cmd_type) {
case 'M' :
exist_index(mob_index, top_of_mobt, tmp2);
exist_index(wld_index, top_of_wldt, tmp4);
break;
case 'O' :
exist_index(obj_index, top_of_objt, tmp2);
exist_index(wld_index, top_of_wldt, tmp4);
break;
case 'G' :
exist_index(obj_index, top_of_objt, tmp2);
break;
case 'E' :
exist_index(obj_index, top_of_objt, tmp2);
break;
case 'P' :
exist_index(obj_index, top_of_objt, tmp2);
exist_index(obj_index, top_of_objt, tmp4);
break;
case 'D' :
exist_index(wld_index, top_of_wldt, tmp2);
break;
case 'R' :
exist_index(wld_index, top_of_wldt, tmp2);
exist_index(obj_index, top_of_objt, tmp3);
break;
case '*' :
break;
deafult :
printf("Illegal command type");
exit();
break;
}
fgets(buf, 80, fl); /* read comment */
line_no++;
}
}
}
/*************************************************************************
* procedures for resetting, both play-time and boot-time *
*********************************************************************** */
/* read a mobile from MOB_FILE */
void check_mobile(FILE *fl)
{
int virtual_nr, old_virtual, antal, flag;
char *temp;
char bogst;
int i, skill_nr;
long tmp, tmp2, tmp3;
struct char_data *mob;
char chk[10];
old_virtual = -1;
rewind(fl);
do {
antal = fscanf(fl, " #%d\n", &virtual_nr);
assume(antal, 1, virtual_nr, "Reading #xxx");
if (old_virtual > virtual_nr)
assume(0, 1, virtual_nr, "Error - #'s not in order.");
old_virtual = virtual_nr;
temp = fread_string(fl); /* Namelist */
if (flag = (*temp != '$')) { /* a new record to be read */
/***** String data *** */
/* Name already read mob->player.name = fread_string(fl); */
temp = fread_string(fl); /* short description */
temp = fread_string(fl); /*long_description */
temp = fread_string(fl); /* player.description */
/* *** Numeric data *** */
antal = fscanf(fl, "%d ", &tmp);
assume(antal, 1, virtual_nr, "ACT error");
antal = fscanf(fl, " %d ", &tmp);
assume(antal, 1, virtual_nr, "affected_by error");
antal = fscanf(fl, " %d ", &tmp);
assume(antal, 1, virtual_nr, "Monster Alignment Error");
antal = fscanf(fl, " %c \n", &bogst);
assume(antal, 1, virtual_nr, "Simple/Detailed error");
if (bogst != 'S')
printf("%c %d\n", bogst, bogst);
if (bogst == 'S') {
/* The new easy monsters */
antal = fscanf(fl, " %D ", &tmp);
assume(antal, 1, virtual_nr, "Level error");
antal = fscanf(fl, " %D ", &tmp);
assume(antal, 1, virtual_nr, "THAC0 error");
antal = fscanf(fl, " %D ", &tmp);
assume(antal, 1, virtual_nr, "AC error");
antal = fscanf(fl, " %Dd%D+%D ", &tmp, &tmp2, &tmp3);
assume(antal, 3, virtual_nr, "Hitpoints");
antal = fscanf(fl, " %Dd%D+%D \n", &tmp, &tmp2, &tmp3);
assume(antal, 3, virtual_nr, "Damage error");
antal = fscanf(fl, " %D ", &tmp);
assume(antal, 1, virtual_nr, "GOLD error");
antal = fscanf(fl, " %D \n", &tmp);
assume(antal, 1, virtual_nr, "XP error");
antal = fscanf(fl, " %D ", &tmp);
assume(antal, 1, virtual_nr, "POSITION error");
antal = fscanf(fl, " %D ", &tmp);
assume(antal, 1, virtual_nr, "DEFAULT POS error");
antal = fscanf(fl, " %D \n", &tmp);
assume(antal, 1, virtual_nr, "SEXY error");
} else { /* The old monsters are down below here */
printf("Detailed monsters can't be syntax-checked (yet).\n\r");
assume(0, 1, virtual_nr, "DETAIL ERROR");
exit();
/* ***************************
fscanf(fl, " %D ", &tmp);
mob->abilities.str = tmp;
fscanf(fl, " %D ", &tmp);
mob->abilities.intel = tmp;
fscanf(fl, " %D ", &tmp);
mob->abilities.wis = tmp;
fscanf(fl, " %D ", &tmp);
mob->abilities.dex = tmp;
fscanf(fl, " %D \n", &tmp);
mob->abilities.con = tmp;
fscanf(fl, " %D ", &tmp);
fscanf(fl, " %D ", &tmp2);
mob->points.max_hit = 0;
mob->points.hit = mob->points.max_hit;
fscanf(fl, " %D ", &tmp);
mob->points.armor = tmp;
fscanf(fl, " %D ", &tmp);
mob->points.mana = tmp;
mob->points.max_mana = tmp;
fscanf(fl, " %D ", &tmp);
mob->points.move = tmp;
mob->points.max_move = tmp;
fscanf(fl, " %D ", &tmp);
mob->points.gold = tmp;
fscanf(fl, " %D \n", &tmp);
GET_EXP(mob) = tmp;
fscanf(fl, " %D ", &tmp);
mob->specials.position = tmp;
fscanf(fl, " %D ", &tmp);
mob->specials.default_pos = tmp;
fscanf(fl, " %D ", &tmp);
mob->player.sex = tmp;
fscanf(fl, " %D ", &tmp);
mob->player.class = tmp;
fscanf(fl, " %D ", &tmp);
GET_LEVEL(mob) = tmp;
fscanf(fl, " %D ", &tmp);
mob->player.birth.hours = time_info.hours;
mob->player.birth.day = time_info.day;
mob->player.birth.month = time_info.month;
mob->player.birth.year = time_info.year - tmp;
fscanf(fl, " %D ", &tmp);
mob->player.weight = tmp;
fscanf(fl, " %D \n", &tmp);
mob->player.height = tmp;
for (i = 0; i < 3; i++)
{
fscanf(fl, " %D ", &tmp);
GET_COND(mob, i) = tmp;
}
fscanf(fl, " \n ");
for (i = 0; i < 5; i++)
{
fscanf(fl, " %D ", &tmp);
mob->specials.apply_saving_throw[i] = tmp;
}
fscanf(fl, " \n ");
mob->points.damroll = 0;
mob->specials.damnodice = 1;
mob->specials.damsizedice = 6;
mob->points.hitroll = 0;
************************************* */
}
}
} while (flag);
}
/* read an object from OBJ_FILE */
void check_objects(FILE *fl)
{
int virtual_nr, old_virtual, antal, flag;
char *temp;
struct obj_data *obj;
int tmp, i;
char chk[256];
struct extra_descr_data *new_descr;
old_virtual = -1;
rewind(fl);
antal = fscanf(fl, " %s \n", chk);
assume(antal, 1, virtual_nr, "First #xxx number");
do {
antal = sscanf(chk, " #%d\n", &virtual_nr);
assume(antal, 1, virtual_nr, "Reading #xxx");
if (old_virtual > virtual_nr)
assume(0, 1, virtual_nr, "Error - #'s not in order.");
old_virtual = virtual_nr;
temp = fread_string(fl); /* Namelist */
if (flag = (*temp != '$')) { /* a new record to be read */
/* *** string data *** */
/* temp = fread_string(fl); name has been read above */
temp = fread_string(fl); /* short */
temp = fread_string(fl); /* descr */
temp = fread_string(fl); /* action */
/* *** numeric data *** */
antal = fscanf(fl, " %d ", &tmp);
assume(antal, 1, virtual_nr, "Error reading type flag");
antal = fscanf(fl, " %d ", &tmp);
assume(antal, 1, virtual_nr, "Extra Flag");
antal = fscanf(fl, " %d ", &tmp);
assume(antal, 1, virtual_nr, "wear_flags");
antal = fscanf(fl, " %d ", &tmp);
assume(antal, 1, virtual_nr, "value[0]");
antal = fscanf(fl, " %d ", &tmp);
assume(antal, 1, virtual_nr, "value[1]");
antal = fscanf(fl, " %d ", &tmp);
assume(antal, 1, virtual_nr, "value[2]");
antal = fscanf(fl, " %d ", &tmp);
assume(antal, 1, virtual_nr, "value[3]");
antal = fscanf(fl, " %d ", &tmp);
assume(antal, 1, virtual_nr, "Weight");
antal = fscanf(fl, " %d \n", &tmp);
assume(antal, 1, virtual_nr, "Cost");
antal = fscanf(fl, " %d \n", &tmp);
assume(antal, 1, virtual_nr, "Cost Per Day");
/* *** extra descriptions *** */
while (fscanf(fl, " %s \n", chk), *chk == 'E') {
temp = fread_string(fl);
temp = fread_string(fl);
}
for ( i = 0 ; (i < MAX_OBJ_AFFECT) && (*chk == 'A') ; i++) {
antal = fscanf(fl, " %d ", &tmp);
assume(antal, 1, virtual_nr, "affected location");
antal = fscanf(fl, " %d \n", &tmp);
assume(antal, 1, virtual_nr, "Modifier");
antal = fscanf(fl, " %s \n", chk);
assume(antal, 1, virtual_nr, "Next string with E/A/$");
}
}
} while (flag);
}
/************************************************************************
* 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)
{
static char buf[MAX_STRING_LENGTH], tmp[100];
char *rslt;
register char *point;
int flag;
bzero(buf, MAX_STRING_LENGTH);
do
{
if (!fgets(tmp, MAX_STRING_LENGTH, fl)) {
printf("fread_str");
exit();
}
if (strlen(tmp) + strlen(buf) > MAX_STRING_LENGTH) {
printf("fread_string: string too large (db.c, fread_string)");
exit();
} else
strcat(buf, tmp);
for (point = buf + strlen(buf) - 2; point >= buf && isspace(*point);
point--)
;
if (flag = (*point == '~'))
if (*(buf + strlen(buf) - 3) == '\n') {
*(buf + strlen(buf) - 2) = '\r';
*(buf + strlen(buf) - 1) = '\0';
}
else
*(buf + strlen(buf) - 2) = '\0';
else
{
*(buf + strlen(buf) + 1) = '\0';
*(buf + strlen(buf)) = '\r';
}
} while (!flag);
return(buf);
}
int main(int argc, char *argv[])
{
char name[256];
if (argc != 2) {
printf("Usage: (from /lib/world dir) %s world-number\n\r", argv[0]);
exit(0);
}
sprintf(name, "wld/%s.wld", argv[1]);
if (!(wld_f = fopen(name, "r"))) {
printf("Could not open world file.\n\r");
exit();
}
sprintf(name, "mob/%s.mob", argv[1]);
if (!(mob_f = fopen(name, "r"))) {
printf("Could not open mobile file.\n\r");
exit();
}
sprintf(name, "obj/%s.obj", argv[1]);
if (!(obj_f = fopen(name, "r"))) {
printf("Could not open object file.\n\r");
exit();
}
sprintf(name, "zon/%s.zon", argv[1]);
if (!(zon_f = fopen(name, "r"))) {
printf("Could not open zone file.\n\r");
exit();
}
printf("Generating world file indexes.\n\r");
wld_index = generate_indices(wld_f, &top_of_wldt);
printf("Generating mobile file indexes.\n\r");
mob_index = generate_indices(mob_f, &top_of_mobt);
printf("Generating object file indexes.\n\r");
obj_index = generate_indices(obj_f, &top_of_objt);
printf("Checking World File.\n\r");
check_world(wld_f);
printf("Checking Mobile File (only simple mobiles).\n\r");
check_mobile(mob_f);
printf("Checking Object File.\n\r");
check_objects(obj_f);
printf("Checking Zone File.\n\r");
check_zones(zon_f);
printf("\n\r\nCheck successfully completed without any obvious errors.\n\r");
fclose(zon_f);
fclose(wld_f);
fclose(mob_f);
fclose(obj_f);
}