<commit_before>//////////////////////////////////////////////////////////////////////////
//
// SneezyMUD - All rights reserved, SneezyMUD Coding Team
//
//    "db.cc" - All functions and routines  related to tinyworld databases
//
//////////////////////////////////////////////////////////////////////////

#include "stdsneezy.h"

#include <sys/types.h>
#include <dirent.h>

#include "socket.h"
#include "statistics.h"
#include "help.h"
#include "mail.h"
#include "obj_component.h"
#include "stdsneezy.h"
#include "loadset.h"
#include "sys_loot.h"
#include "shop.h"
#include "database.h"
#include "obj_spellbag.h"
#include "obj_player_corpse.h"
#include "obj_open_container.h"
#include "obj_corpse.h"
#include "obj_quiver.h"
#include "obj_keyring.h"
#include "obj_chest.h"
#include "obj_bag.h"
#include "obj_base_container.h"
#include "obj_bow.h"
#include "obj_commodity.h"
#include "obj_symbol.h"
#include "obj_table.h"
#include "obj_fuel.h"
#include "obj_audio.h"
#include "obj_boat.h"
#include "obj_drug_container.h"
#include "obj_food.h"
#include "obj_money.h"
#include "obj_opal.h"
#include "obj_organic.h"
#include "obj_pen.h"
#include "obj_smoke.h"
#include "obj_statue.h"
#include "obj_trash.h"
#include "obj_treasure.h"
#include "obj_bandaid.h"
#include "obj_bed.h"
#include "obj_board.h"
#include "obj_book.h"
#include "obj_component.h"
#include "obj_gemstone.h"
#include "obj_key.h"
#include "obj_note.h"
#include "obj_tool.h"
#include "obj_trap.h"
#include "obj_tree.h"
#include "obj_window.h"
#include "obj_portal.h"
#include "obj_arrow.h"
#include "obj_general_weapon.h"
#include "obj_flame.h"
#include "obj_light.h"
#include "obj_gun.h"
#include "obj_vial.h"
#include "obj_pool.h"
#include "obj_base_cup.h"
#include "obj_drinkcon.h"
#include "obj_armor.h"
#include "obj_armor_wand.h"
#include "obj_base_clothing.h"
#include "obj_jewelry.h"
#include "obj_other_obj.h"
#include "obj_potion.h"
#include "obj_scroll.h"
#include "obj_staff.h"
#include "obj_appliedsub.h"
#include "obj_wand.h"
#include "obj_worn.h"
#include "obj_plant.h"
#include "obj_cookware.h"
#include "obj_vehicle.h"
#include "obj_casino_chip.h"
#include "obj_poison.h"
#include "obj_handgonne.h"
#include "obj_egg.h"
#include "obj_cannon.h"
#include "obj_tooth_necklace.h"
#include "obj_trash_pile.h"
#include "liquids.h"

int top_of_world = 0;         // ref to the top element of world 

TRoom *room_db[WORLD_SIZE];

TObjList object_list; // the global linked list of obj's 

TBeing *character_list = 0; // global l-list of chars          
TMonster *pawnman = NULL;
TPCorpse *pc_corpse_list = NULL;
// table of reset data 
vector<zoneData>zone_table(0);

liqInfoT liquidInfo;

int top_of_script = 0;

// Lots o' global variables!!!!!! - Russ 
long total_bc = 0;
long roomCount = 0;
long mobCount = 0;
long objCount = 0;
bool no_mail = 0;
unsigned int help_used_num = 0;
unsigned int news_used_num = 0;
unsigned int wiznews_used_num = 0;
unsigned int wizlist_used_num = 0;
unsigned int total_deaths = 0;
unsigned int total_player_kills = 0;
unsigned int typo_used_num = 0;
unsigned int bug_used_num = 0;
unsigned int idea_used_num = 0;
int mob_tick_count = 0;
int repair_number = 0;
unsigned int total_help_number = 0;
int faction_number = 0;

FILE *mob_f = NULL;        // file containing mob prototypes  

vector<TRoom *>roomspec_db(0);

//struct cached_object { int number; sstring s[17]; };
struct cached_object { int number;map <sstring, sstring> s; };
vector<cached_object *>obj_cache(0);

bool bootTime=false;

struct time_info_data time_info;        // the infomation about the time   
struct weather_data weather_info;        // the infomation about the weather 
class lag_data lag_info;

// local procedures
static void bootZones(void);
static void bootWorld(void);
static void reset_time(void);

struct reset_q_type
{
  resetQElement *head;
  resetQElement *tail;
} r_q;

void bootPulse(const char *str, bool end_str)
{
  /*  This function gets called periodically during bootup
    It basically will do socket stuff to bind new connections
    And sends some boot info to all descriptors.
    This is good for giving feedback during boots that might be long
    But be careful not to send immortal-only info  :)
  */

  Descriptor *d;
  sstring sc;
  static sstring tLastRealMessage("");
  bool tLRMN = false;

  if (str) {
    if (strcmp(str, ".")) {
      sc = MUD_NAME_VERS;
      sc += " Boot Process: ";

      // Set the last real output.
      tLastRealMessage  = sc;
      tLastRealMessage += str;
      tLRMN = true;
    } else
      sc = "";

    sc += str;

    if (end_str)
      sc += "\n\r";
  } else {
    sc += "\n\r";
  }

  gSocket->addNewDescriptorsDuringBoot((tLRMN ? "\n\r" : tLastRealMessage));

  for (d = descriptor_list; d; d = d->next) {
    d->output.putInQ(colorString(NULL, d, sc, NULL, COLOR_BASIC, TRUE));
    d->outputProcessing();
  }

  if (str && strcmp(str, "."))
    vlogf(LOG_MISC, fmt("%s") %  str);
}

void bootDb(void)
{
  bootTime=true;
  bootPulse("Boot db -- BEGIN.");

  bootPulse("Resetting the game time.");
  reset_time();
  bootPulse("Initializing game statistics.");
  if (!init_game_stats()) {
    vlogf(LOG_MISC, "bad result from init_game_stats");
//    exit(0);
  }
  bootPulse("Loading Races.");
  for(race_t rindex=RACE_NORACE;rindex<MAX_RACIAL_TYPES;rindex++)
    Races[rindex] = new Race(rindex);

  bootPulse("Initializing faction data.");
  if (!load_factions()) {
    vlogf(LOG_MISC, "Bad loading of factions.");
    exit(0);
  }
#if 1
  if (!load_newfactions()) {
    vlogf(LOG_MISC, "Bad loading of new factions.");
    exit(0);
  }
#endif

  lockmess.erase();

  // keep this prior to object load
  bootPulse("Initializing Spells.");
  buildSpellArray();
  buildTerrainDamMap();
  buildWeatherDamMap();
//  buildSpellDamArray();
  bootPulse("Initializing Components.");
  buildComponentArray();
  bootPulse("Initializing Terrains.");
  assignTerrainInfo();

  bootPulse("Opening mobile file.");
  if (!(mob_f = fopen(MOB_FILE, "r"))) {
    perror("boot");
    exit(0);
  }
  // mob_f must be open prior to here.
  bootPulse("Generating index tables for mobile file.");
  generate_mob_index();

  bootPulse("Generating index tables for object file.");
  generate_obj_index();

  bootPulse("Building suitset information.");
  suitSets.SetupLoadSetSuits();

  bootPulse("Building help tables.");
  buildHelpIndex();

  bootPulse("Loading zone table.");
  bootZones();

  // must be done before loading objects
  bootPulse("Loading drug-type information.");
  assign_drug_info();

  unsigned int i;
  bootPulse("Loading rooms:", false);
  bootWorld();
  bootPulse(NULL, true);

  vlogf(LOG_MISC, "Assigning function pointers:");
  vlogf(LOG_MISC, "   Shopkeepers.");
  bootTheShops();

  bootPulse("Initializing boards.");
  InitBoards();
  bootPulse("Initializing room specials.");
  assign_rooms();
  bootPulse("Initializing command array.");
  buildCommandArray();

  // command array must be initialized before social messages
  bootPulse("Loading social messages.");
  bootSocialMessages();

  bootPulse("Loading periodic components.");
  assign_component_placement();

  bootPulse("Building item-type information.");
  assign_item_info();

  bootPulse("Building dissection information.");
  readDissectionFile();

  bootPulse("Building creation engine information.");
  SetupCreateEngineData();

  bootPulse("Building whittle information.");
  initWhittle();

  bootPulse("Updating characters with saved items:", false);
  updateRentFiles();
  bootPulse("Processing shop-save files.");
  processShopFiles();
  bootPulse("Processing repair-save files.");
  processRepairFiles();
  bootPulse("Processing saved-room files.");
  updateSavedRoomItems();
  bootPulse("Processing corpse-save files.");
  processCorpseFiles();

  bootPulse("Calculating number of items in rent.");
  vlogf(LOG_MISC, "Totals on limited items:");
  printLimitedInRent();

  bootPulse("Creating Loot List.");
  sysLootBoot();

  for (i = 0; i < zone_table.size(); i++) {
    char *s;
    int d, e;
    s = zone_table[i].name;
    d = (i ? (zone_table[i - 1].top + 1) : 0);
    e = zone_table[i].top;

    if(i==0){
      // all shopkeepers should load in zone 0
      bootPulse("Loading shops.", false);
    } else if(i==1){
      bootPulse(NULL, true);
      bootPulse("Resetting zones:", false);
    }

    vlogf(LOG_MISC, fmt("Performing boot-time reset of %s (rooms %d-%d).") %  s % d % e);
    zone_table[i].resetZone(TRUE);

    // stagger reset times
    zone_table[i].age = ::number(0, zone_table[i].lifespan);

    if (i%10 == 0)
      bootPulse(".", false);
  }
  bootPulse(NULL, true);


  for (unsigned int mobnum = 0; mobnum < mob_index.size(); mobnum++) {
    for (unsigned int zone = 0; zone < zone_table.size(); zone++) {
      if(mob_index[mobnum].virt <= zone_table[zone].top)
	mob_index[mobnum].setMaxNumber(mob_index[mobnum].getNumber());
    }
  }



  // after boot time object loading is minimal, so the cache isn't needed<commit_msg>added object count data to log file on boot<commit_after>//////////////////////////////////////////////////////////////////////////
//
// SneezyMUD - All rights reserved, SneezyMUD Coding Team
//
//    "db.cc" - All functions and routines  related to tinyworld databases
//
//////////////////////////////////////////////////////////////////////////

#include "stdsneezy.h"

#include <sys/types.h>
#include <dirent.h>

#include "socket.h"
#include "statistics.h"
#include "help.h"
#include "mail.h"
#include "obj_component.h"
#include "stdsneezy.h"
#include "loadset.h"
#include "sys_loot.h"
#include "shop.h"
#include "database.h"
#include "obj_spellbag.h"
#include "obj_player_corpse.h"
#include "obj_open_container.h"
#include "obj_corpse.h"
#include "obj_quiver.h"
#include "obj_keyring.h"
#include "obj_chest.h"
#include "obj_bag.h"
#include "obj_base_container.h"
#include "obj_bow.h"
#include "obj_commodity.h"
#include "obj_symbol.h"
#include "obj_table.h"
#include "obj_fuel.h"
#include "obj_audio.h"
#include "obj_boat.h"
#include "obj_drug_container.h"
#include "obj_food.h"
#include "obj_money.h"
#include "obj_opal.h"
#include "obj_organic.h"
#include "obj_pen.h"
#include "obj_smoke.h"
#include "obj_statue.h"
#include "obj_trash.h"
#include "obj_treasure.h"
#include "obj_bandaid.h"
#include "obj_bed.h"
#include "obj_board.h"
#include "obj_book.h"
#include "obj_component.h"
#include "obj_gemstone.h"
#include "obj_key.h"
#include "obj_note.h"
#include "obj_tool.h"
#include "obj_trap.h"
#include "obj_tree.h"
#include "obj_window.h"
#include "obj_portal.h"
#include "obj_arrow.h"
#include "obj_general_weapon.h"
#include "obj_flame.h"
#include "obj_light.h"
#include "obj_gun.h"
#include "obj_vial.h"
#include "obj_pool.h"
#include "obj_base_cup.h"
#include "obj_drinkcon.h"
#include "obj_armor.h"
#include "obj_armor_wand.h"
#include "obj_base_clothing.h"
#include "obj_jewelry.h"
#include "obj_other_obj.h"
#include "obj_potion.h"
#include "obj_scroll.h"
#include "obj_staff.h"
#include "obj_appliedsub.h"
#include "obj_wand.h"
#include "obj_worn.h"
#include "obj_plant.h"
#include "obj_cookware.h"
#include "obj_vehicle.h"
#include "obj_casino_chip.h"
#include "obj_poison.h"
#include "obj_handgonne.h"
#include "obj_egg.h"
#include "obj_cannon.h"
#include "obj_tooth_necklace.h"
#include "obj_trash_pile.h"
#include "liquids.h"

int top_of_world = 0;         // ref to the top element of world 

TRoom *room_db[WORLD_SIZE];

TObjList object_list; // the global linked list of obj's 

TBeing *character_list = 0; // global l-list of chars          
TMonster *pawnman = NULL;
TPCorpse *pc_corpse_list = NULL;
// table of reset data 
vector<zoneData>zone_table(0);

liqInfoT liquidInfo;

int top_of_script = 0;

// Lots o' global variables!!!!!! - Russ 
long total_bc = 0;
long roomCount = 0;
long mobCount = 0;
long objCount = 0;
bool no_mail = 0;
unsigned int help_used_num = 0;
unsigned int news_used_num = 0;
unsigned int wiznews_used_num = 0;
unsigned int wizlist_used_num = 0;
unsigned int total_deaths = 0;
unsigned int total_player_kills = 0;
unsigned int typo_used_num = 0;
unsigned int bug_used_num = 0;
unsigned int idea_used_num = 0;
int mob_tick_count = 0;
int repair_number = 0;
unsigned int total_help_number = 0;
int faction_number = 0;

FILE *mob_f = NULL;        // file containing mob prototypes  

vector<TRoom *>roomspec_db(0);

//struct cached_object { int number; sstring s[17]; };
struct cached_object { int number;map <sstring, sstring> s; };
vector<cached_object *>obj_cache(0);

bool bootTime=false;

struct time_info_data time_info;        // the infomation about the time   
struct weather_data weather_info;        // the infomation about the weather 
class lag_data lag_info;

// local procedures
static void bootZones(void);
static void bootWorld(void);
static void reset_time(void);

struct reset_q_type
{
  resetQElement *head;
  resetQElement *tail;
} r_q;

void bootPulse(const char *str, bool end_str)
{
  /*  This function gets called periodically during bootup
    It basically will do socket stuff to bind new connections
    And sends some boot info to all descriptors.
    This is good for giving feedback during boots that might be long
    But be careful not to send immortal-only info  :)
  */

  Descriptor *d;
  sstring sc;
  static sstring tLastRealMessage("");
  bool tLRMN = false;

  if (str) {
    if (strcmp(str, ".")) {
      sc = MUD_NAME_VERS;
      sc += " Boot Process: ";

      // Set the last real output.
      tLastRealMessage  = sc;
      tLastRealMessage += str;
      tLRMN = true;
    } else
      sc = "";

    sc += str;

    if (end_str)
      sc += "\n\r";
  } else {
    sc += "\n\r";
  }

  gSocket->addNewDescriptorsDuringBoot((tLRMN ? "\n\r" : tLastRealMessage));

  for (d = descriptor_list; d; d = d->next) {
    d->output.putInQ(colorString(NULL, d, sc, NULL, COLOR_BASIC, TRUE));
    d->outputProcessing();
  }

  if (str && strcmp(str, "."))
    vlogf(LOG_MISC, fmt("%s") %  str);
}

void object_stats()
{
  int count[MAX_OBJ_TYPES], i=0, li=0, total=0;

  for(i=0;i<MAX_OBJ_TYPES;++i)
    count[i]=0;
  
  for(TObjIter iter=object_list.begin();iter!=object_list.end();++iter)
    count[(*iter)->itemType()]++;
  
  // BUBBLESORT IS L33T!!!
  while(1){
    for(i=0;i<MAX_OBJ_TYPES;++i){
      if(count[i]>count[li])
	li=i;
    }
    
    if(count[li]==-1)
      break;
    
    vlogf(LOG_MISC, fmt("[%6i] %-17s") %
	  count[li] % ItemInfo[li]->name);
    total += count[li];
    count[li]=-1;
  }
  
  vlogf(LOG_MISC, fmt("[%6i] %-17s") %
	total % "Total");
}



void bootDb(void)
{
  bootTime=true;
  bootPulse("Boot db -- BEGIN.");

  bootPulse("Resetting the game time.");
  reset_time();
  bootPulse("Initializing game statistics.");
  if (!init_game_stats()) {
    vlogf(LOG_MISC, "bad result from init_game_stats");
//    exit(0);
  }
  bootPulse("Loading Races.");
  for(race_t rindex=RACE_NORACE;rindex<MAX_RACIAL_TYPES;rindex++)
    Races[rindex] = new Race(rindex);

  bootPulse("Initializing faction data.");
  if (!load_factions()) {
    vlogf(LOG_MISC, "Bad loading of factions.");
    exit(0);
  }
#if 1
  if (!load_newfactions()) {
    vlogf(LOG_MISC, "Bad loading of new factions.");
    exit(0);
  }
#endif

  lockmess.erase();

  // keep this prior to object load
  bootPulse("Initializing Spells.");
  buildSpellArray();
  buildTerrainDamMap();
  buildWeatherDamMap();
//  buildSpellDamArray();
  bootPulse("Initializing Components.");
  buildComponentArray();
  bootPulse("Initializing Terrains.");
  assignTerrainInfo();

  bootPulse("Opening mobile file.");
  if (!(mob_f = fopen(MOB_FILE, "r"))) {
    perror("boot");
    exit(0);
  }
  // mob_f must be open prior to here.
  bootPulse("Generating index tables for mobile file.");
  generate_mob_index();

  bootPulse("Generating index tables for object file.");
  generate_obj_index();

  bootPulse("Building suitset information.");
  suitSets.SetupLoadSetSuits();

  bootPulse("Building help tables.");
  buildHelpIndex();

  bootPulse("Loading zone table.");
  bootZones();

  // must be done before loading objects
  bootPulse("Loading drug-type information.");
  assign_drug_info();

  unsigned int i;
  bootPulse("Loading rooms:", false);
  bootWorld();
  bootPulse(NULL, true);

  vlogf(LOG_MISC, "Assigning function pointers:");
  vlogf(LOG_MISC, "   Shopkeepers.");
  bootTheShops();

  bootPulse("Initializing boards.");
  InitBoards();
  bootPulse("Initializing room specials.");
  assign_rooms();
  bootPulse("Initializing command array.");
  buildCommandArray();

  // command array must be initialized before social messages
  bootPulse("Loading social messages.");
  bootSocialMessages();

  bootPulse("Loading periodic components.");
  assign_component_placement();

  bootPulse("Building item-type information.");
  assign_item_info();

  bootPulse("Building dissection information.");
  readDissectionFile();

  bootPulse("Building creation engine information.");
  SetupCreateEngineData();

  bootPulse("Building whittle information.");
  initWhittle();

  bootPulse("Updating characters with saved items:", false);
  updateRentFiles();
  bootPulse("Processing shop-save files.");
  processShopFiles();
  bootPulse("Processing repair-save files.");
  processRepairFiles();
  bootPulse("Processing saved-room files.");
  updateSavedRoomItems();
  bootPulse("Processing corpse-save files.");
  processCorpseFiles();

  bootPulse("Calculating number of items in rent.");
  vlogf(LOG_MISC, "Totals on limited items:");
  printLimitedInRent();

  bootPulse("Creating Loot List.");
  sysLootBoot();

  for (i = 0; i < zone_table.size(); i++) {
    char *s;
    int d, e;
    s = zone_table[i].name;
    d = (i ? (zone_table[i - 1].top + 1) : 0);
    e = zone_table[i].top;

    if(i==0){
      // all shopkeepers should load in zone 0
      bootPulse("Loading shops.", false);
    } else if(i==1){
      bootPulse(NULL, true);
      bootPulse("Resetting zones:", false);
    }

    vlogf(LOG_MISC, fmt("Performing boot-time reset of %s (rooms %d-%d).") %  s % d % e);
    zone_table[i].resetZone(TRUE);

    // stagger reset times
    zone_table[i].age = ::number(0, zone_table[i].lifespan);

    if (i%10 == 0)
      bootPulse(".", false);
  }
  bootPulse(NULL, true);


  for (unsigned int mobnum = 0; mobnum < mob_index.size(); mobnum++) {
    for (unsigned int zone = 0; zone < zone_table.size(); zone++) {
      if(mob_index[mobnum].virt <= zone_table[zone].top)
	mob_index[mobnum].setMaxNumber(mob_index[mobnum].getNumber());
    }
  }

  bootPulse("Collecting object count statistics.");
  object_stats();

  // after boot time object loading is minimal, so the cache isn't needed
{'fraction_non_alphanumeric': 0.15705712142321296, 'fraction_numerical': 0.005626406601650412, 'mean_word_length': 3.8576262363352423, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 26, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5844331', 'n_tokens_mistral': 6852, 'n_tokens_neox': 6579, 'n_words': 1624}