FlCodebase3.1/
FlCodebase3.1/bounty/
FlCodebase3.1/challenge/
FlCodebase3.1/clans/
FlCodebase3.1/gods/
FlCodebase3.1/mobprogs/
FlCodebase3.1/player/
FlCodebase3.1/savemud/
/***************************************************************************
 *  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.                              *
 *                                                                         *
 *  In order to use any part of this Envy Diku Mud, you must comply with   *
 *  the original Diku license in 'license.doc', the Merc license in        *
 *  'license.txt', as well as the Envy license in 'license.nvy'.           *
 *  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.                                                  * 
 *                                                                         *
 *      ROM 2.4 is copyright 1993-1998 Russ Taylor                         *
 *      ROM has been brought to you by the ROM consortium                  *
 *          Russ Taylor (rtaylor@hypercube.org)                            *
 *          Gabrielle Taylor (gtaylor@hypercube.org)                       *
 *          Brian Moore (zump@rom.org)                                     *
 *      By using this code, you have agreed to follow the terms of the     *
 *      ROM license, in the file Rom24/doc/rom.license                     *
 *                                                                         *
 * Code Adapted and Improved by Abandoned Realms Mud                       *
 * and Aabahran: The Forsaken Lands Mud by Virigoth                        *
 *                                                                         *
 * Continued Production of this code is available at www.flcodebase.com    *
 ***************************************************************************/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <ctype.h>
#include <time.h>
#include <assert.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include "merc.h"
#include "cabal.h"
#include "db.h"
#include "recycle.h"
#include "interp.h"
#include "save_mud.h"
#include "olc.h"
#include "bounty.h"
#include "armies.h"
#include "tome.h"
#include "clan.h"




#if !defined(OLD_RAND)
// asdfg long random();
int getpid();
time_t time(time_t *tloc);
#endif

/* externals for counting purposes */
extern	OBJ_DATA	*obj_free;
extern	CHAR_DATA	*char_free;
extern  DESCRIPTOR_DATA *descriptor_free;
extern	PC_DATA		*pcdata_free;
extern  AFFECT_DATA	*affect_free;
extern  AFFECT_DATA	*skill_free;
extern  EFFECT_DATA	*effect_free;

/* Globals. */
HELP_DATA *		help_first;
HELP_DATA *		help_last;
SHOP_DATA *		shop_first;
SHOP_DATA *		shop_last;
NOTE_DATA *		note_free;
char			bug_buf		[2*MIL];
CHAR_DATA *		char_list;
TRAP_DATA *		trap_list;
TRAP_INDEX_DATA *	trap_index_list;
CHAR_DATA *		player_list;
char *			help_greeting;
char			log_buf		[2*MIL];
KILL_DATA		kill_table	[MAX_LEVEL];
NOTE_DATA *		note_list;
OBJ_DATA *		object_list;
int                     reboot_tick_counter = -1;
char			reboot_buffer [MIL];

int                     restart = 0;

int			free_vir_vnums[MAX_FREE_VNUM];
int			last_vir_vnum = 0;

PROG_CODE *		mprog_list;
PROG_CODE *             oprog_list;
PROG_CODE *             rprog_list;


int			grn_illithid;
int			grn_half_elf;
int			grn_faerie;
int			grn_feral;
int			grn_undead;
int			grn_demon;
int			grn_fire;
int			grn_stone;
int			grn_werebeast;
int			grn_vampire;
int			grn_ogre;
int			grn_minotaur;

int			gcn_monk;
int			gcn_psi;
int			gcn_vampire;
int			gcn_ranger;
int			gcn_dk;
int			gcn_crusader;
int			gcn_ninja;
int			gcn_necro;
int			gcn_bard;
int			gcn_adventurer;
int			gcn_blademaster;
int			gcn_warrior;
int			gcn_shaman;
int			gcn_healer;
int			gcn_cleric;
int			gcn_druid;
int			gcn_paladin;



sh_int			gsn_backstab;
sh_int			gsn_battlesphere;
sh_int			gsn_battlefocus;
sh_int			gsn_battletrance;
sh_int			gsn_bladestorm;
sh_int			gsn_behead;
sh_int			gsn_baptize;
sh_int			gsn_blanket;
sh_int			gsn_bladework;
sh_int			gsn_battlestance;
sh_int			gsn_avatar_of_steel;
sh_int			gsn_age;
sh_int			gsn_batter;
sh_int			gsn_bolo;
sh_int			gsn_bribe;
sh_int			gsn_breach;
sh_int			gsn_2hands;
sh_int			gsn_2h_handling;
sh_int			gsn_2h_tactics;
sh_int			gsn_2h_mastery;
sh_int			gsn_dodge;
sh_int			gsn_dysentery;
sh_int			gsn_doomsinger;
sh_int			gsn_dheal;
sh_int			gsn_soul_tap;
sh_int			gsn_sretrib;
sh_int			gsn_subvocal;
sh_int			gsn_dwrath;
sh_int			gsn_sbane;
sh_int			gsn_pwater;
sh_int			gsn_probe;
sh_int			gsn_predict;
sh_int			gsn_icefire;
sh_int			gsn_icalm;
sh_int			gsn_identify;
sh_int			gsn_smight;
sh_int			gsn_dmight;
sh_int			gsn_envenom;
sh_int			gsn_enfeeblement;
sh_int			gsn_energy_drain;
sh_int			gsn_hide;
sh_int			gsn_high_sight;
sh_int                  gsn_haymaker;
sh_int                  gsn_harm;
sh_int			gsn_peek;
sh_int			gsn_protective_shield;
sh_int                  gsn_push;
sh_int                  gsn_puppet_master;
sh_int                  gsn_purity;
sh_int                  gsn_const;
sh_int                  gsn_cyclone;
sh_int                  gsn_cont;
sh_int                  gsn_epal;
sh_int			gsn_pick_lock;
sh_int			gsn_sneak;
sh_int			gsn_steal;
sh_int			gsn_steel_wall;
sh_int                  gsn_study;
sh_int			gsn_pry;
sh_int			gsn_plant;
sh_int			gsn_planar_seal;
sh_int			gsn_preserve;
sh_int			gsn_disarm;
sh_int			gsn_dispel_magic;
sh_int                  gsn_disguise;
sh_int			gsn_weapon_cleave;
sh_int			gsn_webbing;
sh_int			gsn_wlock;
sh_int			gsn_weaponcraft;
sh_int			gsn_weaken;
sh_int			gsn_shield_cleave;
sh_int			gsn_sheath;
sh_int			gsn_enhanced_damage;
sh_int			gsn_kick;
sh_int			gsn_parry;
sh_int			gsn_path_anger;
sh_int			gsn_path_fury;
sh_int			gsn_path_dev;
sh_int			gsn_fpart;
sh_int			gsn_fury;
sh_int			gsn_first_parry;
sh_int			gsn_second_parry;
sh_int			gsn_serpent;
sh_int			gsn_secret_arts;
sh_int			gsn_rapid_fire;
sh_int			gsn_rescue;
sh_int			gsn_rev_time;
sh_int			gsn_resurrection;
sh_int			gsn_second_attack;
sh_int			gsn_third_attack;
sh_int			gsn_tracker;
sh_int			gsn_transform;
sh_int			gsn_torment_bind;
sh_int			gsn_turn_undead;
sh_int			gsn_blindness;
sh_int			gsn_bloodhaze;
sh_int			gsn_bloodvow;
sh_int			gsn_chant;
sh_int			gsn_charm_person;
sh_int			gsn_curse;
sh_int			gsn_curse_weapon;
sh_int			gsn_invis;
sh_int			gsn_invigorate;
sh_int			gsn_mark_prey;
sh_int			gsn_marksman;
sh_int			gsn_maelstrom;
sh_int			gsn_mark_fear;
sh_int			gsn_mass_invis;
sh_int			gsn_masochism;
sh_int			gsn_poison;
sh_int			gsn_powerstrike;
sh_int			gsn_plague;
sh_int			gsn_sleep;
sh_int			gsn_sanctuary;
sh_int			gsn_sacred_runes;
sh_int			gsn_fly;
sh_int  		gsn_adv_handling;
sh_int  		gsn_adrenaline_rush;
sh_int  		gsn_apierce;
sh_int  		gsn_arms_main;
sh_int  		gsn_archery;
sh_int  		gsn_armorcraft;
sh_int  		gsn_armored_rush;
sh_int  		gsn_armor_enhance;
sh_int  		gsn_avenger;
sh_int  		gsn_axe;
sh_int  		gsn_abduct;
sh_int  		gsn_dagger;
sh_int			gsn_fired;
sh_int  		gsn_flail;
sh_int  		gsn_mace;
sh_int  		gsn_polearm;
sh_int			gsn_shield_block;
sh_int  		gsn_spear;
sh_int  		gsn_spirit_bind;
sh_int  		gsn_staff;
sh_int  		gsn_sword;
sh_int  		gsn_whip;
sh_int  		gsn_sword_mastery;
sh_int  		gsn_dagger_mastery;
sh_int  		gsn_spear_mastery;
sh_int  		gsn_mace_mastery;
sh_int  		gsn_axe_mastery;
sh_int  		gsn_flail_mastery;
sh_int  		gsn_whip_mastery;
sh_int  		gsn_staff_mastery;
sh_int  		gsn_exotic_mastery;
sh_int  		gsn_exile;
sh_int  		gsn_shield_expert;
sh_int  		gsn_sword_expert;
sh_int  		gsn_dagger_expert;
sh_int  		gsn_mace_expert;
sh_int  		gsn_spear_expert;
sh_int  		gsn_axe_expert;
sh_int  		gsn_flail_expert;
sh_int  		gsn_staff_expert;
sh_int  		gsn_whip_expert;
sh_int  		gsn_polearm_expert;
sh_int  		gsn_exotic_expert;
sh_int  		gsn_polearm_mastery;
sh_int  		gsn_bash;
sh_int  		gsn_basic_armor;
sh_int  		gsn_adv_armor;
sh_int  		gsn_berserk;
sh_int  		gsn_dirt;
sh_int  		gsn_hand_to_hand;
sh_int  		gsn_trip;
sh_int  		gsn_trample;
sh_int  		gsn_lash;
sh_int  		gsn_fast_healing;
sh_int  		gsn_false_weapon;
sh_int  		gsn_fade;
sh_int  		gsn_haggle;
sh_int  		gsn_lore;
sh_int  		gsn_lotus_sc;
sh_int  		gsn_meditation;
sh_int  		gsn_melee;
sh_int  		gsn_scrolls;
sh_int  		gsn_scourge;
sh_int  		gsn_staves;
sh_int  		gsn_stand_ground;
sh_int  		gsn_wands;
sh_int  		gsn_wanted;
sh_int  		gsn_recall;
sh_int                  gsn_hunt;
sh_int                  gsn_dual_wield;
sh_int                  gsn_death_grasp;
sh_int                  gsn_deathweaver;
sh_int                  gsn_death_kiss;
sh_int                  gsn_death_shroud;
sh_int                  gsn_deteriorate;
sh_int                  gsn_detect_traps;
sh_int                  gsn_phantasmal_griffon;
sh_int                  gsn_illusionary_spectre;
sh_int                  gsn_phantom_dragon;
sh_int                  gsn_trance;
sh_int                  gsn_blind_fighting;
sh_int                  gsn_shield_disarm;
sh_int                  gsn_rake;
sh_int                  gsn_raise_morale;
sh_int			gsn_misdirection;
sh_int			gsn_missile_shield;
sh_int			gsn_shadowform;
sh_int			gsn_shadowdancer;
sh_int			gsn_shadow_door;
sh_int			gsn_shadowmaster;
sh_int			gsn_shadow_strike;
sh_int			gsn_treeform;
sh_int			gsn_fourth_attack;
sh_int			gsn_footwork;
sh_int			gsn_forestmeld;
sh_int			gsn_deathblow; 
sh_int			gsn_com_lan;
sh_int			gsn_counter;
sh_int			gsn_lay_on_hands;
sh_int			gsn_detect_hidden;
sh_int			gsn_cleave;
sh_int			gsn_assassinate;
sh_int			gsn_blackjack;
sh_int			gsn_gag;
sh_int			gsn_strangle;
sh_int			gsn_acupuncture;
sh_int			gsn_herb;
sh_int			gsn_hex;
sh_int			gsn_tame;
sh_int			gsn_beast_call;
sh_int			gsn_rage;
sh_int			gsn_regeneration;
sh_int			gsn_bodyslam;
sh_int			gsn_dual_backstab;
sh_int			gsn_grapple;
sh_int			gsn_greenheart;
sh_int			gsn_charge;
sh_int			gsn_shoot;
sh_int			gsn_ambush;
sh_int			gsn_endure;
sh_int			gsn_barkskin;
sh_int			gsn_warcry;
sh_int			gsn_circle;
sh_int			gsn_swing;
sh_int			gsn_headbutt;
sh_int			gsn_camouflage;
sh_int			gsn_chameleon;
sh_int			gsn_quiet_movement;
sh_int			gsn_keen_sight;
sh_int			gsn_vanish;
sh_int			gsn_vredem;
sh_int			gsn_virtues;
sh_int			gsn_vitality;
sh_int			gsn_voodoo_spell;
sh_int			gsn_chii;
sh_int			gsn_blindness_dust;
sh_int			gsn_poison_smoke;
sh_int			gsn_pugil;
sh_int			gsn_butcher;
sh_int			gsn_dual_parry;
sh_int			gsn_caltraps;
sh_int			gsn_nerve;
sh_int			gsn_nerve_amp;
sh_int			gsn_numbness;
sh_int			gsn_righteous;
sh_int			gsn_riposte;
sh_int			gsn_ripple;
sh_int			gsn_truesight;
sh_int			gsn_trophy;
sh_int			gsn_spellbane;
sh_int			gsn_spellkiller;
sh_int			gsn_spell_blast;
sh_int			gsn_spell_trap;
sh_int			gsn_mana_trap;
sh_int			gsn_doppelganger;
sh_int			gsn_mirror_image;
sh_int			gsn_mirage;
sh_int			gsn_mirror_cloak;
sh_int			gsn_cognizance;
sh_int			gsn_stance;
sh_int			gsn_forms;
sh_int			gsn_wanted;
sh_int			gsn_judge;
sh_int			gsn_spy;
sh_int			gsn_knight;
sh_int			gsn_guard;
sh_int			gsn_stallion;
sh_int			gsn_relax;
sh_int			gsn_garble;
sh_int			gsn_brew;
sh_int			gsn_challenge;
sh_int			gsn_bounty_collect;
sh_int			gsn_fatality;
sh_int			gsn_climb;
sh_int                  gsn_damnation;
sh_int                  gsn_dam_masteryB;
sh_int                  gsn_dam_masteryS;
sh_int                  gsn_dam_masteryP;
sh_int                  gsn_flashfire;
sh_int                  gsn_drained;
sh_int                  gsn_dreamprobe;
sh_int                  gsn_mortally_wounded;
sh_int                  gsn_mercy_wait;
sh_int                  gsn_mounted;
sh_int                  gsn_ancient_lore;
sh_int  		gsn_invoke;
sh_int  		gsn_mimic;
sh_int			gsn_camp;
sh_int			gsn_scout;
sh_int			gsn_throw;
sh_int			gsn_roar;
sh_int			gsn_edge_craft;
sh_int			gsn_counterfeit;
sh_int			gsn_ranger_staff;
sh_int			gsn_healer_staff;
sh_int			gsn_heal;
sh_int			gsn_familiar_link;
sh_int			gsn_extort;
sh_int			gsn_squire;
sh_int			gsn_silence;
sh_int			gsn_blasphemy;
sh_int			gsn_blink;
sh_int			gsn_defecate;
sh_int			gsn_vomit;
sh_int			gsn_insomnia;
sh_int			gsn_insight;
sh_int			gsn_mystic_healing;
sh_int			gsn_shield_of_words;
sh_int			gsn_children_sky;
sh_int			gsn_pilfer;
sh_int			gsn_mind_link;
sh_int			gsn_mindsurge;
sh_int			gsn_mind_disrupt;
sh_int			gsn_linked_mind;
sh_int			gsn_ensnare;
sh_int			gsn_timer;
sh_int			gsn_time_comp;
sh_int			gsn_pixie_dust;
sh_int			gsn_bat_form;
sh_int			gsn_wolf_form;
sh_int			gsn_mist_form;
sh_int			gsn_double_kick;
sh_int			gsn_coffin;
sh_int			gsn_stake;
sh_int			gsn_eavesdrop;
sh_int			gsn_kinetics;
sh_int			gsn_thrust;
sh_int			gsn_ecstacy;
sh_int			gsn_anatomy;
sh_int			gsn_beads;
sh_int			gsn_martial_arts_b;
sh_int			gsn_martial_arts_a;
sh_int			gsn_kickboxing_b;
sh_int			gsn_kickboxing_a;
sh_int			gsn_double_grip;
sh_int			gsn_monkey;
sh_int			gsn_tiger;
sh_int			gsn_crane;
sh_int			gsn_mantis;
sh_int			gsn_drunken;
sh_int			gsn_horse;
sh_int			gsn_holy_hands;
sh_int			gsn_dragon;
sh_int			gsn_buddha;
sh_int			gsn_aura;
sh_int			gsn_balance;
sh_int			gsn_sense_motion;
sh_int			gsn_catalepsy;
sh_int			gsn_healing;
sh_int			gsn_kinesis;
sh_int			gsn_mind_thrust;
sh_int			gsn_mind_disruption;
sh_int			gsn_mind_blast;   
sh_int			gsn_psalm_master;     
sh_int			gsn_psychic_crush;
sh_int			gsn_psionic_blast;
sh_int			gsn_psi_amp;
sh_int			gsn_psychic_purge;
sh_int			gsn_photon;
sh_int			gsn_flesh_armor;
sh_int			gsn_detect_aura; 
sh_int			gsn_displacement;
sh_int			gsn_dvoid;
sh_int			gsn_iron_will;
sh_int			gsn_ironarm;
sh_int			gsn_iron_curtain;
sh_int			gsn_bio_manipulation;
sh_int			gsn_ego_whip;
sh_int			gsn_tele_lock; 
sh_int			gsn_telepathy; 
sh_int			gsn_temp_storm; 
sh_int			gsn_there_not_there;
sh_int			gsn_levitate;
sh_int			gsn_leash;
sh_int			gsn_leadership;
sh_int			gsn_gravitate;
sh_int			gsn_bio_feedback;
sh_int			gsn_pyramid_of_force;
sh_int			gsn_body_weaponry;
sh_int			gsn_ectoplasm;
sh_int			gsn_hypnosis; 
sh_int			gsn_forget;
sh_int			gsn_graft_weapon;
sh_int			gsn_mental_barrier; 
sh_int			gsn_mental_knife; 
sh_int			gsn_empower; 
sh_int			gsn_ogtrium; 
sh_int			gsn_onslaught; 
sh_int			gsn_omnipotence; 
sh_int			gsn_ocularis; 
sh_int			gsn_strium; 
sh_int			gsn_ptrium; 
sh_int			gsn_uorder; 
sh_int			gsn_unminding; 
sh_int			gsn_istrength; 
sh_int			gsn_offensive; 
sh_int			gsn_orealts_1st; 
sh_int			gsn_orealts_2nd; 
sh_int			gsn_defensive; 
sh_int			gsn_chii_bolt; 
sh_int			gsn_thrash; 
sh_int			gsn_deadfall; 
sh_int			gsn_windmill;
sh_int			gsn_cusinart;
sh_int			gsn_cure_light;
sh_int			gsn_wire_delay;
sh_int			gsn_siege_delay; 
sh_int			gsn_ghoul_touch; 
sh_int			gsn_paralyze; 
sh_int			gsn_entomb; 
sh_int			gsn_insect_swarm; 
sh_int			gsn_feedback; 
sh_int			gsn_feign; 
sh_int			gsn_con_damage; 
sh_int			gsn_cone; 
sh_int			gsn_dark_ritual; 
sh_int			gsn_covenant; 
sh_int			gsn_burrow; 
sh_int			gsn_cutpurse; 
sh_int			gsn_cutter; 
sh_int			gsn_offhand_disarm; 
sh_int			gsn_werepower;
sh_int			gsn_weretiger;
sh_int			gsn_werewolf;
sh_int			gsn_werebear;
sh_int			gsn_werefalcon;
sh_int			gsn_fasting; 
sh_int			gsn_shed_skin;
sh_int			gsn_crusade;
sh_int			gsn_heroism;
sh_int			gsn_decoy;
sh_int			gsn_prayer;
sh_int			gsn_refrain;
sh_int			gsn_lullaby;
sh_int			gsn_tarot;
sh_int			gsn_tko;
sh_int			gsn_leech;
sh_int			gsn_noquit;
sh_int			gsn_nolearn;
sh_int			gsn_duplicate;
sh_int			gsn_dance_song;
sh_int			gsn_attract;
sh_int			gsn_uppercut;
sh_int			gsn_taunt;
sh_int			gsn_condor;
sh_int			gsn_disorient;
sh_int			gsn_concen;
sh_int			gsn_seasons;
sh_int			gsn_hysteria;
sh_int			gsn_lust;
sh_int			gsn_reputation;
sh_int			gsn_unforgiven;
sh_int			gsn_phoenix;
sh_int			gsn_brawl;
sh_int			gsn_brain_death;
sh_int			gsn_unholy_strength;
sh_int			gsn_ram;
sh_int			gsn_embrace;
sh_int			gsn_embrace_poison;
sh_int			gsn_secarts;
sh_int			gsn_continuum;
sh_int			gsn_tear;
sh_int			gsn_unholy_gift;
sh_int			gsn_mana_charge;
sh_int                  gsn_warmaster_code;
sh_int			gsn_call_roc;
sh_int                  gsn_corrupt;
sh_int			gsn_lifeforce;
sh_int			gsn_life_insurance;
sh_int			gsn_lifedrain;
sh_int			gsn_entangle;
sh_int			gsn_forest_mist;
sh_int			gsn_forest_walk;
sh_int			gsn_druid_staff;
sh_int			gsn_trap_silvanus;
sh_int			gsn_circle_of_protection;
sh_int			gsn_field_fear;
sh_int			gsn_fear;
sh_int			gsn_drug_use;
sh_int			gsn_research;
sh_int			gsn_decipher;

/* BATTLE MAGES */
sh_int			gsn_forcefield;
sh_int			gsn_terra_shield;
sh_int			gsn_rust;
sh_int			gsn_air_shield;
sh_int			gsn_blades;
sh_int			gsn_field_dress;
sh_int			gsn_plumbum;
sh_int			gsn_dan_blade;
sh_int			gsn_mana_lock;
sh_int			gsn_ref_shield;

/* Miners */
sh_int			gsn_sense_vein;
sh_int			gsn_dig;
sh_int			gsn_gemlore;
sh_int			gsn_extrude;

/* anatmy masteries */
sh_int			gsn_mob_expert;
sh_int			gsn_human_expert;
sh_int			gsn_elf_expert;
sh_int			gsn_giant_expert;
sh_int			gsn_dwarf_expert;
sh_int			gsn_demihuman_expert;
sh_int			gsn_flying_expert;
sh_int			gsn_beast_expert;
sh_int			gsn_unique_expert;

sh_int			gsn_mob_master;
sh_int			gsn_human_master;
sh_int			gsn_elf_master;
sh_int			gsn_dwarf_master;
sh_int			gsn_giant_master;
sh_int			gsn_beast_master;
sh_int			gsn_demihuman_master;
sh_int			gsn_flying_master;
sh_int			gsn_unique_master;

/* MOBprogram locals */
int 		mprog_name_to_type	args ( ( char* name ) );
MPROG_DATA *    mprog_file_read         args ( ( char* f, MPROG_DATA* mprg, MOB_INDEX_DATA *pMobIndex ) );
void		load_mobprogs           args ( ( FILE* fp ) );
void            mprog_read_programs     args ( ( FILE* fp, MOB_INDEX_DATA *pMobIndex ) );

/* Locals. */
MOB_INDEX_DATA *	mob_index_hash		[MAX_KEY_HASH];
OBJ_INDEX_DATA *	obj_index_hash		[MAX_KEY_HASH];
ROOM_INDEX_DATA *	room_index_hash		[MAX_KEY_HASH];
AREA_DATA *		area_first;
AREA_DATA *		area_last;
extern char             str_empty       [1];
extern int sOverFlowString;
extern int nOverFlowString;
extern bool Full;
char * daPrompt;
int			top_affect;
int			top_area;
int			top_ed;
int			top_exit;
int			top_help;
int			top_mob_index;
int			top_obj_index;
int			top_reset;
int			top_room;
int			top_vir_room = 0;
int			top_shop;
int                     top_vnum_room;
int                     top_vnum_mob;
int                     top_vnum_obj;
int                     top_mprog_index;
int                     top_oprog_index;
int                     top_rprog_index; 
int                     top_trap_index; 
int                     top_cabal_index = 0; 
int 			mobile_count = 0;
int			newmobs = 0;
int			newobjs = 0;
bool			loadallmobs = TRUE;

/* Memory management.                                        * 
 * Increase MAX_STRING if you have too.                      *
 * Tune the others only if you understand what you're doing. */
#define                 MAX_MEM_LIST             11
void *			rgFreeList	[MAX_MEM_LIST];
const int		rgSizeList	[MAX_MEM_LIST]	=
{ 16, 32, 64, 128, 256, 1024, 2048, 4096, 8192, 16384, 32768-64 };
extern int              nAllocString;
extern int              sAllocString;
int			nAllocPerm;
int			sAllocPerm;

/* Semi-locals. */
bool			fBootDb;
FILE *			fpArea;
char			strArea[MIL];
extern  		int MAX_STRING;
void    		init_string_space( void );
void    		boot_done( void );
struct			social_type	social_table		[MAX_SOCIALS];
int			social_count;
int			night_count;
int			mprog_count;
int			mprogf_count;

/* Local booting procedures. */
void    init_mm         args( ( void ) );
void	load_area	args( ( FILE *fp ) );
void    new_load_area   args( ( FILE *fp ) );
void	load_helps	args( ( FILE *fp ) );
void	load_helps_new	args( ( void	 ) );
void	load_old_mob	args( ( FILE *fp ) );
void 	load_mobiles	args( ( FILE *fp ) );
void 	load_army_indexes args( ( FILE *fp ) );
void 	load_cabal_indexes args( ( FILE *fp ) );
void	load_old_obj	args( ( FILE *fp ) );
void 	load_objects	args( ( FILE *fp ) );
void	load_resets	args( ( FILE *fp ) );
void	load_rooms	args( ( FILE *fp ) );
void	load_shops	args( ( FILE *fp ) );
void 	load_socials	args( ( FILE *fp ) );
void	load_specials	args( ( FILE *fp ) );
void	load_notes	args( ( void ) );
void	load_bans	args( ( void ) );
void	load_objprogs	args(( FILE *fp ));
void	load_roomprogs	args(( FILE *fp ));
void	load_traps	args(( FILE *fp ));

void	fix_exits	args( ( void ) );
void	fix_mobprogs    args( ( void ) );
void	fix_objprogs    args( ( void ) );
void	fix_roomprogs   args( ( void ) );

void	reset_area	args( ( AREA_DATA * pArea ) );
void	load_limits	args( ( void ) );
void	color_rooms	args( ( void ) );

/* extern functions */
extern void make_html_helps();

/* seeds a single object as based on entry in objseed table */
void seed_object( int i ){
  OID* pOI = get_obj_index( objseed_table[i].vnum );
  if (pOI == NULL){
    bug("seed_objects: could not load obj index.", objseed_table[i].vnum);
    return;
  }
  /* check if we need to load one of these */
  if (objseed_table[i].num > pOI->count){
    int j = pOI->count;
    for (; j < objseed_table[i].num; j++){
      OBJ_DATA* pO;		//object
      ROOM_INDEX_DATA* pR;	//room to be put in

      /* check the chance to load */
      if (number_percent() > objseed_table[i].chance)
	continue;
      /* load the object */
      pR = get_rand_room(objseed_table[i].amin,
			 objseed_table[i].amax,
			 objseed_table[i].rmin,
			 objseed_table[i].rmax,
			 
			 objseed_table[i].i_area,
			 objseed_table[i].ia_num,
			 objseed_table[i].e_area,
			 objseed_table[i].ea_num,
			 
			 objseed_table[i].i_sect,
			 objseed_table[i].is_num,
			 objseed_table[i].e_sect,
			 objseed_table[i].es_num,
			 
			 objseed_table[i].i_rom1,
			 objseed_table[i].ir1_num,
			 objseed_table[i].e_rom1,
			 objseed_table[i].er1_num,
			 
			   objseed_table[i].i_rom2,
			 objseed_table[i].ir2_num,
			 objseed_table[i].e_rom2,
			 objseed_table[i].er2_num,
			 
			 objseed_table[i].pool,
			 objseed_table[i].fExit,
			 FALSE, NULL);
      if (pR == NULL){
	bug("seed_obj: NULL room for obj %d.", objseed_table[i].vnum);
	continue;
      }
      /* get the objects */
      if ( (pO = create_object( pOI, pOI->level)) == NULL){
	bug("seed_obj: NULL object for vnum: %d", pOI->vnum);
	continue;
      }
      /* got room and got objects, we put on in the other */
      obj_to_room(pO, pR);
      pO->homevnum = pR->vnum;
    }//END for each unloaded objects
  }//END if
}
/* following seeds random objects into the world */
/* the objseed_table contains all info. The function */
/* runs once after each reboot and loads objects into */
/* appropriate rooms IF they do not exists.	      */
void seed_objects(){
  int i = 0;
/* run through the objseed table till we hit a 0 vnum entry */
  for (i =0; objseed_table[i].vnum > 0; i++){
/* DEBUG
    nlogf("seeding entry %d of vnum %d", i, objseed_table[i].vnum);
*/
    seed_object ( i );
  }//END for each table entry
}

/* Following struct is used to record player stats. */
#define MAX_COUNT	32
struct class_info_type {
  int class_count[MAX_CLASS];	//count for each class
  int race_count[MAX_PC_RACE];	//count for each race

  /* quest stuff to keep track of quest players with counts*/
  char vamp_name[MAX_COUNT][MIL];
  int vamp;
  char crus_name[MAX_COUNT][MIL];
  int crus;
  char psi_name[MAX_COUNT][MIL];
  int psis;
  char lich_name[MAX_COUNT][MIL];
  int lich;

  char undead_name[MAX_COUNT][MIL];
  int undead;
  char demon_name[MAX_COUNT][MIL];
  int demon;
  char avatar_name[MAX_COUNT][MIL];
  int avatar;
  char tatto_name[MAX_COUNT][MIL]; //lists players with tats
  int tatto;
};

/* sends not to immortal with files purged etc. */
void send_pfile_stats(int pfiles, int purged, int wiped, int total){
  char *strtime, *namelist;
  char buf[MSL],arg[MIL];
  char* sender = "`!HAL 1000``";
  
  BUFFER *buffer;
  NOTE_DATA *note;

  buffer = new_buf();
  sprintf(buf,"`!Following generated at %s.``\n\r\n\r",((char *) ctime( &mud_data.current_time )));
  add_buf(buffer,buf);
  sprintf(buf, "Total pfiles checked: %-25d\n\r"\
	  "Pfiles purged: %-25d\n\r"\
	  "Pfiles deleted: %-25d\n\r"\
	  "Pfiles above level 15 (used for limit count): %d\n\r",
	  total, purged, wiped, pfiles);
  add_buf(buffer,buf);
  namelist = str_dup("immortal");
  for (;;)
    {
      namelist = one_argument(namelist,arg);
      if (arg[0] == '\0')
	break;
      note = new_note();
      note->prefix = 0;
      note->next = NULL;
      note->type = NOTE_NOTE;
      free_string(note->sender);
      note->sender = str_dup( sender );
      free_string(note->subject);
      note->subject = str_dup("Pfile Statistics");
      free_string(note->text);
      note->text = str_dup(buf_string(buffer));
      strtime                         = ctime( &mud_data.current_time );
      strtime[strlen(strtime)-1]      = '\0';
      note->date                 = str_dup( strtime );
      note->date_stamp           = mud_data.current_time + 2;
      free_string(note->to_list);
      note->to_list = str_dup(arg);
      append_note(note);    
    }
  free_buf(buffer);
}

/* constructs a note based on structures passed and sends to "immortal" */
void send_stats(struct class_info_type *cl_info){
    char *strtime, *namelist;
    char buf[MSL],arg[MIL];
    char* sender = "`!HAL 1000``";
      
    BUFFER *buffer;
    NOTE_DATA *note;
    int i = 0;
    int j = 0;
    int count = 0;
    int race = 0;
    int class = 0;

    /* begin to generate stats */
    buffer = new_buf();
    sprintf(buf,"`!Following generated at %s.``\n\r\n\r",((char *) ctime( &mud_data.current_time )));
    add_buf(buffer,buf);
    sprintf(buf, "CLASS\t\t\tCOUNT\t\tRACE\t\t\tCOUNT\n\r");
    add_buf(buffer,buf);
    if (MAX_CLASS > MAX_PC_RACE)
      j = MAX_CLASS;
    else
      j = MAX_PC_RACE;
    for (i = 0; i< j; i++){
      bool fLine = FALSE;
      if (class < MAX_CLASS && !IS_NULLSTR(class_table[class].name) ){
	sprintf(buf,"%-25s %-10d", class_table[class].name, cl_info->class_count[class]);
	add_buf(buffer, buf);
	fLine = TRUE;
      }
      class++;
      if (race  < MAX_PC_RACE && cl_info->race_count[race] > 0){
	sprintf(buf,"%-25s %-10d", pc_race_table[race].name, cl_info->race_count[race]);
	add_buf(buffer, buf);
	fLine = TRUE;
      }
      race++;
      if (fLine){
	add_buf(buffer, "\n\r");
	if (count % 5 == 0)
	  add_buf(buffer, "\n\r");
	count++;
      }
    }
    /* show quest races/classes */
    add_buf(buffer, "\n\r\n\rVampires:");
    for (i = 0; i < cl_info->vamp; i++){
      if (i % 6 == 0 && i + 1 < cl_info->vamp)
	add_buf(buffer, "\n\r");
      sprintf(buf, "%s  ", cl_info->vamp_name[i]);
      add_buf(buffer, buf);
    }
    add_buf(buffer, "\n\r\n\rCrusaders:");
    for (i = 0; i < cl_info->crus; i++){
      if (i % 6 == 0 && i + 1 < cl_info->crus)
	add_buf(buffer, "\n\r");
      sprintf(buf, "%s  ", cl_info->crus_name[i]);
      add_buf(buffer, buf);
    }
    add_buf(buffer, "\n\r\n\rPsionicists:");
    for (i = 0; i < cl_info->psis; i++){
      if (i % 6 == 0 && i + 1 < cl_info->psis)
	add_buf(buffer, "\n\r");
      sprintf(buf, "%s  ", cl_info->psi_name[i]);
      add_buf(buffer, buf);
    }
    add_buf(buffer, "\n\r\n\rLiches:");
    for (i = 0; i < cl_info->lich; i++){
      if (i % 6 == 0 && i + 1 < cl_info->lich)
	add_buf(buffer, "\n\r");
      sprintf(buf, "%s  ", cl_info->lich_name[i]);
      add_buf(buffer, buf);
    }
    add_buf(buffer, "\n\r\n\rUndead:");
    for (i = 0; i < cl_info->undead; i++){
      if (i % 6 == 0 && i + 1 < cl_info->undead)
	add_buf(buffer, "\n\r");
      sprintf(buf, "%s  ", cl_info->undead_name[i]);
      add_buf(buffer, buf);
    }
    add_buf(buffer, "\n\r\n\rDemons:");
    for (i = 0; i < cl_info->demon; i++){
      if (i % 6 == 0 && i + 1 < cl_info->demon)
	add_buf(buffer, "\n\r");
      sprintf(buf, "%s  ", cl_info->demon_name[i]);
      add_buf(buffer, buf);
    }
    add_buf(buffer, "\n\r\n\rAvatars:");
    for (i = 0; i < cl_info->avatar; i++){
      if (i % 6 == 0 && i + 1 < cl_info->avatar)
	add_buf(buffer, "\n\r");
      sprintf(buf, "%s ", cl_info->avatar_name[i]);
      add_buf(buffer, buf);
    }
    add_buf(buffer, "\n\r\n\rTattoos:");
    for (i = 0; i < cl_info->tatto; i++){
      if (i % 6 == 0 && i + 1 < cl_info->tatto)
	add_buf(buffer, "\n\r");
      sprintf(buf, "%s ", cl_info->tatto_name[i]);
      add_buf(buffer, buf);
    }
    /* ALL DONE Send the note*/
    namelist = str_dup("immortal");
    for (;;)
    {
      namelist = one_argument(namelist,arg);
      if (arg[0] == '\0')
	break;
      note = new_note();
      note->prefix = 0;
      note->next = NULL;
      note->type = NOTE_NOTE;
      free_string(note->sender);
      note->sender = str_dup( sender );
      free_string(note->subject);
      note->subject = str_dup("Class/Race Statistics");
      free_string(note->text);
      note->text = str_dup(buf_string(buffer));
      strtime                         = ctime( &mud_data.current_time );
      strtime[strlen(strtime)-1]      = '\0';
      note->date                 = str_dup( strtime );
      note->date_stamp           = mud_data.current_time;
      free_string(note->to_list);
      note->to_list = str_dup(arg);
      append_note(note);    
    }

    free_buf(buffer);
}

/* purges all playes in pflies of rares as per purge_limited in comm.c */
/* returns total pfiles to be used in the game limited item calcs */
/* booleans control which actions are done */
int purge_players(bool fPurge, bool fWipe, bool fCount){
  CABAL_DATA* pCab;
  DIR *Directory;	//Directory
  struct dirent *Dir;	//Directory entry
  struct stat Stat;	//File statistics
  char pFile[MIL];	//Current pfile name
  DESCRIPTOR_DATA *d = new_descriptor();

  /*statistical things */
  struct class_info_type cl_info;

  int tot_count = 0;	//Count of all pfiles.
  int p_count = 0;	//Count of pfiles that can carry rares.
  int tot_purged = 0;	//Count of pfiles purged.
  int tot_wiped = 0;	//Count of pfiles wiped.

  /* for speed we try to avoid lookups */
  const int vamp = class_lookup("vampire");
  const int crus = class_lookup("crusader");
  const int psi  = class_lookup("psionicist");
  //const int lich = class_lookup("lich");
  const int undead = race_lookup("undead");
  const int demon = race_lookup("demon");


  /* Zero statistical info just in case */
  memset( &cl_info, 0, sizeof( cl_info ));
  
  /* Open dir, get first entry */  
  if ( (Directory=opendir(PLAYER_DIR)) == NULL){
    bug("purge_players: Could not access PLAYER_DIR", 0);
    return 0;
  }

  Dir= (struct dirent*) malloc (sizeof (struct dirent));
  Dir->d_name[0] = '\0';

  if ( (Dir = readdir(Directory)) == NULL){
    bug("purge_players: Could not access first directory entry.", 0);
    return 0;
  }

  while(Dir!=NULL){
    int fFound = FALSE;	//Tests if char file was loaded

    /* Get info/pointer to file entry*/
    sprintf(pFile, PLAYER_DIR"%s", (char *) Dir->d_name);
    if ( -1 == stat( pFile, &Stat)){
      char buf[MIL];
      sprintf(buf, "purge_players: stat returned error on file: %s.", 
	      pFile);
      bug(buf, 0);
      Dir = readdir(Directory);
      continue;
    }
    /* check if "regular" file */
    if(S_ISREG(Stat.st_mode)){
      /* check for player file name*/
      if (Dir->d_name[0] >= 'A' && Dir->d_name[0] <= 'Z') {
	fFound = load_char (d, Dir->d_name);
	if ( fFound > 0){
	  ROOM_INDEX_DATA* room;
	  CHAR_DATA* ch = d->character;
	  /* Make sure the room is not saved */
	  d->character->pcdata->roomnum/=-1;
	  d->character->logon = 0;
	  load_obj (d->character);

	  /* put character in a room for proper extraction */
	  d->character->next = char_list;
	  char_list = d->character;
	  d->character->next_player = player_list;
	  player_list = d->character;
	  reset_char(d->character);
	  if ( (room = get_room_index(ROOM_VNUM_PORTAL)) == NULL){
	    bug("purge_players: could not get indext to ROOM_PORTAL", ROOM_VNUM_PORTAL);
	    return 0;
	  }
	  char_to_room (d->character, room);

	  /* LIMITED PURGE */
	  if (fPurge){
	    if (purge_limited(d->character))
	      tot_purged ++;
	  }

	  /* Save character at this point, ALL things affecting char should be done before this. */	  
	  save_char_obj(d->character);
	
	  /* FILE WIPE */
	  if (fWipe){
	    if (IS_SET(d->character->act, PLR_DENY)
		|| (mud_data.current_time - d->character->logoff) > (86400 * (20 + UMIN(100,2*d->character->level)))
		){
	      /* Viri: changed to be shown only for significant players, took up too much time */
	      if (d->character->level > 15){
		nlogf("%s (%d) last logged off %d days ago, and has been removed.",
		      d->character->name, 
		      d->character->level,
		      (int) (mud_data.current_time - d->character->logoff) / 86400);
	      }
	      tot_wiped ++;
	      purge_limited(d->character);
	      if (ch->pCabal)
		char_from_cabal( ch );
	      unlink (pFile); 
	      extract_char(d->character, TRUE);

	      Dir = readdir(Directory);
	      continue;
	    }//END if old enough
	  }//END WIPE

	  /* Cabal/Quest/Race Counting */
	  if (fCount && !IS_IMMORTAL(ch)){

	    /* count race/class/quest first */
	    cl_info.class_count[ch->class]++;
	    cl_info.race_count[ch->race]++;

	    /* quest race/class members */
	    if (ch->class == vamp){
	      sprintf(cl_info.vamp_name[cl_info.vamp++], "%s", ch->name);
	    }
	    if (ch->class == crus){
	      sprintf(cl_info.crus_name[cl_info.crus++], "%s", ch->name);
	    }
	    if (ch->class == psi){
	      sprintf(cl_info.psi_name[cl_info.psis++], "%s", ch->name);
	    }
	    /*
	    if (ch->class == lich){
	      sprintf(cl_info.lich_name[cl_info.lich++], "%s", ch->name);
	    */
	    if (ch->race == undead){
	      sprintf(cl_info.undead_name[cl_info.undead++], "%s", ch->name);
	    }
	    if (ch->race == demon){
	      sprintf(cl_info.demon_name[cl_info.demon++], "%s", ch->name);
	    }
	    if (IS_AVATAR(ch)){
	      sprintf(cl_info.avatar_name[cl_info.avatar++], "%s", ch->name);
	    }
	    if (ch->tattoo){
	      sprintf(cl_info.tatto_name[cl_info.tatto++], "%s:%s,", ch->name, deity_table[ch->tattoo].way);
	    }
	  }
	  if (d->character->level > 15)
	    p_count ++;
	  /* extract the char */
	  extract_char(d->character, TRUE);
	  tot_count++;
	}//END if found and loaded
      }//END if A to Z
    }//END If file is regular
    Dir = readdir(Directory);
  }//END while loop. 

  /* Run through cabal members and check if their members exist, if not remove them */
  for(pCab = cabal_list; pCab; pCab = pCab->next){
    CMEMBER_DATA* cm, *cm_next;
    /* reset the member counts */
    pCab->cur_member = 0;
    pCab->cur_elder = 0;
    pCab->cur_leader = 0;

    for (cm = pCab->members; cm; cm = cm_next ){
      cm_next = cm->next;
      /* check if member's file exists if not, remove it */      
      sprintf(pFile, PLAYER_DIR"%s", cm->name);
      if ( -1 == stat( pFile, &Stat)){
	cmember_from_cabal( cm, pCab );
	continue;
      }
      /* increae the member counts */
      pCab->cur_member ++;
      if (cm->rank == RANK_ELDER)
	pCab->cur_elder ++;
      else if (cm->rank == RANK_LEADER)
	pCab->cur_leader ++;
    }
  }

  /* cleanup */
  free_descriptor(d);
  closedir(Directory);

  /* send a note to all about bounties if any */
  if (mud_data.bounties >= 10){
    char buf[MSL];
    sprintf(buf, 
	    "In a gesture of appreciation and gratitude the members of Syndicate wish to\n\r"\
	    "announce that total of %d bounties have been fulfilled, and thank you for your\n\r"\
	    "patronage.\n\r", mud_data.bounties);
    do_hal("all", "Bounty Report", buf, NOTE_NOTE);
    mud_data.bounties = 0;
  }
	    
  /* return count of pfiles */
  if (p_count)
    mud_data.pfiles = p_count;
  if (fPurge)
    nlogf("Total files purged: %d.", tot_purged);
  if (fWipe)
    nlogf("Total files wiped: %d.", tot_wiped);
  if (fCount)
    send_stats(&cl_info);
  send_pfile_stats(mud_data.pfiles, tot_purged, tot_wiped, tot_count);
  nlogf("Total files searched: %d.", tot_count);
  nlogf("Current pfile count at: %d.", mud_data.pfiles);
  return tot_count;
}

/* initiliazes trap to index data */
void init_trap(TRAP_DATA* tr, TRAP_INDEX_DATA* pTrapIndex){
  int i  = 0;
  if (tr->name == NULL)
    tr->name		= str_dup(pTrapIndex->name);
  if (tr->echo == NULL)
    tr->echo		= str_dup(pTrapIndex->echo);
  if (tr->oEcho == NULL)
    tr->oEcho		= str_dup(pTrapIndex->oEcho);
  tr->armed		= IS_SET(pTrapIndex->flags, TRAP_DELAY) ? FALSE : TRUE;
  tr->age		= 0;

  tr->pIndexData	= pTrapIndex;
  tr->vnum		= pTrapIndex->vnum;
  tr->area		= pTrapIndex->area;
  tr->type		= pTrapIndex->type;
  tr->level		= pTrapIndex->level;
  tr->duration		= -1;
  tr->flags		= pTrapIndex->flags;

  for (i = 0; i < MAX_TRAPVAL; i++)
    tr->value[i] = pTrapIndex->value[i];
}


/* Big mama top level function. */
void boot_db( bool fHotReboot )
{
  char pFile [MSL];
  struct stat Stat;	//File statistics
  int sn;

    /* Init string stuff */
    {
	log_string("Initializing shared string manager...");
        init_string_space();
        fBootDb         = TRUE;
    }
    /* Init random number generator.  */
    {
	log_string("Initializing random number generator...");
        init_mm( );
    }
    /* Set mud data */
    reset_mdata();
    
    /* restore mud data if any */
    read_mud();
    /* if this is not hotreboot, reset crash time and deaths */
    if (!fHotReboot){
      mud_data.crash_time = mud_data.current_time;
      mud_data.deaths = 0;
    }

    /* check master questor */
    sprintf(pFile, PLAYER_DIR"%s", mud_data.questor);
    if ( -1 != stat( pFile, &Stat))
      mud_data.max_quest = 1;

    log_string("Assigning GRN's...");
    for ( sn = 0; race_table[sn].name; sn++){
      if (race_table[sn].grn != NULL)
	*race_table[sn].grn = sn;
    }
    /* assign gcn's for classes which have them */
    log_string("Assigning GCN's...");
    for ( sn = 0; class_table[sn].name; sn++){
      if (class_table[sn].gcn != NULL)
	*class_table[sn].gcn = sn;
    }

    /* Assign gsn's for skills which have them. */
    {
	log_string("Assigning GSN's...");
	for ( sn = 0; sn < MAX_SKILL; sn++ )
	    if ( skill_table[sn].pgsn != NULL )
		*skill_table[sn].pgsn = sn;

	/* Assign gen's with values starting at MAX_SKILL */
	log_string("Assigning GEN's...");
	for ( sn = MAX_SKILL; sn < (MAX_SKILL + MAX_EFFECTS); sn++ )
	  {
	    if ( effect_table[gn_pos(sn)].pgen != NULL )
	      *effect_table[gn_pos(sn)].pgen = sn;
	  }
	/* Assign Songs */
	log_string("Assigning SONGS's...");
	for ( sn = 0; sn < MAX_SONG; sn++ ){
	  if ( song_table[sn].pgsn != NULL )
	    *song_table[sn].pgsn = sn;
	}
    }

    /* Read in all the area files. */
    {
	FILE *fpList;
	log_string("Reading area files...");
	if ( ( fpList = fopen( AREA_LIST, "r" ) ) == NULL )
	{
	    perror( AREA_LIST );
	    fpList = fopen( NULL_FILE, "r" );
	    fclose( fpList );
	    exit( 1 );
	}
	for ( ; ; )
	{
	    strcpy( strArea, fread_word( fpList ) );
	    if ( strArea[0] == '$' )
		break;
	    if ( strArea[0] == '-' )
	    {
		fpArea = stdin;
	    }
	    else if ( ( fpArea = fopen( strArea, "r" ) ) == NULL )
	    {
	        perror( strArea );
		fpArea = fopen( NULL_FILE, "r" );
		fclose( fpArea );
	        exit( 1 );
	    }
	    for ( ; ; )
	    {
		char *word;
		if ( fread_letter( fpArea ) != '#' )
		{
		    bug( "Boot_db: # not found.", 0 );
		    exit( 1 );
		}
		word = fread_word( fpArea );
                if ( word[0] == '$'                  )                 break;
		else if ( !str_cmp( word, "AREA"     ) ) load_area    (fpArea);
                else if ( !str_cmp( word, "AREADATA" ) ) new_load_area(fpArea);
		else if ( !str_cmp( word, "HELPS"    ) ) load_helps   (fpArea);
		else if ( !str_cmp( word, "MOBOLD"   ) ) load_old_mob (fpArea);
		else if ( !str_cmp( word, "MOBILES"  ) ) load_mobiles (fpArea);
		else if ( !str_cmp( word, "CABALS"   ) ) load_cabal_indexes(fpArea);
		else if ( !str_cmp( word, "ARMIES"   ) ) load_army_indexes(fpArea);
                else if ( !str_cmp( word, "MOBPROGS" ) ) load_mobprogs(fpArea);
		else if ( !str_cmp( word, "OBJPROGS" ) ) load_objprogs(fpArea);
		else if ( !str_cmp( word, "ROOMPROGS") ) load_roomprogs(fpArea);
		else if ( !str_cmp( word, "TRAPS"    ) ) load_traps(fpArea);
		else if ( !str_cmp( word, "OBJOLD"   ) ) bug("old obj found",0);
	  	else if ( !str_cmp( word, "OBJECTS"  ) ) load_objects (fpArea);
		else if ( !str_cmp( word, "RESETS"   ) ) load_resets  (fpArea);
		else if ( !str_cmp( word, "ROOMS"    ) ) load_rooms   (fpArea);
		else if ( !str_cmp( word, "SHOPS"    ) ) load_shops   (fpArea);
		else if ( !str_cmp( word, "SOCIALS"  ) ) load_socials (fpArea);
		else if ( !str_cmp( word, "SPECIALS" ) ) load_specials(fpArea);
		else
		{
		    bug( "Boot_db: bad section name.", 0 );
		    exit( 1 );
		}
	    }
	    if ( fpArea != stdin )
		fclose( fpArea );
	    fpArea = NULL;
	}
	fclose( fpList );
    }

    /* clans need to be loaded before cabals */
    log_string("Loading clans...");
    LoadClans( );
    /* cabals need to be loaded before their armies and rooms being restored */
    log_string("Loading cabals...");
    load_cabals( );
    log_string("Loading pacts...");
    load_pacts();
    /* area/objects are in, load virtual armies, cabal rooms and objects */
    log_string("Loading Virtual Cabal Data...");
    load_cvrooms( );

    /* Fix up exits.                    *
     * Declare db booting over.         *
     * Reset all areas once.            *
     * Load up the notes and ban files. */
    {
      log_string("Fixing cabals...");
      /* this also fixes up virtual cabal rooms */
      fix_cabals( );
      log_string("Fixing exits...");
      fix_exits( );
      log_string("Refreshing Support...");      
      refresh_cabal_support();
      log_string("Refreshing Area Distances...");      
      CalcCabalDistances();
      log_string("Fixing mobprogs...");
      fix_mobprogs( );
      log_string("Fixing objprogs...");
      fix_objprogs( );
      log_string("Fixing roomprogs...");
      fix_roomprogs( );
      
      daPrompt = str_dup( "<%hhp %mm %vmv> " );

/* CLEAR STRING ALOCATION */
      fBootDb	= FALSE;
      boot_done();

      log_string("Loading eq limits...");
      load_limits();
      log_string("Loading bounties...");
      load_bounties();
      log_string("Loading challenges...");
      load_challenges();
      if (fHotReboot)
	{
	  log_string("Loading saved items...");
	  load_obj(NULL);
	}
      log_string("Seeding objects...");
      seed_objects( );
      log_string("Refreshing area support values...");
      refresh_area_support( );
      log_string("Loading armies...");
      load_armies();
      log_string("Updating areas...");
      area_update( );
      loadallmobs = FALSE;
      log_string("Loading notes...");
      load_notes( );
      log_string("Loading helps...");
      load_helps_new( );
      log_string("Loading bans...");
      load_bans();
      log_string("Loading tomes...");
      InitTomes();      

	/* MAINTANCE */
	if (IS_SET(reboot_act, REBOOT_COLOR)){
	  log_string("COLOR specified: Coloring Rooms...");
	  color_rooms();
	}
	if (IS_SET(reboot_act, REBOOT_PURGE)
	    || IS_SET(reboot_act, REBOOT_COUNT)
	    || IS_SET(reboot_act, REBOOT_WIPE)
	    || IS_SET(reboot_act, REBOOT_CABAL)){

	  if (IS_SET(reboot_act, REBOOT_PURGE))
	    log_string("PURGE specified: Purging rares...");
	  if (IS_SET(reboot_act, REBOOT_WIPE))
	    log_string("WIPE specified: Wiping old pfiles...");
	  if (IS_SET(reboot_act, REBOOT_WIPE))
	    log_string("WIPE specified: Wiping counting pfiles...");
	  if (IS_SET(reboot_act, REBOOT_CABAL))
	    log_string("CABAL specified: Compiling cabal data...");
	  /* if PURGE or WIPE is not set, only counting is done */
	  purge_players(IS_SET(reboot_act, REBOOT_PURGE), 
			IS_SET(reboot_act, REBOOT_WIPE),
			IS_SET(reboot_act, REBOOT_CABAL));
	}
	if (IS_SET(reboot_act, REBOOT_HELPS)){
	  log_string("HELP specified: Generating helps...");
	  make_html_helps();
	}

        MOBtrigger = TRUE;
        if (fHotReboot)
            hotreboot_recover();
    }

}

void load_area( FILE *fp )
{

  AREA_DATA *pArea;
  pArea		= alloc_perm( sizeof(*pArea) );
  pArea->file_name	= fread_string(fp);
  pArea->area_flags   = AREA_LOADING;
  pArea->security     = 9;
  pArea->builders     = str_dup( "None" );
  pArea->vnum         = top_area;
  pArea->name		= fread_string( fp );
  pArea->prefix	= fread_string( fp );
  pArea->credits	= fread_string( fp );
  pArea->min_vnum	= fread_number(fp);
  pArea->max_vnum	= fread_number(fp);
  pArea->age		= 15;
  pArea->nplayer	= 0;
  pArea->empty	= FALSE;
  pArea->pCabal	= NULL;
  
  if ( !area_first )
    area_first = pArea;
  if ( area_last )
    {
      area_last->next = pArea;
      REMOVE_BIT(area_last->area_flags, AREA_LOADING);
    }
    area_last	= pArea;
    pArea->next	= NULL;
    top_area++;
    return;
}

/* OLC - Use these macros to load any new area formats that you *
 * choose to support.  See the new_load_area format below for a *
 * short example.                                               */
#if defined(KEY)
#undef KEY
#endif
#define KEY( literal, field, value )                \
                if ( !str_cmp( word, literal ) )    \
                {                                   \
                    field  = value;                 \
                    fMatch = TRUE;                  \
                    break;                          \
                }
#define SKEY( string, field )                       \
                if ( !str_cmp( word, string ) )     \
                {                                   \
                    free_string( field );           \
                    field = fread_string( fp );     \
                    fMatch = TRUE;                  \
                    break;                          \
                }

/* OLC - Snarf an 'area' header line.                           *
 * #AREAFILE                                                    *
 * Name   { All } Locke    Newbie School~                       *
 * Repop  A teacher pops in the room and says, 'Repop coming!'~ *
 * Recall 3001                                                  *
 * End                                                          */
void new_load_area( FILE *fp )
{
    AREA_DATA *pArea;
    char      *word = NULL;
    bool      fMatch;
    int       count=0;

    pArea               = alloc_perm( sizeof(*pArea) );
    pArea->age          = 15;
    pArea->nplayer      = 0;
    pArea->file_name    = str_dup( strArea );
    pArea->vnum         = top_area;
    pArea->name         = str_dup( "New Area" );
    pArea->builders     = str_dup( "" );
    pArea->prefix	= str_dup( "" );
    pArea->security     = 9;                   
    pArea->min_vnum     = 0;
    pArea->max_vnum     = 0;
    pArea->area_flags   = 0;
    pArea->pCabal	= NULL;
    pArea->bastion_max = 0;
    pArea->bastion_current = 0;

    for (count=0; count < MAX_CRIME; count++) {
      pArea->crimes[count] = 0;
    }
  /* set cabal distances to max */
    for (count  = 0; count < MAX_CABAL; count++){
      pArea->cabal_distance[count] = 999;
    }
    for ( ; ; )
    {
        word   = feof( fp ) ? "End" : fread_word( fp );
        fMatch = FALSE;
        switch ( UPPER(word[0]) )
        {
        case 'B':
            SKEY( "Builders", pArea->builders );
            break;
        case 'C':
	  SKEY( "Credits", pArea->credits );
	  if ( !str_cmp( word, "Crimes" ) ){
	    int max = fread_number( fp );
	    int i = 0;
	    
	    for ( i = 0; i < MAX_CRIME; i++){
	      if (i < max)
		pArea->crimes[i] = fread_number( fp );
	      else
		pArea->crimes[i] = 0;
	      if (i == CRIME_OBSTRUCT)
		pArea->crimes[i] = CRIME_HEAVY;
	      else if (i == CRIME_MURDER)
		pArea->crimes[i] = UMAX(CRIME_LIGHT, pArea->crimes[i]);
	    }
	    break;
	  }
	  break;
        case 'N':
            SKEY( "Name", pArea->name );
	    log_string("Loading new area");
            break;
	case 'P':
            SKEY( "Pref", pArea->prefix );
        case 'S':
            KEY( "Security", pArea->security, fread_number( fp ) );
            KEY( "Startroom", pArea->startroom, fread_number( fp ) );
            break;
        case 'F':
	  if (!str_cmp( word, "Flags")){
	    int i = 0, flag = 0;
	    flag		= fread_number( fp );

	    for (i = 0; area_flags[i].name; i ++){
	      if (area_flags[i].settable == FALSE)
		flag &= ~area_flags[i].bit;
	    }    
	    pArea->area_flags = flag;
	    break;
	  }
	  break;
        case 'V':
	  if ( !str_cmp( word, "VNUMs" ) )
            {
	      pArea->min_vnum = fread_number( fp );
	      pArea->max_vnum = fread_number( fp );
            }
	  break;
        case 'E':
	  if ( word != NULL && !str_cmp( word, "End" ) )
            {
	      fMatch = TRUE;
	      if ( area_first == NULL )
		area_first = pArea;
	      if ( area_last  != NULL )
		area_last->next = pArea;
	      area_last   = pArea;
	      pArea->next = NULL;
	      top_area++;
	      return;
            }
	  break;
	case 'M':
	  if ( !str_cmp( word, "Max_Bastions" ) ) {
	    pArea->bastion_max = fread_number( fp );
	  }
	  break;
        }
    }
}

/* Sets vnum range for area using OLC protection features. */
void assign_area_vnum( int vnum )
{
    if ( area_last->min_vnum == 0 || area_last->max_vnum == 0 )
        area_last->min_vnum = area_last->max_vnum = vnum;
    if ( vnum != URANGE( area_last->min_vnum, vnum, area_last->max_vnum ) )
    {
        if ( vnum < area_last->min_vnum )
            area_last->min_vnum = vnum;
        else
            area_last->max_vnum = vnum;
    }
}

void load_helps( FILE *fp )
{
  CABAL_INDEX_DATA* pci;
    HELP_DATA *pHelp;
    char* string;
    for ( ; ; )
    {
	pHelp		= alloc_perm( sizeof(*pHelp) );
	pHelp->level	= fread_number( fp );
	/* select type based on level and possible next word following */
	switch (pHelp->level){
	default:
	case HELP_ALL:
	  pHelp->type = 0;	
	  break;
	case HELP_CLASS:
	  pHelp->type = class_lookup( fread_string (fp ));
	  break;
	case HELP_RACE:
	  string = fread_string( fp );
	  if (!str_cmp(string, "avatar"))
	    pHelp->type = -1;
	  else
	    pHelp->type = race_lookup( string );
	  free_string( string );
	  break;
	case HELP_CABAL:
	  if ( (pci = get_cabal_index_str( fread_string( fp ))) != NULL)
	    pHelp->type = pci->vnum;
	  break;
	case HELP_PSALM:
	  pHelp->type = psalm_lookup( fread_string (fp ));
	  break;
	}
	pHelp->keyword	= fread_string( fp );
	if ( pHelp->keyword[0] == '$' )
	    break;
	pHelp->text	= fread_string( fp );
	if ( !str_cmp( pHelp->keyword, "greeting" ) )
	    help_greeting = 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++;
    }
}

void load_helps_new( ){
  HELP_DATA* pHelp;
  CABAL_INDEX_DATA* pci;
  FILE *fp;
  char* string;

  fclose( fpReserve );
  if ( ( fp = fopen( HELP_FILE, "r" ) ) == NULL ){
    fp = fopen( NULL_FILE, "r" );
    fclose (fp);
    perror( HELP_FILE );
  }
  else{
    for ( ; ; ){  
      sh_int vnum;
      char letter;
      
      letter		= fread_letter( fp );
      if ( letter != '#' ){
	bug( "Load_help: # not found.", 0 );
	exit( 1 );
      }
      vnum	     	= fread_number( fp );
      if ( vnum == 0 )
	break;
      
      if ( get_help_index( vnum ) != NULL ){
	bug( "Load_helps: vnum %d duplicated.", vnum );
	exit( 1 );
      }
      pHelp		= new_help_index();
      pHelp->vnum		= vnum;
      pHelp->level	= fread_number( fp );
      /* select type based on level and possible next word following */
      switch (pHelp->level){
      default:
      case HELP_ALL:
	pHelp->type = 0;	
	break;
      case HELP_CLASS:
	pHelp->type = class_lookup( fread_string (fp ));
	break;
      case HELP_RACE:
	string = fread_string( fp );
	if (!str_cmp(string, "avatar"))
	  pHelp->type = -1;
	else
	  pHelp->type = race_lookup( string );
	free_string( string );
	break;
      case HELP_CABAL:
	if ( (pci = get_cabal_index_str( fread_string( fp ))) != NULL)
	  pHelp->type = pci->vnum;
	break;
      case HELP_PSALM:
	pHelp->type = psalm_lookup( fread_string (fp ));
	break;
      }
      pHelp->keyword	= fread_string( fp );
      if ( pHelp->keyword[0] == '$' )
	break;
      pHelp->text	= fread_string( fp );
      if ( !str_cmp( pHelp->keyword, "greeting" ) )
	help_greeting = pHelp->text;
      if ( help_first == NULL )
	help_first = pHelp;
      if ( help_last  != NULL )
	help_last->next = pHelp;
      help_last	= pHelp;
      pHelp->next	= NULL;
    }
    fclose(fp);
    fpReserve = fopen( NULL_FILE, "r" );
  }
}

void load_old_mob( FILE *fp )
{
    MOB_INDEX_DATA *pMobIndex;
    int race;
    char name[MSL];
    if ( !area_last )
    {
        bug( "Load_mobiles: no #AREA seen yet.", 0 );
        exit( 1 );
    }
    for ( ; ; )
    {
	sh_int vnum;
	char letter;
	int iHash;
	letter				= fread_letter( fp );
	if ( letter != '#' )
	{
	    bug( "Load_mobiles: # not found.", 0 );
	    exit( 1 );
	}
	vnum				= fread_number( fp );
	if ( vnum == 0 )
	    break;
	fBootDb = FALSE;
	if ( get_mob_index( vnum ) != NULL )
	{
	    bug( "Load_mobiles: vnum %d duplicated.", vnum );
	    exit( 1 );
	}
	fBootDb = TRUE;
	pMobIndex			= alloc_perm( sizeof(*pMobIndex) );
	pMobIndex->vnum			= vnum;
        pMobIndex->area                 = area_last;
	pMobIndex->new_format		= FALSE;
	pMobIndex->player_name		= fread_string( fp );
	pMobIndex->short_descr		= fread_string( fp );
	pMobIndex->long_descr		= fread_string( fp );
	pMobIndex->description		= fread_string( fp );
	pMobIndex->long_descr[0]	= UPPER(pMobIndex->long_descr[0]);
	pMobIndex->description[0]	= UPPER(pMobIndex->description[0]);
	pMobIndex->act			= fread_flag( fp ) | ACT_IS_NPC;
	pMobIndex->affected_by		= fread_flag( fp );
	pMobIndex->pShop		= NULL;
	pMobIndex->alignment		= fread_number( fp );
	letter				= fread_letter( fp );
	pMobIndex->level		= fread_number( fp );
                                          fread_number( fp );   
                                          fread_number( fp );   
                                          fread_number( fp );   
        /* 'd'          */                fread_letter( fp );   
                                          fread_number( fp );   
        /* '+'          */                fread_letter( fp );   
                                          fread_number( fp );   
                                          fread_number( fp );   
        /* 'd'          */                fread_letter( fp );   
                                          fread_number( fp );   
        /* '+'          */                fread_letter( fp );   
                                          fread_number( fp );   
        pMobIndex->gold                 = fread_number( fp )/20; 
                                          fread_number( fp );   
        pMobIndex->start_pos            = fread_number( fp );   
        pMobIndex->default_pos          = fread_number( fp );   
  	if (pMobIndex->start_pos < POS_SLEEPING)
	    pMobIndex->start_pos = POS_STANDING;
	if (pMobIndex->default_pos < POS_SLEEPING)
	    pMobIndex->default_pos = POS_STANDING;
	if (pMobIndex->start_pos > POS_STANDING)
	    pMobIndex->start_pos = POS_STANDING;
	if (pMobIndex->default_pos > POS_STANDING)
	    pMobIndex->default_pos = POS_STANDING;
	pMobIndex->sex			= fread_number( fp );
	if (pMobIndex->sex > 3)
	    pMobIndex->sex = 0;
   	one_argument(pMobIndex->player_name,name);
   	if (name[0] == '\0' || (race =  race_lookup(name)) == 0)
   	{
            pMobIndex->race = race_lookup("human");
            pMobIndex->off_flags = OFF_DODGE|OFF_DISARM|OFF_TRIP|ASSIST_VNUM;
            pMobIndex->imm_flags = 0;
            pMobIndex->res_flags = 0;
            pMobIndex->vuln_flags = 0;
            pMobIndex->form = FORM_EDIBLE|FORM_SENTIENT|FORM_BIPED|FORM_MAMMAL;
            pMobIndex->parts = PART_HEAD|PART_ARMS|PART_LEGS|PART_HEART|PART_BRAINS|PART_GUTS;
    	}
    	else
    	{
            pMobIndex->race = race;
            pMobIndex->off_flags = OFF_DODGE|OFF_DISARM|OFF_TRIP|ASSIST_RACE|race_table[race].off;
            pMobIndex->imm_flags = race_table[race].imm;
            pMobIndex->res_flags = race_table[race].res;
            pMobIndex->vuln_flags = race_table[race].vuln;
            pMobIndex->form = race_table[race].form;
            pMobIndex->parts = race_table[race].parts;
    	}
	if ( letter != 'S' )
	{
	    bug( "Load_mobiles: vnum %d non-S.", vnum );
	    exit( 1 );
	}
        convert_mobile( pMobIndex );
	iHash			= vnum % MAX_KEY_HASH;
	pMobIndex->next		= mob_index_hash[iHash];
	mob_index_hash[iHash]	= pMobIndex;
	top_mob_index++;
        top_vnum_mob = top_vnum_mob < vnum ? vnum : top_vnum_mob;
        assign_area_vnum( vnum );
	kill_table[URANGE(0, pMobIndex->level, MAX_LEVEL-1)].number++;
    }
}

void load_old_obj( FILE *fp )
{
    OBJ_INDEX_DATA *pObjIndex;
    if ( !area_last )
    {
        bug( "Load_objects: no #AREA seen yet.", 0 );
        exit( 1 );
    }
    for ( ; ; )
    {
	sh_int vnum;
	char letter;
	int iHash;
	letter				= fread_letter( fp );
	if ( letter != '#' )
	{
	    bug( "Load_objects: # not found.", 0 );
	    exit( 1 );
	}
	vnum				= fread_number( fp );
	if ( vnum == 0 )
	    break;
	fBootDb = FALSE;
	if ( get_obj_index( vnum ) != NULL )
	{
	    bug( "Load_objects: vnum %d duplicated.", vnum );
	    exit( 1 );
	}
	fBootDb = TRUE;
	pObjIndex			= alloc_perm( sizeof(*pObjIndex) );
	pObjIndex->vnum			= vnum;
        pObjIndex->area                 = area_last;
	pObjIndex->new_format		= FALSE;
	pObjIndex->reset_num	 	= 0;
	pObjIndex->name			= fread_string( fp );
	pObjIndex->short_descr		= fread_string( fp );
	pObjIndex->description		= fread_string( fp );
                                          fread_string( fp );
	pObjIndex->short_descr[0]	= LOWER(pObjIndex->short_descr[0]);
	pObjIndex->description[0]	= UPPER(pObjIndex->description[0]);
	pObjIndex->material		= str_dup("");
	pObjIndex->class		= -1;
	pObjIndex->race			= 0;
	pObjIndex->item_type		= fread_number( fp );
	pObjIndex->extra_flags		= fread_flag( fp );
	pObjIndex->wear_flags		= fread_flag( fp );
        if (pObjIndex->item_type == ITEM_POTION && !CAN_WEAR(pObjIndex, ITEM_HOLD))
	    SET_BIT(pObjIndex->wear_flags,ITEM_HOLD);
	pObjIndex->value[0]		= fread_number( fp );
	pObjIndex->value[1]		= fread_number( fp );
	pObjIndex->value[2]		= fread_number( fp );
	pObjIndex->value[3]		= fread_number( fp );
	pObjIndex->value[4]		= 0;
	pObjIndex->level		= 0;
	pObjIndex->condition 		= 100;
	pObjIndex->weight		= fread_number( fp );
        pObjIndex->cost                 = fread_number( fp );   
                                          fread_number( fp );
	if (pObjIndex->item_type == ITEM_WEAPON
	&& (is_name("two",pObjIndex->name) || is_name("two-handed",pObjIndex->name) || is_name("claymore",pObjIndex->name)))
	    SET_BIT(pObjIndex->value[4],WEAPON_TWO_HANDS);
	for ( ; ; )
	{
	    char letter;
	    letter = fread_letter( fp );
	    if ( letter == 'A' )
	    {
		AFFECT_DATA *paf;
		paf			= alloc_perm( sizeof(*paf) );
		paf->where		= TO_OBJECT;
		paf->type		= -1;
                paf->level              = 20;
		paf->duration		= -1;
		paf->location		= fread_number( fp );
		paf->modifier		= fread_number( fp );
		paf->bitvector		= 0;
		paf->next		= pObjIndex->affected;
		pObjIndex->affected	= paf;
		top_affect++;
	    }
	    else if ( letter == 'E' )
	    {
		EXTRA_DESCR_DATA *ed;
		ed			= alloc_perm( sizeof(*ed) );
		ed->keyword		= fread_string( fp );
		ed->description		= fread_string( fp );
		ed->next		= pObjIndex->extra_descr;
		pObjIndex->extra_descr	= ed;
		top_ed++;
	    }
            else if ( letter == 'O' )
	    {
		PROG_LIST *pOprog;
		char *word;
		int trigger = 0;

		pOprog			= alloc_perm(sizeof(*pOprog));
		word			= fread_word( fp );
		if ( !(trigger = flag_lookup( word, oprog_flags )) )
		{
		    bug( "OBJprogs: invalid trigger.",0);
		    exit(1);
		}
		SET_BIT( pObjIndex->oprog_flags, trigger );
		pOprog->trig_type	= trigger;
		pOprog->vnum	 	= fread_number( fp );
		pOprog->trig_phrase	= fread_string( fp );
		pOprog->next		= pObjIndex->oprogs;
		pObjIndex->oprogs	= pOprog;
	    }
            else if ( letter == 'T' )
            {
                OBJ_SPELL_DATA *new_spell;
                new_spell                  = alloc_perm( sizeof( *new_spell ) );
                new_spell->spell           = fread_number( fp );
                new_spell->target          = fread_number( fp );
		new_spell->percent	   = fread_number( fp );
		new_spell->message	   = fread_string( fp );
		new_spell->message2	   = fread_string( fp );
		new_spell->next		   = pObjIndex->spell;
                pObjIndex->spell           = new_spell;
            }
	    else if ( letter == 'M' )
	    {
		OBJ_MESSAGE_DATA *new_message;
		new_message		= alloc_perm( sizeof( *new_message ) );
		new_message->onself	= fread_string( fp );
		new_message->onother	= fread_string( fp );
		new_message->offself	= fread_string( fp );
		new_message->offother	= fread_string( fp );
		pObjIndex->message	= new_message;
	    }
            else
	    {
		ungetc( letter, fp );
		break;
	    }
	}
        if (pObjIndex->item_type == ITEM_ARMOR)
        {
            pObjIndex->value[1] = pObjIndex->value[0];
            pObjIndex->value[2] = pObjIndex->value[1];
        }
	switch ( pObjIndex->item_type )
	{
	case ITEM_PILL:
	case ITEM_POTION:
	case ITEM_RELIC:
        case ITEM_SOCKET:
	case ITEM_ARTIFACT:
	case ITEM_SCROLL:
	case ITEM_HERB:
	    pObjIndex->value[1] = slot_lookup( pObjIndex->value[1] );
	    pObjIndex->value[2] = slot_lookup( pObjIndex->value[2] );
	    pObjIndex->value[3] = slot_lookup( pObjIndex->value[3] );
	    pObjIndex->value[4] = slot_lookup( pObjIndex->value[4] );
	    break;
	case ITEM_STAFF:
	case ITEM_WAND:
	    pObjIndex->value[3] = slot_lookup( pObjIndex->value[3] );
	    break;
	}
        convert_object( pObjIndex );
	iHash			= vnum % MAX_KEY_HASH;
	pObjIndex->next		= obj_index_hash[iHash];
	obj_index_hash[iHash]	= pObjIndex;
	top_obj_index++;
        top_vnum_obj = top_vnum_obj < vnum ? vnum : top_vnum_obj;
        assign_area_vnum( vnum );
    }
}

/* OLC - Adds a reset to a room. *
 * Similar to add_reset in olc.c */
void new_reset( ROOM_INDEX_DATA *pR, RESET_DATA *pReset )
{
    RESET_DATA *pr;
    if ( !pR )
       return;
    pr = pR->reset_last;
    if ( !pr )
    {
        pR->reset_first = pReset;
        pR->reset_last  = pReset;
    }
    else
    {
        pR->reset_last->next = pReset;
        pR->reset_last       = pReset;
        pR->reset_last->next = NULL;
    }
    top_reset++;
}

void load_reset( FILE* fp ){
  RESET_DATA *pReset = NULL;
  int iLastRoom = 0, iLastObj  = 0;
  
  for ( ; ; )
    {
      ROOM_INDEX_DATA *pRoomIndex;
      OBJ_INDEX_DATA *temp_index;
      char letter = '\0';
      
      letter = fread_letter (fp);
      /* Viri: For some reason compiler thought letter could be uninitilised at this point. */
      if (&letter == NULL)
	letter = '\0';
      
      if (letter == 'S') {
	break;
      }
      if (letter == '*' ) {
	fread_to_eol( fp );
	continue;
      }
      pReset		= alloc_perm( sizeof(*pReset) );
      pReset->command	= letter;
      fread_number( fp );
      pReset->arg1	= fread_number( fp );
      pReset->arg2	= fread_number( fp );
      pReset->arg3    = (letter == 'G' || letter == 'R') ? 0 : fread_number( fp );
      pReset->arg4    = (letter == 'P' || letter == 'M' || letter == 'T') ? fread_number(fp) : 0;
      fread_to_eol( fp );
      switch ( letter )
	{
	default:
	  bug( "Load_resets: bad command '%c'.", letter );
	  exit( 1 );
	  break;
	case 'M':
	  pRoomIndex = get_room_index ( pReset->arg3 );
	  if ( pRoomIndex )
            {
	      new_reset( pRoomIndex, pReset );
	      iLastRoom = pReset->arg3;
            }
	  break;
	case 'O':
	  temp_index = get_obj_index ( pReset->arg1 );
	  temp_index->reset_num++;
	  if ( ( pRoomIndex = get_room_index ( pReset->arg3 ) ) )
            {
	      new_reset( pRoomIndex, pReset );
	      iLastObj = pReset->arg3;
            }
	  break;
	case 'P':
	  temp_index = get_obj_index ( pReset->arg1 );
	  temp_index->reset_num++;
	  if ( ( pRoomIndex = get_room_index ( iLastObj ) ) )
                new_reset( pRoomIndex, pReset );
	    break;
	case 'G':
	case 'E':
            temp_index = get_obj_index  ( pReset->arg1 );
            temp_index->reset_num++;
            if ( ( pRoomIndex = get_room_index ( iLastRoom ) ) )
            {
                new_reset( pRoomIndex, pReset );
                iLastObj = iLastRoom;
            }
            break;
	case 'D':
/* this is now obsolete
   pRoomIndex = get_room_index( pReset->arg1 );
   pexit = pRoomIndex->exit[pReset->arg2];
   if ( pReset->arg2 < 0 || pReset->arg2 > (MAX_DIR -1) || !pRoomIndex || !pexit || !IS_SET( pexit->rs_flags, EX_ISDOOR ) )
   {
   bug( "Load_resets: 'D': exit %d not door.", pReset->arg2 );
   exit( 1 );
   }
   switch ( pReset->arg3 )
   {
   default:
   bug( "Load_resets: 'D': bad 'locks': %d." , pReset->arg3);
   case 0: break;
   case 1: SET_BIT( pexit->rs_flags, EX_CLOSED );
   SET_BIT( pexit->exit_info, EX_CLOSED ); break;
   case 2: SET_BIT( pexit->rs_flags, EX_CLOSED | EX_LOCKED );
                    SET_BIT( pexit->exit_info, EX_CLOSED | EX_LOCKED ); break;
		    }
		    break;
*/
	case 'R':
	  pRoomIndex		= get_room_index( pReset->arg1 );
	  if ( pReset->arg2 < 0 || pReset->arg2 > MAX_DIR )
	    {
	      bug( "Load_resets: 'R': bad exit %d.", pReset->arg2 );
	      exit( 1 );
	    }
	  if ( pRoomIndex )
	    new_reset( pRoomIndex, pReset );
	  break;
	case 'T':
	  if ( ( pRoomIndex = get_room_index ( pReset->arg3 ) ) ){
	    new_reset( pRoomIndex, pReset );
	  }
	  break;
	}
    }
}

void load_resets( FILE *fp )
{
    if ( !area_last )
    {
	bug( "Load_resets: no #AREA seen yet.", 0 );
	exit( 1 );
    }
    load_reset( fp );
}

/* reads a single room's data */
void read_room( FILE *fp, ROOM_INDEX_DATA* pRoomIndex, AREA_DATA* area, int vnum ){
  int watch_vnum;
  Double_List * tmp_list;
  int door = 0;

  pRoomIndex->people		= NULL;
  pRoomIndex->contents		= NULL;
  pRoomIndex->extra_descr	= NULL;
  pRoomIndex->area		= area;
  pRoomIndex->vnum		= vnum;
  pRoomIndex->watch_vnums		= NULL;
  tmp_list = pRoomIndex->watch_vnums;
  pRoomIndex->name		= fread_string( fp );
  pRoomIndex->description	= fread_string( fp );
  pRoomIndex->description2	= fread_string( fp );
  if (pRoomIndex->description2[0])
    night_count++;
  fread_number( fp );
  pRoomIndex->room_flags		= fread_flag( fp );
  pRoomIndex->room_flags2		= fread_flag( fp );
  pRoomIndex->sector_type		= fread_number( fp );
  pRoomIndex->light		= 0;
  pRoomIndex->psitimer		= 0;
  pRoomIndex->temp		= 72;
  for ( door = 0; door <= 5; door++ )
    pRoomIndex->exit[door] = NULL;
  pRoomIndex->heal_rate = 100;
  pRoomIndex->mana_rate = 100;
  
  for ( ; ; ){
    char letter = fread_letter( fp );
    if ( letter == 'S' )
      break;
    else if ( letter == 'H')                  
      pRoomIndex->heal_rate = fread_number(fp);
    else if ( letter == 'M')                  
      pRoomIndex->mana_rate = fread_number(fp); 
    else if ( letter == 'W') {
      watch_vnum = fread_number(fp);
      if (watch_vnum > 0) {
	if (pRoomIndex->watch_vnums == NULL) {
	  pRoomIndex->watch_vnums = (Double_List *) malloc (sizeof (Double_List));
	  pRoomIndex->watch_vnums->cur_entry = (void *) (long) watch_vnum;
	  pRoomIndex->watch_vnums->next_node = NULL;
	  pRoomIndex->watch_vnums->prev_node = NULL;
	  tmp_list = pRoomIndex->watch_vnums;
	}
	else {
	  tmp_list->next_node = (Double_List *) malloc (sizeof (Double_List));
	  tmp_list->next_node->cur_entry = (void *) (long) watch_vnum;
	  tmp_list->next_node->next_node = NULL;
	  tmp_list->next_node->prev_node = tmp_list;
	  tmp_list = tmp_list->next_node;
	}
      }
    }
    else if ( letter == 'C')
      {
	CABAL_INDEX_DATA* pci;
	if (pRoomIndex->pCabal)
	  {
	    bug("read_room duplicate cabal fields.",0);
	    exit(1);
	  }
	else if ( (pci = get_cabal_index_str(fread_string(fp))) != NULL)
	  pRoomIndex->cabal_vnum = pci->vnum;
      }
    else if ( letter == 'T')                  
      pRoomIndex->temp = fread_number(fp);
    else if ( letter == 'D' )
      {
	EXIT_DATA *pexit;
	door = fread_number( fp );
	if ( door < 0 || door >= MAX_DOOR ){
	  bug( "read_room: vnum %d has bad door number.", vnum );
	  exit( 1 );
	}
	pexit			= new_exit();
	pexit->description	= fread_string( fp );
	pexit->keyword		= fread_string( fp );
	pexit->rs_flags         = fread_flag( fp );
	pexit->exit_info	= pexit->rs_flags;
	pexit->key		= fread_number( fp );
	pexit->vnum		= fread_number( fp );
	pexit->orig_door        = door;
	pRoomIndex->exit[door]	= pexit;
	pRoomIndex->old_exit[door] = pexit;
	top_exit++;
      }
    else if ( letter == 'E' )
      {
	EXTRA_DESCR_DATA *ed;
	ed			= alloc_perm( sizeof(*ed) );
	ed->keyword		= fread_string( fp );
	ed->description		= fread_string( fp );
	ed->next		= pRoomIndex->extra_descr;
	pRoomIndex->extra_descr	= ed;
	top_ed++;
      }
    else if ( letter == 'O' )
      fread_string ( fp );
    else if ( letter == 'P' )
      {
	PROG_LIST *pRprog;
	char *word;
	int trigger = 0;
	
	pRprog		= alloc_perm(sizeof(*pRprog));
	word		= fread_word( fp );
	if ( !(trigger = flag_lookup( word, rprog_flags )) )
	  {
	    bug( "ROOMprogs: invalid trigger.",0);
	    exit(1);
	  }
	SET_BIT( pRoomIndex->rprog_flags, trigger );
	pRprog->trig_type	= trigger;
	pRprog->vnum		= fread_number( fp );
	pRprog->trig_phrase	= fread_string( fp );
	pRprog->next		= pRoomIndex->rprogs;
	pRoomIndex->rprogs	= pRprog;
      }
    else
      {
	bug( "read_room: vnum %d has flag not recognized.", vnum );
	exit( 1 );
      }
  }
}

/* gets the next free vnum for vir. room */
int get_vir_vnum(){
  int vnum = 0;
  /* check if there are any unused ones waiting */
  if (last_vir_vnum > 0){
    vnum = free_vir_vnums[--last_vir_vnum];
  }
  else{
    vnum = MAX_ROOM_VNUM + top_vir_room;
    top_vir_room++;
  }
  return vnum;
}
/* records  a vir vnum to be reused */
void free_vir_vnum( int vnum ){
  if (last_vir_vnum < MAX_FREE_VNUM)
    free_vir_vnums[last_vir_vnum++] = vnum;
}

/* assigns a vnum, hashes, and links a single virtual room to its exits */
void load_vir_room( ROOM_INDEX_DATA* pRoom, AREA_DATA* pArea ){
  EXIT_DATA* pexit;
  int door = 0;
  int players = 0;
  int iHash;

  /* first we give the room a new vnum which is 1 higher then the last one */
  pRoom->vnum		= get_vir_vnum();
  pRoom->area		= pArea;
  /* if this room has a cabal, we increase its total */
  if (pRoom->pCabal)
    get_parent(pRoom->pCabal)->cur_room++;


  /* we now hash and link the room to the room index table */
  iHash			= pRoom->vnum % MAX_KEY_HASH;
  pRoom->next		= room_index_hash[iHash];
  room_index_hash[iHash]= pRoom;

  /* refresh resets for new vnum */
  fix_resets( pRoom->reset_first, pRoom->vnum );

  /* deal with exits now if this is after a normal reboot */
  /* during a boot, fix_exits() deals with this */
  if (fBootDb)
    return;

  for ( door = 0; door < MAX_DOOR; door++ ){
    if ( ( pexit = pRoom->exit[door] ) == NULL )
      continue;
    else{
      ROOM_INDEX_DATA* pToRoom;
      int rev = rev_dir[door];

      if ( pexit->vnum <= 0 || (pToRoom = get_room_index(pexit->vnum)) == NULL){
	pexit->to_room = NULL;
	continue;
      }
      pexit->to_room = pToRoom;
      /* make sure the other side has a free exit */
      if (pToRoom->exit[rev] != NULL){
	char buf[MIL];
	sprintf( buf, "load_vir_room: could not link door %d for vir. room %s to room %d as exit already linked.",
		 door, pRoom->name, pexit->vnum);
	bug( buf, 0);
	continue;
      }
      else{
	pToRoom->exit[rev]		=	new_exit();
	pToRoom->exit[rev]->vnum	=	pRoom->vnum;
	pToRoom->exit[rev]->orig_door	=	rev;
	pToRoom->exit[rev]->to_room	=	pRoom;
	pToRoom->exit[rev]->rs_flags	=	pexit->rs_flags;
	pToRoom->exit[rev]->exit_info	=	pexit->exit_info;
	pToRoom->exit[rev]->key		=	pexit->key;
	if (IS_NULLSTR(pToRoom->exit[rev]->keyword))
	  pToRoom->exit[rev]->keyword	=	str_dup( pexit->keyword );
      }
    }//end if exit
  }//end for door

/* clear no reset flag if one exists, and reset room since this is after reboot */
  REMOVE_BIT( pRoom->room_flags2, ROOM_NO_RESET);
  /* we have to cheat here a bit to load objects properly */
  players = pRoom->area->nplayer;
  pRoom->area->nplayer = 0;

  reset_room( pRoom );

  pRoom->area->nplayer = players;
}

/* unlinkes and removes a single virtual room, vnum is recorded to be reused */
bool unload_vir_room( ROOM_INDEX_DATA* pRoom ){
  EXIT_DATA* pexit;
  ROOM_INDEX_DATA* prev;
  CHAR_DATA* vch;
  int iHash;
  int door;

  if (!IS_VIRROOM( pRoom))
    return FALSE;
  
  /* first we free up the virtual vnum */
  free_vir_vnum( pRoom->vnum);

  /* if this room has a cabal, we increase its total */
  if (pRoom->pCabal)
    get_parent(pRoom->pCabal)->cur_room--;


  /* unlink the exits, reverse too if any */
  for ( door = 0; door < MAX_DOOR; door++ ){
    if ( ( pexit = pRoom->exit[door] ) == NULL )
      continue;
    else{
      int rev = rev_dir[door];
      /* we free/unlink any reverse exit that leads here */
      if (pexit->to_room && pexit->to_room->exit[rev] && pexit->to_room->exit[rev]->to_room == pRoom){
	free_exit( pexit->to_room->exit[rev]);
	pexit->to_room->exit[rev] = NULL;
      }
      /* now we free this exit */
      free_exit( pexit );
      pRoom->exit[door] = NULL;
    }
  }

  /* we now throw any players/mobs out of the room */
  if (pRoom->people){
    act_new("With a flash of bright light the area around you disappears and you find yourself elsewhere!.",
	    pRoom->people, NULL, NULL, TO_ALL, POS_DEAD);
    while (pRoom->people){
      vch = pRoom->people;
      char_from_room( vch );

      if (!IS_NPC(vch) || (IS_NPC(vch) && IS_AFFECTED(vch, AFF_CHARM) && vch->leader)){
	ROOM_INDEX_DATA* was_in_room = IS_NPC( vch ) ? vch->leader->was_in_room : vch->was_in_room;
	if (was_in_room)
	  char_to_room( vch, was_in_room );
	else
	  char_to_room( vch, get_room_index( ROOM_VNUM_TEMPLE ) );
      }
      else
	extract_char( vch, TRUE );
    }
  }

  /* and we extract any objects in there */
  while (pRoom->contents){
    OBJ_DATA* obj = pRoom->contents;
    pRoom->contents = obj->next_content;
    obj_from_room( obj );
    extract_obj( obj );
  }

/* we now remove the room */
  iHash			= pRoom->vnum % MAX_KEY_HASH;
  prev			= room_index_hash[iHash];

  if (prev == NULL ){
    bug("unload_vir_room: error unlinking room vnum %d", pRoom->vnum );
    return FALSE;
  }
  if (prev == pRoom){
    room_index_hash[iHash] = prev->next;
  }
  else{
    while ( prev->next != NULL && prev->next != pRoom)
      prev = prev->next;  
    if (prev == NULL){
      bug("unlink_vir_room: room not found vnum %d.", pRoom->vnum);
      return FALSE;
    }
    prev->next = prev->next->next;
  }
  /* free the room now */
  free_room_index( pRoom );
  return TRUE;
}


void load_rooms( FILE *fp )
{
  ROOM_INDEX_DATA *pRoomIndex;
  
  if ( area_last == NULL ){
    bug( "Load_resets: no #AREA seen yet.", 0 );
    exit( 1 );
  }
  for ( ; ; ){
    sh_int vnum;
    char letter;
    int iHash;
    letter				= fread_letter( fp );
    if ( letter != '#' )
      {
	bug( "Load_rooms: # not found.", 0 );
	exit( 1 );
      }
    vnum				= fread_number( fp );
    if ( vnum == 0 )
      break;
    fBootDb = FALSE;
    if ( get_room_index( vnum ) != NULL )
      {
	bug( "Load_rooms: vnum %d duplicated.", vnum );
	exit( 1 );
      }
    fBootDb = TRUE;
    pRoomIndex			= new_room_index();
    
    read_room( fp, pRoomIndex, area_last, vnum );
    
    iHash			= vnum % MAX_KEY_HASH;
    pRoomIndex->next	= room_index_hash[iHash];
    room_index_hash[iHash]	= pRoomIndex;
    top_room++;
    top_vnum_room = top_vnum_room < vnum ? vnum : top_vnum_room;
  }
}

void load_shops( FILE *fp )
{
    SHOP_DATA *pShop;
    for ( ; ; )
    {
	MOB_INDEX_DATA *pMobIndex;
	int iTrade;
	pShop			= alloc_perm( sizeof(*pShop) );
	pShop->keeper		= fread_number( fp );
	if ( pShop->keeper == 0 )
	    break;
	for ( iTrade = 0; iTrade < MAX_TRADE; iTrade++ )
	    pShop->buy_type[iTrade]	= fread_number( fp );
	pShop->profit_buy	= fread_number( fp );
	pShop->profit_sell	= fread_number( fp );
	pShop->open_hour	= fread_number( fp );
	pShop->close_hour	= fread_number( fp );
				  fread_to_eol( fp );
	pMobIndex		= get_mob_index( pShop->keeper );
	pMobIndex->pShop	= pShop;
	if ( shop_first == NULL )
	    shop_first = pShop;
	if ( shop_last  != NULL )
	    shop_last->next = pShop;
	shop_last	= pShop;
	pShop->next	= NULL;
	top_shop++;
    }
}

void load_specials( FILE *fp )
{
    for ( ; ; )
    {
	MOB_INDEX_DATA *pMobIndex;
	char letter;
	switch ( letter = fread_letter( fp ) )
	{
	default:
	    bug( "Load_specials: letter '%c' not *MS.", letter );
	    exit( 1 );
	case 'S':
	    return;
	case '*':
	    break;
	case 'M':
	    pMobIndex		= get_mob_index	( fread_number ( fp ) );
	    pMobIndex->spec_fun	= spec_lookup	( fread_word   ( fp ) );
	    if ( pMobIndex->spec_fun == 0 )
	    {
		bug( "Load_specials: 'M': vnum %d.", pMobIndex->vnum );
		exit( 1 );
	    }
	    break;
	}
	fread_to_eol( fp );
    }
}

/* adds an exit to area list of exits */
void add_area_exit( AREA_DATA* pa, EXIT_DATA* pe ){

  if (pa->exits == NULL)
    pa->exits = pe;
  else{
    pe->next_in_area = pa->exits;
    pa->exits = pe;
  }
}

/* Translate all room exits from virtual to real. *
 * Has to be done after all rooms are read in.    *
 * Check for bad reverse exits.                   */
void fix_exits( void ){
  ROOM_INDEX_DATA *pRoomIndex;
  EXIT_DATA *pexit;
  int iHash, door;
  for ( iHash = 0; iHash < MAX_KEY_HASH; iHash++ ){
    for ( pRoomIndex  = room_index_hash[iHash]; pRoomIndex != NULL; pRoomIndex  = pRoomIndex->next ){
      bool fexit = FALSE;
      bool fVir = IS_VIRROOM( pRoomIndex );

      if (pRoomIndex->cabal_vnum)
	pRoomIndex->pCabal = get_cabal_vnum( pRoomIndex->cabal_vnum );

      for ( door = 0; door <= 5; door++ ){
	ROOM_INDEX_DATA* pToRoom;
	/* check if this room has an exit in this direction */
	if ( ( pexit = pRoomIndex->exit[door] ) == NULL )
	  continue;
	/* if an exit exists, check if the room it leads to exists */
	if ( pexit->vnum <= 0 || (pToRoom = get_room_index(pexit->vnum)) == NULL){
	  char buf[MIL];
	  sprintf( buf, "fix_exists: could not link room %d to vnum %d", pRoomIndex->vnum, pexit->vnum);
	  bug(buf, 0);
	  pexit->to_room = NULL;
	  continue;
	}
	else{
	  fexit = TRUE; 
	  pexit->to_room = pToRoom;
	  /* check for exit leading out of area */
	  if (pRoomIndex->area != pToRoom->area)
	    add_area_exit( pRoomIndex->area, pexit );

	  /* if we are working on a virtual room, and to_room is not virtual we automaticly link the other room 
	     backwards as well */
	  if (fVir && !IS_VIRROOM(pToRoom)){
	    int rev = rev_dir[door];
	    /* make sure the other side has a free exit */
	    if (pToRoom->exit[rev] != NULL){
	      char buf[MIL];
	      sprintf( buf, "fix_exits: could not link door %d for vir. room %s to room %d as exit already linked.",
		       door, pRoomIndex->name, pexit->vnum);
	      bug( buf, 0);
	      continue;
	    }
	    else{
	      pToRoom->exit[rev]		=	new_exit();
	      pToRoom->exit[rev]->orig_door	=	rev;
	      pToRoom->exit[rev]->vnum		=	pRoomIndex->vnum;
	      pToRoom->exit[rev]->to_room	=	pRoomIndex;
	      pToRoom->exit[rev]->rs_flags	=	pexit->rs_flags;
	      pToRoom->exit[rev]->exit_info	=	pexit->exit_info;
	      pToRoom->exit[rev]->key		=	pexit->key;

	      if (pToRoom->exit[rev]->to_room->area != pToRoom->area)
		add_area_exit(pToRoom->area, pToRoom->exit[rev]);
	    }
	  }
	}//end if virtual room
      }//end for door
    }//end for room in current hash position
  }//end for each hash table cell
}

void area_update( void )
{
  AREA_DATA *pArea;
  int stringdif, permdif;
  char buf[MSL];
  int hash;
  ROOM_INDEX_DATA *room;

  for ( pArea = area_first; pArea != NULL; pArea = pArea->next )
    {
      /* cabal influence check */
      AreaInfluenceUpdate( pArea );

      //raid update (no repops during a raid)
      if (pArea->raid){
	raid_update(pArea, pArea->raid );
	continue;
      }

      if ( pArea->idle < 9999 )
	pArea->idle++;
      if ( ++pArea->age < 5 )
	continue;
      /* MUDSCHOOL resets every 5 ticks min */
      else if (IS_AREA(pArea, AREA_MUDSCHOOL))
	pArea->age = 999;
      /* Areas with flag of "NOREPOP" do not reset if player is inside */
      if (IS_SET(pArea->area_flags, AREA_NOREPOP)
	  && pArea->nplayer > 0)
	continue;

      /* EMPTY means "not-dirty".  This flag is set FALSE if a player enters area.  It is only set TRUE below. */
      if ( (!pArea->empty && (pArea->nplayer == 0 || pArea->age >= 15))
	   || pArea->age >= 30)
	{
	  int string_count = nAllocString, perm_count = nAllocPerm, string_size = sAllocString, perm_size = sAllocPerm;
	  reset_area( pArea );
	  sprintf(buf,"%s has just been reset.",pArea->name);
	  wiznet(buf,NULL,NULL,WIZ_RESETS,0,0);
	  if (string_count != nAllocString || perm_count < nAllocPerm )
	    {
	      stringdif = sAllocString - string_size;
	      permdif = sAllocPerm - perm_size;
	      sprintf(buf,"Memcheck: strings %d bytes : perms %d bytes : %s : area reset", stringdif, permdif, pArea->name );
	      wiznet(buf,NULL,NULL,WIZ_MEMORY,0,0);
	    }
	  pArea->age = number_range( 0, 5 );
	  if (pArea->nplayer == 0) 
	    pArea->empty = TRUE;
	}
    }
  /* ROOMprog Triggers and tick updates */
  for ( hash = 0; hash < MAX_KEY_HASH; hash++ ){
    for ( room = room_index_hash[hash]; room; room = room->next ){
      if ( room->area->empty )
		continue;

      /* echos battle progress if people in room and armies in room */
      army_battle_echo( room );

      if ( room->rprog_delay > 0 )
	{
	  if ( --room->rprog_delay <= 0 && HAS_TRIGGER_ROOM( room, TRIG_DELAY ))
	    p_percent_trigger( NULL, NULL, room, NULL, NULL, NULL, TRIG_DELAY );
	}
      if ( HAS_TRIGGER_ROOM( room, TRIG_RANDOM ) )
	p_percent_trigger( NULL, NULL, room, NULL, NULL, NULL, TRIG_RANDOM );
    }
  }
}

/* OLC reset one room.           *
 * Called by reset_area and olc. */
void reset_room( ROOM_INDEX_DATA *pRoom )
{
    RESET_DATA  *pReset;
    CHAR_DATA   *pMob = NULL, *mob, *LastMob = NULL;
    OBJ_DATA    *pObj = NULL, *LastObj = NULL;
    TRAP_DATA* pTrap;
    int iExit, level = 0;
    bool last = FALSE;
    if ( !pRoom )
        return;
/* EXITS */
    for ( iExit = 0;  iExit < MAX_DIR;  iExit++ )
    {
        EXIT_DATA *pExit;
        if ( ( pExit = pRoom->exit[iExit] ) ){
	  pExit->exit_info = pExit->rs_flags;
	  if ( ( pExit->to_room != NULL ) && ( ( pExit = pExit->to_room->exit[rev_dir[iExit]] ) ) )
	    pExit->exit_info = pExit->rs_flags;
        }
    }
/* CABAL GUARD and ALTAR */
    if (pRoom->pCabal && pRoom->pCabal->anchor == pRoom){
      bool fAltar = FALSE;
      /* check if a galtar exists here already */
      for (mob = pRoom->pCabal->anchor->people; mob != NULL; mob = mob->next_in_room){
	if (!IS_NPC(mob))
	  continue;
	else if (mob->pIndexData->vnum == MOB_VNUM_ALTAR && is_same_cabal(mob->pCabal, pRoom->pCabal)){
	  fAltar = TRUE;
	  break;
	}
      }
      /* RESET ALTAR */
      if (!fAltar)
	reset_altar( pRoom, pRoom->pCabal );

      /* RESET GUARD */
      if (IS_CABAL(pRoom->pCabal, CABAL_GUARDMOB) && !is_captured( pRoom->pCabal)){
	reset_cabal_guard( pRoom, pRoom->pCabal );
      }
      /* we remove existing guard if there is no guardmob flag */
      else if (!IS_CABAL(pRoom->pCabal, CABAL_GUARDMOB)){
	remove_cabalguard( pRoom->pCabal );
      }
    }

/* RESETS */
    for ( pReset = pRoom->reset_first; pReset != NULL; pReset = pReset->next )
    {
        MOB_INDEX_DATA  *pMobIndex;
        OBJ_INDEX_DATA  *pObjIndex, *pObjToIndex;
        ROOM_INDEX_DATA *pRoomIndex, *pRoomIndexPrev;
	TRAP_INDEX_DATA *pTrapIndex;
	TRAP_DATA* pTrapTo;
	bool force = FALSE;
        int count = 0;
        switch ( pReset->command )
        {
        default:
            bug( "Reset_room: bad command %c.", pReset->command );
            break;
        case 'M':
            if ( !( pMobIndex = get_mob_index( pReset->arg1 ) ) )
            {
                bug( "Reset_room: 'M': bad vnum %d.", pReset->arg1 );
                continue;
            }
	    if ( ( pRoomIndex = get_room_index( pReset->arg3 ) ) == NULL )
	    {
		bug( "Reset_area: 'R': bad vnum %d.", pReset->arg3 );
		continue;
	    }
	    if (loadallmobs && pReset->arg4 == -1)
		force = TRUE;
            if (!force && pMobIndex->count >= pReset->arg2 )
	    {
		last = FALSE;
		break;
	    }
            for (mob = pRoomIndex->people; mob != NULL; mob = mob->next_in_room)
		if (mob->pIndexData == pMobIndex)
		{
		    count++;
		    if (count >= pReset->arg4)
		    {
		    	last = FALSE;
                        break;
		    }
                }
            if (!force && count >= pReset->arg4)
                break;
            pMob = create_mobile( pMobIndex );
	    pMob->homevnum = pRoom->vnum;
            if ( room_is_dark( pRoom ) )
                SET_BIT(pMob->affected_by, AFF_INFRARED);
            pRoomIndexPrev = get_room_index( pRoom->vnum - 1 );
            if ( pRoomIndexPrev && IS_SET( pRoomIndexPrev->room_flags, ROOM_PET_SHOP ) )
                SET_BIT( pMob->act, ACT_PET);
            char_to_room( pMob, pRoom );
            LastMob = pMob;
            level  = URANGE( 0, pMob->level - 2, LEVEL_HERO - 1 );
            last = TRUE;
            break;
        case 'O':
            if ( !( pObjIndex = get_obj_index( pReset->arg1 ) ) )
            {
                bug( "Reset_room: 'O' 1 : bad vnum %d", pReset->arg1 );
                bugf ("%d %d %d %d",pReset->arg1, pReset->arg2, pReset->arg3,pReset->arg4 );
                continue;
            }
            if ( !( pRoomIndex = get_room_index( pReset->arg3 ) ) )
            {
                bug( "Reset_room: 'O' 2 : bad vnum %d.", pReset->arg3 );
                bugf ("%d %d %d %d",pReset->arg1, pReset->arg2, pReset->arg3,pReset->arg4 );
                continue;
            }
//changed to allow obj repop if players present if ( pRoom->area->nplayer > 0 || count_obj_list( pObjIndex, pRoom->contents ) > 0 )
	    if ( count_obj_list( pObjIndex, pRoom->contents ) > 0 )
	      {
		last = FALSE;
		break;
	      }
            if (!can_spawn(pObjIndex))
	      break;
            pObj = create_object( pObjIndex,UMIN(number_fuzzy( level ), LEVEL_HERO -1) );
	    pObj->homevnum = pRoom->vnum;
            obj_to_room( pObj, pRoom );
	    LastObj = pObj;
	    last = TRUE;
	    break;
	case 'P':
            if ( !( pObjIndex = get_obj_index( pReset->arg1 ) ) )
	    {
		bug( "Reset_area: 'P': bad vnum %d.", pReset->arg1 );
		continue;
	    }
            if ( !( pObjToIndex = get_obj_index( pReset->arg3 ) ) )
	    {
		bug( "Reset_area: 'P': bad vnum %d.", pReset->arg3 );
		continue;
	    }
//Viri: allow conainted objects to reset with players ni area            if (pRoom->area->nplayer > 0 || ( LastObj = get_obj_type( pObjToIndex ) ) == NULL
            if (( LastObj = get_obj_type( pObjToIndex, pRoom ) ) == NULL
		|| ( LastObj->in_room == NULL && !last) 
		|| (count = count_obj_list(pObjIndex,LastObj->contains)) > pReset->arg4 )
	      {
		last = FALSE;
		break;
	      }
	    while (count < pReset->arg4)
	    {
	      if (!can_spawn(pObjIndex))
		break;
	      pObj = create_object( pObjIndex, number_fuzzy( LastObj->level ) );
	      pObj->homevnum = LastObj->homevnum;
	      obj_to_obj( pObj, LastObj );
	      count++;
	    }
            LastObj->value[1] = LastObj->pIndexData->value[1];
	    last = TRUE;
	    break;
        case 'T':
	  if ( (pTrapIndex = get_trap_index( pReset->arg1 )) == NULL ){
	    bug( "Reset_room: 'T' 1 : bad vnum %d", pReset->arg1 );
	    bugf ("%d %d %d %d",pReset->arg1, 
		  pReset->arg2, pReset->arg3,pReset->arg4 );
	    continue;
	  }
	  if ( (pRoomIndex = get_room_index( pReset->arg3 )) == NULL ){
	    bug( "Reset_room: 'T' 2 : bad vnum %d.", pReset->arg3 );
	    bugf ("%d %d %d %d",pReset->arg1, 
		  pReset->arg2, pReset->arg3,pReset->arg4 );
	    continue;
	  }
	  /* check of obj reset requierments */
	  if (pReset->arg2 == TRAP_ON_OBJ){
	    if ( !last || pObj == NULL){
	      continue;
	    }
	    else
	      pTrapTo = pObj->traps;
	  }
	  else if (pReset->arg2 == TRAP_ON_EXIT ){
	    if (pRoomIndex->exit[pReset->arg4] == NULL){
	      bug( "Reset_room 'T' 4 : no exit found for trap in room %d.",
		   pRoomIndex->vnum);
	      bugf ("%d %d %d %d",pReset->arg1, 
		    pReset->arg2, pReset->arg3,pReset->arg4 );
	      continue;
	    }
	    else
	      pTrapTo = pRoomIndex->exit[pReset->arg4]->traps;
	  }
	  else{
	    bug( "Reset_room 'T' 5 : invalid trap in room %d.",
		 pRoomIndex->vnum);
	    bugf ("%d %d %d %d",pReset->arg1, 
		  pReset->arg2, pReset->arg3,pReset->arg4 );
	    continue;
	  }
	  /* make sure we need to create a trap */
	  if (pTrapTo && pTrapTo->pIndexData == pTrapIndex){
	    init_trap( pTrapTo, pTrapTo->pIndexData );
	    continue;
	  }
	  else if (pTrapTo){
	    extract_trap( pRoomIndex->exit[pReset->arg4]->traps );
	  }
	  /* create the trap */
	  if ( (pTrap = create_trap( pTrapIndex, NULL)) == NULL){
	    bug( "Reset_room 'T' 5 : could not load trap in room %d.",
		 pRoomIndex->vnum);
	    bugf ("%d %d %d %d",pReset->arg1, 
		  pReset->arg2, pReset->arg3,pReset->arg4 );
	    continue;
	  }
	  /* attach the trap */
	  if (pReset->arg2 == TRAP_ON_EXIT){
	    trap_to_exit( pTrap, pRoomIndex->exit[pReset->arg4] );
	  }
	  else if (pReset->arg2 == TRAP_ON_OBJ){
	    trap_to_obj( pTrap, pObj );
	  }
	  break;
	case 'G':
	case 'E':
            if ( !( pObjIndex = get_obj_index( pReset->arg1 ) ) )
	    {
		bug( "Reset_area: 'E' or 'G': bad vnum %d.", pReset->arg1 );
		continue;
	    }
	    if ( !last )
		break;
            if ( !LastMob )
	    {
                bug( "Reset_area: 'E' or 'G': null mob for vnum %d.",pReset->arg1 );
		last = FALSE;
		break;
	    }
            if ( LastMob->pIndexData->pShop )
	    {
		int olevel = 0, i, j;
		if (!can_spawn(pObjIndex))
		  break;
                pObj = create_object( pObjIndex,UMIN( number_fuzzy( level ), LEVEL_HERO - 1 ) );
		if (!pObjIndex->new_format){
		  switch ( pObjIndex->item_type )
                    {
                    default: olevel = 0;
                    case ITEM_PILL:
		    case ITEM_RELIC:
		    case ITEM_SOCKET:
		    case ITEM_ARTIFACT:
                    case ITEM_POTION:
                    case ITEM_SCROLL:
                        olevel = 53;
                        for (i = 1; i < 5; i++)
                            if (pObjIndex->value[i] > 0)
			      for (j = 0; j < MAX_CLASS_NOW; j++)
				    olevel = UMIN(olevel, skill_table[pObjIndex->value[i]].skill_level[j]);
                       olevel = UMAX(0,(olevel * 3 / 4) - 2);
                       break;
                    case ITEM_WAND:         olevel = number_range( 10, 20 ); break;
                    case ITEM_STAFF:        olevel = number_range( 15, 25 ); break;
                    case ITEM_ARMOR:        olevel = number_range(  5, 15 ); break;
                    case ITEM_THROW:        olevel = number_range(  5, 15 ); break;
                    case ITEM_WEAPON:       olevel = number_range(  5, 15 ); break;
                    case ITEM_TREASURE:     olevel = number_range( 10, 20 ); break;
 		    case ITEM_RANGED:       olevel = number_range( 10, 20 ); break;
                    case ITEM_INSTRUMENT:   olevel = number_range(  5, 15 ); break;
                    case ITEM_KEY:          olevel = number_range(  1,  5 ); break;
		    case ITEM_PROJECTILE:   olevel = number_range(  5, 15 ); break;
                    }
		}
		SET_BIT( pObj->extra_flags, ITEM_INVENTORY );
            }
	    else
	    {
	      if (!can_spawn(pObjIndex))
		break;
	      pObj = create_object( pObjIndex,UMIN( number_fuzzy( level ), LEVEL_HERO - 1 ) );
	    }
	    pObj->homevnum = LastMob->homevnum;
	    /* hlh	    pObj->homevnum = LastMob->homevnum = -1; */
	    if (!can_take(LastMob, pObj)){
	      char buf[MIL];
	      sprintf(buf, "Bad reset: %s cannot hold vnum:[%d] (use noalign flag).",
		      PERS2(LastMob), pObjIndex->vnum);
	      bug(buf, pObjIndex->vnum);
	    }
            obj_to_ch( pObj, LastMob );
            if ( pReset->command == 'E' ){
	      REMOVE_BIT( pObj->extra_flags, ITEM_INVENTORY );
	      equip_char( LastMob, pObj, pReset->arg3 );
	    }
            last = TRUE;
            break;
        case 'D':
	  break;
	case 'R':
	  if ( !( pRoomIndex = get_room_index( pReset->arg1 ) ) )
	    {
	      bug( "Reset_area: 'R': bad vnum %d.", pReset->arg1 );
	      continue;
	    }
	    {
                EXIT_DATA *pExit;
		int d0, d1;
		for ( d0 = 0; d0 < pReset->arg2 - 1; d0++ )
		{
                    d1                   = number_range( d0, pReset->arg2-1 );
                    pExit                = pRoomIndex->exit[d0];
                    pRoomIndex->exit[d0] = pRoomIndex->exit[d1];
                    pRoomIndex->exit[d1] = pExit;
		}
	    }
	    break;
	}
    }
}

/* OLC - Reset one area. */
void reset_area( AREA_DATA *pArea )
{
    ROOM_INDEX_DATA *pRoom;
    int  vnum;
    for ( vnum = pArea->min_vnum; vnum <= pArea->max_vnum; vnum++ ){
      if ( ( pRoom = get_room_index(vnum) ) != NULL && !IS_SET(pRoom->room_flags2, ROOM_NO_RESET))
	reset_room(pRoom);
    }
    /* reset virtual rooms that belong to this area */
    for ( vnum = MAX_ROOM_VNUM; vnum < MAX_ROOM_VNUM + top_vir_room; vnum++ ){
      if ( ( pRoom = get_room_index(vnum) ) != NULL && pRoom->area == pArea 
	   && !IS_SET(pRoom->room_flags2, ROOM_NO_RESET))
      	reset_room(pRoom);
    }
    return;
}

CHAR_DATA *create_mobile( MOB_INDEX_DATA *pMobIndex )
{
    CHAR_DATA *mob;
    int i;
    AFFECT_DATA af;
    mobile_count++;
    if ( pMobIndex == NULL )
    {
	bug( "Create_mobile: NULL pMobIndex.", 0 );
	exit( 1 );
    }
    mob = new_char();
    mob->pIndexData	= pMobIndex;
    mob->name           = str_dup( pMobIndex->player_name );
    mob->short_descr    = str_dup( pMobIndex->short_descr );
    mob->long_descr     = str_dup( pMobIndex->long_descr );
    mob->description    = str_dup( pMobIndex->description );
    mob->id		= get_mob_id();
    mob->spec_fun	= pMobIndex->spec_fun;
    mob->homevnum	= 0;
    mob->prompt		= NULL;
    if (pMobIndex->gold == 0)
	mob->gold   = 0;
    else
        mob->gold       = number_range(pMobIndex->gold/2, pMobIndex->gold * 3/2);
    if (pMobIndex->new_format)
    {
 	mob->group		= pMobIndex->group;
	if (pMobIndex->pCabal)
	  mob->pCabal		= get_cabal_vnum(pMobIndex->pCabal->vnum);
	mob->act 		= pMobIndex->act;
	mob->act2 		= pMobIndex->act2;
        mob->comm               = COMM_NOCHANNELS|COMM_NOYELL|COMM_NOTELL;
	mob->affected_by	= pMobIndex->affected_by;
	mob->affected2_by	= pMobIndex->affected2_by;
	mob->alignment		= pMobIndex->alignment;
	mob->level		= pMobIndex->level;
	mob->hitroll		= pMobIndex->hitroll;
	mob->damroll		= pMobIndex->damage[DICE_BONUS];
        mob->max_hit            = dice(pMobIndex->hit[DICE_NUMBER],pMobIndex->hit[DICE_TYPE])+pMobIndex->hit[DICE_BONUS];
        mob->hit                = mob->max_hit;
        mob->max_mana           = dice(pMobIndex->mana[DICE_NUMBER],pMobIndex->mana[DICE_TYPE])+pMobIndex->mana[DICE_BONUS];
	mob->mana		= mob->max_mana;
	mob->damage[DICE_NUMBER]= pMobIndex->damage[DICE_NUMBER];
	mob->damage[DICE_TYPE]	= pMobIndex->damage[DICE_TYPE];
	mob->dam_type		= pMobIndex->dam_type;
        if (mob->dam_type == 0)
    	    switch(number_range(1,3))
            {
            case (1): mob->dam_type = 3;        break;           
            case (2): mob->dam_type = 7;        break;              
            case (3): mob->dam_type = 11;       break;              
            }
	for (i = 0; i < 4; i++)
            mob->armor[i]       = pMobIndex->ac[i]; 
	mob->off_flags		= pMobIndex->off_flags;
	mob->imm_flags		= pMobIndex->imm_flags;
	mob->res_flags		= pMobIndex->res_flags;
	mob->vuln_flags		= pMobIndex->vuln_flags;
	mob->start_pos		= pMobIndex->start_pos;
	mob->default_pos	= pMobIndex->default_pos;
	mob->sex		= pMobIndex->sex;
        if (mob->sex == 3)              
            mob->sex = number_range(1,2);
	mob->race		= pMobIndex->race;
	mob->form		= pMobIndex->form;
	mob->parts		= pMobIndex->parts;
	mob->size		= pMobIndex->size;
	mob->extracted		= FALSE;
    	for (i = 0; i < MAX_STATS-1; i ++)
            mob->perm_stat[i] = UMIN(25,11 + mob->level/4);
        mob->perm_stat[STAT_LUCK] = 16;	
        if (IS_SET(mob->act,ACT_WARRIOR))
        {
            mob->perm_stat[STAT_STR] += 3;
            mob->perm_stat[STAT_INT] -= 1;
            mob->perm_stat[STAT_CON] += 2;
        }
        if (IS_SET(mob->act,ACT_THIEF))
        {
            mob->perm_stat[STAT_DEX] += 3;
            mob->perm_stat[STAT_INT] += 1;
            mob->perm_stat[STAT_WIS] -= 1;
        }
        if (IS_SET(mob->act,ACT_CLERIC))
        {
            mob->perm_stat[STAT_WIS] += 3;
            mob->perm_stat[STAT_DEX] -= 1;
            mob->perm_stat[STAT_STR] += 1;
        }
        if (IS_SET(mob->act,ACT_MAGE))
        {
            mob->perm_stat[STAT_INT] += 3;
            mob->perm_stat[STAT_STR] -= 1;
            mob->perm_stat[STAT_DEX] += 1;
        }
        if (IS_SET(mob->off_flags,OFF_FAST))
            mob->perm_stat[STAT_DEX] += 2;
        mob->perm_stat[STAT_STR] += mob->size - SIZE_MEDIUM;
        mob->perm_stat[STAT_CON] += (mob->size - SIZE_MEDIUM) / 2;
	if (IS_AFFECTED(mob,AFF_SANCTUARY))
	{
	    af.where	 = TO_AFFECTS;
	    af.type      = skill_lookup("sanctuary");
	    af.level     = mob->level;
	    af.duration  = -1;
	    af.location  = APPLY_NONE;
	    af.modifier  = 0;
	    af.bitvector = AFF_SANCTUARY;
	    affect_to_char( mob, &af );
	}
	if (IS_AFFECTED(mob,AFF_HASTE))
	{
	    af.where	 = TO_AFFECTS;
	    af.type      = skill_lookup("haste");
    	    af.level     = mob->level;
      	    af.duration  = -1;
    	    af.location  = APPLY_DEX;
            af.modifier  = 1 + (mob->level >= 18) + (mob->level >= 25) + (mob->level >= 32);
    	    af.bitvector = AFF_HASTE;
    	    affect_to_char( mob, &af );
	}
	if (IS_AFFECTED(mob,AFF_PROTECT_EVIL))
	{
	    af.where	 = TO_AFFECTS;
	    af.type	 = skill_lookup("protection evil");
	    af.level	 = mob->level;
	    af.duration	 = -1;
	    af.location	 = APPLY_SAVING_SPELL;
	    af.modifier	 = -1;
	    af.bitvector = AFF_PROTECT_EVIL;
	    affect_to_char(mob,&af);
	}
        if (IS_AFFECTED(mob,AFF_PROTECT_GOOD))
        {
	    af.where	 = TO_AFFECTS;
            af.type      = skill_lookup("protection good");
            af.level     = mob->level;
            af.duration  = -1;
            af.location  = APPLY_SAVING_SPELL;
            af.modifier  = -1;
            af.bitvector = AFF_PROTECT_GOOD;
            affect_to_char(mob,&af);
        }
    }
    else
    {
	mob->act		= pMobIndex->act;
	mob->act2		= pMobIndex->act2;
	mob->affected_by	= pMobIndex->affected_by;
	mob->alignment		= pMobIndex->alignment;
	mob->level		= pMobIndex->level;
	mob->hitroll		= pMobIndex->hitroll;
	mob->damroll		= 0;
        mob->max_hit            = mob->level * 8 + number_range(mob->level * mob->level/4,mob->level * mob->level);
	mob->max_hit *= .9;
	mob->hit		= mob->max_hit;
	mob->max_mana		= 100 + dice(mob->level,10);
	mob->mana		= mob->max_mana;
	switch(number_range(1,3))
	{
            case (1): mob->dam_type = 3;        break;            
            case (2): mob->dam_type = 7;        break;              
            case (3): mob->dam_type = 11;       break;             
	}
	for (i = 0; i < 3; i++)
	    mob->armor[i]	= interpolate(mob->level,100,-100);
	mob->armor[3]		= interpolate(mob->level,100,0);
	mob->race		= pMobIndex->race;
	mob->off_flags		= pMobIndex->off_flags;
	mob->imm_flags		= pMobIndex->imm_flags;
	mob->res_flags		= pMobIndex->res_flags;
	mob->vuln_flags		= pMobIndex->vuln_flags;
	mob->start_pos		= pMobIndex->start_pos;
	mob->default_pos	= pMobIndex->default_pos;
	mob->sex		= pMobIndex->sex;
	mob->form		= pMobIndex->form;
	mob->parts		= pMobIndex->parts;
	mob->size		= SIZE_MEDIUM;
	mob->extracted		= FALSE;
        for (i = 0; i < MAX_STATS-1; i ++)
            mob->perm_stat[i] = 11 + mob->level/4;
        mob->perm_stat[STAT_LUCK] = 16;
    }
    mob->position = mob->start_pos;
    mob->next		= char_list;
    char_list		= mob;
    pMobIndex->count++;
    return mob;
}

/* refreshes list of resets with a new room number */
void fix_resets( RESET_DATA* pReset, int room_vnum ){
  for (; pReset; pReset = pReset->next ){
    switch ( pReset->command ){
    case 'M':
    case 'O':
    case 'T':
      pReset->arg3 = room_vnum;		break;

    case 'R':
    case 'D':
      pReset->arg1 = room_vnum;		break;
    }
  }
}

void clone_room( ROOM_INDEX_DATA* src, ROOM_INDEX_DATA* dest, bool fFull ){
  EXTRA_DESCR_DATA *pExtra, *ed;
  RESET_DATA *pReset, *pr, *pr_last = NULL;
  Double_List *watch, *tmp_list;

/* cabal */
  dest->pCabal		=	src->pCabal;
  
/* name etc. */
  free_string( dest->name );
  free_string( dest->description );
  free_string( dest->description2 );

  dest->name		=	str_dup( src->name );
  dest->description	=	str_dup( src->description  );
  dest->description2	=	str_dup( src->description2 );

/* numeric data */
  dest->sector_type	=	src->sector_type;
  dest->room_flags	=	src->room_flags;
  dest->room_flags2	=	src->room_flags2;
  dest->heal_rate	=	src->heal_rate;
  dest->mana_rate	=	src->mana_rate;
  dest->temp		=	src->temp;


/* extra desc. data */
  while ( (pExtra = dest->extra_descr) != NULL){
    dest->extra_descr = pExtra->next;
    free_extra_descr( pExtra );
  }

  for ( pExtra = src->extra_descr; pExtra; pExtra = pExtra->next ){
    ed			=	new_extra_descr();
    ed->keyword		=	str_dup( pExtra->keyword );
    ed->description	=	str_dup( pExtra->description );
    ed->next		=	dest->extra_descr;
    dest->extra_descr	=	ed;
  }

/* rest of data is only copied on full copy */
  if (!fFull)
    return;

/* resets, we have to copy them in such way as to preserve their current order */
  while ( (pReset = dest->reset_first)){
    dest->reset_first = pReset->next;
    free_reset_data( pReset );
  }
  
  for ( pReset = src->reset_first; pReset; pReset = pReset->next ){
    pr			=	new_reset_data();
    pr->command		=	pReset->command;
    pr->arg1		=	pReset->arg1;
    pr->arg2		=	pReset->arg2;
    pr->arg3		=	pReset->arg3;
    pr->arg4		=	pReset->arg4;

    if (dest->reset_first == NULL){
      dest->reset_first = pr;
      pr->next = NULL;
      pr_last = pr;
    }
    else{
      pr_last->next = pr;
      pr->next = NULL;
      pr_last = pr;
    }      
  }
  /* we now refresh the resets with proper room number */
  fix_resets( dest->reset_first, dest->vnum );
  
/* watch vnums */
  while ( dest->watch_vnums ){
    Double_List * tmp_list = dest->watch_vnums;
    dest->watch_vnums = tmp_list->next_node;
    free (tmp_list);
  }

  for (watch = src->watch_vnums; watch; watch = watch->next_node){
    tmp_list = (Double_List *) malloc (sizeof (Double_List));
    
    tmp_list->cur_entry =	watch->cur_entry;

    if (dest->watch_vnums == NULL){
      tmp_list->next_node	=	NULL;
      tmp_list->prev_node	=	NULL;
      dest->watch_vnums		=	tmp_list;
    }
    else{
      tmp_list->next_node	=	dest->watch_vnums;
      tmp_list->prev_node	=	NULL;
      dest->watch_vnums->prev_node =	tmp_list;
      dest->watch_vnums		=	tmp_list;
    }
  }
}


void clone_mobile(CHAR_DATA *parent, CHAR_DATA *clone)
{
    int i;
    AFFECT_DATA *paf, *paf_next;
    if ( parent == NULL || clone == NULL || !IS_NPC(parent))
	return;
    for (paf = clone->affected; paf != NULL; paf = paf_next)
    {
        paf_next = paf->next;
        affect_remove(clone, paf);
    }
    clone->homevnum	= parent->homevnum;
    clone->name 	= str_dup(parent->name);
    clone->short_descr	= str_dup(parent->short_descr);
    clone->long_descr	= str_dup(parent->long_descr);
    clone->description	= str_dup(parent->description);
    clone->group	= parent->group;
    clone->sex		= parent->sex;
    clone->class	= parent->class;
    clone->race		= parent->race;
    clone->level	= parent->level;
    clone->trust	= 0;
    clone->timer	= parent->timer;
    clone->wait		= parent->wait;
    clone->hit		= parent->hit;
    clone->max_hit	= parent->max_hit;
    clone->mana		= parent->mana;
    clone->max_mana	= parent->max_mana;
    clone->move		= parent->move;
    clone->max_move	= parent->max_move;
    clone->gold		= parent->gold;
    clone->exp		= parent->exp;
    clone->act		= parent->act;
    clone->act2		= parent->act2;
    clone->comm		= parent->comm;
    clone->imm_flags	= parent->imm_flags;
    clone->res_flags	= parent->res_flags;
    clone->vuln_flags	= parent->vuln_flags;
    clone->invis_level	= parent->invis_level;
    clone->affected_by	= parent->affected_by;
    clone->affected2_by	= parent->affected2_by;
    clone->position	= parent->position;
    clone->practice	= parent->practice;
    clone->train	= parent->train;
    clone->savingaffl	= parent->savingaffl;
    clone->savingmaled	= parent->savingmaled;
    clone->savingmental	= parent->savingmental;
    clone->savingbreath	= parent->savingbreath;
    clone->savingspell	= parent->savingspell;
    clone->alignment	= parent->alignment;
    clone->hitroll	= parent->hitroll;
    clone->damroll	= parent->damroll;
    clone->wimpy	= parent->wimpy;
    clone->form		= parent->form;
    clone->parts	= parent->parts;
    clone->size		= parent->size;
    clone->extracted	= parent->extracted;
    clone->off_flags	= parent->off_flags;
    clone->dam_type	= parent->dam_type;
    clone->start_pos	= parent->start_pos;
    clone->default_pos	= parent->default_pos;
    clone->spec_fun	= parent->spec_fun;
    for (i = 0; i < 4; i++)
    	clone->armor[i]	= parent->armor[i];
    for (i = 0; i < MAX_STATS; i++)
    {
	clone->perm_stat[i]	= parent->perm_stat[i];
	clone->mod_stat[i]	= parent->mod_stat[i];
    }
    for (i = 0; i < 3; i++)
	clone->damage[i]	= parent->damage[i];
    for (paf = parent->affected; paf != NULL; paf = paf_next)
    {
        paf_next = paf->next;
        affect_to_char(clone, paf);
    }
}


/* creates a trap, attatches to global list, and zeros the values */
TRAP_DATA* create_trap(TRAP_INDEX_DATA* pTrapIndex, CHAR_DATA* owner){
  TRAP_DATA* tr = new_trap();

  tr->pIndexData	= pTrapIndex;
  init_trap( tr, pTrapIndex);

  if (owner != NULL)
    trap_to_char( tr, owner );
  else
    tr->owner = owner;
  tr->on_obj = NULL;
  tr->on_exit = NULL;

/* attatch to global list */
  if (trap_list == NULL)
    trap_list = tr;
  else{
    tr->next = trap_list;
    trap_list = tr;
  }
  return tr;
}

OBJ_DATA *create_object( OBJ_INDEX_DATA *pObjIndex, int level)
{
    AFFECT_DATA *paf;
    OBJ_DATA *obj;
    if ( pObjIndex == NULL )
    {
	bug( "Create_object: NULL pObjIndex.", 0 );
	exit( 1 );
    }
    obj = new_obj();
    obj->pIndexData	= pObjIndex;
    obj->in_room	= NULL;
    obj->next_bidobj	= NULL;
    obj->enchanted	= FALSE;
    obj->eldritched	= FALSE;
    if (pObjIndex->new_format)
	obj->level = pObjIndex->level;
    else
	obj->level		= UMAX(0,level);
    if (pObjIndex->pCabal)
      obj->pCabal		= get_cabal_vnum(pObjIndex->pCabal->vnum);
    obj->race		= pObjIndex->race;
    obj->class		= pObjIndex->class;
    obj->vnum		= pObjIndex->vnum;
    obj->wear_loc	= -1;
    obj->name           = str_dup( pObjIndex->name );
    obj->short_descr    = str_dup( pObjIndex->short_descr );
    obj->description    = str_dup( pObjIndex->description );
    obj->material       = str_dup(pObjIndex->material);
    obj->item_type	= pObjIndex->item_type;
    obj->extra_flags	= pObjIndex->extra_flags;
    obj->wear_flags	= pObjIndex->wear_flags;
    obj->value[0]	= pObjIndex->value[0];
    obj->value[1]	= pObjIndex->value[1];
    obj->value[2]	= pObjIndex->value[2];
    obj->value[3]	= pObjIndex->value[3];
    obj->value[4]	= pObjIndex->value[4];
    obj->weight		= pObjIndex->weight;
    obj->cost           = pObjIndex->cost;
    obj->condition       = pObjIndex->condition;
    obj->homevnum	= 0;
    obj->idle		= 0;
    obj->extracted	= FALSE;
    obj->owner          = 0;
    obj->traps		= NULL;
    switch ( obj->item_type )
    {
    default:
	bug( "Read_object: vnum %d bad type.", pObjIndex->vnum );
	break;
    case ITEM_CABAL:
        break;
    case ITEM_LIGHT:
	if (obj->value[2] == 999)
            obj->value[2] = -1;
	break;
    case ITEM_FURNITURE:
    case ITEM_TRASH:
    case ITEM_CONTAINER:
    case ITEM_DRINK_CON:
    case ITEM_KEY:
    case ITEM_BOAT:
    case ITEM_CORPSE_NPC:
    case ITEM_CORPSE_PC:
    case ITEM_FOUNTAIN:
    case ITEM_MAP:
    case ITEM_CLOTHING:
    case ITEM_TREASURE:
    case ITEM_INSTRUMENT:
    case ITEM_GEM:
    case ITEM_RANGED:
    case ITEM_PROJECTILE:
    case ITEM_JEWELRY:
	break;
    case ITEM_FOOD:
	if (obj->value[4] == 0)
            obj->value[4] = 168;
	obj->timer = obj->value[4];
	break;
    case ITEM_HERB:
      obj->timer = number_range( 500, 1000);
    case ITEM_RELIC:
    case ITEM_SOCKET:
    case ITEM_ARTIFACT:
    case ITEM_SCROLL:
	if (level != -1 && !pObjIndex->new_format)
            obj->value[0] = number_fuzzy( obj->value[0] );
	break;
    case ITEM_WAND:
    case ITEM_STAFF:
	if (level != -1 && !pObjIndex->new_format)
	{
	    obj->value[0]	= number_fuzzy( obj->value[0] );
	    obj->value[1]	= number_fuzzy( obj->value[1] );
	    obj->value[2]	= obj->value[1];
	}
	break;
    case ITEM_THROW:
    case ITEM_WEAPON:
	if (level != -1 && !pObjIndex->new_format)
	{
	    obj->value[1] = number_fuzzy( number_fuzzy( 1 * level / 4 + 2 ) );
	    obj->value[2] = number_fuzzy( number_fuzzy( 3 * level / 4 + 6 ) );
	}
	break;
    case ITEM_ARMOR:
	if (level != -1 && !pObjIndex->new_format)
	{
	    obj->value[0]	= number_fuzzy( level / 5 + 3 );
	    obj->value[1]	= number_fuzzy( level / 5 + 3 );
	    obj->value[2]	= number_fuzzy( level / 5 + 3 );
	}
	break;
    case ITEM_POTION:
    case ITEM_PILL:
	if (level != -1 && !pObjIndex->new_format)
	    obj->value[0] = number_fuzzy( number_fuzzy( obj->value[0] ) );
	break;
    case ITEM_MONEY:
	if (!pObjIndex->new_format)
	    obj->value[0]	= obj->cost;
	break;
    }
    for (paf = pObjIndex->affected; paf != NULL; paf = paf->next) 
	if ( paf->location == APPLY_SPELL_AFFECT )
	    affect_to_obj(obj,paf);
    obj->next		= object_list;
    object_list		= obj;
    pObjIndex->count++;
    return obj;
}

void clone_object(OBJ_DATA *parent, OBJ_DATA *clone)
{
    int i;
    AFFECT_DATA *paf;
    EXTRA_DESCR_DATA *ed,*ed_new;
    if (parent == NULL || clone == NULL)
	return;
    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->extra_flags	= parent->extra_flags;
    clone->wear_flags	= parent->wear_flags;
    clone->weight	= parent->weight;
    clone->cost		= parent->cost;
    clone->pCabal	= parent->pCabal;
    clone->race		= parent->race;
    clone->class	= parent->class;
    clone->vnum		= parent->vnum;
    clone->level	= parent->level;
    clone->condition	= parent->condition;
    if (!IS_NULLSTR(clone->material))
      free_string(clone->material);
    clone->material	= str_dup(parent->material);
    clone->timer	= parent->timer;
    clone->extracted	= parent->extracted;
    for (i = 0;  i < 5; i ++)
	clone->value[i]	= parent->value[i];
    clone->enchanted	= parent->enchanted;
    for (paf = parent->affected; paf != NULL; paf = paf->next) 
	affect_to_obj(clone,paf);
    for (ed = parent->extra_descr; ed != NULL; ed = ed->next)
    {
        ed_new                  = new_extra_descr();
        ed_new->keyword    	= str_dup( ed->keyword);
        ed_new->description     = str_dup( ed->description );
        ed_new->next           	= clone->extra_descr;
        clone->extra_descr  	= ed_new;
    }
}

void clear_char( CHAR_DATA *ch )
{
    static CHAR_DATA ch_zero;
    int i;
    *ch				= ch_zero;
    ch->name			= &str_empty[0];
    ch->short_descr		= &str_empty[0];
    ch->long_descr		= &str_empty[0];
    ch->description		= &str_empty[0];
    ch->prompt                  = &str_empty[0];
    ch->logon			= mud_data.current_time;
    ch->lines			= PAGELEN;
    for (i = 0; i < 4; i++)
    	ch->armor[i]		= 100;
    ch->position		= POS_STANDING;
    if (!IS_NPC(ch))
    {
	ch->hit			= pc_race_table[ch->race].hit;
	ch->mana		= pc_race_table[ch->race].mana;
    }
    else
    {
        ch->hit			= 20;
        ch->mana		= 100;
    }
    ch->max_hit			= ch->hit;
    ch->max_mana		= ch->mana;
    ch->move			= 100;
    ch->max_move		= ch->move;
    for (i = 0; i < MAX_STATS; i ++)
    {
	ch->perm_stat[i] = 13; 
	ch->mod_stat[i] = 0;
    }
    ch->perm_stat[STAT_LUCK] = 16; 
}

char *get_extra_descr( const char *name, EXTRA_DESCR_DATA *ed )
{
    for ( ; ed != NULL; ed = ed->next )
	if ( is_name( (char *) name, ed->keyword ) )
	    return ed->description;
    return NULL;
}

char *get_auto_extra_descr( const char *name, EXTRA_DESCR_DATA *ed, bool fAuto)
{
    for ( ; ed != NULL; ed = ed->next )
      if ( (fAuto && is_auto_name( (char *) name, ed->keyword ) )
	   || is_name( (char *) name, ed->keyword ) )
	return ed->description;
    return NULL;
}

/* Translates mob virtual number to its mob index struct. *
 * Hash table lookup.                                     */
MOB_INDEX_DATA *get_mob_index( int vnum )
{
    MOB_INDEX_DATA *pMobIndex;
    for ( pMobIndex  = mob_index_hash[vnum % MAX_KEY_HASH]; pMobIndex != NULL; pMobIndex  = pMobIndex->next )
	if ( pMobIndex->vnum == vnum )
	    return pMobIndex;
    if ( fBootDb )
    {
	bug( "Get_mob_index: bad vnum %d.", vnum );
	exit( 1 );
    }
    return NULL;
}

/* Translates mob virtual number to its obj index struct. *
 * Hash table lookup.                                     */
OBJ_INDEX_DATA *get_obj_index( int vnum )
{
    OBJ_INDEX_DATA *pObjIndex;
    for ( pObjIndex  = obj_index_hash[vnum % MAX_KEY_HASH]; pObjIndex != NULL; pObjIndex  = pObjIndex->next )
	if ( pObjIndex->vnum == vnum )
	    return pObjIndex;
    if ( fBootDb )
    {
	bug( "Get_obj_index: bad vnum %d.", vnum );
	exit( 1 );
    }
    return NULL;
}

/* Translates mob virtual number to its room index struct. *
 * Hash table lookup.                                      */
ROOM_INDEX_DATA *get_room_index( int vnum )
{
  ROOM_INDEX_DATA *pRoomIndex;
  if (vnum <= 0)
    return NULL;
  for ( pRoomIndex  = room_index_hash[vnum % MAX_KEY_HASH]; pRoomIndex != NULL; pRoomIndex  = pRoomIndex->next )
	if ( pRoomIndex->vnum == vnum )
	    return pRoomIndex;
    if ( fBootDb )
    {
	bug( "Get_room_index: bad vnum %d.", vnum );
	exit( 1 );
    }
    return NULL;
}

/* Read a letter from a file. */
char fread_letter( FILE *fp )
{
    char c = '\0';
    do
	c = getc( fp );
    while ( isspace(c) );
    return c;
}

/* Read a number from a file. */
int fread_number( FILE *fp )
{
    int number = 0;
    bool sign;
    char c;
    if (!fp){
      bug("fread_number: null file passed", 0);
      return 0;
    }
    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( 1 );
    }
    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;
}

unsigned long fread_unsigned_long( FILE *fp )
{
    unsigned long int number = 0;
    bool sign;
    char c;
    if (!fp){
      bug("fread_number: null file passed", 0);
      return 0;
    }
    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( 1 );
    }
    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;
}

/* read a regular long */
long fread_long( FILE *fp )
{
    long number = 0;
    bool sign;
    char c;
    if (!fp){
      bug("fread_number: null file passed", 0);
      return 0;
    }
    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( 1 );
    }
    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;
    bool negative = FALSE;
    do
	c = getc(fp);
    while ( isspace(c));
    if (c == '-')
    {
	negative = TRUE;
	c = getc(fp);
    }
    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);
    if (negative)
	return -1 * number;
    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;
	for (i = letter; i > 'a'; i --)
	    bitsum *= 2;
    }
    return bitsum;
}

/* 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_noquote( FILE *fp )
{
    static char word[MIL];
    char *pword;
    char cEnd;
    do
	cEnd = getc( fp );
    while ( isspace( cEnd ) && (cEnd != '\r'));
    if ( cEnd == '\'' || cEnd == '"' )
	pword   = word;
    else
    {
	word[0] = cEnd;
	pword   = word+1;
	cEnd    = ' ';
    }
    for ( ; pword < word + MIL; 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( 1 );
    return NULL;
}

/* Read one word (into static buffer). */
char *fread_word( FILE *fp )
{
    static char word[MIL];
    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 + MIL; 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);
    return NULL;
}

/* Allocate some ordinary memory,              *
 * with the expectation of freeing it someday. */
void *alloc_mem( int sMem )
{
    void *pMem;
    int *magic;
    int iList;
    sMem += sizeof(*magic);
    for ( iList = 0; iList < MAX_MEM_LIST; iList++ )
        if ( sMem <= rgSizeList[iList] )
            break;
    if ( iList == MAX_MEM_LIST )
    {
        bug( "Alloc_mem: size %d too large.", sMem );
        exit( 1 );
    }
    if ( rgFreeList[iList] == NULL )
        pMem              = alloc_perm( rgSizeList[iList] );
    else
    {
        pMem              = rgFreeList[iList];
        rgFreeList[iList] = * ((void **) rgFreeList[iList]);
    }
    magic = (int *) pMem;
    *magic = MAGIC_NUM;
    pMem += sizeof(*magic);
    return pMem;
}

/* Free some memory.                                           *
 * Recycle it back onto the free list for blocks of that size. */
void free_mem( void *pMem, int sMem )
{
    int iList;
    int *magic;
    pMem -= sizeof(*magic);
    magic = (int *) pMem;
    if (*magic != MAGIC_NUM)
    {
        bug("Attempt to recyle invalid memory of size %d.",sMem);
        bug((char*) pMem + sizeof(*magic),0);
        return;
    }
    *magic = 0;
    sMem += sizeof(*magic);
    for ( iList = 0; iList < MAX_MEM_LIST; iList++ )
        if ( sMem <= rgSizeList[iList] )
            break;
    if ( iList == MAX_MEM_LIST )
    {
        bug( "Free_mem: size %d too large.", sMem );
        exit( 1 );
    }
    * ((void **) pMem) = rgFreeList[iList];
    rgFreeList[iList]  = pMem;
}


/* Allocate some permanent memory.          *
 * Permanent memory is never freed,         *
 *   pointers into it may be copied safely. */
void *alloc_perm( int sMem )
{
    static char *pMemPerm;
    static int iMemPerm;
    void *pMem = NULL;

    while ( sMem % sizeof(long) != 0 ) {
	sMem++;
    }
    if ( sMem > MAX_PERM_BLOCK ) {
      bug( "Alloc_perm: %d too large.", sMem );
      exit( 1 );
    }
    if ( pMemPerm == NULL || iMemPerm + sMem > MAX_PERM_BLOCK ) {
      iMemPerm = 0;
      init_malloc("calloc alloc_perm");
      if ( ( pMemPerm = calloc( 1, MAX_PERM_BLOCK ) ) == NULL ) {
	perror( "Alloc_perm" );
	exit( 1 );
      }
      end_malloc("calloc alloc_perm");
    }
    pMem        = pMemPerm + iMemPerm;
    iMemPerm   += sMem;
    nAllocPerm += 1;
    sAllocPerm += sMem;
    return pMem;
}

void do_areas( CHAR_DATA *ch, char *argument )
{
    AREA_DATA *pArea1 = area_first, *pArea2 = area_first;
    int iArea, iAreaHalf = (top_area + 1) / 2;
    BUFFER *buffer;
    char buf[MSL];
    if (argument[0] != '\0')
    {
	send_to_char("No argument is used with this command.\n\r",ch);
	return;
    }
    buffer = new_buf();
    for ( iArea = 0; iArea < iAreaHalf; iArea++ )
	pArea2 = pArea2->next;
    for ( iArea = 0; iArea < iAreaHalf; iArea++ )
    {
        sprintf( buf, "%-39s%-39s\n\r", pArea1->credits, (pArea2 != NULL) ? pArea2->credits : "" );
	add_buf(buffer,buf);
	pArea1 = pArea1->next;
	if ( pArea2 != NULL )
	    pArea2 = pArea2->next;
    }
    page_to_char(buf_string(buffer),ch);
    free_buf(buffer);
}
extern int numFree;
void do_memory( CHAR_DATA *ch, char *argument )
{
    sendf( ch, "Affects:           %5d\n\r", top_affect    );
    sendf( ch, "Areas:             %5d (%d bastions)\n\r", top_area, mud_data.tot_bastion  );
    sendf( ch, "ExDes:             %5d\n\r", top_ed        );
    sendf( ch, "Exits:             %5d\n\r", top_exit      );
    sendf( ch, "Helps:             %5d\n\r", top_help      );
    sendf( ch, "Socials:           %5d\n\r", social_count  );
    sendf( ch, "Mobs:              %5d       %7d new format       %7d in use\n\r", top_mob_index,newmobs,mobile_count);
    sendf( ch, "Mob progs:         %5d       %7d files\n\r",mprog_count,mprogf_count  );
    sendf( ch, "Objs:              %5d       %7d new format\n\r", top_obj_index,newobjs );
    sendf( ch, "Traps:             %5d\n\r", top_trap_index);
    sendf( ch, "Cabals:            %5d\n\r", top_cabal_index);
    sendf( ch, "Resets:            %5d\n\r", top_reset     );
    sendf( ch, "Rooms:             %5d\n\r", top_room      );
    sendf( ch, "VirRooms:          %5d\n\r", top_vir_room  );
    sendf( ch, "Night Descrips:    %5d\n\r", night_count   );
    sendf( ch, "Shops:             %5d\n\r", top_shop      );
    sendf( ch, "Share Strings:     %5d strings of %7d bytes       %7d bytes is reboot\n\r",
	nAllocString, sAllocString, 4*MAX_STRING/5 );
    sendf( ch, "Overflow Strings:  %5d strings of %7d bytes\n\r",nOverFlowString, sOverFlowString );
    sendf( ch, "Perm Strings:      %5d blocks  of %7d bytes       %7d blocks is reboot\n\r",
	nAllocPerm, sAllocPerm, MAX_PERM_BLOCK * 4 / 5 );
sendf(ch, "Reboot counter: %d, FreeString %d/%d", reboot_tick_counter, numFree, MAX_FREE);
    if( Full )
        sendf( ch, "Shared String Heap is full, increase MAX_STRING.\n\r" );
}

void do_dump( CHAR_DATA *ch, char *argument )
{
    int count = 0, count2 = 0, num_pcs = 0, aff_count = 0, vnum, nMatch = 0;
    CHAR_DATA *fch;
    MOB_INDEX_DATA *pMobIndex;
    PC_DATA *pc;
    OBJ_DATA *obj;
    OBJ_INDEX_DATA *pObjIndex;
    ROOM_INDEX_DATA *room;
    EXIT_DATA *exit;
    DESCRIPTOR_DATA *d;
    AFFECT_DATA *af;
    FILE *fp;
    if (argument[0] == '\0')
      {
	send_to_char("memory dump: enter anything as an argument to dump the memory.\n\r", ch);
	return;
      }
    fclose(fpReserve);
    fp = fopen("mem.dmp","w");
    fprintf(fp,"MobProt %4d (%8d bytes)\n", top_mob_index, top_mob_index * (sizeof(*pMobIndex)));
    for (fch = char_list; fch != NULL; fch = fch->next)
    {
	count++;
	if (fch->pcdata != NULL)
	    num_pcs++;
	for (af = fch->affected; af != NULL; af = af->next)
	    aff_count++;
    }
    for (fch = char_free; fch != NULL; fch = fch->next)
	count2++;
    fprintf(fp,"Mobs    %4d (%8d bytes), %2d free (%d bytes)\n",
      count, count * (sizeof(*fch)), count2, count2 * (sizeof(*fch)));
    count = 0;
    for (pc = pcdata_free; pc != NULL; pc = pc->next)
	count++; 
    fprintf(fp,"Pcdata  %4d (%8d bytes), %2d free (%d bytes)\n",
      num_pcs, num_pcs * (sizeof(*pc)), count, count * (sizeof(*pc)));
    count = 0; count2 = 0;
    for (d = descriptor_list; d != NULL; d = d->next)
	count++;
    for (d= descriptor_free; d != NULL; d = d->next)
	count2++;
    fprintf(fp, "Descs  %4d (%8d bytes), %2d free (%d bytes)\n",
      count, count * (sizeof(*d)), count2, count2 * (sizeof(*d)));
    for ( vnum = 0; nMatch < top_obj_index; vnum++ )
        if ( ( pObjIndex = get_obj_index( vnum ) ) != NULL )
        {
	    for (af = pObjIndex->affected; af != NULL; af = af->next)
		aff_count++;
            nMatch++;
        }
    fprintf(fp,"ObjProt %4d (%8d bytes)\n",top_obj_index, top_obj_index * (sizeof(*pObjIndex)));
    count = 0;  count2 = 0;
    for (obj = object_list; obj != NULL; obj = obj->next)
    {
	count++;
	for (af = obj->affected; af != NULL; af = af->next)
	    aff_count++;
    }
    for (obj = obj_free; obj != NULL; obj = obj->next)
	count2++;
    fprintf(fp,"Objs    %4d (%8d bytes), %2d free (%d bytes)\n",
      count, count * (sizeof(*obj)), count2, count2 * (sizeof(*obj)));
    count = 0;
    for (af = affect_free; af != NULL; af = af->next)
	count++;
    fprintf(fp,"Affects %4d (%8d bytes), %2d free (%d bytes)\n",
      aff_count, aff_count * (sizeof(*af)), count, count * (sizeof(*af)));
    fprintf(fp,"Rooms   %4d (%8d bytes)\n", top_room, top_room * (sizeof(*room)));
    fprintf(fp,"Exits   %4d (%8d bytes)\n", top_exit, top_exit * (sizeof(*exit)));
    fclose(fp);
    fp = fopen("mob.dmp","w");
    fprintf(fp,"\nMobile Analysis\n");
    fprintf(fp,  "---------------\n");
    nMatch = 0;
    for (vnum = 0; nMatch < top_mob_index; vnum++)
	if ((pMobIndex = get_mob_index(vnum)) != NULL)
	{
	    nMatch++;
	    fprintf(fp,"#%-4d %3d active %3d killed     %s\n",
              pMobIndex->vnum,pMobIndex->count, pMobIndex->killed,pMobIndex->short_descr);
	}
    fclose(fp);
    fp = fopen("obj.dmp","w");
    fprintf(fp,"\nObject Analysis\n");
    fprintf(fp,  "---------------\n");
    nMatch = 0;
    for (vnum = 0; nMatch < top_obj_index; vnum++)
	if ((pObjIndex = get_obj_index(vnum)) != NULL)
	{
	    nMatch++;
	    fprintf(fp,"#%-4d %3d active %3d reset      %s\n",
              pObjIndex->vnum,pObjIndex->count, pObjIndex->reset_num,pObjIndex->short_descr);
	}
    fclose(fp);
    fpReserve = fopen( NULL_FILE, "r" );
}

/* Stick a little fuzz on a number. */
int number_fuzzy( int number )
{
    switch ( number_bits( 2 ) )
    {
    case 0:  number -= 1; break;
    case 3:  number += 1; break;
    }
    return UMAX( 1, number );
}

int temp_adjust( int number )
{
    int hour, month, week;
    if (mud_data.time_info.month <= 8)
	month = mud_data.time_info.month - 4;
    else
	month = 4 - (mud_data.time_info.month - 8);
    week = mud_data.time_info.day / 7 - 2;
    if (mud_data.time_info.hour <= 12)
	hour = mud_data.time_info.hour - 6;
    else
	hour = 6 - (mud_data.time_info.hour - 12);
    return number + (month * 5) + week + hour;
}

/* Generate a random number. */
int number_range( int from, int to )
{
    int power, number;
    if (from == 0 && to == 0)
	return 0;
    if ( ( to = to - from + 1 ) <= 1 )
	return from;
    for ( power = 2; power < to; power <<= 1 );
    while ( ( number = number_mm() & (power -1 ) ) >= to );
    return from + number;
}

/* Generate a percentile roll. */
int number_percent( void )
{
    int percent;
    while ( (percent = number_mm() & (128-1) ) > 99 );
    return 1 + percent;
}

/* Generate a random door. */
int number_door( void )
{
    int door;
    while ( ( door = number_mm() & (8-1) ) > 5);
    return door;
}

/* Generate a random door from the room. */
/* -1 on no valid doors */
int random_door( CHAR_DATA* ch, ROOM_INDEX_DATA* room )
{
    int doors[MAX_DOOR];
    int i = 0;
    int max_door = 0;

    for (i = 0; i < MAX_DOOR; i++){
      if (room->exit[i] != NULL
	  && room->exit[i]->to_room
	  && can_see_room(ch, room->exit[i]->to_room))
	doors[max_door++] = i;
    }

    return max_door == 0 ? -1 : doors[number_range(0, max_door - 1)];
}

int number_bits( int width )
{
    return number_mm( ) & ( ( 1 << width ) - 1 );
}

/* I've gotten too many bad reports on OS-supplied random number generators. *
 * This is the Mitchell-Moore algorithm from Knuth Volume II.                *
 * Best to leave the constants alone unless you've read Knuth.               */

/* I noticed streaking with this random number generator, so I switched *
 * back to the system srandom call.  If this doesn't work for you,      *
 * define OLD_RAND to use the old system.                               */
#if defined (OLD_RAND)
static  int     rgiState[2+55];
#endif
 
void init_mm( )
{
#if defined (OLD_RAND)
    int *piState;
    int iState;
    piState     = &rgiState[2];
    piState[-2] = 55 - 55;
    piState[-1] = 55 - 24;
    piState[0]  = ((int) mud_data.current_time) & ((1 << 30) - 1);
    piState[1]  = 1;
    for ( iState = 2; iState < 55; iState++ )
    {
        piState[iState] = (piState[iState-1] + piState[iState-2]) & ((1 << 30) - 1);
    }
#else
    srandom(time(NULL)^getpid());
#endif
}
 
long number_mm( void )
{
#if defined (OLD_RAND)
    int *piState;
    int iState1, iState2, iRand;
    piState             = &rgiState[2];
    iState1             = piState[-2];
    iState2             = piState[-1];
    iRand               = (piState[iState1] + piState[iState2]) & ((1 << 30) - 1);
    piState[iState1]    = iRand;
    if ( ++iState1 == 55 )
        iState1 = 0;
    if ( ++iState2 == 55 )
        iState2 = 0;
    piState[-2]         = iState1;
    piState[-1]         = iState2;
    return iRand >> 6;
#else
    return random() >> 6;
#endif
}

/* Roll some dice. */
int dice( int number, int size )
{
    int idice, sum;
    switch ( size )
    {
    case 0: return 0;
    case 1: return number;
    }
    for ( idice = 0, sum = 0; idice < number; idice++ )
	sum += number_range( 1, size );
    return sum;
}

/* Simple linear interpolation. */
int interpolate( int level, int value_00, int value_32 )
{
    return value_00 + level * (value_32 - value_00) / 32;
}

/* 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 = '-';
}

void smash_tilde2( char *str )
{
    for ( ; *str != '\0'; str++ )
	if ( *str == '~' )
	    *str = '\0';
}

/* Finds a string and replaces it with another */
void str_replace(char *buf, const char *s, const char *repl)
{
    char out_buf[MSL];
    char *pc, *out;
    int len = strlen(s);
    bool found = FALSE;
    for (pc = buf, out = out_buf; *pc && (out-out_buf) < (MSL-len-4); )
    {
	if (!strncasecmp(pc, s, len))
	{
	    out += sprintf(out, repl);
            pc += len;
            found = TRUE;
	}
	else
	    *out++ = *pc++;
    }
    if (found) /* don't bother copying if we did not change anything */
    {
        *out = '\0';
        strcpy(buf, out_buf);
    }
}

/* Compare strings, case insensitive.           *
 * Return TRUE if different                     *
 *   (compatibility with historical functions). */
bool str_cmp( const char *astr, const char *bstr )
{
    if ( astr == NULL )
    {
	if (bstr == NULL)
	    bug( "Str_cmp %d: null astr.", 1 );
	else
	    bugf( "Str_cmp: null astr, bstr = %s.", bstr );
	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 sensitive.           *
 * Return TRUE if different                     *
 *   (compatibility with historical functions). */
bool str_cmp_2( const char *astr, const char *bstr )
{
    if ( astr == NULL )
    {
	bug( "Str_cmp 2: null astr.", 0 );
	return TRUE;
    }
    if ( bstr == NULL )
    {
	bug( "Str_cmp: null bstr.", 0 );
	return TRUE;
    }
    for ( ; *astr || *bstr; astr++, bstr++ )
	if ((*astr) != (*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, sstr2, 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 = 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[MSL];
    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;
// change back for IS_NPC(ch)
    if (  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, "[%5d] %s: %s\n", ch->in_room ? ch->in_room->vnum : 0, ch->name, str );
    fclose( fp );
    fpReserve = fopen( NULL_FILE, "r" );
    return;
}

/* Append a string to a file. */
void append_string( char *file, char *str )
{
    FILE *fp;
    if ( str[0] == '\0' )
	return;
    fclose( fpReserve );
    if ( ( fp = fopen( file, "a" ) ) == NULL )
	perror( file );
    else
        fprintf( fp, str );
    fclose( fp );
    fpReserve = fopen( NULL_FILE, "r" );
    return;
}

/* Reports a bug. */
void bug( const char *str, int param )
{
    char buf[MSL];
    FILE *fp;
    if ( fpArea != NULL )
    {
	int iLine, 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 );
	}
	nlogf( "[*****] FILE: %s LINE: %d", strArea, iLine );
	if ( ( fp = fopen( "shutdown.txt", "a" ) ) != NULL )
   	    fprintf( fp, "[*****] %s\n", buf );
	else
	    fp = fopen( NULL_FILE, "r" );
        fclose( fp );
    }
    strcpy( buf, "[*****] BUG: " );
    sprintf( buf + strlen(buf), str, param );
    log_string( buf );
}


/* Writes a string into Event log */
void log_event(CHAR_DATA* ch, char* str)
{append_file(ch, EVENT_FILE, str );}



/* Writes a string to the log. */
void log_string( const char *str )
{
    char *strtime = ctime( &mud_data.current_time );
    strtime[strlen(strtime)-1] = '\0';
    fprintf( stderr, "%s :: %s\n", strtime, str );
}

/* 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.                  */
void tail_chain( void )
{
    return;
}

/* returns help index */
HELP_DATA *get_help_index( int vnum ){
  HELP_DATA* pHelp;
  for(pHelp = help_first ; pHelp; pHelp = pHelp->next ){
    if ( pHelp->vnum == vnum )
      return( pHelp );
  }
  return NULL;
}

/* returns cabal index */
CABAL_INDEX_DATA *get_cabal_index( int vnum ){
  CABAL_INDEX_DATA* pCab;
  for(pCab = cabal_index_list ; pCab; pCab = pCab->next ){
    if ( pCab->vnum == vnum )
      return( pCab );
  }
  return NULL;
}

/* returns cabal index */
CABAL_INDEX_DATA *get_cabal_index_str( char* name ){
  CABAL_INDEX_DATA* pCab;
  for(pCab = cabal_index_list ; pCab; pCab = pCab->next ){
    if (LOWER(name[0]) == LOWER(pCab->name[0]) && !str_cmp(name, pCab->name))
      return( pCab );
  }
  return NULL;
}

/* returns trap index */
TRAP_INDEX_DATA *get_trap_index( int vnum ){
  TRAP_INDEX_DATA* pTrap;
  for(pTrap = trap_index_list ; pTrap; pTrap = pTrap->next ){
    if ( pTrap->vnum == vnum )
      return( pTrap );
  }
  return NULL;
}


/* MOB Programs */
/* Returns the index of the prog list */
PROG_CODE *get_prog_index( int vnum, int type )
{
    PROG_CODE *prg;

    switch ( type )
    {
	case PRG_MPROG:
	    prg = mprog_list;
	    break;
	case PRG_OPROG:
	    prg = oprog_list;
	    break;
	case PRG_RPROG:
	    prg = rprog_list;
	    break;
	default:
	    return NULL;
    }

    for( ; prg; prg = prg->next )
    {
	if ( prg->vnum == vnum )
            return( prg );
    }
    return NULL;
}

/* This routine transfers between alpha and numeric forms of the      *
 *  mob_prog bitvector types. This allows the use of the words in the *
 *  mob/script files.                                                 */
int mprog_name_to_type ( char *name )
{
    if ( !str_cmp( name, "in_file_prog"   ) )    return IN_FILE_PROG;
    if ( !str_cmp( name, "act_prog"       ) )    return ACT_PROG;
    if ( !str_cmp( name, "speech_prog"    ) )    return SPEECH_PROG;
    if ( !str_cmp( name, "rand_prog"      ) )    return RAND_PROG;
    if ( !str_cmp( name, "fight_prog"     ) )    return FIGHT_PROG;
    if ( !str_cmp( name, "hitprcnt_prog"  ) )    return HITPRCNT_PROG;
    if ( !str_cmp( name, "death_prog"     ) )    return DEATH_PROG;
    if ( !str_cmp( name, "entry_prog"     ) )    return ENTRY_PROG;
    if ( !str_cmp( name, "greet_prog"     ) )    return GREET_PROG;
    if ( !str_cmp( name, "all_greet_prog" ) )    return ALL_GREET_PROG;
    if ( !str_cmp( name, "give_prog"      ) )    return GIVE_PROG;
    if ( !str_cmp( name, "bribe_prog"     ) )    return BRIBE_PROG;
    if ( !str_cmp( name, "time_prog"	  ) )	 return TIME_PROG;
    if ( !str_cmp( name, "get_prog"       ) )    return GET_PROG;
    if ( !str_cmp( name, "drop_prog"      ) )    return DROP_PROG;
    if ( !str_cmp( name, "guild_prog"     ) )    return GUILD_PROG;
    if ( !str_cmp( name, "bloody_prog"    ) )    return BLOODY_PROG;
    if ( !str_cmp( name, "justice_prog"    ) )   return JUSTICE_PROG;
    return( ERROR_PROG );
}

/* This routine reads in scripts of MOBprograms from a file */
MPROG_DATA* mprog_file_read( char *f, MPROG_DATA *mprg, MOB_INDEX_DATA *pMobIndex )
{
    char        MOBProgfile[MIL];
    char        letter;
    MPROG_DATA *mprg2;
    FILE       *progfile;
    bool        done = FALSE;
    sprintf( MOBProgfile, "%s%s", MOB_DIR, f);
    progfile = fopen( MOBProgfile, "r" );
    if ( !progfile )
    {
        bug( "Mob: %d couldnt open mobprog file", pMobIndex->vnum );
	printf ("File: %s\n", MOBProgfile);
	fclose (progfile);
        exit( 1 );
    }
    mprg2 = mprg;
    switch ( letter = fread_letter( progfile ) )
    {
    case '>':
	mprog_count++;
        break;
    case '|':
        bug( "empty mobprog file.", 0 );
        exit( 1 );
        break;
    default:
        bug( "in mobprog file syntax error.", 0 );
	printf ("File: %s\n", MOBProgfile);
        exit( 1 );
        break;
    }
    while ( !done )
    {
        mprg2->type = mprog_name_to_type( fread_word( progfile ) );
        switch ( mprg2->type )
        {
        case ERROR_PROG:
            bug( "mobprog file type error", 0 );
            exit( 1 );
            break;
        case IN_FILE_PROG:
            bug( "mprog file contains a call to file.", 0 );
            exit( 1 );
            break;
        default:
            pMobIndex->progtypes = pMobIndex->progtypes | mprg2->type;
            mprg2->arglist       = fread_string( progfile );
            mprg2->comlist       = fread_string( progfile );
            switch ( letter = fread_letter( progfile ) )
            {
            case '>':
		mprog_count++;
                mprg2->next = (MPROG_DATA *)alloc_perm( sizeof( MPROG_DATA ) );
                mprg2       = mprg2->next;
                mprg2->next = NULL;
                break;
            case '|':
                done = TRUE;
                break;
            default:
                bug( "in mobprog file syntax error.", 0 );
                exit( 1 );
                break;
            }
            break;
        }
    }
    fclose( progfile );
    return mprg2;
}

/* Snarf a MOBprogram section from the area file. */
/* This handles both the old and new format of mobprogs */
void load_mobprogs( FILE *fp )
{
    MOB_INDEX_DATA *iMob;
    MPROG_DATA     *original, *working;
    PROG_CODE *pMprog;
    TRIGFILE_DATA  *originalt, *workingt;
    char            letter;
    char	   *file;
    int             value;

    if ( area_last == NULL )
    {
	bug( "Load_new_mprogs: no #AREA seen yet.", 0 );
	exit( 1 );
    }

    /* This function distinguishes between oldmobs and new progs */
    for ( ; ; ){
      sh_int vnum = 0;
      switch ( letter = fread_letter( fp ) )
	{
	default:
	  bug( "Load_mobprogs: bad command '%c'.",letter);
	  exit(1);
	  break;
	  /* New progs are always written before S */
	case 'S':
	case 's':
	  fread_to_eol( fp ); 
	  return;
	case '*':
	  fread_to_eol( fp ); 
	  break;
	  /* OLD PROG */
        case 'M':
        case 'm':
	  value = fread_number( fp );
	  mprogf_count++;
	  if ( ( iMob = get_mob_index( value ) ) == NULL )
            {
	      bug( "Load_mobprogs: vnum %d doesnt exist", value );
	      exit( 1 );
            }
	  if ( ( original = iMob->mobprogs ) )
	    for ( ; original->next != NULL; original = original->next );
	  working = (MPROG_DATA *)alloc_perm( sizeof( MPROG_DATA ) );
	  if ( original )
	    original->next = working;
	  else
	    iMob->mobprogs = working;
	  working->dowhen = fread_number(fp);
	  file = fread_word( fp );
	  if ( ( originalt = iMob->trigfile ) )
	    for ( ; originalt->next != NULL; originalt = originalt->next );
	  workingt = (TRIGFILE_DATA *)alloc_perm( sizeof( TRIGFILE_DATA ) );
	  if ( originalt )
	    originalt->next = workingt;
	  else
	    iMob->trigfile = workingt;
	  workingt->name = str_dup( file );
	  workingt->dowhen = working->dowhen;
	  working = mprog_file_read( file , working, iMob );
	  workingt->next= NULL;
	  working->next = NULL;
	  fread_to_eol( fp );
	  break;
	  
	  /* NEW PROG */
	case '#':
	  vnum		 = fread_number( fp );

	  if ( vnum == 0 )
	    continue; 	  /* skip read, old progs follow */	

	  fBootDb = FALSE;
	  if ( get_prog_index( vnum, PRG_MPROG ) != NULL )
	    {
	      bug( "Load_new_mprogs: vnum %d duplicated.", vnum );
	      exit( 1 );
	    }
	  fBootDb = TRUE;
	  pMprog		= alloc_perm( sizeof(*pMprog) );
	  pMprog->vnum  	= vnum;
	  pMprog->code  	= fread_string( fp );
	  if ( mprog_list == NULL )
	    mprog_list = pMprog;
	  else
	    {
	      pMprog->next = mprog_list;
	      mprog_list 	= pMprog;
	    }
	  top_mprog_index++;
	}
    }
}

/* This procedure is responsible for reading any in_file MOBprograms. */
void mprog_read_programs( FILE *fp, MOB_INDEX_DATA *pMobIndex)
{
    MPROG_DATA *mprg;
    char letter;
    bool done = FALSE;
    if ( ( letter = fread_letter( fp ) ) != '>' )
    {
        bug( "Load_mobiles: vnum %d MOBPROG char", pMobIndex->vnum );
        exit( 1 );
    }
    pMobIndex->mobprogs = (MPROG_DATA *)alloc_perm( sizeof( MPROG_DATA ) );
    mprg = pMobIndex->mobprogs;
    while ( !done )
    {
        mprg->type = mprog_name_to_type( fread_word( fp ) );
        switch ( mprg->type )
        {
        case ERROR_PROG:
            bug( "Load_mobiles: vnum %d MOBPROG type.", pMobIndex->vnum );
            exit( 1 );
        break;
        case IN_FILE_PROG:
            mprg = mprog_file_read( fread_string( fp ), mprg,pMobIndex );
            fread_to_eol( fp );
            switch ( letter = fread_letter( fp ) )
            {
            case '>':
                mprg->next = (MPROG_DATA *)alloc_perm( sizeof( MPROG_DATA ) );
                mprg       = mprg->next;
                mprg->next = NULL;
                break;
            case '|':
                mprg->next = NULL;
                fread_to_eol( fp );
                done = TRUE;
                break;
            default:
                bug( "Load_mobiles: vnum %d bad MOBPROG.", pMobIndex->vnum );
                exit( 1 );
                break;
            }
            break;
        default:
            pMobIndex->progtypes = pMobIndex->progtypes | mprg->type;
            mprg->arglist        = fread_string( fp );
            fread_to_eol( fp );
            mprg->comlist        = fread_string( fp );
            fread_to_eol( fp );
            switch ( letter = fread_letter( fp ) )
            {
            case '>':
                mprg->next = (MPROG_DATA *)alloc_perm( sizeof( MPROG_DATA ) );
                mprg       = mprg->next;
                mprg->next = NULL;
                break;
            case '|':
                mprg->next = NULL;
                fread_to_eol( fp );
                done = TRUE;
                break;
            default:
                bug( "Load_mobiles: vnum %d bad MOBPROG.", pMobIndex->vnum );
                exit( 1 );
                break;
            }
            break;
        }
    }
}

void do_repop( CHAR_DATA *ch, char *argument )
{
    AREA_DATA *pArea;
    if ( argument[0] == 0)
    {
        reset_area(ch->in_room->area);
        send_to_char("Area repop!\n\r",ch);
    }   
    if (!strcmp(argument, "room"))
    {
        reset_room(ch->in_room);
        send_to_char("room repop!\n\r",ch);
    }   
    if (!strcmp(argument, "all"))
    {
        for (pArea = area_first; pArea; pArea = pArea->next)
            reset_area(pArea);
        send_to_char("World has been repopped!\n\r",ch);
    }
}

/* To have VLIST show more than vnum 0 - 9900, change the number below: */ 
#define MAX_SHOW_VNUM   327
#define NUL '\0'
#define COLUMNS                 5 
#define MAX_ROW                 ((MAX_SHOW_VNUM / COLUMNS)+1)

extern ROOM_INDEX_DATA *       room_index_hash         [MAX_KEY_HASH];
const sh_int opposite_dir [6] = { DIR_SOUTH, DIR_WEST, DIR_NORTH, DIR_EAST, DIR_DOWN, DIR_UP };
typedef enum {exit_from, exit_to, exit_both} exit_status;

/* get the 'short' name of an area (e.g. MIDGAARD, MIRROR etc. *
 * assumes that the filename saved in the AREA_DATA struct     *
 * is something like midgaard.are                              */
char * area_name (AREA_DATA *pArea)
{
    static char buffer[64];
    char  *period;
    assert (pArea != NULL);
    strncpy (buffer, pArea->file_name, 64);
    period = strchr (buffer, '.');
    if (period)
        *period = '\0';
    return buffer; 
}

void room_pair (ROOM_INDEX_DATA* left, ROOM_INDEX_DATA* right, exit_status ex, char *buffer)
{
    char *sExit;
    switch (ex)
    {
    default:
        sExit = "??"; break;
    case exit_from:
        sExit = "< "; break;
    case exit_to:
        sExit = " >"; break;
    case exit_both:
        sExit = "<>"; break;
    }
    sprintf (buffer, "%5d %-26.26s %s%5d %-26.26s(%-8.8s)\n\r",
      left->vnum, left->name, sExit, right->vnum, right->name, area_name(right->area));
}

void checkexits (ROOM_INDEX_DATA *room, AREA_DATA *pArea, char* buffer)
{
    char buf[MSL];
    int i;
    EXIT_DATA *exit;
    ROOM_INDEX_DATA *to_room;
    strcpy (buffer, "");
    for (i = 0; i < 6; i++)
    {
        exit = room->exit[i];
        if (!exit)
            continue;
        else
            to_room = exit->to_room;
        if (to_room)
        {
            if ( (room->area == pArea) && (to_room->area != pArea) )
            {
                if ( to_room->exit[opposite_dir[i]] && to_room->exit[opposite_dir[i]]->to_room == room )
                    room_pair (room,to_room,exit_both,buf);
                else
                    room_pair (room,to_room,exit_to,buf);
                strcat (buffer, buf);                    
            }                
            else if ( (room->area != pArea) && (exit->to_room->area == pArea) )
                if (!(to_room->exit[opposite_dir[i]] && to_room->exit[opposite_dir[i]]->to_room == room ))
                {                                        
                    room_pair (to_room,room,exit_from,buf);
                    strcat (buffer, buf);
                }
        }
    }
}

void do_exlist (CHAR_DATA *ch, char * argument)
{
    AREA_DATA* pArea;
    ROOM_INDEX_DATA* room;
    int i;
    char buffer[MSL];
    pArea = ch->in_room->area;
    for (i = 0; i < MAX_KEY_HASH; i++)
        for (room = room_index_hash[i]; room != NULL; room = room->next)
        {
            checkexits (room, pArea, buffer);
            send_to_char (buffer, ch);
        }
} 

void do_vlist (CHAR_DATA *ch, char *argument)
{
    int i, j, vnum;
    ROOM_INDEX_DATA *room;
    char buf2 [100];
    BUFFER *buffer;
    buffer = new_buf();
    for (i = 0; i < MAX_ROW; i++)
    {
	add_buf(buffer,"\n\r");
        for (j = 0; j < COLUMNS; j++)
        {
            vnum = (i*COLUMNS + j);
            if (vnum < MAX_SHOW_VNUM)
            {
                room = get_room_index (vnum * 100 + 1);
		if (!room)
		    room = get_room_index (vnum * 100 + 5);
		if (!room)
		    room = get_room_index (vnum * 100 + 11);
                sprintf (buf2, "%3d %-8.8s  ", vnum, room ? area_name(room->area) : "-" ); 
                add_buf (buffer,buf2);                    
            } 
        }
    }
    page_to_char(buf_string(buffer),ch);
    free_buf(buffer);
}

void load_socials( FILE *fp)
{
    for ( ; ; ) 
    {
    	struct social_type social;
    	char *temp;
	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;
    	temp = fread_word(fp);
    	if (!strcmp(temp,"#0"))
            return;
#if defined(social_debug)
	else 
	    fprintf(stderr,"%s\n\r",temp);
#endif
        strcpy(social.name,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++;
   }
}

void load_army_indexes( FILE *fp ){
  
  if ( !area_last ){
    bug( "Load_army_indexes: no #AREA seen yet.", 0 );
    exit( 1 );
  }

  fread_army_indexes( fp, area_last );
}

void load_cabal_indexes( FILE *fp ){
  
  if ( !area_last ){
    bug( "Load_cabal_indexes: no #AREA seen yet.", 0 );
    exit( 1 );
  }
  fread_cabal_indexes( fp, area_last );
}

void load_mobiles( FILE *fp )
{
    MOB_INDEX_DATA *pMobIndex;
    if ( !area_last )
    {
        bug( "Load_mobiles: no #AREA seen yet.", 0 );
        exit( 1 );
    }
    for ( ; ; )
    {
        sh_int vnum;
        char letter;
        int iHash;
        letter                          = fread_letter( fp );
        if ( letter != '#' )
        {
            bug( "Load_mobiles: # not found.", 0 );
            exit( 1 );
        }
        vnum                            = fread_number( fp );
        if ( vnum == 0 )
            break;
        fBootDb = FALSE;
        if ( get_mob_index( vnum ) != NULL )
        {
            bug( "Load_mobiles: vnum %d duplicated.", vnum );
            exit( 1 );
        }
        fBootDb = TRUE;
        pMobIndex                       = alloc_perm( sizeof(*pMobIndex) );
        pMobIndex->vnum                 = vnum;
        pMobIndex->area                 = area_last;
	pMobIndex->new_format		= TRUE;
	newmobs++;
        pMobIndex->player_name          = fread_string( fp );
        pMobIndex->short_descr          = fread_string( fp );
        pMobIndex->long_descr           = fread_string( fp );
        pMobIndex->description          = fread_string( fp );
	pMobIndex->race		 	= race_lookup(fread_string( fp ));
        pMobIndex->long_descr[0]        = UPPER(pMobIndex->long_descr[0]);
        pMobIndex->description[0]       = UPPER(pMobIndex->description[0]);
        pMobIndex->act                  = fread_flag( fp ) | ACT_IS_NPC | race_table[pMobIndex->race].act;
        pMobIndex->act2                 = fread_flag( fp ) | ACT_IS_NPC | race_table[pMobIndex->race].act2;
        pMobIndex->affected_by          = fread_flag( fp ) | race_table[pMobIndex->race].aff;
        pMobIndex->affected2_by         = fread_flag( fp );
        pMobIndex->pShop                = NULL;
        pMobIndex->alignment            = fread_number( fp );
        pMobIndex->group                = fread_number( fp );
        pMobIndex->level                = fread_number( fp );
        pMobIndex->hitroll              = fread_number( fp );  
        pMobIndex->hit[DICE_NUMBER]     = fread_number( fp );  
        /* 'd'          */                fread_letter( fp ); 
        pMobIndex->hit[DICE_TYPE]   	= fread_number( fp );
        /* '+'          */                fread_letter( fp );   
        pMobIndex->hit[DICE_BONUS]      = fread_number( fp ); 
	pMobIndex->mana[DICE_NUMBER]	= fread_number( fp );
					  fread_letter( fp );
	pMobIndex->mana[DICE_TYPE]	= fread_number( fp );
					  fread_letter( fp );
	pMobIndex->mana[DICE_BONUS]	= fread_number( fp );
	pMobIndex->damage[DICE_NUMBER]	= fread_number( fp );
					  fread_letter( fp );
	pMobIndex->damage[DICE_TYPE]	= fread_number( fp );
					  fread_letter( fp );
	pMobIndex->damage[DICE_BONUS]	= fread_number( fp );
	pMobIndex->dam_type		= attack_lookup(fread_word(fp));
	pMobIndex->ac[AC_PIERCE]	= fread_number( fp ) * 10;
	pMobIndex->ac[AC_BASH]		= fread_number( fp ) * 10;
	pMobIndex->ac[AC_SLASH]		= fread_number( fp ) * 10;
	pMobIndex->ac[AC_EXOTIC]	= fread_number( fp ) * 10;
        pMobIndex->off_flags            = fread_flag( fp ) | race_table[pMobIndex->race].off;
        pMobIndex->imm_flags            = fread_flag( fp ) | race_table[pMobIndex->race].imm;
        pMobIndex->res_flags            = fread_flag( fp ) | race_table[pMobIndex->race].res;
        pMobIndex->vuln_flags           = fread_flag( fp ) | race_table[pMobIndex->race].vuln;
	pMobIndex->start_pos		= position_lookup(fread_word(fp));
	pMobIndex->default_pos		= position_lookup(fread_word(fp));
	pMobIndex->sex			= sex_lookup(fread_word(fp));
	pMobIndex->pCabal		= get_cabal_index_str( fread_string( fp ) );

  	if (pMobIndex->start_pos < POS_SLEEPING)
	    pMobIndex->start_pos = POS_STANDING;
	if (pMobIndex->default_pos < POS_SLEEPING)
	    pMobIndex->default_pos = POS_STANDING;
	if (pMobIndex->start_pos > POS_STANDING)
	    pMobIndex->start_pos = POS_STANDING;
	if (pMobIndex->default_pos > POS_STANDING)
	    pMobIndex->default_pos = POS_STANDING;
	if (pMobIndex->sex > 3)
	    pMobIndex->sex = 0;
        pMobIndex->gold                 = fread_number( fp );
	if (!str_cmp(race_table[pMobIndex->race].name, "unique"))
	{
            pMobIndex->form             = fread_flag( fp ) | race_table[pMobIndex->race].form;
            pMobIndex->parts            = fread_flag( fp ) | race_table[pMobIndex->race].parts;
	}
	else
	{
	    fread_flag( fp );
	    fread_flag( fp );
            pMobIndex->form             = race_table[pMobIndex->race].form;
            pMobIndex->parts            = race_table[pMobIndex->race].parts;
	}
	if (IS_SET(pMobIndex->form, FORM_SNAKE))
	    SET_BIT(pMobIndex->form, FORM_REPTILE);
	if (IS_SET(pMobIndex->form, FORM_REPTILE))
	    SET_BIT(pMobIndex->form, FORM_COLD_BLOOD);
	if (IS_SET(pMobIndex->form, FORM_AMPHIBIAN))
	    SET_BIT(pMobIndex->form, FORM_COLD_BLOOD);
	if (IS_SET(pMobIndex->form, FORM_FISH))
	    SET_BIT(pMobIndex->form, FORM_COLD_BLOOD);
	pMobIndex->size			= size_lookup(fread_word(fp));
	fread_word(fp);
	for ( ; ; )
        {
            letter = fread_letter( fp );
            if (letter == 'F')
            {
		char *word;
		long vector;
                word                    = fread_word(fp);
		vector			= fread_flag(fp);
		if (!str_prefix(word,"act"))
		    REMOVE_BIT(pMobIndex->act,vector);
                else if (!str_prefix(word,"aff"))
		    REMOVE_BIT(pMobIndex->affected_by,vector);
		else if (!str_prefix(word,"off"))
		    REMOVE_BIT(pMobIndex->off_flags,vector);
		else if (!str_prefix(word,"imm"))
		    REMOVE_BIT(pMobIndex->imm_flags,vector);
		else if (!str_prefix(word,"res"))
		    REMOVE_BIT(pMobIndex->res_flags,vector);
		else if (!str_prefix(word,"vul"))
		    REMOVE_BIT(pMobIndex->vuln_flags,vector);
		else if (!str_prefix(word,"for"))
		    REMOVE_BIT(pMobIndex->form,vector);
		else if (!str_prefix(word,"par"))
		    REMOVE_BIT(pMobIndex->parts,vector);
		else
		{
		    bug("Flag remove: flag not found.",0);
		    exit(1);
		}
	     }
             else if ( letter == '>' )
	     {
		ungetc(letter,fp);
                mprog_read_programs( fp, pMobIndex );
                break;
             }
	    else if ( letter == 'P' )
	      {
		PROG_LIST *pMprog;
		char *word;
		int trigger = 0;
		
		pMprog		= alloc_perm(sizeof(*pMprog));
		word		= fread_word( fp );
		if ( !(trigger = flag_lookup( word, mprog_flags )) )
		  {
		    bug( "MOBprogs: invalid trigger.",0);
		    exit(1);
		  }
		SET_BIT( pMobIndex->mprog_flags, trigger );
		pMprog->trig_type	= trigger;
		pMprog->vnum		= fread_number( fp );
		pMprog->trig_phrase	= fread_string( fp );
		pMprog->next		= pMobIndex->mprogs;
		pMobIndex->mprogs	= pMprog;
	      }
	     else
	     {
		ungetc(letter,fp);
		break;
	     }
	}
        iHash                   = vnum % MAX_KEY_HASH;
        pMobIndex->next         = mob_index_hash[iHash];
        mob_index_hash[iHash]   = pMobIndex;
        top_mob_index++;
        top_vnum_mob = top_vnum_mob < vnum ? vnum : top_vnum_mob;
        assign_area_vnum( vnum );
        kill_table[URANGE(0, pMobIndex->level, MAX_LEVEL-1)].number++;
    }
}

void load_objects( FILE *fp )
{
  sh_int vnum = 0;
    OBJ_INDEX_DATA *pObjIndex;
    if ( !area_last )
    {
        bug( "Load_objects: no #AREA seen yet.", 0 );
        exit( 1 );
    }
    for ( ; ; )
    {
      int iHash;
      char letter = '\0';
      vnum = 0;
      letter = fread_letter( fp );
      if ( letter != '#' )
        {
            bug( "Load_objects: # not found.", 0 );
            exit( 1 );
        }
      vnum = fread_number( fp );
      if ( vnum == 0 ) {
	break;
      }
      fBootDb = FALSE;
      if ( get_obj_index( vnum ) != NULL )
        {
	  bug( "Load_objects: vnum %d duplicated.", vnum );
	  exit( 1 );
        }
      fBootDb = TRUE;
      pObjIndex                       = alloc_perm( sizeof(*pObjIndex) );
      pObjIndex->vnum                 = vnum;
      pObjIndex->area                 = area_last;
      pObjIndex->new_format           = TRUE;
      pObjIndex->pCabal		      = NULL;
      pObjIndex->race		      = 0;
      pObjIndex->class		      = -1;
      pObjIndex->reset_num	      = 0;
      newobjs++;
      pObjIndex->name                 = fread_string( fp );
      pObjIndex->short_descr          = fread_string( fp );
      pObjIndex->description          = fread_string( fp );
      pObjIndex->material	      = fread_string( fp );
      pObjIndex->item_type            = item_lookup(fread_word( fp ));
      pObjIndex->extra_flags          = fread_flag( fp );
      pObjIndex->wear_flags           = fread_flag( fp );
      
      if (pObjIndex->item_type == ITEM_POTION && !CAN_WEAR(pObjIndex, ITEM_HOLD))
	SET_BIT(pObjIndex->wear_flags,ITEM_HOLD);
      switch(pObjIndex->item_type)
	{
	case ITEM_WEAPON:
	  pObjIndex->value[0]		= weapon_type(fread_word(fp));
	  pObjIndex->value[1]		= fread_number(fp);
	  pObjIndex->value[2]		= fread_number(fp);
	  pObjIndex->value[3]		= attack_lookup(fread_word(fp));
	  pObjIndex->value[4]		= fread_flag(fp);
	  break;
	case ITEM_THROW:
	  pObjIndex->value[0]		= fread_number(fp);
	  pObjIndex->value[1]		= fread_number(fp);
	  pObjIndex->value[2]		= fread_number(fp);
	  pObjIndex->value[3]		= attack_lookup(fread_word(fp));
	  pObjIndex->value[4]		= fread_flag(fp);
	  break;
	case ITEM_CONTAINER:
	  pObjIndex->value[0]		= fread_number(fp);
	  pObjIndex->value[1]		= fread_flag(fp);
	  pObjIndex->value[2]		= fread_number(fp);
	  pObjIndex->value[3]		= fread_number(fp);
	  pObjIndex->value[4]		= fread_number(fp);
	  break;
        case ITEM_DRINK_CON:
	case ITEM_FOUNTAIN:
	  pObjIndex->value[0]         = fread_number(fp);
	  pObjIndex->value[1]         = fread_number(fp);
	  pObjIndex->value[2]         = liq_lookup(fread_word(fp));
	  if (pObjIndex->value[2] == -1)
	    {
	      pObjIndex->value[2] = 0;
	      bug("Unknown liquid type",0);
	    }
	  pObjIndex->value[3]         = fread_number(fp);
	  pObjIndex->value[4]         = fread_number(fp);
	  break;
	case ITEM_WAND:
	case ITEM_STAFF:
	  pObjIndex->value[0]		= fread_number(fp);
	  pObjIndex->value[1]		= fread_number(fp);
	  pObjIndex->value[2]		= fread_number(fp);
	  pObjIndex->value[3]		= skill_lookup(fread_word(fp));
	  pObjIndex->value[4]		= fread_number(fp);
	  break;
	case ITEM_POTION:
	case ITEM_RELIC:
	case ITEM_ARTIFACT:
	case ITEM_PILL:
	case ITEM_SCROLL:
	case ITEM_HERB:
	  pObjIndex->value[0]		= fread_number(fp);
	  pObjIndex->value[1]		= skill_lookup(fread_word(fp));
	  pObjIndex->value[2]		= skill_lookup(fread_word(fp));
	  pObjIndex->value[3]		= skill_lookup(fread_word(fp));
	  pObjIndex->value[4]		= skill_lookup(fread_word(fp));
	  break;
        case ITEM_SOCKET:
	  pObjIndex->value[0]		= fread_flag(fp);
	  pObjIndex->value[1]		= fread_flag(fp);
	  pObjIndex->value[2]		= fread_flag(fp);
	  pObjIndex->value[3]		= fread_flag(fp);
	  pObjIndex->value[4]		= fread_flag(fp);
	  break;
	case ITEM_RANGED:
	  pObjIndex->value[0]		= fread_flag(fp);
	  pObjIndex->value[1]		= fread_number(fp);
	  pObjIndex->value[2]		= fread_number(fp);
	  pObjIndex->value[3]		= fread_number(fp);
	  pObjIndex->value[4]		= fread_flag(fp);
	  break;
        case ITEM_PROJECTILE:
          pObjIndex->value[0]           = fread_flag(fp);
          pObjIndex->value[1]           = fread_number(fp);
          pObjIndex->value[2]           = fread_number(fp);
          pObjIndex->value[3]           = attack_lookup(fread_word(fp));
          pObjIndex->value[4]           = fread_flag(fp);
          break;     
	default:
	  pObjIndex->value[0]             = fread_flag( fp );
	  pObjIndex->value[1]             = fread_flag( fp );
	  pObjIndex->value[2]             = fread_flag( fp );
	  pObjIndex->value[3]             = fread_flag( fp );
	  pObjIndex->value[4]		  = fread_flag( fp );
	  break;
	}
      pObjIndex->level		= fread_number( fp );
      pObjIndex->weight               = fread_number( fp );
      pObjIndex->cost                 = fread_number( fp ); 
      letter 				= fread_letter( fp );
      switch (letter)
 	{
	case ('P') :		pObjIndex->condition = 100; break;
	case ('G') :		pObjIndex->condition =  90; break;
	case ('A') :		pObjIndex->condition =  75; break;
	case ('W') :		pObjIndex->condition =  50; break;
	case ('D') :		pObjIndex->condition =  25; break;
	case ('B') :		pObjIndex->condition =  10; break;
	case ('R') :		pObjIndex->condition =   0; break;
	default:			pObjIndex->condition = 100; break;
	}
      for ( ; ; )
        {
	  char letter;
	  letter = fread_letter( fp );
	  if ( letter == 'E' )
            {
	      EXTRA_DESCR_DATA *ed;
	      ed                      = alloc_perm( sizeof(*ed) );
	      ed->keyword             = fread_string( fp );
	      ed->description         = fread_string( fp );
	      ed->next                = pObjIndex->extra_descr;
	      pObjIndex->extra_descr  = ed;
	      top_ed++;
            }
	  else if ( letter == 'A' )
            {
	      AFFECT_DATA *paf;
	      paf                     = alloc_perm( sizeof(*paf) );
	      paf->where		= TO_OBJECT;
	      paf->type               = -1;
	      paf->level              = pObjIndex->level;
	      paf->duration           = -1;
	      paf->location           = fread_number( fp );
	      paf->modifier           = fread_number( fp );
	      paf->bitvector          = 0;
	      paf->next               = pObjIndex->affected;
	      pObjIndex->affected     = paf;
	      top_affect++;
            }
	  else if ( letter == 'C')
	    pObjIndex->pCabal		= get_cabal_index_str( fread_string( fp ) );
	  else if (letter == 'F')
            {
	      AFFECT_DATA *paf;
	      paf                     = alloc_perm( sizeof(*paf) );
	      letter 			= fread_letter(fp);
	      switch (letter)
	 	{
                case 'A': paf->where = TO_AFFECTS;  break;
                case 'I': paf->where = TO_IMMUNE;   break;
                case 'R': paf->where = TO_RESIST;   break;
                case 'S': paf->where = TO_SKILL;   break;
                case 'V': paf->where = TO_VULN;     break;
                default:  bug( "Load_objects: Bad where on flag set.", 0 ); exit( 1 );
		}
                paf->type               = -1;
                paf->level              = pObjIndex->level;
                paf->duration           = -1;
                paf->location           = fread_number(fp);
                paf->modifier           = fread_number(fp);
                paf->bitvector          = fread_flag(fp);
                paf->next               = pObjIndex->affected;
                pObjIndex->affected     = paf;
                top_affect++;
            }
	  else if ( letter == 'L')
	    pObjIndex->class = fread_number (fp );
	  else if ( letter == 'M' )
	    {
		OBJ_MESSAGE_DATA *new_message;
		new_message		= alloc_perm( sizeof( *new_message ) );
		new_message->onself	= fread_string( fp );
		new_message->onother	= fread_string( fp );
		new_message->offself	= fread_string( fp );
		new_message->offother	= fread_string( fp );
		pObjIndex->message	= new_message;
	    }
	  else if ( letter == 'P' )
	      {
		PROG_LIST *pOprog;
		char *word;
		int trigger = 0;
		
		pOprog		= alloc_perm(sizeof(*pOprog));
		word		= fread_word( fp );
		if ( !(trigger = flag_lookup( word, oprog_flags )) )
		  {
		    bug( "OBJprogs: invalid trigger.",0);
		    exit(1);
		  }
		SET_BIT( pObjIndex->oprog_flags, trigger );
		pOprog->trig_type	= trigger;
		pOprog->vnum		= fread_number( fp );
		pOprog->trig_phrase	= fread_string( fp );
		pOprog->next		= pObjIndex->oprogs;
		pObjIndex->oprogs	= pOprog;
	      }
	  else if ( letter == 'R')
	    pObjIndex->race = fread_number (fp );
	  else if( letter == 'T' )
            {
                OBJ_SPELL_DATA *new_spell;
                new_spell                  = alloc_perm( sizeof( *new_spell ) );
                new_spell->spell           = fread_number( fp );
                new_spell->target          = fread_number( fp );
		new_spell->percent	   = fread_number( fp );
		new_spell->message	   = fread_string( fp );
		new_spell->message2	   = fread_string( fp );
		new_spell->next		   = pObjIndex->spell;
                pObjIndex->spell           = new_spell;
            }

	  else
            {
	      ungetc( letter, fp );
	      break;
            }
        }
        iHash                   = vnum % MAX_KEY_HASH;
        pObjIndex->next         = obj_index_hash[iHash];
        obj_index_hash[iHash]   = pObjIndex;
        top_obj_index++;
        top_vnum_obj = top_vnum_obj < vnum ? vnum : top_vnum_obj;
        assign_area_vnum( vnum );
    }
}

/* Converts all old format objects to new format.     *
 * Called by boot_db (db.c).                          *
 * Loops over all resets to find the level of the mob *
 * loaded before the object to determine the level of *
 * the object.                                        */
void convert_objects( void )
{
    int vnum;
    AREA_DATA  *pArea;
    RESET_DATA *pReset;
    MOB_INDEX_DATA *pMob = NULL;
    OBJ_INDEX_DATA *pObj;
    ROOM_INDEX_DATA *pRoom;
    if ( newobjs == top_obj_index )
	return;
    for ( pArea = area_first; pArea; pArea = pArea->next )
    {
        for ( vnum = pArea->min_vnum; vnum <= pArea->max_vnum; vnum++ )
        {
            if ( !( pRoom = get_room_index( vnum ) ) )
                continue;
            for ( pReset = pRoom->reset_first; pReset; pReset = pReset->next )
            {
                switch ( pReset->command )
                {
                case 'M':
                    if ( !( pMob = get_mob_index( pReset->arg1 ) ) )
                        bug( "Convert_objects: 'M': bad vnum %d.", pReset->arg1 );
                    break;
                case 'O':
                    if ( !( pObj = get_obj_index( pReset->arg1 ) ) )
                    {
                        bug( "Convert_objects: 'O': bad vnum %d.", pReset->arg1 );
                        break;
                    }
                    if ( pObj->new_format )
                        continue;
                    if ( !pMob )
                    {
                        bug( "Convert_objects: 'O': No mob reset yet.", 0 );
                        break;
                    }
                    pObj->level = pObj->level < 1 ? pMob->level - 2 : UMIN(pObj->level, pMob->level - 2);
                    break;
                case 'P':
                    {
                        OBJ_INDEX_DATA *pObj, *pObjTo;
                        if ( !( pObj = get_obj_index( pReset->arg1 ) ) )
                        {
                            bug( "Convert_objects: 'P': bad vnum %d.", pReset->arg1 );
                            break;
                        }
                        if ( pObj->new_format )
                            continue;
                        if ( !( pObjTo = get_obj_index( pReset->arg3 ) ) )
                        {
                            bug( "Convert_objects: 'P': bad vnum %d.", pReset->arg3 );
                            break;
                        }
                        pObj->level = pObj->level < 1 ? pObjTo->level : UMIN(pObj->level, pObjTo->level);
                    }
                    break;
                case 'G':
                case 'E':
                    if ( !( pObj = get_obj_index( pReset->arg1 ) ) )
                    {
                        bug( "Convert_objects: 'E' or 'G': bad vnum %d.", pReset->arg1 );
                        break;
                    }
                    if ( !pMob )
                    {
                        bug( "Convert_objects: 'E' or 'G': null mob for vnum %d.",pReset->arg1 );
                        break;
                    }
                    if ( pObj->new_format )
                        continue;
                    if ( pMob->pShop )
                    {
                        switch ( pObj->item_type )
                        {
                        default:            pObj->level = UMAX(0, pObj->level); break;
                        case ITEM_PILL:
			case ITEM_RELIC:
			case ITEM_SOCKET:
			case ITEM_ARTIFACT:
                        case ITEM_POTION:   pObj->level = UMAX(5, pObj->level); break;
                        case ITEM_SCROLL:
                        case ITEM_ARMOR:
                        case ITEM_THROW:
                        case ITEM_WEAPON:   pObj->level = UMAX(10, pObj->level); break;
                        case ITEM_WAND:
                        case ITEM_TREASURE: pObj->level = UMAX(15, pObj->level); break;
			case ITEM_RANGED: pObj->level = UMAX(15, pObj->level); break;        
                        case ITEM_PROJECTILE: pObj->level = UMAX(15,pObj->level); break;
                        case ITEM_INSTRUMENT:pObj->level= UMAX(10, pObj->level); break;
                        case ITEM_STAFF:    pObj->level = UMAX(20, pObj->level); break;
                        }
                    }
                    else
                        pObj->level = pObj->level < 1 ? pMob->level : UMIN( pObj->level, pMob->level );
                    break;
                }
            }
        }
    }
    for ( pArea = area_first; pArea ; pArea = pArea->next )
        for ( vnum = pArea->min_vnum; vnum <= pArea->max_vnum; vnum++ )
            if ( (pObj = get_obj_index( vnum )) )
                if ( !pObj->new_format )
                    convert_object( pObj );
}

/* Converts an old_format obj to new_format. *
 * Called by convert_objects (db2.c).        *
 * Dug out of create_obj (db.c)              */
void convert_object( OBJ_INDEX_DATA *pObjIndex )
{
    int level, number, type;
    if ( !pObjIndex || pObjIndex->new_format )
	return;
    level = pObjIndex->level;
    pObjIndex->level    = UMAX( 0, pObjIndex->level ); 
    pObjIndex->cost     = 10*level;
    switch ( pObjIndex->item_type )
    {
        default:
            bug( "Obj_convert: vnum %d bad type.", pObjIndex->item_type );
            break;
        case ITEM_LIGHT:
        case ITEM_TREASURE:
	case ITEM_RANGED:
        case ITEM_INSTRUMENT:
        case ITEM_FURNITURE:
        case ITEM_TRASH:
        case ITEM_CONTAINER:
        case ITEM_DRINK_CON:
        case ITEM_KEY:
        case ITEM_FOOD:
	case ITEM_HERB:
        case ITEM_BOAT:
        case ITEM_CORPSE_NPC:
        case ITEM_CORPSE_PC:
        case ITEM_FOUNTAIN:
        case ITEM_MAP:
        case ITEM_CLOTHING:
        case ITEM_SCROLL:
            break;
        case ITEM_WAND:
        case ITEM_STAFF:
            pObjIndex->value[2] = pObjIndex->value[1];
            break;
        case ITEM_THROW:
        case ITEM_WEAPON:
           /* The conversion below is based on the values generated *
            * in one_hit() (fight.c).  Since I don't want a lvl 50  *
            * weapon to do 15d3 damage, the min value will be below *
            * the one in one_hit, and to make up for it, I've made  *
            * the max value higher.                                 *
            * (I don't want 15d2 because this will hardly ever roll *
            * 15 or 30, it will only roll damage close to 23.       *
            * I can't do 4d8+11, because one_hit there is no dice-  *
            * bounus value to set...)                               *
            * The conversion below gives:                           *
            * level:   dice      min      max      mean             *
            *   1:     1d8      1( 2)    8( 7)     5( 5)            *
            *   2:     2d5      2( 3)   10( 8)     6( 6)            8
            *   3:     2d5      2( 3)   10( 8)     6( 6)            8
            *   5:     2d6      2( 3)   12(10)     7( 7)            *
            *  10:     4d5      4( 5)   20(14)    12(10)            *
            *  20:     5d5      5( 7)   25(21)    15(14)            *
            *  30:     5d7      5(10)   35(29)    20(20)            *
            *  50:     5d11     5(15)   55(44)    30(30)            */
            number = UMIN(level/4 + 1, 5);
            type   = (level + 7)/number;
            pObjIndex->value[1] = number;
            pObjIndex->value[2] = type;
            break;
        case ITEM_ARMOR:
            pObjIndex->value[0] = level / 5 + 3;
            pObjIndex->value[1] = pObjIndex->value[0];
            pObjIndex->value[2] = pObjIndex->value[0];
            break;
        case ITEM_POTION:
	case ITEM_RELIC:
	case ITEM_SOCKET:
	case ITEM_ARTIFACT:
        case ITEM_PILL:
            break;
        case ITEM_MONEY:
           pObjIndex->value[0] = pObjIndex->cost;
           break;
    }
    pObjIndex->new_format = TRUE;
    ++newobjs;
}

/* Converts an old_format mob into new_format. *
 * Called by load_old_mob (db.c).              *
 * Dug out of create_mobile (db.c)             */
void convert_mobile( MOB_INDEX_DATA *pMobIndex )
{
    int i, type, number, bonus, level;
    if ( !pMobIndex || pMobIndex->new_format )
	return;
    level = pMobIndex->level;
    pMobIndex->act              |= ACT_WARRIOR;
    pMobIndex->act2		= 0;
   /* Calculate hit dice.  Gives close to the hitpoints                     *
    * of old format mobs created with create_mobile()  (db.c)               *
    * A high number of dice makes for less variance in mobiles              *
    * hitpoints.                                                            *
    * (might be a good idea to reduce the max number of dice)               *
    * The conversion below gives:                                           *
    *                                                                       *
    *  level:     dice         min         max        diff       mean       *
    *    1:       1d2+6       7(  7)     8(   8)     1(   1)     8(   8)    *
    *    2:       1d3+15     16( 15)    18(  18)     2(   3)    17(  17)    *
    *    3:       1d6+24     25( 24)    30(  30)     5(   6)    27(  27)    *
    *    5:      1d17+42     43( 42)    59(  59)    16(  17)    51(  51)    *
    *   10:      3d22+96     99( 95)   162( 162)    63(  67)   131(    )    *
    *   15:     5d30+161    166(159)   311( 311)   145( 150)   239(    )    *
    *   30:    10d61+416    426(419)  1026(1026)   600( 607)   726(    )    *
    *   50:    10d169+920   930(923)  2610(2610)  1680(1688)  1770(    )    *
    *                                                                       *
    * The values in parenthesis give the values generated in create_mobile. *
    * Diff = max - min.  Mean is the arithmetic mean.                       *
    * (hmm.. must be some roundoff error in my calculations.. smurfette got *
    * 1d6+23 hp at level 3 ? -- anyway.. the values above should be         *
    * approximately right..)                                                */
    type   = level*level*27/40;
    number = UMIN(type/40 + 1, 10);
    type   = UMAX(2, type/number);
    bonus  = UMAX(0, level*(8 + level)*.9 - number*type);
    pMobIndex->hit[DICE_NUMBER]    = number;
    pMobIndex->hit[DICE_TYPE]      = type;
    pMobIndex->hit[DICE_BONUS]     = bonus;
    pMobIndex->mana[DICE_NUMBER]   = level;
    pMobIndex->mana[DICE_TYPE]     = 10;
    pMobIndex->mana[DICE_BONUS]    = 100;
   /* Calculate dam dice.  Gives close to the damage *
    * of old format mobs in damage()  (fight.c)      */
    type   = level*7/4;
    number = UMIN(type/8 + 1, 5);
    type   = UMAX(2, type/number);
    bonus  = UMAX(0, level*9/4 - number*type);
    pMobIndex->damage[DICE_NUMBER] = number;
    pMobIndex->damage[DICE_TYPE]   = type;
    pMobIndex->damage[DICE_BONUS]  = bonus;
    switch ( number_range( 1, 3 ) )
    {
        case (1): pMobIndex->dam_type =  3;       break;
        case (2): pMobIndex->dam_type =  7;       break;
        case (3): pMobIndex->dam_type = 11;       break;
    }
    for (i = 0; i < 3; i++)
        pMobIndex->ac[i]         = interpolate( level, 100, -100);
    pMobIndex->ac[3]             = interpolate( level, 100, 0);    
    pMobIndex->gold              /= 100;
    pMobIndex->size              = SIZE_MEDIUM;
    pMobIndex->new_format        = TRUE;
    ++newmobs;
}

void do_hotreboot (CHAR_DATA *ch, char * argument)
{
    FILE *fp;
    DESCRIPTOR_DATA *d, *d_next;
    OBJ_DATA *obj, *obj_next;
    char buf [100], buf2[100];
    extern int control;
    char arg[MIL];
    bool fSave = FALSE; //if arg == 0 then safe, otherwise its due to a signal

    argument = one_argument(argument,arg);

    fp = fopen (HOTREBOOT_FILE, "w");
    if (!fp)
    {
        sprintf(buf,"`&Mud Control`8: ``Hot Reboot file not writeable, aborted.\n\r");
        do_echo(NULL,buf);
	log_string ("Could not write to hot reboot file.");
	perror ("do_hotreboot:fopen");
	fclose (fp);
	return;
    }
    /* Consider changing all saved areas here, if you use OLC */
    if (atoi(arg)==1)
	sprintf (buf, "\n\r *** SIGBUS detected: Mud Crash is imminent - Trying to Hot Reboot ***\n\r");
    else if (atoi(arg)==2)
	sprintf (buf, "\n\r *** SIGTERM detected: Mud Crash is imminent - Trying to Hot Reboot ***\n\r");
    else if (atoi(arg)==3)
	sprintf (buf, "\n\r *** SIGABRT detected: Mud Crash is imminent - Trying to Hot Reboot ***\n\r");
    else if (atoi(arg)==4)
	sprintf (buf, "\n\r *** Planetary anomaly detected! World destruction is imminent! Trying to world shift...  ***\n\r");
    else{
      fSave = TRUE;
      if (ch != NULL){
	sprintf (buf, "\n\r *** %s has initiated a world shift - please wait! *** \n\r", PERS2(ch));
      }
      else{
	sprintf (buf, "\n\r *** The world is shifting - please wait! *** \n\r");
      }
    }
    
    if (fSave){
      /* SAVE MUD STATUS */
      save_mud();
      /* SAVE CABAL DATA */
      save_cabals(TRUE, NULL );
      /* SAVE ARMIES */
      save_armies();
      /* SAVE CLANS */
      SaveClans();
    }
    /* Check for Maintance */
    if (reboot_buffer[0] != '\0')
      strcat(buf," *** Extended world shift, this may take some time. *** \n\r");

    /* For each playing descriptor, save its state */
    for (d = descriptor_list; d ; d = d_next)
    {
	CHAR_DATA * och = CH (d);
	d_next = d->next; /* We delete from the list , so need to save this */
	if (!d->character || d->connected != CON_PLAYING ) /* drop those logging on */
	{
	    write_to_descriptor (d->descriptor, "\n\rSorry, we are rebooting.  Come back in a few seconds.\n\r", 0);
	    close_socket (d); /* throw'em out */
	}
	else
	{
	    /* clean off blanket of darkness between reboots */
	    affect_strip(och, gsn_blanket);

	    /* force revert */
	    do_revert(och, "" );

	    /* same for charm person */
	    if (!IS_AFFECTED(och, AFF_CHARM))
	      affect_strip(och, gsn_charm_person);

	    fprintf (fp, "%d %s %s %s %ld\n", d->descriptor, och->name, d->ident, d->host, och->logon );
	    if (fSave)
	      save_char_obj (och);

	    write_to_descriptor (d->descriptor, buf, 0);
	    if (d->character->level > 51 && atoi(arg)>=1 && atoi(arg)<=4)
	    {
		write_to_descriptor (d->descriptor, last_malloc, 0);
		write_to_descriptor (d->descriptor, "\n\r", 0);
		write_to_descriptor (d->descriptor, last_loop, 0);
		write_to_descriptor (d->descriptor, "\n\r", 0);
		write_to_descriptor (d->descriptor, last_command, 0);
		write_to_descriptor (d->descriptor, "\n\r", 0);
		write_to_descriptor (d->descriptor, last_mprog, 0);
		write_to_descriptor (d->descriptor, "\n\r", 0);
	    }
	    extract_char(och, TRUE);
	}
    }
    fprintf (fp, "-1\n");
    fprintf (fp, "%d\n", mud_data.max_on);
    fprintf (fp, "%d\n", mud_data.deaths);
    fprintf (fp, "%ld\n", mud_data.crash_time);
    fclose (fp);
    fp = fopen (OBJSAVE_FILE, "w");
    if (fSave){
      for (obj = object_list; obj != NULL; obj = obj_next )
	{
	  obj_next = obj->next;
	  if (IS_OBJ_STAT(obj,ITEM_MELT_DROP))
	    continue;
	  if (obj->in_room != NULL 
	      && obj->in_room->vnum != ROOM_VNUM_BOUNTY	//objects in bounty room are saved/loaded with bounties
	      && obj->carried_by == NULL 
	      && !IS_VIRROOM(obj->in_room)
	      && (IS_LIMITED(obj) 
		  || obj->homevnum != obj->in_room->vnum 
		  || obj->contains != NULL
		|| CAN_WEAR(obj, ITEM_HAS_OWNER)) )
	    fwrite_obj(NULL, obj, fp, 0, 0, FALSE);
	  else if (obj->item_type == ITEM_CABAL && obj->carried_by && obj->carried_by->in_room)
	    fwrite_obj(NULL, obj, fp, 9999, 0, TRUE);
	}
    }
    fprintf (fp, "#END\n");
    fclose (fp);
    /* Close reserve and other always-open files and release other resources */
    fclose (fpReserve);
    /* exec - descriptors are inherited */
    sprintf (buf, "%d", mud_data.mudport);
    sprintf (buf2, "%d", control);
    execl ("../src/clands", "MUD", buf, "Forsaken_Lands", buf2, reboot_buffer, (char *) NULL);

    /* Failed - sucessful exec will not return */
    perror ("do_hotreboot: execl");
    sprintf(buf,"[`&The Voice of God`7]`8 - World shift FAILED!``");
    do_echo(NULL,buf);
    /* Here you might want to reopen fpReserve */
    fpReserve = fopen (NULL_FILE, "r");
}

/* Recover from a Hot Reboot - load players */
void hotreboot_recover ()
{
    DESCRIPTOR_DATA *d;
    CHAR_DATA *ch, *ch_next;
    FILE *fp;
    char name [100], ident[MSL], host[MSL];
    time_t logont, temp;
    int tempmax, tempdeaths, desc;
    bool fOld;
    int i = 0;
    log_string ("World shift recovery initiated");
    fp = fopen (HOTREBOOT_FILE, "r");
    if (!fp) /* there are some descriptors open which will hang forever then ? */
    {
	perror ("hotreboot_recover:fopen");
	log_string ("World shift file not found. Exiting.");
	fclose (fp);
	exit (1);
    }
    unlink (HOTREBOOT_FILE); /* In case something crashes - doesn't prevent reading	*/
    for (i = 0; i < 1000; i++)
    {
	fscanf (fp, "%d ", &desc);
	if (desc == -1)
	{
	    fscanf (fp, "\n%d\n", &tempmax);
	    fscanf (fp, "\n%d\n", &tempdeaths);
	    fscanf (fp, "%ld\n", &temp);
	    mud_data.max_on = tempmax;
	    mud_data.deaths = tempdeaths;
	    mud_data.crash_time = temp;
	    break;
	}
	fscanf (fp, "%s %s %s %ld\n", name, ident, host, &logont);
	/* Write something, and check if it goes error-free */		
	if (!write_to_descriptor (desc, "\n\rRestoring from world shift...\n\r",0))
	{
	    close (desc); /* nope */
	    continue;
	}
	d = new_descriptor();
	d->descriptor = desc;
	d->ident = str_dup (ident);
	d->host = str_dup (host);
	d->next = descriptor_list;
	descriptor_list = d;
	d->connected = CON_HOTREBOOT_RECOVER; /* -15, so close_socket frees the char */
	/* Now, find the pfile */
	fOld = load_char (d, name);
	d->character->logon = logont;
	if (!fOld) /* Player file not found?! */
	{
	    write_to_descriptor (desc, "\n\rSomehow, your character was lost in the Hot Reboot. Sorry.\n\r", 0);
	    close_socket (d);			
	}
	else /* ok! */
	{
	    write_to_descriptor (desc, "\n\rWorld shifting is complete.\n\r",0);
	    /* Just In Case */
	    if (!d->character->in_room)
	        d->character->in_room = get_room_index (ROOM_VNUM_TEMPLE);
	    /* Insert in the char_list */
	    load_obj (d->character);
	    d->character->next = char_list;
	    char_list = d->character;
	    char_to_room (d->character, d->character->in_room);
	    d->character->next_player = player_list;
	    player_list = d->character;
	    reset_char(d->character);
	    do_look (d->character, "");
	    act ("$n materializes!", d->character, NULL, NULL, TO_ROOM);
	    d->connected = CON_PLAYING;
	}
    }
    fclose (fp);
    /* This is to get the player's stallions and familiars and other stuff back after reboot */
    for ( ch = char_list; ch != NULL; ch = ch_next )
    {
	ch_next = ch->next;
	if (!IS_NPC(ch) || ch->in_room == NULL)
	    continue;
	if ((ch->pIndexData->vnum >= MOB_VNUM_SERVANT_FIRE 
	     && ch->pIndexData->vnum <= MOB_VNUM_SERVANT_EARTH)
	    && ch->summoner != NULL && !IS_NPC(ch->summoner)){
	  ch->summoner->pcdata->familiar = ch;
	}
	else if (ch->pIndexData->vnum == MOB_VNUM_MONSTER
		 && ch->summoner != NULL 
		 && !IS_NPC(ch->summoner)){
	  ch->summoner->pcdata->familiar = ch;
	}
	/* reset zombies after rebot to originals (Viri: not needed, save in pfiles now
	else if (ch->pIndexData->vnum == MOB_VNUM_ZOMBIE){
	  AFFECT_DATA* paf;
	  MOB_INDEX_DATA* mob;
	  if ( (paf = affect_find(ch->affected, skill_lookup("animate corpse"))) != NULL
	       && (mob = get_mob_index(paf->modifier)) != NULL){
	    ch->off_flags = paf->bitvector;
	    ch->dam_type = mob->dam_type;
	    ch->act = mob->act;
	    REMOVE_BIT(mob->act,ACT_SCAVENGER);
	    REMOVE_BIT(mob->act,ACT_IS_HEALER);
	    REMOVE_BIT(mob->act,ACT_TRAIN);
	    REMOVE_BIT(mob->act,ACT_PRACTICE);
	    REMOVE_BIT(mob->act,ACT_TOO_BIG);
	  }
	}
	*/
    }
}

/* format_room_name */
/* links in db.c cabal.c */
/* written by viri */
bool format_room_name(ROOM_INDEX_DATA* room, char* room_name)
{
  //The following function attaches appropriate 
  //ascii color string to the room name based on the
  //room_color_table in tables.c

  //buffer for the name.
  char buf[MIL];

  //pointers for the string
  char* strptr;
  char* bufptr;


/*
  1)prefix buf with appropriate ascii code.
  2)Run through the room_name copying non-ascii char's only.
  3)When terminator is hit or MIL is reached stop.
  4)attatch end of ascii sequence, termianate string.
*/
  if (room == NULL || room_name == NULL)
    return FALSE;

  strptr = room_name;
  bufptr = buf;
  
//we prefix the buffer.
  *bufptr++ = '`';
  *bufptr++ = room_color_table[UMIN(MAX_SECT, room->sector_type)].ch;

//First we cleant the name length is MSL - 2(prefix) - 2 (postifx).
  while( *strptr != '\0')
    {
      //we copy the string normaly unless there is asci code.
      if ( *strptr != '`')
	{
	  *bufptr++ = *strptr++;
	  continue;
	}
      //got a ascii code, we skip  the next 2 char.
      strptr++;
      strptr++;
    }//end copy loop;
  //we terminate ascii
  *bufptr++ = '`';
  *bufptr++ = '`';
  //terminate string
  *bufptr++ = '\0';
  //free string
  free_string(room->name);
  room->name = str_dup(buf);
  return TRUE;
}//end room_name_formant



/* color_rooms*/
/* only in db.c */
/* Viri */
void color_rooms()
{
  /* We run through ALL the rooms, coloring the names. */

  ROOM_INDEX_DATA* room;
  int i = 0;

  for (i = 0; i < MAX_KEY_HASH; i++)
    for (room = room_index_hash[i]; room != NULL; room = room->next)
      {
	if (room == NULL)
	  continue;

	if (!format_room_name(room, room->name))
	  {
	    log_string("ERROR IN ROOM NAME FORMAT");
	    nlogf("format_room_name returned error on room %d", room->vnum);
	  }	
      }
}

void load_objprogs( FILE *fp )
{
    PROG_CODE *pOprog;

    if ( area_last == NULL )
    {
	bug( "Load_objprogs: no #AREA seen yet.", 0 );
	exit( 1 );
    }

    for ( ; ; )
    {
	sh_int vnum;
	char letter;

	letter		  = fread_letter( fp );
	if ( letter != '#' )
	{
	    bug( "Load_objprogs: # not found.", 0 );
	    exit( 1 );
	}

	vnum		 = fread_number( fp );
	if ( vnum == 0 )
	    break;

	fBootDb = FALSE;
	if ( get_prog_index( vnum, PRG_OPROG ) != NULL )
	{
	    bug( "Load_objprogs: vnum %d duplicated.", vnum );
	    exit( 1 );
	}
	fBootDb = TRUE;

	pOprog		= alloc_perm( sizeof(*pOprog) );
	pOprog->vnum  	= vnum;
	pOprog->code  	= fread_string( fp );
	if ( oprog_list == NULL )
	    oprog_list = pOprog;
	else
	{
	    pOprog->next = oprog_list;
	    oprog_list 	= pOprog;
	}
	top_oprog_index++;
    }
    return;
}

void load_roomprogs( FILE *fp )
{
    PROG_CODE *pRprog;

    if ( area_last == NULL )
    {
	bug( "Load_roomprogs: no #AREA seen yet.", 0 );
	exit( 1 );
    }

    for ( ; ; )
    {
	sh_int vnum;
	char letter;

	letter		  = fread_letter( fp );
	if ( letter != '#' )
	{
	    bug( "Load_roomprogs: # not found.", 0 );
	    exit( 1 );
	}

	vnum		 = fread_number( fp );
	if ( vnum == 0 )
	    break;

	fBootDb = FALSE;
	if ( get_prog_index( vnum, PRG_RPROG ) != NULL )
	{
	    bug( "Load_roomprogs: vnum %d duplicated.", vnum );
	    exit( 1 );
	}
	fBootDb = TRUE;

	pRprog		= alloc_perm( sizeof(*pRprog) );
	pRprog->vnum  	= vnum;
	pRprog->code  	= fread_string( fp );
	if ( rprog_list == NULL )
	    rprog_list = pRprog;
	else
	{
	    pRprog->next = rprog_list;
	    rprog_list 	= pRprog;
	}
	top_rprog_index++;
    }
    return;
}

void load_traps( FILE *fp ){
  TRAP_INDEX_DATA *pTrap;
  char* temp;
  
  if ( area_last == NULL ){
    bug( "Load_traps: no #AREA seen yet.", 0 );
    exit( 1 );
  }

  for ( ; ; ){
    sh_int vnum;
    char letter;

    letter		  = fread_letter( fp );
    if ( letter != '#' ){
      bug( "Load_traps: # not found.", 0 );
      exit( 1 );
    }

    vnum		 = fread_number( fp );
    if ( vnum <= 0 )
      break;

    fBootDb = FALSE;
    if ( get_trap_index( vnum ) != NULL ){
      bug( "Load_traps: vnum %d duplicated.", vnum );
      exit( 1 );
    }
    fBootDb = TRUE;

    pTrap		= new_trap_index();
    pTrap->area		= area_last;
    pTrap->vnum  	= vnum;
    /* read in commons */
    pTrap->name	      = fread_string( fp );
    pTrap->echo	      = fread_string( fp );
    pTrap->oEcho      = fread_string( fp );
    if ( (pTrap->type = trap_lookup( fread_word( fp ) )) < 1)
      bug("load_traps: Unknown trap type for vnum %d.", vnum);
    pTrap->level = fread_number( fp );
    pTrap->flags = fread_flag( fp );

    /* read in type based stuff */
    switch (pTrap->type){
    default:
    case TTYPE_DUMMY:
      pTrap->value[0] = fread_number( fp );
      pTrap->value[1] = fread_number( fp );
      pTrap->value[2] = fread_number( fp );
      pTrap->value[3] = fread_number( fp );
      pTrap->value[4] = fread_number( fp );
      break;
    case TTYPE_DAMAGE:
      pTrap->value[0] = attack_lookup( fread_word( fp ));
      if (pTrap->value[0] < 0){
	bug("Load_traps: value[0] of TTYPE_DAMAGE vnum %d was incorrect.", vnum);
	pTrap->value[0] = 1;
      }
      pTrap->value[1] = fread_number( fp );
      pTrap->value[2] = fread_number( fp );
      pTrap->value[3] = fread_number( fp );
      pTrap->value[4] = fread_number( fp );
      break;
    case TTYPE_XDAMAGE:
      temp = fread_string( fp );
      pTrap->value[0] = skill_lookup(temp);
      free_string( temp );
      if (pTrap->value[0] < 0){
	bug("Load_traps: value[0] of TTYPE_XDAMAGE vnum %d was incorrect.", vnum);
	pTrap->value[0] = 1;
      }
      pTrap->value[1] = fread_number( fp );
      pTrap->value[2] = fread_number( fp );
      pTrap->value[3] = fread_number( fp );
      pTrap->value[4] = fread_number( fp );
      break;
    case TTYPE_SPELL:
      temp = fread_string( fp );
      pTrap->value[0] = skill_lookup(temp);
      if (pTrap->value[0] < 0){
	bug("Load_traps: value[0] of TTYPE_SPELL vnum %d was incorrect.", vnum);
	pTrap->value[0] = 1;
      }
      pTrap->value[1] = fread_number( fp );
      temp = fread_string( fp );
      pTrap->value[2] = skill_lookup(temp);
      free_string( temp );
      if (pTrap->value[2] < 0){
	bug("Load_traps: value[2] of TTYPE_SPELL vnum %d was incorrect.", vnum);
	pTrap->value[2] = 1;
      }
      pTrap->value[3] = fread_number( fp );
      pTrap->value[4] = fread_number( fp );
      break;
    case TTYPE_MOB:
      pTrap->value[0] = fread_number( fp );
      pTrap->value[1] = fread_number( fp );
      pTrap->value[2] = fread_number( fp );
      pTrap->value[3] = fread_number( fp );
      pTrap->value[4] = fread_number( fp );
      break;
    }
    if ( trap_index_list == NULL )
      trap_index_list = pTrap;
    else{
      pTrap->next = trap_index_list;
      trap_index_list = pTrap;
    }
  }
  return;
}
 
void fix_mobprogs( void )
{
    MOB_INDEX_DATA *pMobIndex;
    PROG_LIST        *list;
    PROG_CODE        *prog;
    int iHash;

    for ( iHash = 0; iHash < MAX_KEY_HASH; iHash++ )
    {
	for ( pMobIndex   = mob_index_hash[iHash];
	      pMobIndex   != NULL;
	      pMobIndex   = pMobIndex->next )
	{
	    for( list = pMobIndex->mprogs; list != NULL; list = list->next )
	    {
		if ( ( prog = get_prog_index( list->vnum, PRG_MPROG ) ) != NULL )
		    list->code = prog->code;
		else
		{
		    bug( "Fix_mobprogs: code vnum %d not found.", list->vnum );
		    exit( 1 );
		}
	    }
	}
    }
}
 
void fix_objprogs( void )
{
    OBJ_INDEX_DATA *pObjIndex;
    PROG_LIST        *list;
    PROG_CODE        *prog;
    int iHash;

    for ( iHash = 0; iHash < MAX_KEY_HASH; iHash++ )
    {
	for ( pObjIndex   = obj_index_hash[iHash];
	      pObjIndex   != NULL;
	      pObjIndex   = pObjIndex->next )
	{
	    for( list = pObjIndex->oprogs; list != NULL; list = list->next )
	    {
		if ( ( prog = get_prog_index( list->vnum, PRG_OPROG ) ) != NULL )
		    list->code = prog->code;
		else
		{
		    bug( "Fix_objprogs: code vnum %d not found.", list->vnum );
		    exit( 1 );
		}
	    }
	}
    }
}

void fix_roomprogs( void )
{
    ROOM_INDEX_DATA *pRoomIndex;
    PROG_LIST        *list;
    PROG_CODE        *prog;
    int iHash;

    for ( iHash = 0; iHash < MAX_KEY_HASH; iHash++ )
    {
	for ( pRoomIndex   = room_index_hash[iHash];
	      pRoomIndex   != NULL;
	      pRoomIndex   = pRoomIndex->next )
	{
	    for( list = pRoomIndex->rprogs; list != NULL; list = list->next )
	    {
		if ( ( prog = get_prog_index( list->vnum, PRG_RPROG ) ) != NULL )
		    list->code = prog->code;
		else
		{
		    bug( "Fix_roomprogs: code vnum %d not found.", list->vnum );
		    exit( 1 );
		}
	    }
	}
    }
}


//prints a text entry for an object
void dump_object( FILE* fp, OBJ_INDEX_DATA* obj ){
  AFFECT_DATA* paf;
  int i;
  char buf[MIL];

//vnum rare unique type level material extra_flags weight keywords area  name
  fprintf(fp, "%d \"%s\" \"%s\" %d %d \"%s\" \"%s\" \"%s\" \"%s\"",
	  obj->vnum,
	  IS_SET(obj->wear_flags, ITEM_RARE) ? "R" : IS_SET(obj->wear_flags, ITEM_UNIQUE) ? "U" : "",
	  item_name(obj->item_type),
	  obj->level,
	  obj->weight,
	  obj->material,
	  extra_bit_name(obj->extra_flags),
	  obj->area->name,
	  obj->short_descr);

  //print item dependent info
  fprintf(fp, "\"" );

  switch ( obj->item_type ){
  case ITEM_SOCKET:
    if (IS_SOC_STAT(obj, SOCKET_ARMOR)
	&& IS_SOC_STAT(obj, SOCKET_WEAPON))
      fprintf(fp, "Ar/Wep");
    else if (IS_SOC_STAT(obj, SOCKET_ARMOR))
      fprintf(fp, "Ar    ");
    else if (IS_SOC_STAT(obj, SOCKET_WEAPON))
      fprintf(fp, "   Wep");
    else 
      fprintf(fp, "   Wep");
    if (obj->value[1]){
      sprintf(buf, " Extra: %s",
	      flag_string( extra_flags,  obj->value[1] ) );
      fprintf(fp, buf);
    }
    if (obj->value[4]){
      sprintf(buf, " Flags: %s\n",
	      flag_string( weapon_type2,  obj->value[4] ) );
      fprintf(fp, buf);
    }
    break;
  case ITEM_SCROLL: 
  case ITEM_ARTIFACT:
  case ITEM_POTION:
  case ITEM_PILL:
    sprintf( buf, "Level %d: ", obj->value[0] );
    for ( i = 1; i <= 4; i++ ){
      if ( obj->value[i] >= 0 
	   && obj->value[i] < MAX_SKILL 
	   && skill_table[obj->value[i]].name != NULL){
	strcat( buf, " '" );
	strcat( buf, skill_table[obj->value[i]].name );
	strcat( buf, "' " );
      }
    }
    fprintf(fp, buf);
    break;
  case ITEM_WAND: 
  case ITEM_STAFF: 
    if (skill_table[obj->value[3]].name == NULL)
      break;
    sprintf( buf, "%dx%dLvl ", obj->value[2], obj->value[0] );
    if ( obj->value[3] >= 0 && obj->value[3] < MAX_SKILL ){
      strcat( buf, " '" );
      strcat( buf, skill_table[obj->value[3]].name );
      strcat( buf, "' " );
    }
    fprintf(fp, buf);
    break;
  case ITEM_DRINK_CON:
    sprintf(buf,"%s %s ", 
	    liq_table[obj->value[2]].liq_color, 
	    liq_table[obj->value[2]].liq_name);
    fprintf(fp, buf);
    break;
  case ITEM_CONTAINER:
    sprintf(buf,"%d at %d# ",
	    obj->value[3], obj->value[0]);
    fprintf(fp, buf);
    if (obj->value[4] != 100){
      sprintf(buf," %d%%", obj->value[4]);
      fprintf(fp, buf);
    }
    break;
  case ITEM_WEAPON:
    buf[0] = 0;
    if (IS_WEAPON_STAT(obj, WEAPON_TWO_HANDS) )
      strcat(buf, "2h");
    switch (obj->value[0]){
    case(WEAPON_EXOTIC) : strcat(buf,"Ex");       break;
    case(WEAPON_SWORD)  : strcat(buf,"Sw");        break; 
    case(WEAPON_DAGGER) : strcat(buf,"Da");       break;
    case(WEAPON_SPEAR)  : strcat(buf,"Sp");        break;
    case(WEAPON_MACE)   : strcat(buf,"Ma");    break;
    case(WEAPON_AXE)    : strcat(buf,"Ax");          break;
    case(WEAPON_FLAIL)  : strcat(buf,"Fl");        break;
    case(WEAPON_WHIP)   : strcat(buf,"Wh");         break;
    case(WEAPON_POLEARM): strcat(buf,"Po");      break;
    case(WEAPON_STAFF)  : strcat(buf,"St");        break;
    default             : strcat(buf,"??");      break;
    }
    fprintf(fp, "%s ", buf);
    if (obj->new_format){
      sprintf(buf,"%dd%d(%d)", obj->value[1],obj->value[2], (1 + obj->value[2]) * obj->value[1] / 2);
    }
    else{
      sprintf( buf, "%d-%d(%d)", obj->value[1], obj->value[2], ( obj->value[1] + obj->value[2] ) / 2 );
    }
    fprintf(fp, buf );
    
    fprintf(fp, " [%s] ",
	    (obj->value[3] > 0 && obj->value[3] < MAX_DAMAGE_MESSAGE) ? attack_table[obj->value[3]].noun : "undefined");
    if (obj->value[4])
      fprintf(fp, "Flags: %s", weapon_bit_name(obj->value[4]));
    break;
  case ITEM_ARMOR:
    sprintf( buf, "AC %d %d %d %d", 
	     obj->value[0], obj->value[1], obj->value[2], obj->value[3] );
    break;
  case ITEM_THROW:
    if (obj->new_format)
      sprintf(buf,"%dd%d (%d)",
	      obj->value[1],obj->value[2], (1 + obj->value[2]) * obj->value[1] / 2);
    else
      sprintf( buf, "%d-%d (%d)",
	       obj->value[1], obj->value[2], ( obj->value[1] + obj->value[2] ) / 2 );
    fprintf(fp,  buf );
    break;
  case ITEM_RANGED:
    if (obj->value[3] == 0)
      sprintf(buf, "%s ", 
	      flag_string(projectile_type, obj->value[0]));
    else{
      OBJ_INDEX_DATA* ammo = get_obj_index( obj->value[3] );
      sprintf(buf, "%s ", 
	      ammo == NULL ? "NOT FOUND" : ammo->short_descr);
    }
    fprintf(fp, buf);
    sprintf(buf, "Ammo %d Rate %d ",
	      obj->value[1], obj->value[2]);
    fprintf(fp, buf);
    sprintf(buf, "Flags: %s ",flag_string(ranged_type, obj->value[4]));
    fprintf(fp, buf);
    break;
  case ITEM_PROJECTILE:
    sprintf(buf, "%s", 
	    flag_string(projectile_type, obj->value[0]));
    fprintf(fp, buf);
    if (obj->new_format)
      sprintf(buf, "%dd%d (%d) ",
	      obj->value[1],obj->value[2], (1 + obj->value[2]) * obj->value[1] / 2);
    else
      sprintf( buf, "%d-%d (%d) ",
	       obj->value[1], obj->value[2], ( obj->value[1] + obj->value[2] ) / 2 );
    fprintf(fp, buf);
  }
  fprintf(fp, "\" " );
  fprintf(fp, "\"" );
  //now affects
  for ( paf = obj->affected; paf != NULL; paf = paf->next ){
    if ( paf->location != APPLY_NONE 
	 && (paf->location < APPLY_O_COND || paf->where == TO_SKILL)
	 && paf->modifier != 0 ){
      sprintf( buf, "%s by %d.", 
	       (paf->where == TO_SKILL ? skill_table[paf->location].name : affect_loc_name( paf->location )), 
	       paf->modifier );
      fprintf( fp, "%-70.70s", buf );
    }
    if (paf->bitvector){
      switch(paf->where){
      case TO_AFFECTS: sprintf(buf,"Adds %s affect.", affect_bit_name(paf->bitvector)); break;
      case TO_OBJECT:  sprintf(buf,"Adds %s object flag.", extra_bit_name(paf->bitvector)); break;
      case TO_WEAPON:  sprintf(buf,"Adds %s weapon flags.", weapon_bit_name(paf->bitvector)); break;
      case TO_IMMUNE:  sprintf(buf,"Adds immunity to %s.", imm_bit_name(paf->bitvector)); break;
      case TO_RESIST:  sprintf(buf,"Adds resistance to %s.", imm_bit_name(paf->bitvector)); break;
      case TO_VULN:    sprintf(buf,"Adds vulnerability to %s.", imm_bit_name(paf->bitvector)); break;
      case TO_SKILL:   /* handled above */ break;
      default:         sprintf(buf,"Unknown bit %d: %d", paf->where,paf->bitvector); break;
      }
      fprintf( fp, "%-70.70s", buf );
    }
  }  
  fprintf(fp, "\"" );
  fprintf(fp, "\n" );
}