/***************************************************************************
* Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, *
* Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. *
* *
* Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael *
* Chastain, Michael Quan, and Mitchell Tse. *
* *
* Ground ZERO improvements copyright pending 1994, 1995 by James Hilke *
* *
* In order to use any part of this Merc Diku Mud, you must comply with *
* both the original Diku license in 'license.doc' as well the Merc *
* license in 'license.txt'. In particular, you may not remove either of *
* these copyright notices. *
* *
* Much time and thought has gone into this software and you are *
* benefitting. We hope that you share your changes too. What goes *
* around, comes around. *
***************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include <ctype.h>
#include <time.h>
#if defined(macintosh)
#include <types.h>
#else
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#endif
#include "ground0.h"
#include "db.h"
#include "memory.h"
#if defined(unix)
extern int getrlimit(int resource, struct rlimit *rlp);
extern int setrlimit(int resource, const struct rlimit *rlp);
#endif
#if !defined(macintosh)
extern int _filbuf args( (FILE *) );
#endif
void distribute_mobs ();
void scatter_objects ();
void randomize_level args( (LEVEL_DATA *a_level));
void find_level_commonality args ((LEVEL_DATA *first_level,
LEVEL_DATA *second_level, int *x_size,
int *y_size, int *lev1_lower_x,
int *lev1_lower_y, int *lev2_lower_x,
int *lev2_lower_y));
/*
* Globals.
*/
OBJ_INDEX_DATA * all_objects = NULL;
LEVEL_DATA * the_city;
HELP_DATA * help_first;
HELP_DATA * help_last;
char bug_buf [2*MAX_INPUT_LENGTH];
CHAR_DATA * char_list;
char *help_greeting1, *help_greeting2a, *help_greeting2b;
char log_buf [2*MAX_INPUT_LENGTH];
NOTE_DATA * note_list = NULL;
OBJ_DATA * object_list;
ACCOUNT_DATA *accounts_list;
TIME_INFO_DATA time_info;
int mobile_count = 0;
int newmobs = 0;
int newobjs = 0;
GOD_TYPE *god_table;
CHAR_DATA *enforcer;
CHAR_DATA *pill_box;
CHAR_DATA *guardian;
int expansions = 0;
TOP_DATA top_players_kills[NUM_TOP];
int expand_event = 0;
/*
* Semi-locals.
*/
bool fBootDb;
FILE * fpArea;
char strArea[MAX_INPUT_LENGTH];
struct social_type social_table [MAX_SOCIALS];
int social_count = 0;
/*
* Local booting procedures.
*/
void init_mm args( ( void ) );
void load_area args( ( FILE *fp ) );
void load_helps args( ( FILE *fp ) );
void load_obj_header args( ( FILE *fp ) );
void load_objects args( ( FILE *fp ) );
void load_socials args( ( FILE *fp ) );
void load_notes args( ( void ) );
void load_whole_game args( ( FILE *fp ) );
void load_gods args( ( FILE *fp ) );
void load_site_bans args( ( FILE *fp, int newbie ) );
void load_mobs args( ( FILE *fp ) );
#if defined(unix)
/* RT max open files fix */
void maxfilelimit()
{
struct rlimit r;
getrlimit(RLIMIT_NOFILE, &r);
r.rlim_cur = r.rlim_max;
setrlimit(RLIMIT_NOFILE, &r);
}
#endif
/*
* Big mama top level function.
*/
void boot_db( void )
{
char buf[MAX_STRING_LENGTH];
FILE *start_file;
#if defined(unix)
/* open file fix */
maxfilelimit();
#endif
get_string_space ();
fBootDb = TRUE;
/* get a start file if there is one */
start_file = fopen ("../boot/startfile.txt", "r");
/*
* Set time.
*/
{
long lhour, lday, lmonth;
lhour = (current_time - 650336715)
/ (PULSE_TICK / PULSE_PER_SECOND);
time_info.hour = lhour % 24;
lday = lhour / 24;
time_info.day = lday % 35;
lmonth = lday / 35;
time_info.month = lmonth % 17;
time_info.year = lmonth / 17;
sprintf (buf, "%s%s", BOOT_DIR, "boot.seed");
if ((fpArea = fopen (buf, "r")) == NULL)
{
bug ("failed to open boot.seed", 0);
exit (STATUS_ERROR);
}
else
{
boot_seed = fread_number (fpArea);
fclose (fpArea);
}
sprintf (buf, "boot seed = %d", boot_seed);
log_string (buf);
/* note that we srandom game seed right after this */
srandom (boot_seed);
if (start_file)
{
int count;
fscanf (start_file, "%d", &game_seed);
sprintf (buf, "previous game seed %d\n\r", game_seed);
log_string (buf);
fscanf (start_file, "%d", &max_on);
sprintf (buf, "previous max chars %d\n\r", max_on);
log_string (buf);
fscanf (start_file, "%d", &tick_counter);
sprintf (buf, "previous tick counter %d\n\r", tick_counter);
log_string (buf);
fscanf (start_file, "%d", &expansions);
sprintf (buf, "previous expansions %d\n\r", expansions);
log_string (buf);
}
else
{
game_seed = current_time;
sprintf (buf, "new seed %d\n\r", game_seed);
log_string (buf);
}
srandom (game_seed);
}
log_string ("Reading boot files.");
/*
* Read in all the area files.
*/
{
FILE *fpList;
sprintf (buf, "%s%s", BOOT_DIR, BOOT_LIST);
if ( ( fpList = fopen( buf, "r" ) ) == NULL )
{
perror( buf );
exit (STATUS_ERROR);
}
for ( ; ; )
{
strcpy( strArea, fread_word( fpList ) );
if ( strArea[0] == '$' )
break;
if ( strArea[0] == '-' )
{
fpArea = stdin;
}
else
{
sprintf (buf, "%s%s", BOOT_DIR, strArea);
if ( ( fpArea = fopen( buf, "r" ) ) == NULL )
{
perror( buf );
exit (STATUS_ERROR);
}
}
for ( ; ; )
{
char *word;
if ( fread_letter( fpArea ) != '#' )
{
bug( "Boot_db: # not found.", 0 );
exit (STATUS_ERROR);
}
word = fread_word( fpArea );
if (word[0] == '$')
break;
else
{
int err = 0;
switch (word[0])
{
default:
err = 1;
case 'O':
if (!str_cmp (word, "OBJ_HEADER"))
load_obj_header (fpArea);
else
if (!str_cmp (word, "OBJECTS"))
load_objects (fpArea);
else
err = 1;
break;
case 'A':
if (!str_cmp (word, "AREA"))
load_area (fpArea);
else
if (!str_cmp (word, "ACCOUNTS"))
load_accounts (fpArea);
else
err = 1;
break;
case 'H':
if (!str_cmp (word, "HELPS"))
load_helps (fpArea);
else
err = 1;
break;
case 'S':
if (!str_cmp(word, "SOCIALS"))
load_socials (fpArea);
else
err = 1;
break;
case 'G':
if (!str_cmp(word, "GODS"))
load_gods (fpArea);
else
err = 1;
break;
case 'B':
if (!str_cmp(word, "BANS"))
load_site_bans (fpArea, 0);
else
err = 1;
break;
case 'N':
if (!str_cmp(word, "NBANS"))
load_site_bans (fpArea, 1);
else
err = 1;
break;
case 'M':
if (!str_cmp(word, "MOBS"))
load_mobs (fpArea);
else err = 1;
break;
case 'T':
if (!str_cmp(word, "TOP"))
load_top (fpArea);
else err = 1;
break;
}
if (err)
{
bug( "Boot_db: bad section name.", 0 );
exit (STATUS_ERROR);
}
}
}
if ( fpArea != stdin )
fclose( fpArea );
fpArea = NULL;
}
log_string ("All files read.");
fclose( fpList );
}
srandom (boot_seed);
set_eq_numbers ();
srandom (game_seed);
{
int x = number_range (0, the_city->x_size - 1);
int y = number_range (0, the_city->y_size - 1);
ammo_repop[0] = index_room (the_city->rooms_on_level, x, y);
ammo_repop[2] = index_room (the_city->rooms_on_level,
the_city->x_size - 1 - x,
the_city->y_size - 1 - y);
ammo_repop[1] = index_room (the_city->rooms_on_level,
the_city->x_size / 2, the_city->y_size / 2);
log_string ("ammo repops at: (%d, %d), (%d, %d), (%d, %d)",
x,y,y,x,the_city->x_size / 2, the_city->y_size / 2);
}
if (!start_file)
{
log_string ("Distributing objects . . .");
scatter_objects ();
do_save_all (NULL, "");
}
else
{
log_string ("Loading from saved game . . .");
fpArea = start_file;
load_whole_game (fpArea);
fclose (fpArea);
fpArea = NULL;
system ("mv ../boot/startfile.txt ../boot/fullsave.txt");
}
log_string ("Setting bases . . .");
set_bases ();
log_string ("Distributing mobs . . .");
distribute_mobs ();
/*
* Declare db booting over.
* Load up the notes file.
*/
log_string ("Reading notes . . .");
load_notes( );
fBootDb = FALSE;
}
void load_whole_game (FILE *fp)
{
CHAR_DATA *inject_char;
OBJ_DATA *inject_obj, *obj;
LEVEL_DATA *level_finder;
char a_file_name [MAX_STRING_LENGTH] = "!";
int special, x, y, level, a_vnum, load_counter = 0;
int count;
for (count = 0; count < expansions; count++)
expand_city();
fscanf (fp, "%s", a_file_name);
while (a_file_name[0] == '!')
{
log_string (a_file_name+1);
inject_char = load_char_obj (NULL, &(a_file_name[1]));
if (!inject_char)
{
bug ("Character listed in startfile.txt not found.", 0);
log_string ("%s", &(a_file_name[1]));
system ("touch ../boot/shutdown.txt");
exit (STATUS_BOOT_ERROR);
}
inject_char->ld_timer = LD_TICKS;
inject_char->next = char_list;
char_list = inject_char;
fscanf (fp, "%d%d%d%d%d%d\n", &(inject_char->kills),
&(inject_char->deaths), &x, &y, &level, &(inject_char->hit));
if (level < 0)
if (level == -2)
char_to_room (inject_char, god_general_area);
else
char_to_room (inject_char, safe_area);
else
{
for (level_finder = the_city; level_finder->level_down != the_city;
level_finder = level_finder->level_down)
if (level_finder->level_number == level) break;
if (level_finder->level_number != level)
{
bug ("level not found", 0);
system ("mv ../boot/startfile.txt ..");
exit (STATUS_ERROR);
}
else
if ((x > (level_finder->x_size - 1)) || (x < 0) ||
(y > (level_finder->y_size - 1)) || (y < 0))
{
bug ("Coordinates out of range", 0);
system ("mv ../boot/startfile.txt ..");
exit (STATUS_ERROR);
}
else
char_to_room (inject_char,
index_room (level_finder->rooms_on_level, x, y));
}
if (inject_char->trust != 10)
inject_char->max_hit = HIT_POINTS_MORTAL;
else
inject_char->max_hit = HIT_POINTS_IMMORTAL;
fscanf (fp, "%d\n", &a_vnum);
while (a_vnum)
{
inject_obj = create_object (get_obj_index (a_vnum), 0);
obj_to_char (inject_obj, inject_char);
load_counter++;
fscanf (fp, "%d%d", &(inject_obj->hp_char),
&(inject_obj->hp_struct));
fscanf (fp, "%d", &a_vnum);
}
do_wear (inject_char, "all");
do_load (inject_char, "");
fscanf (fp, "\n", &a_vnum);
fscanf (fp, "%s", a_file_name);
}
fscanf (fp, "%d", &a_vnum);
while (a_vnum)
{
if (feof (fp))
{
sprintf (log_buf, "Incorrect termination of start file. Exiting "
"with status %d.", STATUS_REBOOT);
log_string (log_buf);
system ("rm ../boot/startfile.txt");
exit (STATUS_REBOOT);
}
inject_obj = create_object (get_obj_index (a_vnum), 0);
fscanf (fp, "%d %d %d", &x, &y, &level);
if ((x < 0) && (y < 0) && (level < 0))
scatter_obj (inject_obj);
else
{
for (level_finder = the_city; level_finder->level_down != the_city;
level_finder = level_finder->level_down)
if (level_finder->level_number == level) break;
if (level_finder->level_number != level)
{
bug ("level not found", 0);
system ("mv ../boot/startfile.txt ..");
exit (STATUS_ERROR);
}
else
if ((x > (level_finder->x_size - 1)) || (x < 0) ||
(y > (level_finder->y_size - 1)) || (y < 0))
{
bug ("Coordinates out of range", 0);
system ("mv ../boot/startfile.txt ..");
exit (STATUS_ERROR);
}
else
obj_to_room (inject_obj,
index_room (level_finder->rooms_on_level, x, y));
}
load_counter++;
fscanf (fp, "%d %d %d", &inject_obj->hp_struct, &inject_obj->hp_char,
&special);
switch (special)
{
case 1:
inject_obj->in_room->mine = inject_obj;
inject_obj->destination = inject_obj->in_room;
obj_from_room (inject_obj);
break;
}
fscanf(fp, "\n");
fscanf (fp, "%d", &a_vnum);
}
/* you might want to comment this back in if you are expecting at least X number of objects to be loaded. Then you can look at
the saved file later if that number didn't load and see why it was so low */
/* if (load_counter < 500)
{
system ("cp ../boot/startfile.txt ..");
bug ("0 encounterred and only %d objects loaded. copying startfile "
"to ..", load_counter);
}*/
fscanf (fp, "\n");
log_string ("Old game read in successfully.");
}
void set_bases ()
{
OBJ_DATA *obj;
/* RELEASE: obviously this set all the bases before I modifed the code */
obj = create_object (get_obj_index (VNUM_HQ), 0);
obj->name = str_dup ("An HQ.");
obj->short_descr = str_dup ("a headquarters entrance");
obj->description = str_dup ("The headquarters entrance is here.");
obj->interior->name = str_dup ("The inside of HQ.");
obj_to_room (obj, safe_area);
}
void scatter_objects ()
{
OBJ_INDEX_DATA *obj_ind;
OBJ_DATA *obj;
int count;
int add_obj;
char buf[MAX_INPUT_LENGTH];
for (obj_ind = all_objects; obj_ind->name[0] != '$'; obj_ind = &(obj_ind[1]))
if (obj_ind->number_to_put_in > 0)
{
add_obj = 0;
if (fBootDb)
add_obj = 1;
else
/* we don't want to add vehicles every time we expand the grid */
if (obj_ind->item_type != ITEM_TEAM_VEHICLE)
add_obj = 1;
if (add_obj)
for (count = 0; count < obj_ind->number_to_put_in; count++)
{
obj = create_object(obj_ind, 0);
scatter_obj (obj);
}
}
}
void load_site_bans( FILE *fp, int newbie )
{
char *site, *reason;
char buf[MAX_INPUT_LENGTH];
log_string ("Banning troublesome sites . . .");
site = fread_string (fp);
while (site[0] != '$')
{
reason = fread_string (fp);
if (strlen (reason) + strlen (site) > MAX_INPUT_LENGTH - 3)
{
bug ("Reason too long.", 0);
exit (STATUS_ERROR);
}
sprintf (buf, "%s %s %s", newbie ? "newbie" : "full", site, reason);
do_ban (NULL, buf);
site = fread_string (fp);
}
}
void load_gods( FILE *fp )
{
int num_gods, count = 0;
log_string ("Reading the god list . . .");
num_gods = fread_number(fp);
num_gods++; /* blank record at the end. */
god_table = alloc_perm (num_gods*sizeof (GOD_TYPE));
god_table[count].rl_name = fread_string(fp);
while (god_table[count].rl_name[0] != '$')
{
god_table[count].trust = fread_number(fp);
if (god_table[count].trust >= MAX_TRUST)
{
bug ("No characters of IMP trust are allowed in the god bootfile.",
0);
exit (STATUS_ERROR);
}
god_table[count].game_names = fread_string(fp);
god_table[count].password = fread_string(fp);
god_table[count].room_name = fread_string(fp);
god_table[count].honorary = fread_number (fp);
count++;
if (count == num_gods)
{
bug ("More gods were listed than were declared", 0);
exit (STATUS_ERROR);
}
god_table[count].rl_name = fread_string(fp);
}
god_table[count].rl_name = god_table[count].game_names =
god_table[count].password = god_table[count].room_name = "";
god_table[count].trust = 0;
}
void distribute_mobs()
{
CHAR_DATA *mob;
ROOM_DATA *room;
char stat_buf[MAX_INPUT_LENGTH];
int count;
for (mob = char_list; mob; mob = mob->next)
if (IS_NPC (mob))
do_goto (mob, mob->where_start);
/* RELEASE: code I wrote to destribute guardians - feel free to adapt */
#if 0
for (count = TEAM_RED; count <= MAX_TEAM; count++)
{
if (!*team_table[count].team_on)
continue;
mob = clone_mobile (guardian);
sprintf (stat_buf, "%s guardian", team_table[count].name);
mob->names = str_dup (stat_buf);
sprintf (stat_buf, "The %s GUARDIAN", team_table[count].f_color_name);
mob->short_descript = str_dup (stat_buf);
mob->team = count;
char_from_room (mob);
sprintf (log_buf, "Sending %s to %d, %d.", mob->names,
(the_city->x_size - 1)*team_table[count].x_mult,
(the_city->y_size - 1)*team_table[count].y_mult);
log_string (log_buf);
room = index_room (the_city->rooms_on_level,
(the_city->x_size - 1)*team_table[count].x_mult,
(the_city->y_size - 1)*team_table[count].y_mult);
char_to_room (mob, room);
}
#endif
}
void load_mobs( FILE *fp )
{
CHAR_DATA *inject_mob;
char *buf;
int num_objects, vnum;
int low, high;
srandom (boot_seed);
log_string ("Reading mobs . . .");
buf = NULL;
do
{
buf = fread_string_eol (fp);
} while (buf[0] == ']');
buf = fread_string (fp);
while (buf[0] != '$')
{
inject_mob = alloc_char ();
clear_char(inject_mob);
inject_mob->names = str_dup(buf);
if (!str_cmp (inject_mob->names, "droid"))
pill_box = inject_mob;
if (!str_cmp (inject_mob->names, "tank"))
tank_mob = inject_mob;
if (!str_cmp (inject_mob->names, "enforcer"))
enforcer = inject_mob;
if (!str_cmp (inject_mob->names, "guardian"))
guardian = inject_mob;
inject_mob->short_descript = fread_string (fp);
set_char_defaults(inject_mob);
inject_mob->pcdata = NULL;
fread_word (fp);
{
low = fread_number (fp);
if (fgetc (fp) != '-')
{
bug ("'-' expected.", 0);
exit (STATUS_ERROR);
}
high = fread_number (fp);
inject_mob->hit = inject_mob->max_hit = number_range (low, high);
}
fread_word (fp);
inject_mob->move_delay = fread_number (fp);
fread_word (fp);
inject_mob->ld_behavior = fread_number (fp);
fread_word (fp);
inject_mob->act = fread_number (fp);
fread_word (fp);
inject_mob->sex = fread_number (fp);
fread_word (fp);
inject_mob->where_start = fread_string (fp);
char_to_room (inject_mob, safe_area);
fread_word (fp);
while ((vnum = fread_number (fp)) != 0)
obj_to_char (create_object (get_obj_index (vnum), 0), inject_mob);
do_wear (inject_mob, "all");
do_load (inject_mob, "");
inject_mob->next = char_list;
char_list = inject_mob;
buf = fread_string (fp);
}
log_string ("Mobs have been read.");
srandom (game_seed);
return;
}
void load_obj_header( FILE *fp )
{
char *buf, arg[MAX_STRING_LENGTH];
int num_objects;
log_string ("Reading the object header file");
buf = NULL;
do
{
buf = fread_string_eol (fp);
} while (buf[0] == ']');
buf = one_argument (buf, arg);
one_argument (buf, arg);
num_objects = atoi (arg);
all_objects = alloc_perm (sizeof (OBJ_INDEX_DATA) * num_objects);
/*malloc (sizeof (OBJ_INDEX_DATA) * num_objects);*/
log_string ("Object header has been read.");
return;
}
void load_damage_numbers (FILE *fp, OBJ_INDEX_DATA *current_obj)
{
char *buf;
int count;
buf = fread_word (fp);
if (strcmp (buf, "DAM_CH"))
{
log_string ("got %s instead of DAM_CH.", buf);
bug ("DAM_CH expected.", 0);
exit (STATUS_ERROR);
}
for (count = 0; count < 3; count++)
current_obj->damage_char[count] = fread_number (fp);
fread_to_eol (fp);
buf = fread_word (fp);
for (count = 0; count < 3; count++)
current_obj->damage_structural[count] = fread_number (fp);
}
void load_gen_obj_flags (FILE *fp, OBJ_INDEX_DATA *current_obj)
{
char *buf;
unsigned int flags;
buf = fread_word (fp);
flags = current_obj->general_flags = fread_flag (fp);
if (IS_SET (flags, GEN_BURNS_ROOM))
load_damage_numbers (fp, current_obj);
}
void load_extract_obj_flags (FILE *fp, OBJ_INDEX_DATA *current_obj)
{
char *buf;
unsigned int flags;
int count;
buf = fread_word (fp);
flags = current_obj->extract_flags = fread_flag (fp);
if (flags)
current_obj->explode_desc = fread_string (fp);
if (IS_SET (flags, EXTRACT_EXPLODE_ON_EXTRACT))
load_damage_numbers (fp, current_obj);
if (IS_SET (flags, EXTRACT_BURN_ON_EXTRACT))
{
buf = fread_word (fp);
current_obj->burn_time = fread_number (fp);
}
}
void load_use_obj_flags (FILE *fp, OBJ_INDEX_DATA *current_obj)
{
char *buf;
unsigned int flags;
buf = fread_word (fp);
if (strcmp (buf, "USE"))
{
log_string ("got %s instead of USE.", buf);
bug ("USE expected.", 0);
exit (STATUS_ERROR);
}
flags = current_obj->usage_flags = fread_flag (fp);
if (IS_SET (flags, USE_HEAL))
load_damage_numbers (fp, current_obj);
}
void load_obj_item_type (FILE *fp, OBJ_INDEX_DATA *current_obj)
{
char *buf;
buf = fread_word (fp);
if (strcmp (buf, "ITEM_TYPE"))
{
log_string ("got %s instead of item_type.", buf);
bug ("Item_type expected.", 0);
exit (STATUS_ERROR);
}
current_obj->item_type = fread_number (fp);
buf = fread_word (fp);
if (strcmp (buf, "WEAR"))
{
log_string ("got %s instead of wear.", buf);
bug ("Wear expected.", 0);
exit (STATUS_ERROR);
}
current_obj->wear_flags = fread_number (fp);
switch (current_obj->item_type)
{
case ITEM_WEAPON:
buf = fread_word (fp);
current_obj->rounds_per_second = fread_number (fp);
buf = fread_word (fp);
current_obj->ammo_type = fread_number (fp);
buf = fread_word (fp);
current_obj->range = fread_number (fp);
break;
case ITEM_ARMOR:
buf = fread_word (fp);
current_obj->armor = fread_number (fp);
break;
case ITEM_EXPLOSIVE:
buf = fread_word (fp);
current_obj->range = fread_number (fp);
break;
case ITEM_AMMO:
buf = fread_word (fp);
current_obj->ammo_type = fread_number (fp);
buf = fread_word (fp);
current_obj->ammo = fread_number (fp);
load_damage_numbers (fp, current_obj);
case ITEM_TEAM_VEHICLE:
case ITEM_TEAM_ENTRANCE:
case ITEM_MISC:
break;
default:
log_string ("Illegal item type %d found.", current_obj->item_type);
exit (STATUS_ERROR);
}
}
int get_next_char (FILE *fp)
{
int ch = ' ';
while (isspace (ch))
ch = fgetc (fp);
return ch;
}
int get_count_num (int item_type)
{
switch (item_type)
{
case ITEM_WEAPON:
return COUNT_WEAPONS;
case ITEM_ARMOR:
return COUNT_ARMOR;
case ITEM_EXPLOSIVE:
return COUNT_EXPLOSIVES;
case ITEM_AMMO:
return COUNT_AMMO;
default:
return COUNT_MISC;
}
}
int counts_match (int *counter, int *counter2)
{
int count;
for (count = 0; count < NUM_COUNTS; count++)
if (counter[count] != counter2[count])
return 0;
return 1;
}
void set_eq_numbers ()
{
int current_vnum;
int counters[NUM_COUNTS];
int objectives[NUM_COUNTS];
int count;
OBJ_INDEX_DATA *current_obj;
int top_vnum;
for (count = 0; count < NUM_COUNTS; count++)
{
counters[count] = 0;
objectives[count] = 0;
}
/* first we find our objective counts and set the current to the number
that are guaranteed to be in it. */
for (current_vnum = 1; all_objects[current_vnum - 1].name[0] != '$';
current_vnum++)
{
int count_num;
current_obj = all_objects + current_vnum - 1;
count_num = get_count_num (current_obj->item_type);
if (current_obj->prob_in > 0)
{
objectives[count_num]++;
if (current_obj->prob_in == 100)
counters[count_num]++;
}
}
top_vnum = current_vnum;
/* we want 3/4 of them for everything but ammo/guns */
for (count = 0; count < NUM_COUNTS; count++)
if ((count == COUNT_WEAPONS) || (count == COUNT_AMMO))
objectives[count] = (objectives[count] * 87) / 100;
else
objectives[count] = (objectives[count] * 3) / 4;
/* now make them match */
while (!counts_match (counters, objectives))
{
current_obj = all_objects + number_range (0, top_vnum - 1);
if ((current_obj->prob_in != 100) &&
(number_range (1, 100) < current_obj->prob_in))
{
int count_num = get_count_num (current_obj->item_type);
if (counters[count_num] < objectives[count_num])
{
counters[count_num]++;
current_obj->prob_in = 100;
}
}
}
/* everything that isn't 100% now should not go in */
for (current_vnum = 1; all_objects[current_vnum - 1].name[0] != '$';
current_vnum++)
{
current_obj = all_objects + current_vnum - 1;
if (current_obj->prob_in != 100)
{
current_obj->prob_in = 0;
current_obj->number_to_put_in = 0;
}
}
}
/*
* Snarf some objects
*/
void load_objects( FILE *fp )
{
char *buf;
sh_int count2;
OBJ_INDEX_DATA *current_obj;
int low, high;
int a_char;
static int current_vnum = 1;
srandom (boot_seed);
if (!all_objects)
{
log_string ("Attempt to load objects before header.");
exit (STATUS_ERROR);
}
log_string ("Reading an object file . . .");
a_char = get_next_char (fp);
for (;a_char != '$'; current_vnum++)
{
ungetc (a_char, fp);
current_obj = all_objects + current_vnum - 1;
current_obj->vnum = current_vnum;
load_obj_item_type (fp, current_obj);
load_gen_obj_flags (fp, current_obj);
load_extract_obj_flags (fp, current_obj);
load_use_obj_flags (fp, current_obj);
current_obj->name = fread_string (fp);
current_obj->short_descr = fread_string (fp);
current_obj->description = fread_string (fp);
buf = fread_word (fp);
if ((current_obj->prob_in = fread_number (fp)) > 0)
{
low = fread_number (fp);
if (fgetc (fp) != '-')
{
bug ("'-' expected.", 0);
exit (STATUS_ERROR);
}
high = fread_number (fp);
current_obj->number_to_put_in = number_range (low, high);
}
else
current_obj->number_to_put_in = 0;
buf = fread_word (fp);
current_obj->hp_char = fread_number (fp);
current_obj->hp_struct = fread_number (fp);
a_char = get_next_char (fp);
}
top_obj_index = current_obj->vnum + 1;
current_obj = all_objects + current_vnum - 1;
current_obj->name = str_dup ("$");
srandom (game_seed);
}
void clear_level (ROOM_DATA *rooms_on_level, int x_size, int y_size,
LEVEL_DATA *the_level)
{
static ROOM_DATA room_zero;
int current_x, current_y;
for (current_x = 0; current_x < x_size; current_x++)
for (current_y = 0; current_y < y_size; current_y++)
rooms_on_level[current_x + x_size * current_y] = room_zero;
}
void set_descs_level (ROOM_DATA *rooms_on_level, int x_size, int y_size,
LEVEL_DATA *the_level)
{
ROOM_DATA *temp_room;
int current_x, current_y;
char *the_desc[9] =
{
"room description 1",
"room description 2",
"room description 3",
"room description 4",
"room description 5",
"room description 6",
"room description 7",
"room description 8",
"room description 9",
};
log_string ("Initializing all room_descs");
for (current_x = 0; current_x < x_size; current_x++)
for (current_y = 0; current_y < y_size; current_y++)
{
temp_room = &(rooms_on_level[current_x + x_size * current_y]);
temp_room->level = the_level->level_number;
temp_room->this_level = the_level;
temp_room->people = NULL;
temp_room->interior_of = NULL;
temp_room->contents = NULL;
temp_room->mine = NULL;
temp_room->room_flags = NULL;
if (current_x < x_size / 3)
{
if (current_y < y_size / 3)
temp_room->name = the_desc[0];
else
if (current_y >= (y_size * 2) / 3)
temp_room->name = the_desc[1];
else
temp_room->name = the_desc[2];
}
else
if (current_x >= (x_size * 2) / 3)
{
if (current_y < y_size / 3)
temp_room->name = the_desc[3];
else
if (current_y >= (y_size * 2) / 3)
temp_room->name = the_desc[4];
else
temp_room->name = the_desc[5];
}
else
{
if (current_y < y_size / 3)
temp_room->name = the_desc[6];
else
if (current_y >= (y_size * 2) / 3)
temp_room->name = the_desc[7];
else
temp_room->name = the_desc[8];
}
temp_room->x = current_x;
temp_room->y = current_y;
temp_room->description = the_desc;
temp_room->mine = NULL;
}
}
void set_walls_level (ROOM_DATA *rooms_on_level, int x_size, int y_size)
{
int current_x, current_y;
ROOM_DATA *temp_room;
int room_killer;
for (current_x = 0; current_x < x_size; current_x++)
for (current_y = 0; current_y < y_size; current_y++)
{
temp_room = index_room (rooms_on_level, current_x, current_y);
for (room_killer = 0; room_killer < 6; room_killer++)
{
temp_room->exit[room_killer] = 0;
if ((!current_x && (room_killer == DIR_WEST)) ||
(!current_y && (room_killer == DIR_SOUTH)) ||
((current_x == x_size - 1) && (room_killer == DIR_EAST)) ||
((current_y == y_size - 1) && (room_killer == DIR_NORTH)) ||
(room_killer == DIR_DOWN) || (room_killer == DIR_UP))
{
SET_BIT (temp_room->exit[room_killer], EX_ISWALL);
SET_BIT (temp_room->exit[room_killer], EX_ISNOBREAKWALL);
}
}
}
}
/*
* Snarf the whole city
*/
void load_area( FILE *fp )
{
static ROOM_DATA room_zero;
char *buf, *dirs = "neswud", *tracker;
char number_buf [20];
LEVEL_DATA *current_level;
ROOM_DATA *some_room;
sh_int x_size, y_size, num_levels, count_levels, count_extra_rooms;
sh_int count;
the_city = alloc_perm (sizeof (LEVEL_DATA));
the_city->level_up = the_city;
the_city->level_down = the_city;
log_string ("Loading city.");
do
{
buf = fread_string_eol (fp);
} while (buf[0] == ']');
buf = &(buf[2]);
buf = one_argument (buf, number_buf);
num_levels = atoi (number_buf);
sprintf (log_buf, "There will be %d levels in the city.", num_levels);
log_string (log_buf);
current_level = the_city;
for (count_levels = 0; count_levels < num_levels; count_levels++)
{
log_string ("Reading a level . . .");
if (count_levels)
{
current_level->level_down = alloc_perm (sizeof (LEVEL_DATA));
current_level->level_down->level_up = current_level;
current_level = current_level->level_down;
the_city->level_up = current_level;
}
buf = fread_string_eol (fp);
buf = buf + 3;
buf = one_argument (buf, number_buf);
x_size = atoi (number_buf);
buf = one_argument (buf, number_buf);
y_size = atoi (number_buf);
current_level->num_levels = num_levels;
current_level->level_number = count_levels;
current_level->x_size = x_size;
current_level->y_size = y_size;
current_level->reference_x = number_range (0, x_size - 1);
current_level->reference_y = number_range (0, y_size - 1);
sprintf (buf, "Level %d has reference point (%d, %d).",
current_level->level_number, current_level->reference_x,
current_level->reference_y);
log_string (buf);
current_level->level_down = the_city;
current_level->rooms_on_level =
alloc_mem(x_size*y_size*sizeof (ROOM_DATA));
clear_level (current_level->rooms_on_level, x_size, y_size,
current_level);
set_descs_level (current_level->rooms_on_level, x_size, y_size,
current_level);
set_walls_level (current_level->rooms_on_level, x_size, y_size);
}
/* make a safe area for people to start from and god rooms for the friendly
imms */
log_string ("Making safe room and god rooms . . .");
#define NUM_EXTRA_ROOMS 5
for (count_extra_rooms = 0; count_extra_rooms < NUM_EXTRA_ROOMS;
count_extra_rooms++)
{
some_room = alloc_perm (sizeof (ROOM_DATA));
*some_room = room_zero;
switch (count_extra_rooms)
{
case 0 : some_room->name =
str_dup ("Type 'leave' to leave the safe room and enter the game.");
safe_area = some_room;
break;
case 1 : some_room->name =
str_dup ("Explosives depot. Dropping things here will lag game.");
explosive_area = some_room;
break;
case 2 : some_room->name =
str_dup ("This is a standard imp room. WOW!");
someimp_area = some_room;
break;
case 3 : some_room->name =
str_dup ("This is a general god room. WOW!");
god_general_area = some_room;
break;
case 4 : some_room->name =
str_dup ("This is a mob storage room. Do not destroy any of these "
"mobs.");
store_area = some_room;
break;
}
some_room->description =
some_room->name;
for (count = 0; count < 6; count++)
{
SET_BIT (some_room->exit[count], EX_ISWALL);
SET_BIT (some_room->exit[count], EX_ISNOBREAKWALL);
}
some_room->contents = NULL;
some_room->people = NULL;
some_room->mine = NULL;
some_room->interior_of = NULL;
some_room->this_level = the_city;
some_room->x = some_room->y = some_room->level = -1;
}
log_string ("City has been fully read.");
log_string ("Randomizing all levels.");
for (current_level = the_city; current_level->level_down != the_city;
current_level = current_level->level_down)
{
sprintf (buf, "Randomizing level %d.", current_level->level_number);
log_string(buf);
randomize_level (current_level);
}
sprintf (buf, "Randomizing level %d.", current_level->level_number);
log_string(buf);
randomize_level (current_level);
return;
}
/* returns info on the common area where 2 levels correspond */
void find_level_commonality (LEVEL_DATA *first_level,
LEVEL_DATA *second_level, int *x_size,
int *y_size, int *lev1_lower_x,
int *lev1_lower_y, int *lev2_lower_x,
int *lev2_lower_y)
{
int x_dist_first, x_dist_second, y_dist_first, y_dist_second;
/* use x/y level referrences to determine the amount of area the level
has with its up and down neighbors and then calculate the number of up
and down exits there should be */
if ((*lev1_lower_x = first_level->reference_x -
second_level->reference_x) >= 0)
/* left limit of second level has corresponding square on first level */
*lev2_lower_x = 0;
else
{
*lev1_lower_x = 0;
*lev2_lower_x = second_level->reference_x - first_level->reference_x;
}
if ((*lev1_lower_y = first_level->reference_y -
second_level->reference_y) >= 0)
/* bottom limit of second level has corresponding square on first level */
*lev2_lower_y = 0;
else
{
*lev1_lower_y = 0;
*lev2_lower_y = second_level->reference_y - first_level->reference_y;
}
x_dist_first = (first_level->x_size - 1) - first_level->reference_x;
x_dist_second = (second_level->x_size - 1) - second_level->reference_x;
y_dist_first = (first_level->y_size - 1) - first_level->reference_y;
y_dist_second = (second_level->y_size - 1) - second_level->reference_y;
*x_size = (first_level->reference_x - *lev1_lower_x) +
((x_dist_first > x_dist_second) ? x_dist_second : x_dist_first);
*y_size = (first_level->reference_y - *lev1_lower_y) +
((y_dist_first > y_dist_second) ? y_dist_second : y_dist_first);
}
void mark_connected (ROOM_DATA *a_room)
{
int count;
SET_BIT (a_room->room_flags, ROOM_CONNECTED);
for (count = 0; count < 4; count++)
if (!IS_SET (a_room->exit[count], EX_ISWALL) &&
!IS_SET ((get_to_room (a_room, count))->room_flags, ROOM_CONNECTED))
mark_connected (get_to_room (a_room, count));
}
void connect_level (LEVEL_DATA *a_level)
{
int x, y, topx, topy, dir;
ROOM_DATA *curr_room, *to_room;
const sh_int rev_dir [] =
{
2, 3, 0, 1, 5, 4
};
mark_connected (a_level->rooms_on_level);
topx = a_level->x_size - 2;
topy = a_level->y_size - 2;
for (x = 1; x <= topx; x++)
for (y = 1; y <= topy; y++)
if (!IS_SET ((curr_room = to_room =
index_room (a_level->rooms_on_level, x, y))->room_flags,
ROOM_CONNECTED))
{
do
{
curr_room = to_room;
dir = number_range (0, 3);
to_room = get_to_room (curr_room, dir);
REMOVE_BIT (curr_room->exit[dir], EX_ISWALL);
REMOVE_BIT (curr_room->exit[dir], EX_ISNOBREAKWALL);
REMOVE_BIT (to_room->exit[rev_dir[dir]], EX_ISWALL);
REMOVE_BIT (to_room->exit[rev_dir[dir]], EX_ISNOBREAKWALL);
} while (!IS_SET(to_room->room_flags, ROOM_CONNECTED));
mark_connected (curr_room);
}
/* just to make sure */
log_string ("Disconnected:");
for (x = 1; x <= topx; x++)
for (y = 1; y <= topy; y++)
if (!IS_SET ((index_room (a_level->rooms_on_level, x, y))->room_flags,
ROOM_CONNECTED))
{
sprintf (log_buf, "%d, %d", x, y);
log_string (log_buf);
}
}
void randomize_level (LEVEL_DATA *a_level)
{
const sh_int rev_dir [] =
{
2, 3, 0, 1, 5, 4
};
char buf[MAX_STRING_LENGTH];
ROOM_DATA *temp_room;
sh_int count, x, y, topx, topy, the_exit;
sh_int common_area, num_up_exits, num_down_exits;
int x_area, y_area, lev_x_lower, lev_y_lower, down_x_lower, down_y_lower;
int up_x_lower, up_y_lower;
log_string ("Randomizing cardinal direction exits.");
topx = a_level->x_size - 2;
topy = a_level->y_size - 2;
for (count = 0; count < (topx*topy*3) / 4; count++)
{
x = number_range (1, topx);
y = number_range (1, topy);
the_exit = number_range (0, 3);
temp_room = index_room (a_level->rooms_on_level, x, y);
SET_BIT (temp_room->exit[the_exit], EX_ISWALL);
temp_room = get_to_room(temp_room, the_exit);
SET_BIT (temp_room->exit[rev_dir[the_exit]], EX_ISWALL);
}
log_string ("Guaranteeing level connectivity.");
connect_level (a_level);
log_string ("Randomizing verticle exits.");
find_level_commonality (a_level, a_level->level_down, &x_area, &y_area,
&lev_x_lower, &lev_y_lower, &down_x_lower,
&down_y_lower);
if (a_level->level_down == the_city)
num_down_exits = 0;
else
{
/* one exit per 5X5 area on average */
num_down_exits = x_area*y_area / (5*5);
if (num_down_exits < 1)
num_down_exits = 1;
}
if (num_down_exits)
sprintf (buf, "There will be %d down exits on level %d in the range "
"(%d - %d, %d - %d)", num_down_exits, a_level->level_number,
lev_x_lower, lev_x_lower + x_area, lev_y_lower, lev_y_lower +
y_area);
else
sprintf (buf, "no down exits are possible on this level.");
log_string (buf);
for (count = 0; count < num_down_exits; count++)
{
do
{
temp_room = index_room (a_level->rooms_on_level,
x = number_range (lev_x_lower, lev_x_lower +
x_area),
y = number_range (lev_y_lower, lev_y_lower +
y_area));
}
while (!IS_SET (temp_room->exit[DIR_DOWN], EX_ISWALL));
log_string ("down added to %d, %d, %d", temp_room->x,
temp_room->y, temp_room->level);
temp_room->exit[DIR_DOWN] = 0;
}
find_level_commonality (a_level, a_level->level_up, &x_area, &y_area,
&lev_x_lower, &lev_y_lower, &up_x_lower,
&up_y_lower);
if (a_level == the_city)
num_up_exits = 0;
else
{
/* one exit per 5X5 area on average */
num_up_exits = x_area*y_area / (5*5);
if (num_up_exits < 1)
num_up_exits = 1;
}
if (num_up_exits)
sprintf (buf, "There will be %d up exits on level %d in the range "
"(%d - %d, %d - %d)", num_up_exits, a_level->level_number,
lev_x_lower, lev_x_lower + x_area, lev_y_lower, lev_y_lower +
y_area);
else
sprintf (buf, "no up exits are possible on this level.");
log_string (buf);
for (count = 0; count < num_up_exits; count++)
{
do
{
temp_room = index_room (a_level->rooms_on_level,
x = number_range (lev_x_lower, lev_x_lower +
x_area),
y = number_range (lev_y_lower, lev_y_lower +
y_area));
}
while (!IS_SET (temp_room->exit[DIR_UP], EX_ISWALL));
log_string ("up added to %d, %d, %d", temp_room->x,
temp_room->y, temp_room->level);
temp_room->exit[DIR_UP] = 0;
}
}
/*
* Snarf a help section.
*/
void load_helps( FILE *fp )
{
HELP_DATA *pHelp;
log_string ("Loading helps.");
for ( ; ; )
{
pHelp = alloc_perm( sizeof(*pHelp) );
pHelp->level = fread_number( fp );
pHelp->keyword = fread_string( fp );
if ( pHelp->keyword[0] == '$' )
break;
pHelp->text = fread_string( fp );
if ( !str_cmp( pHelp->keyword, "greeting1" ) )
help_greeting1 = pHelp->text;
if ( !str_cmp( pHelp->keyword, "greeting2a" ) )
help_greeting2a = pHelp->text;
if ( !str_cmp( pHelp->keyword, "greeting2b" ) )
help_greeting2b = pHelp->text;
if ( help_first == NULL )
help_first = pHelp;
if ( help_last != NULL )
help_last->next = pHelp;
help_last = pHelp;
pHelp->next = NULL;
top_help++;
}
log_string ("Helps have been read.");
return;
}
/*
* Snarf notes file.
*/
void load_notes( void )
{
FILE *fp;
NOTE_DATA *pnotelast;
if ( ( fp = fopen( NOTE_FILE, "r" ) ) == NULL )
return;
pnotelast = NULL;
for ( ; ; )
{
NOTE_DATA *pnote;
char letter;
do
{
letter = getc( fp );
if ( feof(fp) )
{
fclose( fp );
return;
}
}
while ( isspace(letter) );
ungetc( letter, fp );
pnote = alloc_perm( sizeof(*pnote) );
if ( str_cmp( fread_word( fp ), "sender" ) )
break;
pnote->sender = fread_string( fp );
if ( str_cmp( fread_word( fp ), "date" ) )
break;
pnote->date = fread_string( fp );
if ( str_cmp( fread_word( fp ), "stamp" ) )
break;
pnote->date_stamp = fread_number(fp);
if ( str_cmp( fread_word( fp ), "to" ) )
break;
pnote->to_list = fread_string( fp );
if ( str_cmp( fread_word( fp ), "subject" ) )
break;
pnote->subject = fread_string( fp );
if ( str_cmp( fread_word( fp ), "text" ) )
break;
pnote->text = fread_string( fp );
pnote->next = NULL;
if ( pnote->date_stamp < current_time - (14*24*60*60) /* 2 wks */)
{
free_string( pnote->text );
free_string( pnote->subject );
free_string( pnote->to_list );
free_string( pnote->date );
free_string( pnote->sender );
pnote->next = note_free;
note_free = pnote;
pnote = NULL;
continue;
}
if ( note_list == NULL )
note_list = pnote;
else
pnotelast->next = pnote;
pnotelast = pnote;
}
strcpy( strArea, NOTE_FILE );
fpArea = fp;
bug( "Load_notes: bad key word.", 0 );
exit (STATUS_ERROR);
return;
}
void load_accounts (FILE *fp)
{
char *login;
ACCOUNT_DATA *creator;
log_string ("loading accounts . . .");
while ((login = fread_word (fp))[0] != '$')
{
creator = alloc_mem (sizeof(ACCOUNT_DATA));
creator->login = str_dup(login);
creator->password = str_dup (fread_word(fp));
creator->character = NULL;
creator->next = accounts_list;
accounts_list = creator;
}
log_string ("Done.");
}
void load_top (FILE *fp)
{
int kills;
int count;
log_string ("loading top file . . .");
for (count = 0; count < NUM_TOP; count++)
{
top_players_kills[count].kills = fread_number(fp);
top_players_kills[count].name = fread_string(fp);
}
log_string ("Done.");
}
/*
* Create an instance of an object.
*/
OBJ_DATA *create_object( OBJ_INDEX_DATA *pObjIndex, int level )
{
static OBJ_DATA obj_zero;
static ROOM_DATA room_zero;
OBJ_DATA *obj;
sh_int count;
if ( pObjIndex == NULL )
{
bug( "Create_object: NULL pObjIndex.", 0 );
exit (STATUS_ERROR);
}
if ( obj_free == NULL )
{
obj = alloc_perm( sizeof(*obj) );
}
else
{
obj = obj_free;
obj_free = obj_free->next;
}
*obj = obj_zero;
obj->pIndexData = pObjIndex;
obj->in_room = NULL;
obj->wear_loc = -1;
obj->name = pObjIndex->name;
obj->short_descr = pObjIndex->short_descr;
obj->description = pObjIndex->description;
obj->explode_desc = pObjIndex->explode_desc;
obj->extract_flags = pObjIndex->extract_flags;
obj->general_flags = pObjIndex->general_flags;
obj->usage_flags = pObjIndex->usage_flags;
obj->wear_flags = pObjIndex->wear_flags;
obj->weight = pObjIndex->weight;
obj->item_type = pObjIndex->item_type;
obj->next = object_list;
obj->range = pObjIndex->range;
obj->owner = NULL;
obj->arrival_time = -1;
obj->ammo = pObjIndex->ammo;
obj->ammo_type = pObjIndex->ammo_type;
obj->burn_time = pObjIndex->burn_time;
obj->rounds_per_second = pObjIndex->rounds_per_second;
obj->armor = pObjIndex->armor;
obj->wait_time = pObjIndex->rounds_per_second;
obj->hp_char = pObjIndex->hp_char;
obj->hp_struct = pObjIndex->hp_struct;
obj->extract_me = 0;
obj->destination = NULL;
obj->valid = VALID_VALUE;
if ((obj->item_type == ITEM_TEAM_VEHICLE) ||
(obj->item_type == ITEM_TEAM_ENTRANCE))
{
obj->interior = alloc_mem (sizeof (ROOM_DATA));
/*malloc (sizeof (ROOM_DATA));*/
*(obj->interior) = room_zero;
obj->interior->interior_of = obj;
switch (obj->item_type)
{
case ITEM_TEAM_VEHICLE:
obj->interior->name = str_dup ("The inside of a tank.");
SET_BIT (obj->interior->room_flags, ROOM_TANK);
break;
}
obj->interior->description = obj->interior->name;
for (count = 0; count < 6; count++)
{
SET_BIT (obj->interior->exit[count], EX_ISWALL);
SET_BIT (obj->interior->exit[count], EX_ISNOBREAKWALL);
}
obj->interior->contents = NULL;
obj->interior->people = NULL;
obj->interior->mine = NULL;
obj->interior->this_level = the_city;
obj->interior->x = obj->interior->y = obj->interior->level = -1;
}
else
obj->interior = NULL;
for (count = 0; count < 3; count++)
{
obj->damage_char[count] = pObjIndex->damage_char[count];
obj->damage_structural[count] = pObjIndex->damage_structural[count];
}
object_list = obj;
pObjIndex->count++;
return obj;
}
/* duplicate an object exactly -- except contents */
void clone_object(OBJ_DATA *parent, OBJ_DATA *clone)
{
int i, count;
AFFECT_DATA *paf;
/* EXTRA_DESCR_DATA *ed,*ed_new; */
if (parent == NULL || clone == NULL)
return;
/* start fixing the object */
clone->name = str_dup(parent->name);
clone->short_descr = str_dup(parent->short_descr);
clone->description = str_dup(parent->description);
clone->item_type = parent->item_type;
clone->extract_flags = parent->extract_flags;
clone->general_flags = parent->general_flags;
clone->usage_flags = parent->usage_flags;
clone->wear_flags = parent->wear_flags;
clone->weight = parent->weight;
clone->timer = parent->timer;
clone->owner = parent->owner;
clone->range = parent->range;
for (count = 0; count < 3; count++)
{
clone->damage_char[count] = parent->damage_char[count];
clone->damage_structural[count] = parent->damage_structural[count];
}
}
CHAR_DATA *clone_mobile (CHAR_DATA *ch)
{
CHAR_DATA *clone;
OBJ_DATA *tracker;
OBJ_DATA *obj, *obj2;
clone = alloc_char ();
*clone = *ch;
/* duplicate inventory */
clone->carrying = NULL;
char_to_room (clone, ch->in_room);
for (tracker = ch->carrying; tracker; tracker = tracker->next_content)
{
obj_to_char (obj = create_object (tracker->pIndexData, 0), clone);
obj->extract_me = 1;
if (tracker->contains)
{
obj_to_obj (obj2 = create_object (tracker->contains->pIndexData, 0),
obj);
obj2->extract_me = 1;
}
}
do_wear (clone, "all");
do_load (clone, "");
clone->next = char_list;
char_list = clone;
return clone;
}
/*
* Clear a new character.
*/
void clear_char( CHAR_DATA *ch )
{
static CHAR_DATA ch_zero;
int i;
*ch = ch_zero;
ch->logon = current_time;
ch->lines = PAGELEN;
ch->position = POS_STANDING;
ch->hit = 1;
ch->max_hit = 3000;
return;
}
/*
* Translates mob virtual number to its obj index struct.
* Hash table lookup.
*/
OBJ_INDEX_DATA *get_obj_index( int vnum )
{
OBJ_INDEX_DATA *pObjIndex;
if ((vnum >= top_obj_index) || all_objects[vnum - 1].vnum != vnum )
{
if ( fBootDb )
{
log_string( "Get_obj_index: bad vnum %d.", vnum);
exit (STATUS_ERROR);
}
return NULL;
}
return &(all_objects[vnum-1]);
}
/*
* Read a letter from a file.
*/
char fread_letter( FILE *fp )
{
char c;
do
{
c = getc( fp );
}
while ( isspace(c) );
return c;
}
/*
* Read a number from a file.
*/
int fread_number( FILE *fp )
{
int number;
bool sign;
char c;
do
{
c = getc( fp );
}
while ( isspace(c) );
number = 0;
sign = FALSE;
if ( c == '+' )
{
c = getc( fp );
}
else if ( c == '-' )
{
sign = TRUE;
c = getc( fp );
}
if ( !isdigit(c) )
{
bug( "Fread_number: bad format.", 0 );
exit (STATUS_ERROR);
}
while ( isdigit(c) )
{
number = number * 10 + c - '0';
c = getc( fp );
}
if ( sign )
number = 0 - number;
if ( c == '|' )
number += fread_number( fp );
else if ( c != ' ' )
ungetc( c, fp );
return number;
}
long fread_flag( FILE *fp)
{
int number;
char c;
do
{
c = getc(fp);
}
while ( isspace(c));
number = 0;
if (!isdigit(c))
{
while (('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z'))
{
number |= flag_convert(c);
c = getc(fp);
}
}
while (isdigit(c))
{
number = number * 10 + c - '0';
c = getc(fp);
}
if (c == '|')
number |= fread_flag(fp);
else if ( c != ' ')
ungetc(c,fp);
return number;
}
long flag_convert(char letter )
{
long bitsum = 0;
char i;
if ('A' <= letter && letter <= 'Z')
{
bitsum = 1;
for (i = letter; i > 'A'; i--)
bitsum *= 2;
}
else if ('a' <= letter && letter <= 'z')
{
bitsum = 67108864; /* 2^26 */
for (i = letter; i > 'a'; i --)
bitsum *= 2;
}
return bitsum;
}
char *fread_string( FILE *fp )
{
char temp [32000], *thestring;
int count = 1;
temp[0] = getc(fp);
while (isspace (temp[0]))
temp[0] = getc (fp);
if (temp[0] != '~')
{
while ((count < 32000) && ((temp[count++] = getc(fp)) != '~'))
if (temp[count - 1] == '\n')
{
temp[count++ - 1] = '\r';
temp[count - 1] = '\n';
}
else
if (temp[count - 1] == '\r')
count--;
temp[count - 1] = '\0';
if (count >= 20000) log_string ("REALBUG: Unterminated string found in "
"fread_string.");
thestring = top_string;
top_string = &(top_string[strlen(temp) + 1]);
if (top_string > string_space + MAX_STRING)
{
log_string ("REALBUG: Out of string memory.");
exit (STATUS_ERROR);
}
strcpy (thestring, temp);
return thestring;
}
else
return &str_empty[0];
}
char *fread_string_eol( FILE *fp )
{
char temp [32000], *thestring;
int count = 1;
temp[0] = getc(fp);
while (isspace (temp[0]))
temp[0] = getc (fp);
if (temp[0] != '~')
{
while ((count < 32000) && ((temp[count++] = getc(fp)) != '\n'))
if (temp[count - 1] == '\n')
{
temp[count++ - 1] = '\r';
temp[count - 1] = '\n';
}
else
if (temp[count - 1] == '\r')
count--;
temp[count - 1] = '\0';
if (count >= 32000) log_string ("REALBUG: Unterminated string found in "
"fread_string.");
thestring = top_string;
top_string = &(top_string[strlen(temp) + 1]);
if (top_string > string_space + MAX_STRING)
{
log_string ("REALBUG: Out of string memory.");
exit (STATUS_ERROR);
}
strcpy (thestring, temp);
return thestring;
}
else
return &str_empty[0];
}
/*
* Read to end of line (for comments).
*/
void fread_to_eol( FILE *fp )
{
char c;
do
{
c = getc( fp );
}
while ( c != '\n' && c != '\r' );
do
{
c = getc( fp );
}
while ( c == '\n' || c == '\r' );
ungetc( c, fp );
return;
}
/*
* Read one word (into static buffer).
*/
char *fread_word( FILE *fp )
{
static char word[MAX_INPUT_LENGTH];
char *pword;
char cEnd;
do
{
cEnd = getc( fp );
}
while ( isspace( cEnd ) );
if ( cEnd == '\'' || cEnd == '"' )
{
pword = word;
}
else
{
word[0] = cEnd;
pword = word+1;
cEnd = ' ';
}
for ( ; pword < word + MAX_INPUT_LENGTH; pword++ )
{
*pword = getc( fp );
if ( cEnd == ' ' ? isspace(*pword) : *pword == cEnd )
{
if ( cEnd == ' ' )
ungetc( *pword, fp );
*pword = '\0';
return word;
}
}
bug( "Fread_word: word too long.", 0 );
exit (STATUS_ERROR);
return NULL;
}
/*
* Removes the tildes from a string.
* Used for player-entered strings that go into disk files.
*/
void smash_tilde( char *str )
{
for ( ; *str != '\0'; str++ )
{
if ( *str == '~' )
*str = '-';
}
return;
}
/*
* Compare strings, case insensitive.
* Return TRUE if different
* (compatibility with historical functions).
*/
bool str_cmp( const char *astr, const char *bstr )
{
if ( astr == NULL )
{
bug( "Str_cmp: null astr.", 0 );
return TRUE;
}
if ( bstr == NULL )
{
bug( "Str_cmp: null bstr.", 0 );
return TRUE;
}
for ( ; *astr || *bstr; astr++, bstr++ )
{
if ( LOWER(*astr) != LOWER(*bstr) )
return TRUE;
}
return FALSE;
}
/*
* Compare strings, case insensitive, for prefix matching.
* Return TRUE if astr not a prefix of bstr
* (compatibility with historical functions).
*/
bool str_prefix( const char *astr, const char *bstr )
{
if ( astr == NULL )
{
bug( "Strn_cmp: null astr.", 0 );
return TRUE;
}
if ( bstr == NULL )
{
bug( "Strn_cmp: null bstr.", 0 );
return TRUE;
}
for ( ; *astr; astr++, bstr++ )
{
if ( LOWER(*astr) != LOWER(*bstr) )
return TRUE;
}
return FALSE;
}
/*
* Compare strings, case insensitive, for match anywhere.
* Returns TRUE is astr not part of bstr.
* (compatibility with historical functions).
*/
bool str_infix( const char *astr, const char *bstr )
{
int sstr1;
int sstr2;
int ichar;
char c0;
if ( ( c0 = LOWER(astr[0]) ) == '\0' )
return FALSE;
sstr1 = strlen(astr);
sstr2 = strlen(bstr);
for ( ichar = 0; ichar <= sstr2 - sstr1; ichar++ )
{
if ( c0 == LOWER(bstr[ichar]) && !str_prefix( astr, bstr + ichar ) )
return FALSE;
}
return TRUE;
}
/*
* Compare strings, case insensitive, for suffix matching.
* Return TRUE if astr not a suffix of bstr
* (compatibility with historical functions).
*/
bool str_suffix( const char *astr, const char *bstr )
{
int sstr1;
int sstr2;
sstr1 = strlen(astr);
sstr2 = strlen(bstr);
if ( sstr1 <= sstr2 && !str_cmp( astr, bstr + sstr2 - sstr1 ) )
return FALSE;
else
return TRUE;
}
/*
* Returns an initial-capped string.
*/
char *capitalize( const char *str )
{
static char strcap[MAX_STRING_LENGTH];
int i;
for ( i = 0; str[i] != '\0'; i++ )
strcap[i] = LOWER(str[i]);
strcap[i] = '\0';
strcap[0] = UPPER(strcap[0]);
return strcap;
}
/*
* Append a string to a file.
*/
void append_file( CHAR_DATA *ch, char *file, char *str )
{
FILE *fp;
if ( IS_NPC(ch) || str[0] == '\0' )
return;
fclose( fpReserve );
if ( ( fp = fopen( file, "a" ) ) == NULL )
{
perror( file );
send_to_char( "Could not open the file!\n\r", ch );
}
else
{
fprintf( fp, "%s: %s\n", ch->names, str );
fclose( fp );
}
fpReserve = fopen( NULL_FILE, "r" );
return;
}
/*
* Reports a bug.
*/
void bug( const char *str, int param )
{
char buf[MAX_STRING_LENGTH];
FILE *fp;
if ( fpArea != NULL )
{
int iLine;
int iChar;
if ( fpArea == stdin )
{
iLine = 0;
}
else
{
iChar = ftell( fpArea );
fseek( fpArea, 0, 0 );
for ( iLine = 0; ftell( fpArea ) < iChar; iLine++ )
{
while ( getc( fpArea ) != '\n' )
;
}
fseek( fpArea, iChar, 0 );
}
sprintf( buf, "[*****] FILE: %s LINE: %d", strArea, iLine );
log_string( buf );
if ( ( fp = fopen( "../boot/shutdown.txt", "a" ) ) != NULL )
{
fprintf( fp, "[*****] %s\n", buf );
fclose( fp );
}
}
strcpy( buf, "[*****] BUG: " );
sprintf( buf + strlen(buf), str, param );
log_string( buf );
return;
}
void log_string (char *format, ...)
{
va_list ap;
struct timeval time;
char *dateline;
char buf[MAX_STRING_LENGTH], *buf_p = buf;
gettimeofday (&time, NULL);
dateline = ctime((time_t*)&(time.tv_sec));
dateline[strlen(dateline)-1] = '\0';
sprintf (buf_p, "%d %s: ", iteration, dateline);
buf_p += strlen (buf_p);
va_start (ap, format);
vsprintf (buf_p, format, ap);
buf_p += strlen (buf_p);
buf_p[0] = '\n';
buf_p[1] = '\r';
buf_p[2] = '\0';
va_end (ap);
fprintf (stderr, "%s", buf);
}
int number_range (int from, int to)
{
return random ()%(to-from + 1) + from;
}
void expand_city ()
{
#define EXPAND_AMOUNT 6
ROOM_DATA *old_level1;
int old_size, x, y;
OBJ_DATA *obj;
CHAR_DATA *ch;
ROOM_DATA *old_room;
int count;
expand_event = 1;
log_string ("EXPANDING CITY");
srandom (game_seed);
old_level1 = the_city->rooms_on_level;
old_size = the_city->x_size * the_city->y_size * sizeof (ROOM_DATA);
the_city->x_size += EXPAND_AMOUNT;
the_city->y_size += EXPAND_AMOUNT;
the_city->rooms_on_level =
alloc_mem(the_city->x_size*the_city->y_size*sizeof (ROOM_DATA));
/* room descriptions */
clear_level (the_city->rooms_on_level, the_city->x_size, the_city->y_size,
the_city);
set_descs_level (the_city->rooms_on_level, the_city->x_size,
the_city->y_size, the_city);
/* walls */
set_walls_level (the_city->rooms_on_level, the_city->x_size,
the_city->y_size);
/* we add more downs to make them more plentiful with the bigger grid */
the_city->reference_x += EXPAND_AMOUNT / 2;
the_city->reference_y += EXPAND_AMOUNT / 2;
randomize_level (the_city);
/* down exits */
for (x = 0; x < the_city->x_size-EXPAND_AMOUNT; x++)
for (y = 0; y < the_city->y_size-EXPAND_AMOUNT; y++)
{
/* this is a dirty hack, but it preserves the call to index_room */
/* (index_room relies on old_level1->this_level which points to
the_city) */
the_city->x_size -= EXPAND_AMOUNT;
the_city->y_size -= EXPAND_AMOUNT;
old_room = index_room(old_level1, x, y);
the_city->x_size += EXPAND_AMOUNT;
the_city->y_size += EXPAND_AMOUNT;
if (!old_room->exit[DIR_DOWN])
{
log_string ("copying down exit for %d, %d", x, y);
(index_room(the_city->rooms_on_level, x + EXPAND_AMOUNT / 2,
y + EXPAND_AMOUNT / 2))->exit[DIR_DOWN] = 0;
}
}
/* move objects from old level to new level */
for (obj = object_list; obj; obj = obj->next)
{
if (!obj->in_room)
if (!obj->destination)
{
if (obj->carried_by || obj->in_obj ||
(obj->item_type == ITEM_TEAM_ENTRANCE))
continue;
log_string ("lost object detected.");
*((char*)NULL) = 'b';
}
else
{
x = obj->destination->x + EXPAND_AMOUNT / 2;
y = obj->destination->y + EXPAND_AMOUNT / 2;
if (obj->destination->mine == obj)
{
(index_room (the_city->rooms_on_level, x, y))->mine = obj;
obj->destination->mine = NULL;
}
obj->destination = index_room (the_city->rooms_on_level, x, y);
}
else
{
if (obj->in_room->level)
continue;
if (!obj->in_room->x)
x = 0;
else
x = (obj->in_room->x == the_city->x_size - EXPAND_AMOUNT - 1) ?
the_city->x_size - 1 : obj->in_room->x + EXPAND_AMOUNT / 2;
if (!obj->in_room->y)
y = 0;
else
y = (obj->in_room->y == the_city->y_size - EXPAND_AMOUNT - 1) ?
the_city->y_size - 1 : obj->in_room->y + EXPAND_AMOUNT / 2;
obj_from_room (obj);
obj_to_room (obj, index_room (the_city->rooms_on_level, x, y));
}
}
/* move mobs from old level to new level */
for (ch = char_list; ch; ch = ch->next)
{
if (ch->in_room->level)
continue;
if (!ch->in_room->x)
x = 0;
else
x = (ch->in_room->x == the_city->x_size - EXPAND_AMOUNT - 1) ?
the_city->x_size - 1 : ch->in_room->x + EXPAND_AMOUNT / 2;
if (!ch->in_room->y)
y = 0;
else
y = (ch->in_room->y == the_city->y_size - EXPAND_AMOUNT - 1) ?
the_city->y_size - 1 : ch->in_room->y + EXPAND_AMOUNT / 2;
char_from_room (ch);
char_to_room (ch, index_room (the_city->rooms_on_level, x, y));
}
for (count = 0; count <3; count++)
ammo_repop[count] = index_room (the_city->rooms_on_level,
ammo_repop[count]->x + EXPAND_AMOUNT / 2,
ammo_repop[count]->y + EXPAND_AMOUNT / 2);
free_mem (old_level1, old_size);
log_string ("EXPANSION COMPLETE");
expand_event = 0;
}
/* snarf a socials file */
void load_socials( FILE *fp)
{
char buf[MAX_STRING_LENGTH];
log_string ("Loading socials.");
for ( ; ; )
{
struct social_type social;
char *temp;
/* clear social */
social.char_no_arg = NULL;
social.others_no_arg = NULL;
social.char_found = NULL;
social.others_found = NULL;
social.vict_found = NULL;
social.char_not_found = NULL;
social.char_auto = NULL;
social.others_auto = NULL;
social.name = NULL;
temp = fread_word(fp);
if (!strcmp(temp,"#0"))
break; /* done */
social.name = str_dup(temp);
fread_to_eol(fp);
temp = fread_string_eol(fp);
if (!strcmp(temp,"$"))
social.char_no_arg = NULL;
else if (!strcmp(temp,"#"))
{
social_table[social_count] = social;
social_count++;
continue;
}
else
social.char_no_arg = temp;
temp = fread_string_eol(fp);
if (!strcmp(temp,"$"))
social.others_no_arg = NULL;
else if (!strcmp(temp,"#"))
{
social_table[social_count] = social;
social_count++;
continue;
}
else
social.others_no_arg = temp;
temp = fread_string_eol(fp);
if (!strcmp(temp,"$"))
social.char_found = NULL;
else if (!strcmp(temp,"#"))
{
social_table[social_count] = social;
social_count++;
continue;
}
else
social.char_found = temp;
temp = fread_string_eol(fp);
if (!strcmp(temp,"$"))
social.others_found = NULL;
else if (!strcmp(temp,"#"))
{
social_table[social_count] = social;
social_count++;
continue;
}
else
social.others_found = temp;
temp = fread_string_eol(fp);
if (!strcmp(temp,"$"))
social.vict_found = NULL;
else if (!strcmp(temp,"#"))
{
social_table[social_count] = social;
social_count++;
continue;
}
else
social.vict_found = temp;
temp = fread_string_eol(fp);
if (!strcmp(temp,"$"))
social.char_not_found = NULL;
else if (!strcmp(temp,"#"))
{
social_table[social_count] = social;
social_count++;
continue;
}
else
social.char_not_found = temp;
temp = fread_string_eol(fp);
if (!strcmp(temp,"$"))
social.char_auto = NULL;
else if (!strcmp(temp,"#"))
{
social_table[social_count] = social;
social_count++;
continue;
}
else
social.char_auto = temp;
temp = fread_string_eol(fp);
if (!strcmp(temp,"$"))
social.others_auto = NULL;
else if (!strcmp(temp,"#"))
{
social_table[social_count] = social;
social_count++;
continue;
}
else
social.others_auto = temp;
social_table[social_count] = social;
social_count++;
}
social_table[social_count].name = NULL;
sprintf (buf, "%d socials read in.", social_count);
log_string (buf);
if (social_count >= MAX_SOCIALS)
{
log_string ("Too many socials.");
exit (STATUS_ERROR);
}
return;
}
/*
* This function is here to aid in debugging.
* If the last expression in a function is another function call,
* gcc likes to generate a JMP instead of a CALL.
* This is called "tail chaining."
* It hoses the debugger call stack for that call.
* So I make this the last call in certain critical functions,
* where I really need the call stack to be right for debugging!
*
* If you don't understand this, then LEAVE IT ALONE.
* Don't remove any calls to tail_chain anywhere.
*
* -- Furey
*/
void tail_chain( void )
{
return;
}