//---------------------------------------------------------------------------
#include <vcl.h>
#include <vcl\registry.hpp>
#include <windows.h>
#pragma hdrstop
#define CPP
#define CONSOLE 4
#define MAX_STRING 5242880
#include "EmberForm.h"
#include <time.h>
#include <shellapi.h>
#include <io.h>
#include <process.h>
extern "C" {
#include "merc.h"
}
#include "EmberThread.h"
#include "EmberDialog.h"
//---------------------------------------------------------------------------
#pragma resource "*.dfm"
extern "C" {
void do_shutdown ( CHAR_DATA *ch, char *argument );
void do_reboot ( CHAR_DATA *ch, char *argument );
char * remove_color( const char *str );
void logf_string ( const char *str, ... );
void log_string ( const char *str );
void insert_sort (CHAR_DATA *who_list[300], CHAR_DATA *ch, int length);
void AddUser (CHAR_DATA *ch);
void RemoveUser (CHAR_DATA *ch);
void ChannelMessage (char *mesg, CHAR_DATA *ch);
void do_disconnect( CHAR_DATA *ch, char *argument );
void do_freeze ( CHAR_DATA *ch, char *argument );
void do_ban ( CHAR_DATA *ch, char *argument );
void do_restore ( CHAR_DATA *ch, char *argument );
void do_shout ( CHAR_DATA *ch, char *argument );
void do_immtalk ( CHAR_DATA *ch, char *argument );
void do_question ( CHAR_DATA *ch, char *argument );
void do_gossip ( CHAR_DATA *ch, char *argument );
void do_answer ( CHAR_DATA *ch, char *argument );
void do_auction ( CHAR_DATA *ch, char *argument );
void do_sendinfo ( CHAR_DATA *ch, char *argument );
void do_echo ( CHAR_DATA *ch, char *argument );
};
void SetStatus (char *Message);
bool LogSave (void);
void UpdateStats (void);
void MudStart (void);
void LoadRegistry(void);
void SaveRegistry(void);
extern time_t current_time;
extern bool merc_down;
extern int social_count;
extern int mobile_count;
extern int nAllocString;
extern int sAllocString;
extern int nAllocPerm;
extern int sAllocPerm;
TForm1 *Form1;
Ember *EmberThread;
NOTIFYICONDATA *IconData;
TIcon *TrayIcon;
int LastLog=-1;
bool LogFull=false;
bool NightlySave=true;
tm *TempTime;
bool MudDown=true;
bool ShuttingDown=false;
bool SaveLogfile=false;
bool Reboot=false;
bool LogChanged=false;
CHAR_DATA *ConsoleChar;
int UserCount=0;
char tbuff[MAX_STRING_LENGTH];
int RestartTime=0;
bool DownFromGui=false;
char tname[MAX_STRING_LENGTH];
#define LOG_DIR "..\\log\\" // Log Directory
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
char buff[200];
int TempLength;
IconData=new NOTIFYICONDATA;
TrayIcon=new TIcon;
Application->OnMinimize=AppMinimize;
Application->OnRestore=AppRestore;
_wtzset();
ConsoleChar=new CHAR_DATA;
ConsoleChar->Class=CONSOLE;
ConsoleChar->level=MAX_LEVEL;
ConsoleChar->desc=NULL;
ConsoleChar->act=PLR_CONSOLE;
ConsoleChar->next=NULL;
ConsoleChar->next_in_room=NULL;
ConsoleChar->master=NULL;
ConsoleChar->fighting=NULL;
ConsoleChar->reply=NULL;
ConsoleChar->pet=NULL;
ConsoleChar->memory=NULL;
ConsoleChar->spec_fun=NULL;
ConsoleChar->pIndexData=NULL;
ConsoleChar->desc=NULL;
ConsoleChar->affected=NULL;
ConsoleChar->carrying=NULL;
ConsoleChar->in_room=NULL;
ConsoleChar->was_in_room=NULL;
ConsoleChar->pcdata=NULL;
ConsoleChar->gen_data=NULL;
ConsoleChar->TNode=NULL;
Pages->ActivePage=LogSheet;
Form1->ChannelBox->ItemIndex=0;
strcpy(buff, remove_color(EMBER_MUD_VERSION));
TempLength=strlen(buff);
buff[TempLength-1]=0;
buff[TempLength-2]=0;
Caption=buff;
LoadRegistry();
if (CheckVisible->State == cbChecked)
ConsoleChar->comm=VIS_CONSOLE;
else
ConsoleChar->comm=0;
strcpy(tname, Form1->ConsoleName->Text.c_str());
ConsoleChar->name=tname;
RestartTime=RestartEdit->Text.ToInt() * 1000;
if (CheckStartOnline->State == cbChecked)
{
EmberThread=new Ember(true);
EmberThread->Port=Form1->PortEdit->Text;
EmberThread->Resume();
}
}
//---------------------------------------------------------------------------
void log_string( const char *str )
{
if (LogFull)
return;
char Output[4096];
char *strtime;
int LogResult;
LogChanged=true;
strtime = ctime( ¤t_time );
strtime[strlen(strtime)-1] = '\0';
sprintf( Output, "%s :: %s", strtime, str );
LogResult=Form1->LogMemo->Lines->Add(Output);
if (LastLog==LogResult)
{
char Temp[4096];
if (LogSave())
sprintf( Temp, "%s :: Log file saved.", strtime);
else
sprintf( Temp, "%s :: Error saving log file!", strtime);
Form1->LogMemo->Lines->Clear();
Form1->LogMemo->Lines->Add(Temp);
LogResult=Form1->LogMemo->Lines->Add(Output);
}
LastLog=LogResult;
return;
}
//---------------------------------------------------------------------------
void logf_string( const char *str, ... )
{
if (LogFull)
return;
char Output[4096];
char *strtime;
char list[ 4096*4 ];
int LogResult;
{
va_list param;
va_start(param, str);
vsprintf( list, str, param );
va_end(param);
}
LogChanged=true;
strtime = ctime( ¤t_time );
strtime[strlen(strtime)-1] = '\0';
sprintf( Output, "%s :: %s", strtime, list );
LogResult=Form1->LogMemo->Lines->Add(Output);
if (LastLog==LogResult)
{
char Temp[4096];
if (LogSave())
sprintf( Temp, "%s :: Log file saved.", strtime);
else
sprintf( Temp, "%s :: Error saving log file!", strtime);
Form1->LogMemo->Lines->Clear();
Form1->LogMemo->Lines->Add(Temp);
LogResult=Form1->LogMemo->Lines->Add(Output);
}
LastLog=LogResult;
return;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormShow(TObject *Sender)
{
Form1->Images->GetIcon(0,TrayIcon);
IconData->cbSize=sizeof(NOTIFYICONDATA);
IconData->hWnd=Form1->Handle;
IconData->uID=9000;
IconData->uFlags=NIF_ICON|NIF_MESSAGE|NIF_TIP;
IconData->uCallbackMessage=9000;
IconData->hIcon=TrayIcon->Handle;
strcpy(IconData->szTip,Form1->Caption.c_str());
}
//---------------------------------------------------------------------------
void SetStatus(char *Message)
{
Form1->MudStatus->SimpleText=Message;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::AppMinimize(TObject *Sender)
{
ShowWindow(Application->Handle, SW_HIDE);
Shell_NotifyIcon(NIM_ADD, IconData);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::AppRestore(TObject *Sender)
{
Shell_NotifyIcon(NIM_DELETE, IconData);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::WndProc(Messages::TMessage &Message)
{
if( (Message.Msg == 9000) && (Message.LParam == 515) )
{
ShowWindow(Application->Handle, SW_SHOW);
Application->Restore();
Form1->LogMemo->Perform(EM_LINESCROLL,0,Form1->LogMemo->Lines->Count-1);
}
else
TForm::WndProc(Message);
}
//---------------------------------------------------------------------------
bool LogSave(void)
{
LogFull=true;
char LogFile[4096];
char TimeString[4096];
tm *CurrTm;
time_t t;
int x=0;
long Error;
t=time(NULL);
CurrTm=gmtime(&t);
sprintf(TimeString,"%02d%02d%02d",CurrTm->tm_mon+1,CurrTm->tm_mday,CurrTm->tm_year);
sprintf(LogFile, "%sEmber-%s.log",LOG_DIR,TimeString);
if (!access(LogFile,0))
do {
x++;
sprintf(LogFile,"%sEmber-%s-%d.log",LOG_DIR,TimeString,x);
} while (!access(LogFile,0));
try
{
Form1->LogMemo->Lines->SaveToFile(LogFile);
}
catch (Exception &exception)
{
return false;
}
LastLog=-1;
LogFull=false;
LogChanged=false;
return true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::TimeyTimer(TObject *Sender)
{
TempTime=gmtime(¤t_time);
if ((TempTime->tm_min==59)&&(TempTime->tm_hour==23)&&(NightlySave))
{
char *strtime;
strtime = ctime( ¤t_time );
strtime[strlen(strtime)-1] = '\0';
if (LogSave())
{
Form1->LogMemo->Lines->Clear();
logf_string("%s :: Nightly log file saved successfully.", strtime);
}
else
{
Form1->LogMemo->Lines->Clear();
logf_string("%s :: Unable to save Nightly log!", strtime);
}
NightlySave=false;
}
if ((!NightlySave)&&(TempTime->tm_hour!=23))
NightlySave=true;
if (!merc_down && Form1->Pages->ActivePage==Form1->StatSheet)
UpdateStats();
}
//---------------------------------------------------------------------------
void UpdateStats(void)
{
char buf[MAX_STRING_LENGTH];
sprintf( buf, "Affects %5d\n\r", top_affect );
Form1->Affects->Caption=buf;
sprintf( buf, "Areas %5d\n\r", top_area );
Form1->Areas->Caption=buf;
sprintf( buf, "ExDes %5d\n\r", top_ed );
Form1->ExDes->Caption=buf;
sprintf( buf, "Exits %5d\n\r", top_exit );
Form1->Exits->Caption=buf;
sprintf( buf, "Helps %5d\n\r", top_help );
Form1->Helps->Caption=buf;
sprintf( buf, "Socials %5d\n\r", social_count );
Form1->Socials->Caption=buf;
sprintf( buf, "Mobs %5d\n\r", top_mob_index );
Form1->Mobs->Caption=buf;
sprintf( buf, "(in use)%5d\n\r", mobile_count );
Form1->InUse->Caption=buf;
sprintf( buf, "Objs %5d\n\r", top_obj_index );
Form1->Objects->Caption=buf;
sprintf( buf, "Resets %5d\n\r", top_reset );
Form1->Resets->Caption=buf;
sprintf( buf, "Rooms %5d\n\r", top_room );
Form1->Rooms->Caption=buf;
sprintf( buf, "Shops %5d\n\r", top_shop );
Form1->Shops->Caption=buf;
sprintf( buf, "Strings %5d strings of %7d bytes (max %d).\n\r",
nAllocString, sAllocString, MAX_STRING );
Form1->Strings->Caption=buf;
sprintf( buf, "Perms %5d blocks of %7d bytes.\n\r",
nAllocPerm, sAllocPerm );
Form1->Perms->Caption=buf;
UserCount=0;
for ( DESCRIPTOR_DATA * d = descriptor_list ; d ; d = d->next )
if ( (d->connected == CON_PLAYING) || (d->connected == CON_NOTE_TO) ||
(d->connected == CON_NOTE_SUBJECT) || (d->connected == CON_NOTE_EXPIRE)
|| (d->connected == CON_NOTE_TEXT) || (d->connected == CON_NOTE_FINISH))
UserCount++;
sprintf(buf, "Users %5d", UserCount);
Form1->Users->Caption=buf;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Exit1Click(TObject *Sender)
{
Form1->Close();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Shutdown1Click(TObject *Sender)
{
if (merc_down)
{
ShowMessage("EmberMUD isn't currently running.");
return;
}
do_shutdown(ConsoleChar, "");
SaveLogfile=true;
DownFromGui=true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCloseQuery(TObject *Sender, bool &CanClose)
{
if (!merc_down)
do_shutdown(ConsoleChar, "");
ShuttingDown=true;
if (MudDown)
CanClose=true;
else
CanClose=false;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
Shell_NotifyIcon(NIM_DELETE, IconData);
if (SaveLogfile)
LogSave();
SaveRegistry();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::DownTimerTimer(TObject *Sender)
{
if (ShuttingDown)
{
SaveLogfile=true;
Form1->Close();
return;
}
if ((SaveLogfile) && (MudDown))
{
LogSave();
SaveLogfile=false;
}
if (Reboot)
MudStart();
if (!MudDown)
{
RestartTime-=DownTimer->Interval;
if (RestartTime<=0)
MudStart();
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Startup1Click(TObject *Sender)
{
if (!MudDown)
{
ShowMessage("EmberMUD is already running.");
return;
}
if (EmberThread)
MudStart();
else
{
EmberThread=new Ember(true);
EmberThread->Port=Form1->PortEdit->Text;
EmberThread->Resume();
}
}
//---------------------------------------------------------------------------
void MudStart(void)
{
SaveRegistry();
execl("..\\src\\embergui.exe", "embergui.exe", NULL);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Reboot1Click(TObject *Sender)
{
do_reboot(ConsoleChar, "");
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ClearLog1Click(TObject *Sender)
{
if (LogChanged)
LogSave();
Form1->LogMemo->Lines->Clear();
}
//---------------------------------------------------------------------------
void StatusUp(void)
{
Form1->MudStatus->SimpleText="EmberMUD Running.";
}
//---------------------------------------------------------------------------
void StatusDown(void)
{
Form1->MudStatus->SimpleText="EmberMUD Down.";
}
//---------------------------------------------------------------------------
void AddUser(CHAR_DATA *ch)
{
TTreeNode *TempNode;
ch->TNode=(void *)Form1->UserTree->Items->Add(Form1->UserTree->Items->GetFirstNode(), ch->name);
TempNode=(TTreeNode *)ch->TNode;
TempNode->Data=(void *)ch;
}
//---------------------------------------------------------------------------
void RemoveUser(CHAR_DATA *ch)
{
if (!ch)
{
log_string("Error: NULL pointer passed to RemoveUser(CHAR_DATA *ch)");
return;
}
Form1->UserTree->Items->Delete((TTreeNode *)ch->TNode);
}
//---------------------------------------------------------------------------
void ChannelMessage(char *mesg, CHAR_DATA *ch)
{
int length;
if (ch)
sprintf(tbuff, "%s%s", ch->name, remove_color(mesg));
else
sprintf(tbuff, "%s", remove_color(mesg));
length=strlen(tbuff);
tbuff[length-1]=0;
tbuff[length-2]=0;
EmberThread->Synchronize(EmberThread->AddMessage);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::UserTreeMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int x, int y)
{
if (Button=mbRight)
{
TTreeNode *TempNode;
TempNode=Form1->UserTree->GetNodeAt(x, y);
if(TempNode)
{
Form1->UserTree->Selected=TempNode;
Form1->Kick1->Visible=true;
Form1->Freeze1->Visible=true;
Form1->Ban1->Visible=true;
Form1->N3->Visible=true;
Form1->SendMessage1->Visible=true;
Form1->Restore1->Visible=true;
}
else
{
Form1->Kick1->Visible=false;
Form1->Freeze1->Visible=false;
Form1->Ban1->Visible=false;
Form1->N3->Visible=false;
Form1->SendMessage1->Visible=false;
Form1->Restore1->Visible=false;
}
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Kick1Click(TObject *Sender)
{
CHAR_DATA *ch;
ch=(CHAR_DATA *) Form1->UserTree->Selected->Data;
do_disconnect(ConsoleChar,ch->name);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Freeze1Click(TObject *Sender)
{
CHAR_DATA *ch;
ch=(CHAR_DATA *) Form1->UserTree->Selected->Data;
do_freeze(ConsoleChar,ch->name);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Ban1Click(TObject *Sender)
{
CHAR_DATA *ch;
ch=(CHAR_DATA *) Form1->UserTree->Selected->Data;
do_ban(ConsoleChar,ch->desc->host);
Kick1Click(this);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Restore1Click(TObject *Sender)
{
CHAR_DATA *ch;
ch=(CHAR_DATA *) Form1->UserTree->Selected->Data;
do_restore(ConsoleChar,ch->name);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::RestoreAll1Click(TObject *Sender)
{
do_restore(ConsoleChar, "all");
}
//---------------------------------------------------------------------------
void __fastcall TForm1::SendMessage1Click(TObject *Sender)
{
SendDialog->Visible=true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ChanMessageKeyPress(TObject *Sender, char &Key)
{
if (Key == 13)
{
if (merc_down || MudDown)
{
ShowMessage("Sorry, EmberMUD is currently down.");
return;
}
if (Form1->ChanMessage->Text == "")
return;
switch (Form1->ChannelBox->ItemIndex)
{
case 0:
do_gossip(ConsoleChar, Form1->ChanMessage->Text.c_str());
Form1->ChanMessage->Clear();
break;
case 1:
do_shout(ConsoleChar, Form1->ChanMessage->Text.c_str());
Form1->ChanMessage->Clear();
break;
case 2:
do_auction(ConsoleChar, Form1->ChanMessage->Text.c_str());
Form1->ChanMessage->Clear();
break;
case 3:
do_question(ConsoleChar, Form1->ChanMessage->Text.c_str());
Form1->ChanMessage->Clear();
break;
case 4:
do_answer(ConsoleChar, Form1->ChanMessage->Text.c_str());
Form1->ChanMessage->Clear();
break;
case 5:
do_immtalk(ConsoleChar, Form1->ChanMessage->Text.c_str());
Form1->ChanMessage->Clear();
break;
case 6:
do_sendinfo(ConsoleChar, Form1->ChanMessage->Text.c_str());
Form1->ChanMessage->Clear();
break;
case 7:
do_echo(ConsoleChar, Form1->ChanMessage->Text.c_str());
Form1->ChanMessage->Clear();
break;
default:
ShowMessage("Unhandled Channel selected.");
return;
break;
}
}
}
//---------------------------------------------------------------------------
void LoadRegistry(void)
{
TRegistry *MyReg = new TRegistry;
MyReg->RootKey = HKEY_LOCAL_MACHINE;
if (MyReg->OpenKey("\\Software\\EmberMUD", FALSE))
{
try
{
Form1->ConsoleName->Text=MyReg->ReadString("ConsoleName");
}
catch (...)
{
;
}
try
{
Form1->PortEdit->Text=MyReg->ReadString("Port");
}
catch (...)
{
;
}
try
{
Form1->RestartEdit->Text=MyReg->ReadString("RestartInterval");
}
catch (...)
{
;
}
try
{
Form1->CheckVisible->State=MyReg->ReadInteger("Visible");
}
catch (...)
{
;
}
try
{
Form1->CheckMinimized->State=MyReg->ReadInteger("StartMinimized");
}
catch (...)
{
;
}
try
{
Form1->CheckStartOnline->State=MyReg->ReadInteger("StartOnline");
}
catch (...)
{
;
}
}
}
//---------------------------------------------------------------------------
void SaveRegistry(void)
{
TRegistry *MyReg = new TRegistry;
MyReg->RootKey = HKEY_LOCAL_MACHINE;
if (MyReg->OpenKey("\\Software\\EmberMUD", TRUE))
{
try
{
MyReg->WriteString("ConsoleName", Form1->ConsoleName->Text.c_str());
}
catch (...)
{
;
}
try
{
MyReg->WriteString("Port", Form1->PortEdit->Text.c_str());
}
catch (...)
{
;
}
try
{
MyReg->WriteString("RestartInterval", Form1->RestartEdit->Text.c_str());
}
catch (...)
{
;
}
try
{
MyReg->WriteInteger("Visible", Form1->CheckVisible->State);
}
catch (...)
{
;
}
try
{
MyReg->WriteInteger("StartMinimized", Form1->CheckMinimized->State);
}
catch (...)
{
;
}
try
{
MyReg->WriteInteger("StartOnline", Form1->CheckStartOnline->State);
}
catch (...)
{
;
}
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::PortEditKeyPress(TObject *Sender, char &Key)
{
if (Key == VK_SPACE || (isalpha(Key) && !isdigit(Key)))
{
ShowMessage("Numbers only please.");
Key=0;
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
if (CheckMinimized->State == cbChecked)
Application->Minimize();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ConsoleNameChange(TObject *Sender)
{
strcpy(tname, Form1->ConsoleName->Text.c_str());
}
//---------------------------------------------------------------------------