// $Id: load_wld.cc,v 1.6.2.11 2000/05/14 01:06:16 greear Exp $
// $Revision: 1.6.2.11 $ $Author: greear $ $Date: 2000/05/14 01:06:16 $
//
//ScryMUD Server Code
//Copyright (C) 1998 Ben Greear
//
//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either version 2
//of the License, or (at your option) any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// To contact the Author, Ben Greear: greear@cyberhighway.net, (preferred)
// greearb@agcs.com
//
#include "misc.h"
#include "commands.h"
#include <iostream.h>
#include <fstream.h>
#include <stdio.h>
#include "classes.h"
#include "olc2.h"
#include "load_wld.h"
#include <PtrArray.h>
#include "vehicle.h"
#include "SkillSpell.h"
void recursive_init_loads(object& obj, int depth) {
obj_list[obj.OBJ_NUM].incrementCurInGame();
if (depth > 80) {
mudlog << "ERROR: reached max depth in recursive_init_loads(obj), obj: "
<< obj.getIdNum() << endl;
return;
}
Cell<object*> cll(obj.inv);
object* ptr;
while ((ptr = cll.next())) {
recursive_init_loads(*ptr, ++depth);
}//while
}//recursive object loads
// Only do objects now, critters are taken care of as they are put
// into a room.
void recursive_init_loads(critter& mob) {
for(int i = 1; i<MAX_EQ; i++) {
if (mob.EQ[i])
recursive_init_loads(*(mob.EQ[i]), 0);
}//for
Cell<object*> cll(mob.inv);
object* ptr;
while ((ptr = cll.next())) {
recursive_init_loads(*ptr, 0);
}//while
}//recursive mob loads
void recursive_init_unload(object& obj, int depth) {
obj.decrementCurInGame();
if (depth > 80) {
mudlog << "WARNING: reached max depth in recursive_init_unload(obj), obj: "
<< obj.getIdNum() << endl;
return;
}
Cell<object*> cll(obj.inv);
object* ptr;
while ((ptr = cll.next())) {
recursive_init_unload(*ptr, ++depth);
}//while
}//recursive object unloads
// Only do objects now, critters are taken care of as they are put
// into a room.
void recursive_init_unload(critter& mob) {
for(int i = 1; i<MAX_EQ; i++) {
if (mob.EQ[i])
recursive_init_unload(*(mob.EQ[i]), 0);
}//for
Cell<object*> cll(mob.inv);
object* ptr;
while ((ptr = cll.next())) {
recursive_init_unload(*ptr, 0);
}//while
}//recursive mob unload
void init_loads() { //this takes a LOT of time, use sparingly (once I hope)
int i;
/* this assumes cur_in_game is zero to start with */
// Zero these guys out...
for (i = 0; i<NUMBER_OF_MOBS; i++) {
if (mob_list[i].isInUse()) {
mob_list[i].setCurInGame(0);
}//if
}
// Zero out the objects...
for (i = 0; i<NUMBER_OF_ITEMS; i++) {
if (obj_list[i].isInUse()) {
obj_list[i].setCurInGame(0);
}
}
for (i = 0; i<NUMBER_OF_ROOMS; i++) {
if (room_list.elementAtNoCreate(i)) {
room_list[i].recursivelyLoad();
}//if
}//for
}//init_loads
void readSiteBanned() {
ifstream file("./World/SITE_BANNED");
if (!file) {
mudlog << "WARNING: Creating a new ./World/SITE_BANNED file.\n";
system("echo \"~\" > ./World/SITE_BANNED");
}//if
String buf(100);
while (TRUE) {
buf.Getline(file, 98);
buf.Strip();
if ((buf == "~") || (!file))
break;
if (buf.Strlen() > 0)
banned_hosts.append(new String(buf));
}//while
}//readSiteBanned
void writeSiteBanned() {
ofstream file("./World/SITE_BANNED");
if (!file) {
mudlog << "ERROR: Could NOT open ./World/SITE_BANNED file to write."
<< endl;
return;
}//if
Cell<String*> cll(banned_hosts);
String* ptr;
while ((ptr = cll.next())) {
file << *ptr << endl;
}
file << "~" << endl;
}//writeSiteBanned
void load_wld() {
int i;
String buf(100);
ZoneCollection::instance().readSelf();
for (i = 0; i < NUMBER_OF_ZONES; i++ ) {
if (ZoneCollection::instance().elementAt(i).isInUse()) {
load_objects(i, ZoneCollection::instance().elementAt(i).isLocked());
}//if
}//for
for (int j = 0; j<NUMBER_OF_ITEMS; j++) {
obj_list[j].setIdNum(j);
}//for
mudlog.log(WRN, "ALL OBJECTS LOADED.\n");
for (i = 0; i < NUMBER_OF_ZONES; i++ ) {
if (ZoneCollection::instance().elementAt(i).isInUse()) {
load_doors(i);
}//if
}//for
for (int j = 0; j<NUMBER_OF_DOORS; j++) {
door_list[j].setIdNum(j);
}//for
mudlog.log(WRN, "ALL DOORS LOADED.\n");
for (i = 0; i < NUMBER_OF_ZONES; i++ ) {
if (ZoneCollection::instance().elementAt(i).isInUse()) {
load_critters(i, ZoneCollection::instance().elementAt(i).isLocked());
}//if
}//for
for (int j = 0; j<NUMBER_OF_MOBS; j++) {
mob_list[j].setIdNum(j);
}//for
mudlog.log(WRN, "ALL CRITTERS LOADED.\n");
for (i = 0; i < NUMBER_OF_ZONES; i++ ) {
if (ZoneCollection::instance().elementAt(i).isInUse()) {
load_zone(i, ZoneCollection::instance().elementAt(i).isLocked());
}//if
// No need to initialize room numbers here.
}//for
mudlog.log(WRN, "ALL ROOMs LOADED.\n");
load_boards(); //add messages to all the boards
load_skill_spells(); //skill/spell DB info
cout << "Max_Obj# is: " << Cur_Max_Obj_Num << endl;
cout << "Max_Door# is: " << Cur_Max_Door_Num << endl;
cout << "Max_Crit# is: " << Cur_Max_Crit_Num << endl;
cout << "Max_Room# is: " << Cur_Max_Room_Num << endl;
init_loads(); /* calculate how many of each item is in game.
*these values are stored in the CUR_IN_GAME fields
*as of now, shopkeeper's permanent inventory is
* not counted. */
// Write out addresses of all objects in the object list.
for (int i = 0; i<Cur_Max_Crit_Num; i++) {
if (obj_list[i].isInUse()) {
obj_ptr_log << "OBJ_LST " << i << " " << &(obj_list[i]) << "\n";
}//if
}//for
// Write out addresses of all critters in the object list.
for (int i = 0; i<Cur_Max_Crit_Num; i++) {
if (mob_list[i].isInUse()) {
obj_ptr_log << "CRI_LST " << i << " " << &(mob_list[i]) << "\n";
}//if
}//for
// Write out addresses of all critters in the object list.
for (int i = 0; i<Cur_Max_Room_Num; i++) {
if (room_list.elementAtNoCreate(i)) {
if (room_list[i].isInUse()) {
obj_ptr_log << "RM_LST " << i << " " << &(room_list[i]) << "\n";
}//if
}//if
}//for
init_casting_objs(); //Initialize the SkillSpell list
cout << "The world has been constructed at least somewhat successfully!"
<< endl;
//write_all_zones(); //this used for updating the WORLD DB
//write_all_doors();
//log("DB_UPDATE WORKED\n");
//do_shutdown = TRUE;
//exit(100);
}//load_wld
void init_casting_objs() {
for (int i = 0; i<NUMBER_OF_ITEMS; i++) {
if (obj_list[i].isInUse()) {
if (obj_list[i].obj_proc) {
Cell<stat_spell_cell*> cll(obj_list[i].obj_proc->casts_these_spells);
stat_spell_cell* ptr;
while ((ptr = cll.next())) {
SSCollection::instance().getSS(ptr->stat_spell).addNewCaster(i);
}//while
}//if could cast spells
}//if in use
}//for all objects
}//init_casting_objects
void write_all_zones() {
String buf(50);
int j;
for (int i = 0; i<NUMBER_OF_ZONES; i++) {
if (ZoneCollection::instance().elementAt(i).isInUse()) { //if exists
Sprintf(buf, "./World/zone_%i", i);
ofstream rfile(buf);
if (!rfile) {
mudlog.log(ERROR,
"ERROR: rfile not opened in 'write_all_zones'.\n");
return;
}//if
for (j = ZoneCollection::instance().elementAt(i).getBeginRoomNum();
j <= ZoneCollection::instance().elementAt(i).getEndRoomNum();
j++) {
if (room_list[j].isInUse()) {
if (room_list[j].isVehicle()) {
rfile << (j | 0x01000000) <<"\t\tRoom Number\n";
}
else {
rfile << j <<"\t\tRoom Number\n";
}
room_list[j].Write(rfile);
}//if
}//for
rfile << "\n\n" << -1 << "\t\tEND OF FILE MARKER\n" << flush;
}//if
}//for
}//write_all_zones
void load_skill_spells() {
SSCollection::instance().read();
}//load_skill_spells()
void load_zone(int zone_num, int read_all) {
#ifdef USEMYSQL
if (config.useMySQL)
db_load_zone(zone_num, read_all);
else
#endif
file_load_zone(zone_num, read_all);
}
#ifdef USEMYSQL
void db_load_zone(int zone_num, int read_all) {
int k;
MYSQL_RES* result;
MYSQL_ROW row;
String query="select ROOM_NUM from Rooms where IN_ZONE=";
query += zone_num;
if (mysql_real_query(database, query, strlen(query))==0) {
if ((result=mysql_store_result(database))==NULL) {
if (mudlog.ofLevel(WRN)) {
mudlog << "In db_load_zone(int, int):\n";
mudlog << "Error retrieving query results: "
<< mysql_error(database) << endl;
}
return;
}
while ((row=mysql_fetch_row(result))) {
k = atoi(row[0]);
if ((k & ~(0x01000000)) > NUMBER_OF_ROOMS) {
if (mudlog.ofLevel(ERROR)) {
mudlog << "In db_load_zone(int, int):\n";
mudlog << "Room# " << k << "is too high for the room_list.\n"
<< "Consider increasing the value of NUMBER_OF_ROOMS "
<< "in const.h\n";
}
return;
}
if ((k & ~(0x01000000)) > Cur_Max_Room_Num)
Cur_Max_Room_Num = (k & ~(0x01000000));
if ((k & 0x01000000)) {
vehicle* tmp_v = new vehicle;
tmp_v->dbRead(k, read_all);
pulsed_proc_rooms.gainData(tmp_v);
room_list.set(tmp_v, k);
}
room_list[k].dbRead(k, read_all);
}
mysql_free_result(result);
}
else {
if (mudlog.ofLevel(WRN)) {
mudlog << "In db_load_zone(int, int):\n";
mudlog << "Error executing query: " << mysql_error(database) << endl;
}
return;
}
}
#endif
void file_load_zone(int zone_num, int read_all) {
char buf[81];
int k = 0;
String buff(100);
Sprintf(buff, "In load_zone: %i.\n", zone_num);
mudlog.log(TRC, buff);
sprintf(buf, "./World/zone_%i", zone_num);
ifstream rfile(buf);
if (!rfile) {
String tmp("cp ./World/DEFAULT_ZONE ");
tmp += buf;
system(tmp); //create the file then
return;
}//if
rfile >> k;
rfile.getline(buf, 80); //junk line
while ((k != -1) && rfile) {
// This is embarrassing, but it works! Don't you just love backwards
// compatibility!
if ((k & ~(0x01000000)) > NUMBER_OF_ROOMS) {
sprintf(buf, "Room# %i is too high for the room_list.\n", k);
mudlog.log(ERROR, buf);
exit(100);
}//if
if ((k & ~(0x01000000)) > Cur_Max_Room_Num)
Cur_Max_Room_Num = (k & ~(0x01000000));
Sprintf(buff, "Reading room number: %i in zone %i.\n", k, zone_num);
mudlog.log(DBG, buff);
if ((k & 0x01000000)) { //then it's a vehicle
k = (k & ~(0x01000000));
if (mudlog.ofLevel(DB))
mudlog << "Reading a vehicle number: " << k << endl;
vehicle* tmp_v = new vehicle;
pulsed_proc_rooms.gainData(tmp_v);
room_list.set(tmp_v, k);
}
room_list[k].fileRead(rfile, read_all);
room_list[k].setRoomNum(k); //just in case
rfile >> k;
mudlog << "About to read room: " << k << endl;
rfile.getline(buf, 80); //comments after the room number
}//while, the big loop, reads in a whole room
if (!rfile) {
mudlog << "Dropped out of reading zone because of !rfile." << endl;
}
}//load_zone
void load_boards() {
int k, i;
char buf[100];
String sbuf(100);
object* new_obj;
mudlog.log(TRC, "in load_boards\n");
for (i = 0; i< NUMBER_OF_ITEMS; i++) {
if (obj_list[i].OBJ_FLAGS.get(10)) {
if (obj_list[i].OBJ_FLAGS.get(74)) { //if a board
sbuf = "./Boards/board_";
sbuf.Append(i);
ifstream rfile(sbuf);
if (!rfile) {
String tmp("cp ./World/DEFAULT_OBJECTS ");
tmp += sbuf;
system(tmp); //create the file then
return;
}//if
rfile >> k;
rfile.getline(buf, 80); //allows comments after the mob num
while ((k != -1) && rfile) {
if (k > NUMBER_OF_ITEMS) {
sprintf(buf, "Item# %i is too high for the obj_list.\n", k);
mudlog.log(DIS, buf);
exit(100);
}//if
sprintf(buf, "Reading message Number %i.\n", k);
mudlog.log(DBG, buf);
new_obj = new object;
new_obj->fileRead(rfile, TRUE);
Cell<object*> sort_cll(obj_list[i].inv);
object* tmp_optr;
int inserted = FALSE;
while ((tmp_optr = sort_cll.next())) {
if (atoi(*(tmp_optr->names.peekFront())) >
(atoi(*(new_obj->names.peekFront())))) {
inserted = TRUE;
obj_list[i].inv.insertBefore(sort_cll, new_obj);
break;
}//if
}//while
if (!inserted) {
obj_list[i].inv.append(new_obj);
}
new_obj->in_list = &(obj_list[i].inv); //make it SOBJ
rfile >> k;
rfile.getline(buf, 80);
}//while, the big loop, reads in a whole room
}//if
}//if
}//for
}//load_boardss
void load_objects(int for_zone, int read_all) {
#ifdef USEMYSQL
if (config.useMySQL)
db_load_objects(for_zone, read_all);
else
#endif
file_load_objects(for_zone, read_all);
}
#ifdef USEMYSQL
void db_load_objects(int for_zone, int read_all) {
long k;
MYSQL_RES* result;
MYSQL_ROW row;
String query="select OBJ_NUM, SOBJ_NUM from Objects";
if (mysql_real_query(database, query, strlen(query))==0) {
if ((result=mysql_store_result(database))==NULL) {
if (mudlog.ofLevel(WRN)) {
mudlog << "In db_load_objects(int, int):\n";
mudlog << "Error retrieving query results: "
<< mysql_error(database) << endl;
}
return;
}
while ((row=mysql_fetch_row(result))) {
k=atol(row[1]);
if (k != -1) {
// Must be an SOBJ, we'll skip it now and load it when we load the
// critter or object it's on.
continue;
}
k=atol(row[0]);
if (k > NUMBER_OF_ITEMS) {
if (mudlog.ofLevel(ERROR)) {
mudlog << "In db_load_objects(int, int): \n";
mudlog << "Item# " << k << " is too high for the obj_list.\n";
mudlog << "Consider increasing NUMBER_OF_ITEMS in const.h\n";
continue;
}
}
if (k > Cur_Max_Obj_Num)
Cur_Max_Obj_Num = k;
obj_list[k].dbRead(k, -1, read_all);
obj_list[k].OBJ_FLAGS.turn_off(70);
obj_list[k].OBJ_IN_ZONE = for_zone;
}
}
}
#endif
void file_load_objects(int for_zone, int read_all) {
int k;
char buf[100];
String sbuf(100);
mudlog.log(TRC, "in load_objects\n");
sbuf = "./World/objects_";
sbuf.Append(for_zone);
ifstream rfile(sbuf);
if (!rfile) {
String tmp("cp ./World/DEFAULT_OBJECTS ");
tmp += sbuf;
system(tmp); //create the file then
return;
}//if
rfile >> k;
rfile.getline(buf, 80); //allows comments after the mob num
while ((k != -1) && rfile) {
if (k > NUMBER_OF_ITEMS) {
sprintf(buf, "Item# %i is too high for the obj_list.\n", k);
mudlog.log(DIS, buf);
exit(100);
}//if
if (k > Cur_Max_Obj_Num)
Cur_Max_Obj_Num = k;
sprintf(buf, "Reading Item Number %i.\n", k);
mudlog.log(DBG, buf);
obj_list[k].fileRead(rfile, read_all);
//normalize_obj(obj_list[k]); //make it normal as possible
obj_list[k].OBJ_FLAGS.turn_off(70); //doesn't need resetting
obj_list[k].OBJ_IN_ZONE = for_zone;
rfile >> k;
rfile.getline(buf, 80);
}//while, the big loop, reads in a whole room
}//load_items
void load_critters(int for_zone, int read_all) {
#ifdef USEMYSQL
if (config.useMySQL)
db_load_critters(for_zone, read_all);
else
#endif
file_load_critters(for_zone, read_all);
}
#ifdef USEMYSQL
void db_load_critters(int for_zone, int read_all) {
int k;
MYSQL_RES* result;
MYSQL_ROW row;
String query="select MOB_NUMBER from Critters where PC_NUM=0 and FROM_ZONE=";
query+=for_zone;
if (mysql_real_query(database, query, strlen(query))==0) {
if ((result=mysql_store_result(database))==NULL) {
if (mudlog.ofLevel(WRN)) {
mudlog << "In db_load_critters(int, int):\n";
mudlog << "Error retrieving query results: "
<< mysql_error(database) << endl;
}
return;
}
while ((row=mysql_fetch_row(result))) {
k=atoi(row[0]);
if (k > NUMBER_OF_MOBS) {
if (mudlog.ofLevel(ERROR)) {
mudlog << "In db_load_critters(int, int):\n";
mudlog << "Critter# " << k << " is too high for the mob list.\n"
<< "Consider increasing NUMBER_OF_MOBS in const.h.\n";
}
return;
}
if (k > Cur_Max_Crit_Num)
Cur_Max_Crit_Num = k;
mob_list[k].dbRead(k, 0, read_all);
if (mob_list[k].mob)
mob_list[k].MOB_FLAGS.turn_off(4);
}
mysql_free_result(result);
}
else {
if (mudlog.ofLevel(WRN)) {
mudlog << "In db_load_critters(int, int):\n";
mudlog << "Error executing query: " << mysql_error(database) << endl;
}
return;
}
}
#endif
void file_load_critters(int for_zone, int read_all) {
int k;
char buf[100];
String sbuf(100);
Sprintf(sbuf, "In load_critters: zone %i\n", for_zone);
mudlog.log(TRC, sbuf);
sbuf = "./World/critters_";
sbuf.Append(for_zone);
ifstream rfile(sbuf);
if (!rfile) {
String tmp("cp ./World/DEFAULT_CRITTERS ");
tmp += sbuf;
system(tmp); //create the file then
return;
}//if
rfile >> k; //critter number
rfile.getline(buf, 80);
while ((k != -1) && rfile) {
Sprintf(sbuf, "Reading critter# %i", k);
mudlog.log(DBG, sbuf);
if (k > NUMBER_OF_MOBS) {
sprintf(buf, "Critter# %i is too high for the mob_list.\n", k);
mudlog.log(DIS, buf);
exit(100);
}//if
if (k > Cur_Max_Crit_Num)
Cur_Max_Crit_Num = k;
mob_list[k].fileRead(rfile, read_all);
if (mob_list[k].mob) {
mob_list[k].MOB_FLAGS.turn_off(4); //init to !need_resetting
}//if
rfile >> k;
rfile.getline(buf, 80);
}//while, the big loop, reads in a whole critter
}//load_critters
void load_doors(int for_zone) {
#ifdef USEMYSQL
if (config.useMySQL)
db_load_doors(for_zone);
else
#endif
file_load_doors(for_zone);
}
#ifdef USEMYSQL
void db_load_doors(int for_zone) {
long k;
MYSQL_RES* result;
MYSQL_ROW row;
String query="select DOOR_NUM from Doors";
if (mysql_real_query(database, query, strlen(query))==0) {
if ((result=mysql_store_result(database))==NULL) {
if (mudlog.ofLevel(WRN)) {
mudlog << "In db_load_doors(int):\n";
mudlog << "Error retrieving query results: "
<< mysql_error(database) << endl;
}
return;
}
while ((row=mysql_fetch_row(result))) {
k=atol(row[0]);
if (k > NUMBER_OF_DOORS) {
if (mudlog.ofLevel(ERROR)) {
mudlog << "In db_load_doors(int): \n";
mudlog << "Door# " << k << " is too high for the obj_list.\n";
mudlog << "Consider increasing NUMBER_OF_DOORS in const.h\n";
continue;
}
}
if (k > Cur_Max_Door_Num)
Cur_Max_Door_Num = k;
door_list[k].dbRead(k);
}
}
else {
if (mudlog.ofLevel(WRN)) {
mudlog << "In db_load_critters(int, int):\n";
mudlog << "Error executing query: " << mysql_error(database) << endl;
}
return;
}
}
#endif
void file_load_doors(int for_zone) {
int k;
char temp_str[100];
String sbuf(100);
mudlog.log(TRC, "in load_doors\n");
sbuf = "./World/doors_";
sbuf.Append(for_zone);
ifstream rfile(sbuf);
if (!rfile) {
String tmp("cp ./World/DEFAULT_DOORS ");
tmp += sbuf;
system(tmp); //create the file then
return;
}//if
rfile >> k;
rfile.getline(temp_str, 80);
while ((k != -1) && rfile) {
if (k > NUMBER_OF_DOORS) {
sprintf(temp_str, "Door# %i is too high for the door_list.\n", k);
mudlog.log(DIS, temp_str);
exit(100);
}//if
if (k > Cur_Max_Door_Num)
Cur_Max_Door_Num = k;
door_list[k].fileRead(rfile);
rfile >> k;
rfile.getline(temp_str, 80);
}//while, the big loop, reads in a whole room
}//load_doors