/
ScryMUD/mud/
ScryMUD/mud/grrmud/Boards/
ScryMUD/mud/grrmud/Help/
ScryMUD/mud/grrmud/Pfiles/
ScryMUD/mud/grrmud/PlayerSacks/
ScryMUD/mud/grrmud/PlayerShops/
ScryMUD/mud/grrmud/help_filter/
ScryMUD/mud/hegemon/
ScryMUD/mud/hegemon/data/
ScryMUD/mud/hegemon/data/help/battle/
ScryMUD/mud/hegemon/data/help/client/
ScryMUD/mud/hegemon/data/help/communications/
ScryMUD/mud/hegemon/data/help/skills/
ScryMUD/mud/hegemon/data/help/spells/
ScryMUD/mud/include/
ScryMUD/mud/lib/
ScryMUD/mud/lib/bitfield/
ScryMUD/mud/lib/log/
ScryMUD/mud/lib/string2/
// $Id: door.cc,v 1.3.2.11 2000/05/03 02:25:12 justin Exp $
// $Revision: 1.3.2.11 $  $Author: justin $ $Date: 2000/05/03 02:25:12 $

//
//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
//

//*********************************************************************// 
///**************************  struct door data   ********************///

#include "door.h"
#include "misc.h"
#include "misc2.h"
#include "commands.h"
#include "room.h"
#include <PtrArray.h>

int door_data::_cnt = 0;

door_data::door_data () { //default constructor
   _cnt++;
   Clear();
}//door_data constructor

door_data::door_data (const door_data& source) {
   _cnt++;
   *this = source; 
}//door

door_data::~door_data () {
   _cnt--;
   Clear();
} //destructor

door_data& door_data::operator= (const door_data& source) {

   if (this == &source)
      return *this;

   String* st_ptr;
   Cell<String*> st_cell(source.names);
   
   vis_bit = source.vis_bit;
   door_num = source.door_num;
   token_num = source.token_num;
   key_num = source.token_num;
   in_zone = source.in_zone;
   
   door_data_flags = source.door_data_flags; //bitfield overloaded =
   
   clear_ptr_list(names);
   while ((st_ptr = st_cell.next())) {
      names.append(new String(*st_ptr));
   }//while
   
   long_desc = source.long_desc;
   return *this;
}//operator=


void door_data::Clear() {
   vis_bit = door_num = key_num = token_num = in_zone = 0;
   clear_ptr_list(names);
   long_desc.Clear();
   door_data_flags.off_all();
}//clear

#ifdef USEMYSQL
void door_data::dbRead(int door_num) {
   MYSQL_RES* result;
   MYSQL_ROW row;
   String query="select * from Doors where DOOR_NUM=";
   query += door_num;

   if (mysql_real_query(database, query, strlen(query))==0) {
      if ((result=mysql_store_result(database))==NULL) {
         if (mudlog.ofLevel(WRN)) {
            mudlog << "In door_data::dbRead(int):\n";
            mudlog << "Error retrieving query results: "
                   << mysql_error(database) << endl;
         }
         return;
      }
      row=mysql_fetch_row(result);

      vis_bit = atoi(row[DOORTBL_VIS_BIT]);
      door_num = atoi(row[DOORTBL_DOOR_NUM]);
      token_num = atoi(row[DOORTBL_TOKEN_NUM]);
      in_zone = atoi(row[DOORTBL_IN_ZONE]);

      vis_bit |= 1024;

      door_data_flags.set(DDFLAG_OPEN_EXIT, atoi(row[DOORTBL_OPEN_EXIT]));
      door_data_flags.set(DDFLAG_MAGIC_LOCKABLE, atoi(row[DOORTBL_MAGIC_LOCKABLE]));
      door_data_flags.set(DDFLAG_CLOSED, atoi(row[DOORTBL_CLOSED]));
      door_data_flags.set(DDFLAG_LOCKED, atoi(row[DOORTBL_LOCKED]));
      door_data_flags.set(DDFLAG_PICKABLE, atoi(row[DOORTBL_PICKABLE]));
      door_data_flags.set(DDFLAG_LOCKABLE, atoi(row[DOORTBL_LOCKABLE]));
      door_data_flags.set(DDFLAG_MAG_LOCKED, atoi(row[DOORTBL_MAG_LOCKED]));
      door_data_flags.set(DDFLAG_DESTRUCTABLE, atoi(row[DOORTBL_DESTRUCTABLE]));
      door_data_flags.set(DDFLAG_CLOSABLE, atoi(row[DOORTBL_CLOSABLE]));
      door_data_flags.set(DDFLAG_FLIPPABLE, atoi(row[DOORTBL_FLIPPABLE]));
      door_data_flags.set(DDFLAG_PC_CANT_OPEN, atoi(row[DOORTBL_PC_CANT_OPEN]));
      door_data_flags.set(DDFLAG_VEHICLE_EXIT, atoi(row[DOORTBL_VEHICLE_EXIT]));
      door_data_flags.set(DDFLAG_SECRET, atoi(row[DOORTBL_SECRET]));
      door_data_flags.set(DDFLAG_BLOCKED, atoi(row[DOORTBL_BLOCKED]));
      door_data_flags.set(DDFLAG_SECRET_WHEN_OPEN, atoi(row[DOORTBL_SECRET_WHEN_OPEN]));
      door_data_flags.set(DDFLAG_CONSUMES_KEY, atoi(row[DOORTBL_CONSUMES_KEY]));
      door_data_flags.set(DDFLAG_NO_PASSDOOR, atoi(row[DOORTBL_NO_PASSDOOR]));

      door_data_flags.turn_on(DDFLAG_IN_USE);
      setComplete();
      mysql_free_result(result);
   }
   else {
      if (mudlog.ofLevel(WRN)) {
         mudlog << "In door_data::dbRead(int):\n";
         mudlog << "Error executing query: " << mysql_error(database) << endl;
      }
      return;
   }

   // names
   query = "select NAME from DoorNames where DOOR_NUM=";
   query += door_num;

   if (mysql_real_query(database, query, strlen(query))==0) {
      if ((result=mysql_store_result(database))==NULL) {
         if (mudlog.ofLevel(WRN)) {
            mudlog << "In door_data::dbRead(int):\n";
            mudlog << "Error retrieving query results: "
                   << mysql_error(database) << endl;
         }
         return;
      }
      while ((row=mysql_fetch_row(result))) {
         Put(new String(row[0]), names);
      }
      mysql_free_result(result);
   }
   else {
      if (mudlog.ofLevel(WRN)) {
         mudlog << "In door_data::dbRead(int):\n";
         mudlog << "Error executing query: " << mysql_error(database) << endl;
      }
      return;
   }
}
#endif

void door_data::fileRead(ifstream& da_file) {
   char tmp[81];
   String tmp_str(80);
   String* string;
   int test = TRUE;
   
   Clear();
   
   if (!da_file) {
      if (mudlog.ofLevel(ERROR)) {
         mudlog << "ERROR:  da_file FALSE in door_data read." << endl;
      }
      return;
   }

   da_file >> vis_bit >> door_num >> token_num >> key_num >> in_zone;
   da_file.getline(tmp, 80);         
   
   vis_bit |= 1024; //hack, forgot blindness bit :P
   
   door_data_flags.Read(da_file);
   door_data_flags.turn_on(10); //set in use flag no matter what

   setComplete();  //if we can read it, it's complete!

   test = TRUE;
   while (test) {
      if (!da_file) {
         if (mudlog.ofLevel(ERROR)) {
            mudlog << "ERROR:  da_file FALSE in door_data read." << endl;
         }
         return;
      }

      da_file >> tmp_str;
      if (strcmp(tmp_str, "~") == 0) {
         test = FALSE;
      }//if
      else {
         string = new String(tmp_str);
         Put(string, names);
      }//else
   }//while            
   da_file.getline(tmp, 80);         
   
   long_desc.Termed_Read(da_file);
}//Read


void door_data::Write(ofstream& da_file) {
   Cell<String*> cll(names);
   String* ptr;
   
   da_file << vis_bit << " " << door_num << " "
           << token_num << " " << key_num << " " << in_zone
           << "\tvbit, door#, token#, key#\n";
   
   door_data_flags.Write(da_file);
   
   int len = 0;
   while ((ptr = cll.next())) {
      len += ptr->Strlen() + 1;
      if (len > 79) {
         da_file << endl;
         len = 0;
      }//if
      da_file << *ptr << " ";
   }//while            
   da_file << "~" << "\tnames\n";         
   
   parse_for_max_80(long_desc);
   da_file << long_desc << endl << "~" << endl;
}//Write



//*******************************************************//
//*********************** door **************************//
 
int door::_cnt = 0;

door::door() {
   _cnt++;
   dr_data = NULL;
   crit_blocking = NULL;
   destination = in_room = 0;
   distance = 0; /* number of battle rounds it takes to move
                    can be used to slow ppl/vehicles down when logical */
   ticks_till_disolve = -1; // don't disolve
}//door constructor

door::door(const door& source) {
   _cnt++;
   dr_data = NULL;
   crit_blocking = NULL;
   *this = source;
   ticks_till_disolve = -1;
}//door copy constructor

door::~door() {
   _cnt--;
   affected_doors.loseData(this);
   Clear();
}//destructor

void door::Clear() {
   dr_data = NULL; //do not delete data pointed too, its in static arrays
   crit_blocking = NULL;
   destination = in_room = 0;
   distance = 0;
   clear_ptr_list(affected_by);
   ticks_till_disolve = -1;
}//Clear()


door& door::operator= (const door& source) {

   if (this == &source)
      return *this;

   Clear();
   
   if (!source.dr_data) {
      mudlog.log(ERROR, "ERROR:  assigning with empty door as source.\n");
      return *this;
   }//if
   
   if (!dr_data) {
      dr_data = new door_data(*(source.dr_data));
   }//if 
   else {
      *dr_data = *(source.dr_data);
   }//else
   destination = source.destination;
   distance = source.distance;
   
   Cell<stat_spell_cell*> cll(source.affected_by);
   stat_spell_cell* ptr;
   while ((ptr = cll.next())) {
      Put(new stat_spell_cell(*ptr), affected_by);
   }//while
   
   crit_blocking = source.crit_blocking;
   ticks_till_disolve = source.ticks_till_disolve;
   in_room = source.in_room;
   return *this;
}//operator=

void door::Read(ifstream& da_file) {
   int data_index;
   int i, tmp;
   char buf[82];
  
   Clear();

   if (!da_file) {
      if (mudlog.ofLevel(ERROR)) {
         mudlog << "ERROR:  da_file FALSE in door read." << endl;
      }
      return;
   }

   da_file >> data_index;
   if (!check_l_range(data_index, 0, NUMBER_OF_DOORS, mob_list[0], FALSE)) {
      mudlog.log(ERROR, "ERROR:  door_index is out of range.\n");
      data_index = 1; //at least it won't crash this way
   }//if
   /* ok, got good data_index */
   
   dr_data = &(door_list[data_index]);
   da_file >> destination;
   da_file >> distance;
   
   /* comment this out for reading original, DB_UPGRADE */
   da_file.getline(buf, 80);
   da_file >> i;
   int is_affected = FALSE;
   while (i != -1) { //affected by
      if (!da_file) {
         if (mudlog.ofLevel(ERROR)) {
            mudlog << "ERROR:  da_file FALSE in door read." << endl;
         }
         return;
      }

      is_affected = TRUE;
      da_file >> tmp;
      Put(new stat_spell_cell(i, tmp), affected_by);
      da_file >> i;
   }//while
   
   if (is_affected) {
      affected_doors.gainData(this);
   }

   da_file.getline(buf, 80);
}// Read()


void door::Write(ofstream& da_file) {
   int count = 0;
   
   da_file << dr_data->door_num << " " << destination << " "
           << distance << " door# dest# distance\n";
   
   Cell<stat_spell_cell*> cll(affected_by);
   stat_spell_cell* ptr;
   while ((ptr = cll.next())) {
      da_file << ptr->stat_spell << " " << ptr->bonus_duration << " ";
      if (++count > 20) {
         da_file << endl;
         count = 0;
      }//if
   }//while
   da_file << -1 << "\tdoor Affected_Bye (end of door)\n";
}//Write()



   ///******************  Static Functions ***************************///

/* static */
door* door::findDoor(const List<door*> &lst, const int i_th,
                     const String* name, const int see_bit,
                     const room& rm) {
   int foo = 0;
   return findDoor(lst, i_th, name, see_bit, rm, foo);
}

door* door::findDoor(const List<door*> &lst, const int i_th,
                     const String* name, const int see_bit,
                     const room& rm, int& count_sofar) {
   return door::findDoor(lst, i_th, name, see_bit, rm.getVisBit(), count_sofar);
}

door* door::findDoor(const List<door*> &lst, const int i_th,
                     const String* name, const int see_bit,
                     const int rm_vis_bit) {
   int foo = 0;
   return findDoor(lst, i_th, name, see_bit, rm_vis_bit, foo);
}

/* static */
door* door::findDoor(const List<door*> &lst, const int i_th,
                     const String* name, const int see_bit,
                     const int rm_vis_bit, int& count_sofar) {
   Cell<String*> char_cell;
   Cell<door*> cell(lst);
   door* door_ptr;
   int count = 0, ptr_v_bit, len;
   String *string;

   if ((len = name->Strlen()) == 0) {
      //mudlog.log(WRN, "WARNING:  len was zero in have_door_named.\n");
      return NULL;
   }//if

   while ((door_ptr = cell.next())) {
      ptr_v_bit = (door_ptr->DOOR_VIS_BIT | rm_vis_bit); 
      if (detect(see_bit, ptr_v_bit)) {
         door_ptr->dr_data->names.head(char_cell);
         if (door_ptr->destination < 0) {
            string = char_cell.prev();
            if (string) {
               while (*string != "#") {
                  if (strncasecmp(*string, *name, len) == 0) {
                     count++;
                     count_sofar++;
                     if (count == i_th) {
                        return door_ptr;
                     }//if
                     break;
                  }//if
                  string = char_cell.prev();
               }//while
            }
         }//if
         else {
            while ((string = char_cell.next())) {
               if (*string == "#") {
                  break;
               }//if
               else {
                  if (strncasecmp(*string, *name, name->Strlen()) == 0) {
                     count++;
                     count_sofar++;
                     if (count == i_th) {
                        return door_ptr;
                     }//if
                     break;
                  }//if
               }//else
            }//while
         }//if
      }//if
   }//while
   return NULL;
}//haveDoor

door* door::findDoorByDest(const List<door*>& lst, int dest_room) {
   Cell<door*> cll(lst);
   door* ptr;

   while ((ptr = cll.next())) {
      if (abs(ptr->destination) == dest_room) {
         return ptr;
      }//if
   }//while
   return ptr;
}

room* door::getDestRoom() {
   return room_list.elementAtNoCreate(bound(0, NUMBER_OF_ROOMS,
                                            abs(destination)));
}//getDestRoom


String* door::getDirection() {
   return direction_of_door(*this);
}


stat_spell_cell* door::isAffectedBy(int spell_num) {
   Cell<stat_spell_cell*> cll(affected_by);
   stat_spell_cell* sp;
   while ((sp = cll.next())) {
      if (sp->stat_spell == spell_num) {
         return sp;
      }
   }//while
   return NULL;
}