aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TODO.md1
-rw-r--r--reference/enums.hh378
-rw-r--r--reference/game.c1747
-rw-r--r--reference/types.hh377
-rw-r--r--src/config.cc6
-rw-r--r--src/connection.hh56
-rw-r--r--src/containers.hh338
-rw-r--r--src/containers/matrix.hh132
-rw-r--r--src/containers/priority_queue.hh94
-rw-r--r--src/containers/vector.hh123
-rw-r--r--src/creature.cc2
-rw-r--r--src/creature.hh61
-rw-r--r--src/enums.hh198
-rw-r--r--src/main.cc569
-rw-r--r--src/main.hh58
-rw-r--r--src/map.hh26
-rw-r--r--src/monster.hh88
-rw-r--r--src/player.hh9
-rw-r--r--src/shm.cc385
-rw-r--r--src/skill.cc6
-rw-r--r--src/skill.hh14
-rw-r--r--src/time.cc96
-rw-r--r--src/util.cc42
23 files changed, 1925 insertions, 2881 deletions
diff --git a/TODO.md b/TODO.md
index 148632c..562a2d6 100644
--- a/TODO.md
+++ b/TODO.md
@@ -1,4 +1,5 @@
## TODO NEXT
+- CONFIG
- TCreature
- TPlayer
- TNonPlayer
diff --git a/reference/enums.hh b/reference/enums.hh
index 9e999c4..254781e 100644
--- a/reference/enums.hh
+++ b/reference/enums.hh
@@ -1,47 +1,4 @@
-enum CreatureType: int {
- PLAYER=0,
- MONSTER=1,
- NPC=2
-};
-
-enum CONNECTIONSTATE: int {
- CONNECTION_FREE=0,
- CONNECTION_ASSIGNED=1,
- CONNECTION_CONNECTED=2,
- CONNECTION_LOGIN=3,
- CONNECTION_GAME=4,
- CONNECTION_DEAD=5,
- CONNECTION_LOGOUT=6,
- CONNECTION_DISCONNECTED=7
-};
-
-enum KNOWNCREATURESTATE: int {
- KNOWNCREATURE_FREE=0,
- KNOWNCREATURE_UPTODATE=1,
- KNOWNCREATURE_OUTDATED=2
-};
-
-enum ToDoType: int {
- TDWait=0,
- TDGo=1,
- TDRotate=2,
- TDMove=3,
- TDTrade=4,
- TDUse=5,
- TDTurn=6,
- TDAttack=7,
- TDTalk=8,
- TDChangeState=9
-};
-
-enum GAMESTATE: int {
- GAME_STARTING=0,
- GAME_RUNNING=1,
- GAME_CLOSING=2,
- GAME_ENDING=3
-};
-
enum STATE: int {
SLEEPING=0,
IDLE=1,
@@ -52,90 +9,6 @@ enum STATE: int {
PANIC=6
};
-enum SpellShapeType: int {
- SHAPE_ACTOR=0,
- SHAPE_VICTIM=1,
- SHAPE_ORIGIN=2,
- SHAPE_DESTINATION=3,
- SHAPE_ANGLE=4
-};
-
-enum SpellImpactType: int {
- IMPACT_DAMAGE=0,
- IMPACT_FIELD=1,
- IMPACT_HEALING=2,
- IMPACT_SPEED=3,
- IMPACT_DRUNKEN=4,
- IMPACT_STRENGTH=5,
- IMPACT_OUTFIT=6,
- IMPACT_SUMMON=7
-};
-
-enum RESULT: int {
- ERROR=-1,
- NOERROR=0,
- NOTACCESSIBLE=1,
- NOTMOVABLE=2,
- NOTTAKABLE=3,
- NOROOM=4,
- OUTOFRANGE=5,
- OUTOFHOME=6,
- CANNOTTHROW=7,
- TOOHEAVY=8,
- CROSSREFERENCE=9,
- CONTAINERFULL=10,
- WRONGPOSITION=11,
- WRONGPOSITION2=12,
- WRONGCLOTHES=13,
- HANDSNOTFREE=14,
- HANDBLOCKED=15,
- ONEWEAPONONLY=16,
- NOMATCH=17,
- NOTCUMULABLE=18,
- TOOMANYPARTS=19,
- EMPTYCONTAINER=20,
- SPLITOBJECT=21,
- NOKEYMATCH=22,
- UPSTAIRS=23,
- DOWNSTAIRS=24,
- CREATURENOTEXISTING=25,
- PLAYERNOTEXISTING=26,
- PLAYERNOTONLINE=27,
- NAMEAMBIGUOUS=28,
- NOTUSABLE=29,
- FEDUP=30,
- DESTROYED=31,
- SPELLUNKNOWN=32,
- LOWMAGICLEVEL=33,
- MAGICITEM=34,
- NOTENOUGHMANA=35,
- NOSKILL=36,
- TARGETLOST=37,
- OUTOFAMMO=38,
- NOCREATURE=39,
- TOOLONG=40,
- TARGETOUTOFRANGE=41,
- TARGETHIDDEN=42,
- ATTACKNOTALLOWED=43,
- NOWAY=44,
- LOGINERROR=45,
- LOGINABORT=46,
- PROTECTIONZONE=47,
- ENTERPROTECTIONZONE=48,
- EXHAUSTED=49,
- NOTINVITED=50,
- NOPREMIUMACCOUNT=51,
- MOVENOTPOSSIBLE=52,
- ALREADYTRADING=53,
- PARTNERTRADING=54,
- TOOMANYOBJECTS=55,
- TOOMANYSLAVES=56,
- NOTTURNABLE=57,
- SECUREMODE=58,
- NOTENOUGHSOULPOINTS=59,
- LOWLEVEL=60
-};
-
enum ActionType: int {
ACTION_CREATEONMAP=0,
ACTION_CREATE=1,
@@ -233,140 +106,6 @@ enum INSTANCEATTRIBUTE: int {
REMAININGUSES=17
};
-enum TYPEATTRIBUTE: int {
- WAYPOINTS=0,
- CAPACITY=1,
- CHANGETARGET=2,
- KEYDOORTARGET=3,
- NAMEDOORTARGET=4,
- LEVELDOORTARGET=5,
- QUESTDOORTARGET=6,
- NUTRITION=7,
- INFORMATIONTYPE=8,
- FONTSIZE=9,
- MAXLENGTH=10,
- MAXLENGTHONCE=11,
- SOURCELIQUIDTYPE=12,
- ABSTELEPORTEFFECT=13,
- RELTELEPORTDISPLACEMENT=14,
- RELTELEPORTEFFECT=15,
- AVOIDDAMAGETYPES=16,
- MINIMUMLEVEL=17,
- PROFESSIONS=18,
- WEIGHT=19,
- ROTATETARGET=20,
- DESTROYTARGET=21,
- BODYPOSITION=22,
- SKILLNUMBER=23,
- SKILLMODIFICATION=24,
- PROTECTIONDAMAGETYPES=25,
- DAMAGEREDUCTION=26,
- BRIGHTNESS=27,
- LIGHTCOLOR=28,
- CORPSETYPE=29,
- TOTALEXPIRETIME=30,
- EXPIRETARGET=31,
- TOTALUSES=32,
- WEAROUTTARGET=33,
- WEAPONTYPE=34,
- WEAPONATTACKVALUE=35,
- WEAPONDEFENDVALUE=36,
- SHIELDDEFENDVALUE=37,
- BOWRANGE=38,
- BOWAMMOTYPE=39,
- THROWRANGE=40,
- THROWATTACKVALUE=41,
- THROWDEFENDVALUE=42,
- THROWMISSILE=43,
- THROWSPECIALEFFECT=44,
- THROWEFFECTSTRENGTH=45,
- THROWFRAGILITY=46,
- WANDRANGE=47,
- WANDMANACONSUMPTION=48,
- WANDATTACKSTRENGTH=49,
- WANDATTACKVARIATION=50,
- WANDDAMAGETYPE=51,
- WANDMISSILE=52,
- AMMOTYPE=53,
- AMMOATTACKVALUE=54,
- AMMOMISSILE=55,
- AMMOSPECIALEFFECT=56,
- AMMOEFFECTSTRENGTH=57,
- ARMORVALUE=58,
- ELEVATION=59,
- DISGUISETARGET=60,
- MEANING=61
-};
-
-enum FLAG: int {
- BANK=0,
- CLIP=1,
- BOTTOM=2,
- TOP=3,
- CONTAINER=4,
- CHEST=5,
- CUMULATIVE=6,
- USEEVENT=7,
- CHANGEUSE=8,
- FORCEUSE=9,
- MULTIUSE=10,
- DISTUSE=11,
- MOVEMENTEVENT=12,
- COLLISIONEVENT=13,
- SEPARATIONEVENT=14,
- KEY=15,
- KEYDOOR=16,
- NAMEDOOR=17,
- LEVELDOOR=18,
- QUESTDOOR=19,
- BED=20,
- FOOD=21,
- RUNE=22,
- INFORMATION=23,
- TEXT=24,
- WRITE=25,
- WRITEONCE=26,
- LIQUIDCONTAINER=27,
- LIQUIDSOURCE=28,
- LIQUIDPOOL=29,
- TELEPORTABSOLUTE=30,
- TELEPORTRELATIVE=31,
- UNPASS=32,
- UNMOVE=33,
- UNTHROW=34,
- UNLAY=35,
- AVOID=36,
- MAGICFIELD=37,
- RESTRICTLEVEL=38,
- RESTRICTPROFESSION=39,
- TAKE=40,
- HANG=41,
- HOOKSOUTH=42,
- HOOKEAST=43,
- ROTATE=44,
- DESTROY=45,
- CLOTHES=46,
- SKILLBOOST=47,
- PROTECTION=48,
- LIGHT=49,
- ROPESPOT=50,
- CORPSE=51,
- EXPIRE=52,
- EXPIRESTOP=53,
- WEAROUT=54,
- WEAPON=55,
- SHIELD=56,
- BOW=57,
- THROW=58,
- WAND=59,
- AMMO=60,
- ARMOR=61,
- HEIGHT=62,
- DISGUISE=63,
- SHOWDETAIL=64,
- SPECIALOBJECT=65
-};
-
enum SPECIALMEANING: int {
MONEY_ONE=1,
MONEY_HUNDRED=2,
@@ -397,91 +136,6 @@ enum SPECIALMEANING: int {
MAGICFIELD_RUSHWOOD=48
};
-enum RIGHT: int {
- PREMIUM_ACCOUNT=0,
- NOTATION=1,
- NAMELOCK=2,
- STATEMENT_REPORT=3,
- BANISHMENT=4,
- FINAL_WARNING=5,
- IP_BANISHMENT=6,
- KICK=7,
- HOME_TELEPORT=8,
- GAMEMASTER_BROADCAST=9,
- ANONYMOUS_BROADCAST=10,
- NO_BANISHMENT=11,
- ALLOW_MULTICLIENT=12,
- LOG_COMMUNICATION=13,
- READ_GAMEMASTER_CHANNEL=14,
- READ_TUTOR_CHANNEL=15,
- HIGHLIGHT_HELP_CHANNEL=16,
- SEND_BUGREPORTS=17,
- NAME_INSULTING=18,
- NAME_SENTENCE=19,
- NAME_NONSENSICAL_LETTERS=20,
- NAME_BADLY_FORMATTED=21,
- NAME_NO_PERSON=22,
- NAME_CELEBRITY=23,
- NAME_COUNTRY=24,
- NAME_FAKE_IDENTITY=25,
- NAME_FAKE_POSITION=26,
- STATEMENT_INSULTING=27,
- STATEMENT_SPAMMING=28,
- STATEMENT_ADVERT_OFFTOPIC=29,
- STATEMENT_ADVERT_MONEY=30,
- STATEMENT_NON_ENGLISH=31,
- STATEMENT_CHANNEL_OFFTOPIC=32,
- STATEMENT_VIOLATION_INCITING=33,
- CHEATING_BUG_ABUSE=34,
- CHEATING_GAME_WEAKNESS=35,
- CHEATING_MACRO_USE=36,
- CHEATING_MODIFIED_CLIENT=37,
- CHEATING_HACKING=38,
- CHEATING_MULTI_CLIENT=39,
- CHEATING_ACCOUNT_TRADING=40,
- CHEATING_ACCOUNT_SHARING=41,
- GAMEMASTER_THREATENING=42,
- GAMEMASTER_PRETENDING=43,
- GAMEMASTER_INFLUENCE=44,
- GAMEMASTER_FALSE_REPORTS=45,
- KILLING_EXCESSIVE_UNJUSTIFIED=46,
- DESTRUCTIVE_BEHAVIOUR=47,
- SPOILING_AUCTION=48,
- INVALID_PAYMENT=49,
- TELEPORT_TO_CHARACTER=50,
- TELEPORT_TO_MARK=51,
- TELEPORT_VERTICAL=52,
- TELEPORT_TO_COORDINATE=53,
- LEVITATE=54,
- SPECIAL_MOVEUSE=55,
- MODIFY_GOSTRENGTH=56,
- SHOW_COORDINATE=57,
- RETRIEVE=58,
- ENTER_HOUSES=59,
- OPEN_NAMEDOORS=60,
- INVULNERABLE=61,
- UNLIMITED_MANA=62,
- KEEP_INVENTORY=63,
- ALL_SPELLS=64,
- UNLIMITED_CAPACITY=65,
- ZERO_CAPACITY=66,
- ATTACK_EVERYWHERE=67,
- NO_ATTACK=68,
- NO_RUNES=69,
- NO_LOGOUT_BLOCK=70,
- GAMEMASTER_OUTFIT=71,
- ILLUMINATE=72,
- CHANGE_PROFESSION=73,
- IGNORED_BY_MONSTERS=74,
- SHOW_KEYHOLE_NUMBERS=75,
- CREATE_OBJECTS=76,
- CREATE_MONEY=77,
- CREATE_MONSTERS=78,
- CHANGE_SKILLS=79,
- CLEANUP_FIELDS=80,
- NO_STATISTICS=81
-};
-
enum TWriterThreadReplyType: int {
REPLY_BROADCAST=0,
REPLY_DIRECT=1,
@@ -501,32 +155,6 @@ enum TWriterThreadOrderType: int {
ORDER_SAVEPLAYERDATA=9
};
-enum TALK_MODE: int {
- TALK_SAY=1,
- TALK_WHISPER=2,
- TALK_YELL=3,
- TALK_PRIVATE_MESSAGE=4,
- TALK_CHANNEL_CALL=5,
- TALK_GAMEMASTER_REQUEST=6,
- TALK_GAMEMASTER_ANSWER=7,
- TALK_PLAYER_ANSWER=8,
- TALK_GAMEMASTER_BROADCAST=9,
- TALK_GAMEMASTER_CHANNELCALL=10,
- TALK_GAMEMASTER_MESSAGE=11,
- TALK_HIGHLIGHT_CHANNELCALL=12,
- TALK_ANONYMOUS_BROADCAST=13,
- TALK_ANONYMOUS_CHANNELCALL=14,
- TALK_ANONYMOUS_MESSAGE=15,
- TALK_ANIMAL_LOW=16,
- TALK_ANIMAL_LOUD=17,
- TALK_ADMIN_MESSAGE=18,
- TALK_EVENT_MESSAGE=19,
- TALK_LOGIN_MESSAGE=20,
- TALK_STATUS_MESSAGE=21,
- TALK_INFO_MESSAGE=22,
- TALK_FAILURE_MESSAGE=23
-};
-
enum CHANNEL: int {
GUILD_CHANNEL=0,
GAMEMASTER_CHANNEL=1,
@@ -597,9 +225,3 @@ enum BloodType: int {
BT_FIRE=3,
BT_ENERGY=4
};
-
-enum TWorldType: int {
- NORMAL=0,
- NON_PVP=1,
- PVP_ENFORCED=2
-};
diff --git a/reference/game.c b/reference/game.c
index a005445..07e6991 100644
--- a/reference/game.c
+++ b/reference/game.c
@@ -1946,833 +1946,6 @@ void __static_initialization_and_destruction_0(int __initialize_p,int __priority
return;
}
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void ProcessCommand(void)
-
-{
- char *CommandBuffer;
- int iVar1;
- char *pcVar2;
- int Command;
-
- iVar1 = GetCommand();
- if (iVar1 != 0) {
- pcVar2 = GetCommandBuffer();
- if (iVar1 == 1) {
- if (pcVar2 == (char *)0x0) {
- error(&DAT_080ee440);
- }
- else {
- BroadcastMessage(0x12,"%s",pcVar2);
- }
- }
- else {
- error("ProcessCommand: Unbekanntes Kommando %d.\n",iVar1);
- }
- SetCommand(0,(char *)0x0);
- }
- return;
-}
-
-
-
-// WARNING: Variable defined which should be unmapped: Color
-
-void AdvanceGame(int Delay)
-
-{
- int iVar1;
- TConnection *Connection_00;
- TConnection *Connection;
- int Time;
- char *pcVar2;
- int local_20;
- int Hour;
- int Minute;
- int Brightness;
- int Color;
-
- AdvanceGame::SkillTimeCounter = AdvanceGame::SkillTimeCounter + Delay;
- AdvanceGame::OtherTimeCounter = AdvanceGame::OtherTimeCounter + Delay;
- AdvanceGame::CreaturesTimeCounter = AdvanceGame::CreaturesTimeCounter + Delay;
- AdvanceGame::CronTimeCounter = AdvanceGame::CronTimeCounter + Delay;
- if (0x6d5 < AdvanceGame::CreaturesTimeCounter) {
- AdvanceGame::CreaturesTimeCounter = AdvanceGame::CreaturesTimeCounter + -1000;
- ProcessCreatures();
- }
- if (0x5db < AdvanceGame::CronTimeCounter) {
- AdvanceGame::CronTimeCounter = AdvanceGame::CronTimeCounter + -1000;
- ProcessCronSystem();
- }
- if (0x4e1 < AdvanceGame::SkillTimeCounter) {
- AdvanceGame::SkillTimeCounter = AdvanceGame::SkillTimeCounter + -1000;
- ProcessSkills();
- }
- if (999 < AdvanceGame::OtherTimeCounter) {
- AdvanceGame::OtherTimeCounter = AdvanceGame::OtherTimeCounter + -1000;
- RoundNr = RoundNr + 1;
- SetRoundNr(RoundNr);
- ProcessConnections();
- ProcessMonsterhomes();
- ProcessMonsterRaids();
- ProcessCommunicationControl();
- ProcessReaderThreadReplies(RefreshSector,SendMails);
- ProcessWriterThreadReplies();
- ProcessCommand();
- GetAmbiente(&Minute,&Brightness);
- if (Minute != AdvanceGame::OldAmbiente) {
- AdvanceGame::OldAmbiente = Minute;
- Connection_00 = GetFirstConnection();
- while (Connection_00 != (TConnection *)0x0) {
- if (Connection_00->State - CONNECTION_LOGIN < 4) {
- SendAmbiente(Connection_00);
- }
- Connection_00 = GetNextConnection();
- }
- }
- if (RoundNr == (RoundNr / 10) * 10) {
- NetLoadCheck();
- }
- if (AdvanceGame::NextMinute <= RoundNr) {
- GetRealTime(&local_20,&Hour);
- RefreshCylinders();
- if (Hour == (Hour / 5) * 5) {
- CreatePlayerList(true);
- }
- if (Hour == (Hour / 0xf) * 0xf) {
- SavePlayerDataOrder();
- }
- if (Hour == 0) {
- NetLoadSummary();
- }
- if (Hour == 0x37) {
- WriteKillStatistics();
- }
- iVar1 = Hour + local_20 * 0x3c;
- if ((iVar1 + 5) % 0x5a0 == RebootTime) {
- if (Reboot == false) {
- pcVar2 = "Server is going down in 5 minutes.\nPlease log out.";
- }
- else {
- pcVar2 = "Server is saving game in 5 minutes.\nPlease come back in 10 minutes.";
- }
- BroadcastMessage(0x12,pcVar2);
- CloseGame();
- }
- if ((iVar1 + 3) % 0x5a0 == RebootTime) {
- if (Reboot == false) {
- pcVar2 = "Server is going down in 3 minutes.\nPlease log out.";
- }
- else {
- pcVar2 = "Server is saving game in 3 minutes.\nPlease come back in 10 minutes.";
- }
- BroadcastMessage(0x12,pcVar2);
- }
- if ((iVar1 + 1) % 0x5a0 == RebootTime) {
- if (Reboot == false) {
- pcVar2 = "Server is going down in one minute.\nPlease log out.";
- }
- else {
- pcVar2 = "Server is saving game in one minute.\nPlease log out.";
- }
- BroadcastMessage(0x12,pcVar2);
- }
- if (iVar1 == RebootTime) {
- CloseGame();
- LogoutAllPlayers();
- SendAll();
- if (Reboot != false) {
- RefreshMap();
- }
- SaveMap();
- SaveMapOn = false;
- EndGame();
- }
- AdvanceGame::NextMinute = GetRoundForNextMinute();
- }
- CleanupDynamicStrings();
- }
- if (Beat < Delay) {
- Log("lag",&DAT_080ee9c7,Delay);
- }
- if (Delay < 1000) {
- MoveCreatures(Delay);
- AdvanceGame::Lag = false;
- }
- else {
- if ((AdvanceGame::Lag == false) && (10 < RoundNr)) {
- error(&DAT_080ee480,Delay);
- }
- AdvanceGame::Lag = true;
- }
- SendAll();
- return;
-}
-
-
-
-void HandlerSigAlarm(int param_1)
-
-{
- undefined1 local_2c [4];
- itimerval ov;
- itimerval v;
-
- ov.it_value.tv_usec = 0;
- SigAlarmCounter = SigAlarmCounter + 1;
- setitimer(ITIMER_REAL,(itimerval *)&ov.it_value.tv_usec,(itimerval *)local_2c);
- return;
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void TimeReset(void)
-
-{
- SigAlarmCounter = 0;
- return;
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void InitTime(void)
-
-{
- undefined1 local_2c [4];
- itimerval ov;
- itimerval v;
-
- SigAlarmCounter = 0;
- handler(0xe,HandlerSigAlarm);
- ov.it_value.tv_usec = 0;
- SigAlarmCounter = SigAlarmCounter + 1;
- setitimer(ITIMER_REAL,(itimerval *)&ov.it_value.tv_usec,(itimerval *)local_2c);
- return;
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void ExitTime(void)
-
-{
- undefined1 local_2c [4];
- itimerval ov;
- itimerval v;
-
- ov.it_value.tv_usec = 0;
- setitimer(ITIMER_REAL,(itimerval *)&ov.it_value.tv_usec,(itimerval *)local_2c);
- handler(0xe,(_func_void_int *)0x1);
- return;
-}
-
-
-
-void SigHupHandler(int param_1)
-
-{
- return;
-}
-
-
-
-void SigAbortHandler(int param_1)
-
-{
- print();
- AbortWriter();
- return;
-}
-
-
-
-void HandlerSigUsr1(int param_1)
-
-{
- SigUsr1Counter = SigUsr1Counter + 1;
- return;
-}
-
-
-
-// WARNING: Variable defined which should be unmapped: s
-
-void DefaultHandler(int signo)
-
-{
- int local_94;
- int Hour;
- int Minute;
- char s [128];
-
- snprintf((char *)&Minute,0x80,"SigNr. %d: %s",signo,*(undefined4 *)(sys_siglist + signo * 4));
- print();
- handler(2,(_func_void_int *)0x1);
- handler(3,(_func_void_int *)0x1);
- handler(0xf,(_func_void_int *)0x1);
- handler(0x18,(_func_void_int *)0x1);
- handler(0x19,(_func_void_int *)0x1);
- handler(0x1e,(_func_void_int *)0x1);
- SaveMapOn = false;
- if (((signo == 3) || (signo == 0xf)) || (signo == 0x1e)) {
- SaveMapOn = true;
- }
- if (signo == 0xf) {
- GetRealTime(&local_94,&Hour);
- RebootTime = (Hour + 6 + local_94 * 0x3c) % 0x5a0;
- CloseGame();
- }
- else {
- EndGame();
- }
- Reboot = false;
- return;
-}
-
-
-
-void ErrorHandler(int signo)
-
-{
- char local_8c [4];
- char s [128];
-
- snprintf(local_8c,0x80,"SigNr. %d: %s",signo,*(undefined4 *)(sys_siglist + signo * 4));
- error("ErrorHandler: %s\n",local_8c);
- EndGame();
- LogoutAllPlayers();
- // WARNING: Subroutine does not return
- exit(1);
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void InitSignalHandler(void)
-
-{
- int count;
-
- handler(1,SigHupHandler);
- handler(2,DefaultHandler);
- handler(3,DefaultHandler);
- handler(6,SigAbortHandler);
- handler(10,(_func_void_int *)0x1);
- handler(0xc,(_func_void_int *)0x1);
- handler(0xd,(_func_void_int *)0x1);
- handler(0xe,(_func_void_int *)0x1);
- handler(0xf,DefaultHandler);
- handler(0x10,(_func_void_int *)0x1);
- handler(0x11,(_func_void_int *)0x1);
- handler(0x14,(_func_void_int *)0x1);
- handler(0x15,(_func_void_int *)0x1);
- handler(0x16,(_func_void_int *)0x1);
- handler(0x17,(_func_void_int *)0x1);
- handler(0x18,DefaultHandler);
- handler(0x19,DefaultHandler);
- handler(0x1a,(_func_void_int *)0x1);
- handler(0x1c,(_func_void_int *)0x1);
- handler(0x1d,(_func_void_int *)0x1);
- handler(0x1e,DefaultHandler);
- print();
- return;
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void ExitSignalHandler(void)
-
-{
- return;
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void UnlockGame(void)
-
-{
- int iVar1;
- __pid_t _Var2;
- int local_1140;
- int Pid;
- ifstream IF;
- undefined4 local_1134 [3];
- uint auStack_1128 [23];
- __basic_file<char> local_10cc [25];
- undefined1 local_10b3;
- undefined *local_10ac;
- ios_base local_10a8 [16];
- uint local_1098;
- char local_101c [4];
- char FileName [4096];
-
- std::ios_base::ios_base(local_10a8);
- local_10ac = (undefined *)0x8128950;
- // try { // try from 0804bd94 to 0804bd98 has its CatchHandler @ 0804bf54
- std::istream::istream((istream *)&Pid,(streambuf *)(std::ifstream::VTT + 4));
- Pid = (int)&DAT_08128994;
- local_10ac = &DAT_081289a8;
- // try { // try from 0804bdb8 to 0804bdbc has its CatchHandler @ 0804bf50
- std::filebuf::filebuf((filebuf *)local_1134);
- // try { // try from 0804bdca to 0804bdce has its CatchHandler @ 0804bf14
- std::ios::init((EVP_PKEY_CTX *)&local_10ac);
- strcpy(local_101c,SAVEPATH);
- strcat(local_101c,"/game.pid");
- // try { // try from 0804be04 to 0804be36 has its CatchHandler @ 0804bf58
- iVar1 = std::filebuf::open((char *)local_1134,(int)local_101c,8);
- if (iVar1 == 0) {
- std::ios::clear((istream *)&Pid + *(int *)(Pid + -0xc),
- *(uint *)((int)auStack_1128 + *(int *)(Pid + -0xc)) | 4);
- }
- if ((local_1098 & 5) == 0) {
- std::istream::operator>>((istream *)&Pid,&local_1140);
- iVar1 = std::filebuf::close((int)local_1134);
- if (iVar1 == 0) {
- // try { // try from 0804bee1 to 0804bf0e has its CatchHandler @ 0804bf58
- std::ios::clear((istream *)&Pid + *(int *)(Pid + -0xc),
- *(uint *)((int)auStack_1128 + *(int *)(Pid + -0xc)) | 4);
- }
- _Var2 = getpid();
- if (local_1140 == _Var2) {
- unlink(local_101c);
- }
- }
- Pid = (int)&DAT_08128994;
- local_10ac = &DAT_081289a8;
- local_1134[0] = 0x8128ad0;
- std::filebuf::close((int)local_1134);
- local_10b3 = 0;
- std::__basic_file<char>::~__basic_file(local_10cc);
- std::streambuf::~streambuf((streambuf *)local_1134);
- std::istream::~istream((istream *)&Pid);
- std::ios::~ios((ios *)&local_10ac);
- return;
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void LockGame(void)
-
-{
- uint uVar1;
- int iVar2;
- ulong uVar3;
- undefined4 *puVar4;
- int local_1260;
- int Pid;
- char FileName [4096];
- ofstream OF;
- uint auStack_250 [24];
- __basic_file<char> local_1f0 [25];
- undefined1 local_1d7;
- undefined *local_1d0;
- ios_base local_1cc [144];
- undefined *local_13c;
- ifstream IF;
- undefined4 local_134 [3];
- uint auStack_128 [23];
- __basic_file<char> local_cc [25];
- undefined1 local_b3;
- undefined *local_ac;
- ios_base local_a8 [16];
- uint local_98;
-
- // try { // try from 0804bff1 to 0804bff5 has its CatchHandler @ 0804c550
- std::ios_base::ios_base(local_a8);
- local_ac = (undefined *)0x8128950;
- // try { // try from 0804c014 to 0804c018 has its CatchHandler @ 0804c3f0
- std::istream::istream((istream *)&local_13c,(streambuf *)(std::ifstream::VTT + 4));
- local_13c = &DAT_08128994;
- local_ac = &DAT_081289a8;
- // try { // try from 0804c038 to 0804c03c has its CatchHandler @ 0804c3e7
- std::filebuf::filebuf((filebuf *)local_134);
- // try { // try from 0804c050 to 0804c054 has its CatchHandler @ 0804c3a0
- std::ios::init((EVP_PKEY_CTX *)&local_ac);
- // try { // try from 0804c05e to 0804c062 has its CatchHandler @ 0804c546
- std::ios_base::ios_base(local_1cc);
- local_1d0 = (undefined *)0x8128950;
- // try { // try from 0804c087 to 0804c08b has its CatchHandler @ 0804c4be
- std::ostream::ostream((ostream *)(FileName + 0xffc),(streambuf *)(std::ofstream::VTT + 4));
- FileName._4092_4_ = &DAT_08128a64;
- local_1d0 = &DAT_08128a78;
- // try { // try from 0804c0ab to 0804c0af has its CatchHandler @ 0804c4b5
- std::filebuf::filebuf((filebuf *)&OF);
- // try { // try from 0804c0c3 to 0804c0c7 has its CatchHandler @ 0804c3f6
- std::ios::init((EVP_PKEY_CTX *)&local_1d0);
- strcpy((char *)&Pid,SAVEPATH);
- strcat((char *)&Pid,"/game.pid");
- // try { // try from 0804c103 to 0804c194 has its CatchHandler @ 0804c4c7
- iVar2 = std::filebuf::open((char *)local_134,(int)&Pid,8);
- if (iVar2 == 0) {
- std::ios::clear((istream *)&local_13c + *(int *)(local_13c + -0xc),
- *(uint *)((int)auStack_128 + *(int *)(local_13c + -0xc)) | 4);
- }
- if ((local_98 & 5) == 0) {
- std::istream::operator>>((istream *)&local_13c,&local_1260);
- iVar2 = std::filebuf::close((int)local_134);
- if (iVar2 == 0) {
- std::ios::clear((istream *)&local_13c + *(int *)(local_13c + -0xc),
- *(uint *)((int)auStack_128 + *(int *)(local_13c + -0xc)) | 4);
- }
- if (local_1260 != 0) {
- puVar4 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar4 = "Game-Server is already running, PID file exists.";
- // WARNING: Subroutine does not return
- __cxa_throw(puVar4,char_const*::typeinfo,0);
- }
- }
- else {
- iVar2 = std::filebuf::close((int)local_134);
- if (iVar2 == 0) {
- std::ios::clear((istream *)&local_13c + *(int *)(local_13c + -0xc),
- *(uint *)((int)auStack_128 + *(int *)(local_13c + -0xc)) | 4);
- }
- iVar2 = std::filebuf::open((char *)&OF,(int)&Pid,0x30);
- if (iVar2 == 0) {
- std::ios::clear(FileName + *(int *)(FileName._4092_4_ + -0xc) + 0xffc,
- *(uint *)((int)auStack_250 + *(int *)(FileName._4092_4_ + -0xc) + 8) | 4
- );
- }
- uVar3 = getpid();
- uVar1 = *(uint *)((int)auStack_250 + *(int *)(FileName._4092_4_ + -0xc));
- if (((uVar1 & 0x40) == 0) && ((uVar1 & 8) == 0)) {
- // try { // try from 0804c2a1 to 0804c397 has its CatchHandler @ 0804c4c7
- std::ostream::operator<<((ostream *)(FileName + 0xffc),uVar3);
- }
- else {
- std::ostream::operator<<((ostream *)(FileName + 0xffc),uVar3);
- }
- atexit(UnlockGame);
- }
- FileName._4092_4_ = &DAT_08128a64;
- local_1d0 = &DAT_08128a78;
- _OF = 0x8128ad0;
- // try { // try from 0804c1cb to 0804c216 has its CatchHandler @ 0804c546
- std::filebuf::close((int)&OF);
- local_1d7 = 0;
- std::__basic_file<char>::~__basic_file(local_1f0);
- std::streambuf::~streambuf((streambuf *)&OF);
- std::ostream::~ostream((ostream *)(FileName + 0xffc));
- std::ios::~ios((ios *)&local_1d0);
- local_13c = &DAT_08128994;
- local_ac = &DAT_081289a8;
- local_134[0] = 0x8128ad0;
- // try { // try from 0804c241 to 0804c286 has its CatchHandler @ 0804c550
- std::filebuf::close((int)local_134);
- local_b3 = 0;
- std::__basic_file<char>::~__basic_file(local_cc);
- std::streambuf::~streambuf((streambuf *)local_134);
- std::istream::~istream((istream *)&local_13c);
- std::ios::~ios((ios *)&local_ac);
- return;
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void LoadWorldConfig(void)
-
-{
- TQueryManagerConnection *this;
- int iVar1;
- undefined4 *puVar2;
- TWorldType *pTVar3;
- int *piVar4;
- int *piVar5;
- int *piVar6;
- int *piVar7;
- int *piVar8;
- int *piVar9;
- int *piVar10;
- TWorldType local_60;
- int HelpWorldType;
- int HelpGameAddress [4];
- TQueryManagerConnection Connection;
-
- this = (TQueryManagerConnection *)(HelpGameAddress + 3);
- // try { // try from 0804c590 to 0804c594 has its CatchHandler @ 0804c6b7
- TQueryManagerConnection::TQueryManagerConnection(this,0x4000);
- if (Connection.WriteBuffer.Position < 0) {
- error("LoadWorldConfig: Kann nicht zum Query-Manager verbinden.\n");
- puVar2 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar2 = "cannot connect to querymanager";
- }
- else {
- piVar10 = &PremiumNewbieBuffer;
- piVar5 = &HelpWorldType;
- pTVar3 = &local_60;
- piVar9 = &MaxNewbies;
- piVar8 = &PremiumPlayerBuffer;
- piVar7 = &MaxPlayers;
- piVar6 = &GamePort;
- piVar4 = &RebootTime;
- // try { // try from 0804c5e6 to 0804c5ea has its CatchHandler @ 0804c6a0
- iVar1 = TQueryManagerConnection::loadWorldConfig(this);
- if (iVar1 == 0) {
- iVar1 = 0x10;
- WorldType = local_60;
- snprintf(GameAddress,0x10,"%d.%d.%d.%d",HelpWorldType,HelpGameAddress[0],
- HelpGameAddress[1],HelpGameAddress[2]);
- // try { // try from 0804c632 to 0804c636 has its CatchHandler @ 0804c6b7
- TQueryManagerConnection::~TQueryManagerConnection(this,iVar1);
- return;
- }
- // try { // try from 0804c64b to 0804c685 has its CatchHandler @ 0804c6a0
- error("LoadWorldConfig: Kann Konfigurationsdaten nicht holen.\n",pTVar3,piVar4,piVar5,piVar6
- ,piVar7,piVar8,piVar9,piVar10);
- puVar2 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar2 = "cannot load world config";
- }
- // WARNING: Subroutine does not return
- __cxa_throw(puVar2,char_const*::typeinfo,0);
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void InitAll(void)
-
-{
- uint __seed;
- undefined1 local_2c [4];
- itimerval ov;
- itimerval v;
-
- // try { // try from 0804c6d9 to 0804c7d4 has its CatchHandler @ 0804c7e0
- ReadConfig();
- SetQueryManagerLoginData(1,WorldName);
- LoadWorldConfig();
- InitSHM((bool)(BeADaemon ^ 1));
- LockGame();
- InitLog("game");
- __seed = time((time_t *)0x0);
- srand(__seed);
- InitSignalHandler();
- InitConnections();
- InitCommunication();
- InitStrings();
- InitWriter();
- InitReader();
- InitObjects();
- InitMap();
- InitInfo();
- InitMoveUse();
- InitMagic();
- InitCr();
- InitHouses();
- SigAlarmCounter = 0;
- handler(0xe,HandlerSigAlarm);
- SigAlarmCounter = SigAlarmCounter + 1;
- ov.it_value.tv_usec = 0;
- setitimer(ITIMER_REAL,(itimerval *)&ov.it_value.tv_usec,(itimerval *)local_2c);
- ApplyPatches();
- return;
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void ExitAll(void)
-
-{
- undefined1 local_2c [4];
- itimerval ov;
- itimerval v;
-
- EndGame();
- ov.it_value.tv_usec = 0;
- setitimer(ITIMER_REAL,(itimerval *)&ov.it_value.tv_usec,(itimerval *)local_2c);
- handler(0xe,(_func_void_int *)0x1);
- ExitCr();
- ExitMagic();
- ExitMoveUse();
- ExitInfo();
- ExitHouses();
- ExitMap(SaveMapOn);
- ExitObjects();
- ExitReader();
- ExitWriter();
- ExitStrings();
- ExitCommunication();
- ExitConnections();
- ExitSHM();
- return;
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void LaunchGame(void)
-
-{
- int iVar1;
- bool bVar2;
-
- SigUsr1Counter = 0;
- handler(10,HandlerSigUsr1);
- StartGame();
- getpid();
- print();
- SaveMapOn = true;
- SigAlarmCounter = 0;
- while (bVar2 = GameRunning(), bVar2) {
- sigblock(0x200);
- while ((SigUsr1Counter == 0 && (SigAlarmCounter == 0))) {
- __sigpause(0,0);
- }
- if (0 < SigUsr1Counter) {
- SigUsr1Counter = 0;
- ReceiveData();
- }
- iVar1 = SigAlarmCounter;
- if (0 < SigAlarmCounter) {
- SigAlarmCounter = 0;
- AdvanceGame(iVar1 * Beat);
- }
- }
- LogoutAllPlayers();
- return;
-}
-
-
-
-int DaemonInit(bool NoFork)
-
-{
- pid_t Pid;
- __pid_t _Var1;
- long lVar2;
- int i;
- int __fd;
- int iVar3;
- int openmax;
-
- if (!NoFork) {
- _Var1 = fork();
- if (_Var1 < 0) {
- return 1;
- }
- if (_Var1 != 0) {
- // WARNING: Subroutine does not return
- exit(0);
- }
- setsid();
- }
- umask(0);
- umask(0x7f);
- chdir(SAVEPATH);
- lVar2 = sysconf(4);
- if (lVar2 < 0) {
- lVar2 = 0x400;
- }
- __fd = 0;
- if (0 < lVar2) {
- do {
- iVar3 = __fd + 1;
- close(__fd);
- __fd = iVar3;
- } while (iVar3 < lVar2);
- }
- return 0;
-}
-
-
-
-int main(int argc,char **argv)
-
-{
- RESULT r;
- int iVar1;
- char *pcVar2;
- char *pcVar3;
- bool bVar4;
- int local_1024;
- int i;
- char local_101c [3];
- bool NoFork;
- char FileName [4096];
-
- local_1024 = 1;
- bVar4 = argc == 1;
- i._3_1_ = false;
- BeADaemon = false;
- Reboot = true;
- if (1 < argc) {
- do {
- iVar1 = 7;
- pcVar2 = argv[local_1024];
- pcVar3 = "daemon";
- do {
- if (iVar1 == 0) break;
- iVar1 = iVar1 + -1;
- bVar4 = *pcVar2 == *pcVar3;
- pcVar2 = pcVar2 + 1;
- pcVar3 = pcVar3 + 1;
- } while (bVar4);
- if (bVar4) {
- BeADaemon = true;
- }
- iVar1 = 7;
- pcVar2 = argv[local_1024];
- pcVar3 = "nofork";
- do {
- if (iVar1 == 0) break;
- iVar1 = iVar1 + -1;
- bVar4 = *pcVar2 == *pcVar3;
- pcVar2 = pcVar2 + 1;
- pcVar3 = pcVar3 + 1;
- } while (bVar4);
- if (bVar4) {
- i._3_1_ = true;
- }
- local_1024 = local_1024 + 1;
- bVar4 = local_1024 == argc;
- } while (local_1024 < argc);
- }
- if (((BeADaemon != false) ||
- (puts("Tibia Game-Server\n(c) by CIP Productions, 2003.\n"), BeADaemon != false)) &&
- (iVar1 = DaemonInit(i._3_1_), iVar1 != 0)) {
- return 2;
- }
- InitAll();
- atexit(ExitAll);
- // try { // try from 0804cb24 to 0804cb28 has its CatchHandler @ 0804cbb5
- LaunchGame();
- if (Reboot != false) {
- UnlockGame();
- sprintf(local_101c,"%s/reboot-daily",BINPATH);
- bVar4 = FileExists(local_101c);
- if (bVar4) {
- ExitAll();
- print();
- execv(local_101c,argv);
- }
- }
- print();
- return 0;
-}
-
-
-
// WARNING: Unknown calling convention -- yet parameter storage is locked
void _GLOBAL__I_BeADaemon(void)
@@ -2782,34 +1955,6 @@ void _GLOBAL__I_BeADaemon(void)
return;
}
-
-
-_func_void_int * handler(int signr,_func_void_int *sighandler)
-
-{
- int iVar1;
- _union_1051 _Var2;
- _union_1051 local_12c;
- sigaction alt_handler;
- _union_1051 local_9c;
- sigaction neu_handler;
-
- local_9c.sa_handler = (__sighandler_t)sighandler;
- sigemptyset((sigset_t *)&neu_handler);
- neu_handler.sa_mask.__val[0x1f] = 0x20000000;
- if (signr != 0xe) {
- neu_handler.sa_mask.__val[0x1f] = 0x10000000;
- }
- iVar1 = sigaction(signr,(sigaction *)&local_9c,(sigaction *)&local_12c);
- _Var2 = (_union_1051)0xffffffff;
- if (-1 < iVar1) {
- _Var2 = local_12c;
- }
- return (_func_void_int *)_Var2.sa_handler;
-}
-
-
-
bool isSpace(int c)
{
@@ -8631,180 +7776,6 @@ void ReadConfig(void)
} while( true );
}
-
-
-// WARNING: Variable defined which should be unmapped: t
-
-void GetAmbiente(int *Brightness,int *Color)
-
-{
- int iVar1;
- int Time;
- tm *ptVar2;
- time_t local_14;
- time_t t;
-
- local_14 = time((time_t *)0x0);
- ptVar2 = localtime(&local_14);
- iVar1 = ptVar2->tm_sec + ptVar2->tm_min * 0x3c;
- iVar1 = ((iVar1 % 0x96) * 2) / 5 + (iVar1 / 0x96) * 0x3c;
- if (iVar1 < 0x3c) {
-LAB_08053cb0:
- *Brightness = 0x33;
- }
- else {
- if (0x77 < iVar1) {
- if (iVar1 < 0xb4) {
- *Brightness = 0x99;
-LAB_08053c88:
- *Color = 0xad;
- return;
- }
- if (iVar1 < 0xf0) {
- *Brightness = 0xcc;
- goto LAB_08053c88;
- }
- if (0x564 < iVar1) goto LAB_08053cb0;
- if (iVar1 < 0x529) {
- if (0x4ec < iVar1) {
- *Brightness = 0x99;
-LAB_08053ce5:
- *Color = 0xd0;
- return;
- }
- if (0x4b0 < iVar1) {
- *Brightness = 0xcc;
- goto LAB_08053ce5;
- }
- *Brightness = 0xff;
- goto LAB_08053cb6;
- }
- }
- *Brightness = 0x66;
- }
-LAB_08053cb6:
- *Color = 0xd7;
- return;
-}
-
-
-
-// WARNING: Variable defined which should be unmapped: t
-
-void GetDate(int *Year,int *Cycle,int *Day)
-
-{
- tm *ptVar1;
- tm *Time;
- int local_10;
- time_t t;
-
- local_10 = time((time_t *)0x0);
- ptVar1 = localtime(&local_10);
- *Year = (local_10 / 0x15180 + 4) / 7;
- *Cycle = ptVar1->tm_wday;
- *Day = ptVar1->tm_hour;
- return;
-}
-
-
-
-// WARNING: Variable defined which should be unmapped: t
-
-void GetTime(int *Hour,int *Minute)
-
-{
- tm *ptVar1;
- tm *Time;
- time_t local_14;
- time_t t;
-
- local_14 = time((time_t *)0x0);
- ptVar1 = localtime(&local_14);
- *Hour = (ptVar1->tm_sec + ptVar1->tm_min * 0x3c) / 0x96;
- *Minute = (((ptVar1->tm_sec + ptVar1->tm_min * 0x3c) % 0x96) * 2) / 5;
- return;
-}
-
-
-
-// WARNING: Variable defined which should be unmapped: t
-
-void GetRealTime(int *Hour,int *Minute)
-
-{
- tm *ptVar1;
- time_t local_8;
- time_t t;
-
- local_8 = time((time_t *)0x0);
- ptVar1 = localtime(&local_8);
- *Hour = ptVar1->tm_hour;
- *Minute = ptVar1->tm_min;
- return;
-}
-
-
-
-// WARNING: Variable defined which should be unmapped: t
-
-ulong GetRoundAtTime(int Hour,int Minute)
-
-{
- int Delta;
- tm *ptVar1;
- uint uVar2;
- tm *Time;
- time_t local_c;
- time_t t;
-
- local_c = time((time_t *)0x0);
- ptVar1 = localtime(&local_c);
- uVar2 = ((Hour - ptVar1->tm_hour) * 0xe10 + (Minute - ptVar1->tm_min) * 0x3c) - ptVar1->tm_sec;
- if (0x7fffffff < uVar2) {
- uVar2 = uVar2 + 0x15180;
- }
- return uVar2 + RoundNr;
-}
-
-
-
-// WARNING: Variable defined which should be unmapped: t
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-ulong GetRoundForNextMinute(void)
-
-{
- int iVar1;
- int iVar2;
- ulong NewRound;
- tm *ptVar3;
- int Delta;
- uint uVar4;
- time_t local_14;
- time_t t_1;
- time_t t;
-
- t_1 = time((time_t *)0x0);
- ptVar3 = localtime(&t_1);
- iVar1 = ptVar3->tm_hour;
- iVar2 = ptVar3->tm_min;
- local_14 = time((time_t *)0x0);
- ptVar3 = localtime(&local_14);
- uVar4 = ((iVar1 - ptVar3->tm_hour) * 0xe10 + ((iVar2 + 1) - ptVar3->tm_min) * 0x3c) -
- ptVar3->tm_sec;
- if (0x7fffffff < uVar4) {
- uVar4 = uVar4 + 0x15180;
- }
- for (uVar4 = uVar4 + 0x1e + RoundNr; uVar4 < RoundNr + 0x1e; uVar4 = uVar4 + 0x3c) {
- }
- for (; RoundNr + 0x5a < uVar4; uVar4 = uVar4 - 0x3c) {
- }
- return uVar4;
-}
-
-
-
void __static_initialization_and_destruction_0(int __initialize_p,int __priority)
{
@@ -10104,724 +9075,6 @@ void __static_initialization_and_destruction_0(int __initialize_p,int __priority
return;
}
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void StartGame(void)
-
-{
- if (SHM == (TSharedMemory *)0x0) {
- error("StartGame: SharedMemory existiert nicht.\n");
- }
- else if (SHM->GameState == GAME_STARTING) {
- SHM->GameState = GAME_RUNNING;
- }
- return;
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void CloseGame(void)
-
-{
- if (SHM == (TSharedMemory *)0x0) {
- error("CloseGame: SharedMemory existiert nicht.\n");
- }
- else if (SHM->GameState == GAME_RUNNING) {
- SHM->GameState = GAME_CLOSING;
- }
- return;
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void EndGame(void)
-
-{
- if (SHM == (TSharedMemory *)0x0) {
- error("EndGame: SharedMemory existiert nicht.\n");
- }
- else {
- SHM->GameState = GAME_ENDING;
- }
- return;
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-bool LoginAllowed(void)
-
-{
- bool bVar1;
-
- if (SHM == (TSharedMemory *)0x0) {
- error("IsLoginAllowed: SharedMemory existiert nicht.\n");
- bVar1 = false;
- }
- else {
- bVar1 = SHM->GameState == GAME_RUNNING;
- }
- return bVar1;
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-bool GameRunning(void)
-
-{
- bool bVar1;
-
- if (SHM == (TSharedMemory *)0x0) {
- error("GameRunning: SharedMemory existiert nicht.\n");
- bVar1 = false;
- }
- else {
- bVar1 = SHM->GameState < GAME_ENDING;
- }
- return bVar1;
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-bool GameStarting(void)
-
-{
- bool bVar1;
-
- if (SHM == (TSharedMemory *)0x0) {
- error("GameStarting: SharedMemory existiert nicht.\n");
- bVar1 = false;
- }
- else {
- bVar1 = SHM->GameState == GAME_STARTING;
- }
- return bVar1;
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-bool GameEnding(void)
-
-{
- bool bVar1;
-
- if (SHM == (TSharedMemory *)0x0) {
- error("GameEnding: SharedMemory existiert nicht.\n");
- bVar1 = false;
- }
- else {
- bVar1 = SHM->GameState - GAME_CLOSING < 2;
- }
- return bVar1;
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-pid_t GetGameThreadPID(void)
-
-{
- pid_t pVar1;
-
- pVar1 = 0;
- if (SHM != (TSharedMemory *)0x0) {
- pVar1 = SHM->GameThreadPID;
- }
- return pVar1;
-}
-
-
-
-void ErrorHandler(char *Text)
-
-{
- ulong uVar1;
-
- if (VerboseOutput) {
- printf("%s",Text);
- }
- if (SHM != (TSharedMemory *)0x0) {
- if (SHM->Errors < 0x8000) {
- Log("error",Text);
- }
- uVar1 = SHM->Errors + 1;
- SHM->Errors = uVar1;
- if (uVar1 == 0x8000) {
- Log("error","Zu viele Fehler. Keine weitere Protokollierung.\n");
- }
- }
- return;
-}
-
-
-
-void PrintHandler(int Level,char *Text)
-
-{
- size_t sVar1;
- int iVar2;
- int iVar3;
- TSharedMemory *pTVar4;
-
- if (Level <= DebugLevel) {
- if (VerboseOutput) {
- printf("%s",Text);
- }
- if (SHM != (TSharedMemory *)0x0) {
- Semaphore::down(&LogfileMutex);
- strncpy(SHM->PrintBuffer[SHM->PrintBufferPosition],Text,0x7f);
- SHM->PrintBuffer[SHM->PrintBufferPosition][0x7e] = '\0';
- pTVar4 = SHM;
- iVar3 = SHM->PrintBufferPosition;
- if (SHM->PrintBuffer[iVar3][0] != '\0') {
- sVar1 = strlen(SHM->PrintBuffer[iVar3]);
- if (pTVar4->PrintBuffer[iVar3 + -1][sVar1 + 0x7f] != '\n') {
- strcat(pTVar4->PrintBuffer[pTVar4->PrintBufferPosition],"\n");
- pTVar4 = SHM;
- }
- }
- iVar2 = pTVar4->PrintBufferPosition + 1;
- iVar3 = 0;
- if (iVar2 < 200) {
- iVar3 = iVar2;
- }
- pTVar4->PrintBufferPosition = iVar3;
- Semaphore::up(&LogfileMutex);
- return;
- }
- }
- return;
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-int GetPrintlogPosition(void)
-
-{
- int iVar1;
-
- iVar1 = 0;
- if (SHM != (TSharedMemory *)0x0) {
- iVar1 = SHM->PrintBufferPosition;
- }
- return iVar1;
-}
-
-
-
-char * GetPrintlogLine(int Line)
-
-{
- char (*pacVar1) [128];
-
- if ((SHM == (TSharedMemory *)0x0) || (199 < Line)) {
- pacVar1 = (char (*) [128])0x0;
- }
- else {
- pacVar1 = SHM->PrintBuffer + Line;
- }
- return *pacVar1;
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void IncrementObjectCounter(void)
-
-{
- if (SHM != (TSharedMemory *)0x0) {
- SHM->ObjectCounter = SHM->ObjectCounter + 1;
- }
- return;
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void DecrementObjectCounter(void)
-
-{
- if (SHM != (TSharedMemory *)0x0) {
- SHM->ObjectCounter = SHM->ObjectCounter - 1;
- }
- return;
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-ulong GetObjectCounter(void)
-
-{
- ulong uVar1;
-
- uVar1 = 0;
- if (SHM != (TSharedMemory *)0x0) {
- uVar1 = SHM->ObjectCounter;
- }
- return uVar1;
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void IncrementPlayersOnline(void)
-
-{
- if (SHM != (TSharedMemory *)0x0) {
- SHM->PlayersOnline = SHM->PlayersOnline + 1;
- }
- return;
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void DecrementPlayersOnline(void)
-
-{
- if (SHM != (TSharedMemory *)0x0) {
- SHM->PlayersOnline = SHM->PlayersOnline + -1;
- }
- return;
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-int GetPlayersOnline(void)
-
-{
- int iVar1;
-
- iVar1 = 0;
- if (SHM != (TSharedMemory *)0x0) {
- iVar1 = SHM->PlayersOnline;
- }
- return iVar1;
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void IncrementNewbiesOnline(void)
-
-{
- if (SHM != (TSharedMemory *)0x0) {
- SHM->NewbiesOnline = SHM->NewbiesOnline + 1;
- }
- return;
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void DecrementNewbiesOnline(void)
-
-{
- if (SHM != (TSharedMemory *)0x0) {
- SHM->NewbiesOnline = SHM->NewbiesOnline + -1;
- }
- return;
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-int GetNewbiesOnline(void)
-
-{
- int iVar1;
-
- iVar1 = 0;
- if (SHM != (TSharedMemory *)0x0) {
- iVar1 = SHM->NewbiesOnline;
- }
- return iVar1;
-}
-
-
-
-void SetRoundNr(ulong RoundNr)
-
-{
- if (SHM != (TSharedMemory *)0x0) {
- SHM->RoundNr = RoundNr;
- }
- return;
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-ulong GetRoundNr(void)
-
-{
- ulong uVar1;
-
- uVar1 = 0;
- if (SHM != (TSharedMemory *)0x0) {
- uVar1 = SHM->RoundNr;
- }
- return uVar1;
-}
-
-
-
-void SetCommand(int Command,char *Text)
-
-{
- TSharedMemory *pTVar1;
-
- pTVar1 = SHM;
- if (SHM != (TSharedMemory *)0x0) {
- SHM->Command = Command;
- if (Text == (char *)0x0) {
- pTVar1->CommandBuffer[0] = '\0';
- }
- else {
- strncpy(pTVar1->CommandBuffer,Text,0x100);
- SHM->CommandBuffer[0xff] = '\0';
- }
- }
- return;
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-int GetCommand(void)
-
-{
- int iVar1;
-
- iVar1 = 0;
- if (SHM != (TSharedMemory *)0x0) {
- iVar1 = SHM->Command;
- }
- return iVar1;
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-char * GetCommandBuffer(void)
-
-{
- char *pcVar1;
-
- pcVar1 = (char *)0x0;
- if (SHM != (TSharedMemory *)0x0) {
- if (SHM->Command == 0) {
- pcVar1 = (char *)0x0;
- }
- else {
- pcVar1 = SHM->CommandBuffer;
- }
- }
- return pcVar1;
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-bool DeleteSHM(void)
-
-{
- int SHMID;
- int iVar1;
- bool bVar2;
-
- iVar1 = shmget(SHMKey,0,0);
- if (iVar1 == -1) {
- if (VerboseOutput != false) {
- puts("DeleteSHM: SharedMemory existiert nicht.");
- }
- bVar2 = true;
- }
- else {
- iVar1 = shmctl(iVar1,0,(shmid_ds *)0x0);
- bVar2 = true;
- if (iVar1 == -1) {
- if (VerboseOutput != false) {
- puts(&DAT_080f1020);
- }
- bVar2 = false;
- }
- }
- return bVar2;
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void CreateSHM(void)
-
-{
- bool bVar1;
- int SHMID;
- int iVar2;
- int *piVar3;
- undefined4 *puVar4;
- int iter;
-
- bVar1 = false;
- while( true ) {
- iVar2 = shmget(SHMKey,0x6524,0x7ff);
- if (iVar2 != -1) {
- return;
- }
- piVar3 = __errno_location();
- if ((*piVar3 != 0x11) || (bVar1)) break;
- bVar1 = DeleteSHM();
- if (!bVar1) {
- puVar4 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar4 = "Cannot delete SharedMemory";
- goto LAB_08056d20;
- }
- bVar1 = true;
- }
- if (VerboseOutput != false) {
- piVar3 = __errno_location();
- printf("CreateSHM: Kann SharedMemory nicht anlegen (Fehler %d).\n",*piVar3);
- }
- puVar4 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar4 = "Cannot create SharedMemory";
-LAB_08056d20:
- // WARNING: Subroutine does not return
- // try { // try from 08056d33 to 08056d37 has its CatchHandler @ 08056d72
- __cxa_throw(puVar4,char_const*::typeinfo,0);
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void AttachSHM(void)
-
-{
- int SHMID;
- int __shmid;
- undefined4 *puVar1;
-
- __shmid = shmget(SHMKey,0x6524,0);
- if (__shmid == -1) {
- if (VerboseOutput != false) {
- puts("AttachSHM: Kann SharedMemory nicht fassen.");
- }
- SHM = (TSharedMemory *)0x0;
- puVar1 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar1 = "Cannot get SharedMemory";
- }
- else {
- SHM = (TSharedMemory *)shmat(__shmid,(void *)0x0,0);
- if (SHM != (TSharedMemory *)0xffffffff) {
- return;
- }
- if (VerboseOutput != false) {
- puts("AttachSHM: Kann SharedMemory nicht anbinden.");
- }
- SHM = (TSharedMemory *)0x0;
- puVar1 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar1 = "Cannot attach SharedMemory";
- }
- // WARNING: Subroutine does not return
- // try { // try from 08056e1e to 08056e22 has its CatchHandler @ 08056e54
- __cxa_throw(puVar1,char_const*::typeinfo,0);
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void DetachSHM(void)
-
-{
- int result;
- int iVar1;
-
- if (SHM != (TSharedMemory *)0x0) {
- iVar1 = shmdt(SHM);
- if ((iVar1 == -1) && (VerboseOutput != false)) {
- puts(&DAT_080f1160);
- }
- SHM = (TSharedMemory *)0x0;
- }
- return;
-}
-
-
-
-void InitSHM(bool Verbose)
-
-{
- TSharedMemory *pTVar1;
- uint uVar2;
- __pid_t _Var3;
- TSharedMemory *pTVar4;
-
- IsGameServer = true;
- VerboseOutput = Verbose;
- // try { // try from 08056ecb to 08056eec has its CatchHandler @ 08056fe8
- CreateSHM();
- AttachSHM();
- SetErrorFunction(ErrorHandler);
- SetPrintFunction(PrintHandler);
- pTVar4 = SHM;
- uVar2 = 0x6524;
- if (((uint)SHM & 4) != 0) {
- SHM->Command = 0;
- uVar2 = 0x6520;
- pTVar4 = (TSharedMemory *)pTVar4->CommandBuffer;
- }
- for (uVar2 = uVar2 >> 2; uVar2 != 0; uVar2 = uVar2 - 1) {
- pTVar4->Command = 0;
- pTVar4 = (TSharedMemory *)pTVar4->CommandBuffer;
- }
- pTVar4 = SHM;
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 0) = 'S';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 1) = 'H';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 2) = 'M';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 3) = ' ';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 4) = 'i';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 5) = 'n';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 6) = 'i';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 7) = 't';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 8) = 'i';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 9) = 'a';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 10) = 'l';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 0xb) = 'i';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 0xc) = 'z';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 0xd) = 'e';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 0xe) = 'd';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 0xf) = '.';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 0x10) = ' ';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 0x11) = 'S';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 0x12) = 'y';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 0x13) = 's';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 0x14) = 't';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 0x15) = 'e';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 0x16) = 'm';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 0x17) = ' ';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 0x18) = 'p';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 0x19) = 'r';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 0x1a) = 'i';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 0x1b) = 'n';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 0x1c) = 't';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 0x1d) = 'i';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 0x1e) = 'n';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 0x1f) = 'g';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 0x20) = ' ';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 0x21) = 'i';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 0x22) = 's';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 0x23) = ' ';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 0x24) = 'w';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 0x25) = 'o';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 0x26) = 'r';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 0x27) = 'k';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 0x28) = 'i';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 0x29) = 'n';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 0x2a) = 'g';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 0x2b) = '!';
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 0x2c) = '\n';
- pTVar1 = SHM;
- *(char *)((int)(pTVar4->PrintBuffer + 0) + 0x2d) = '\0';
- SHM->Errors = 0;
- pTVar1->RoundNr = 0;
- pTVar1->PrintBufferPosition = 1;
- pTVar1->ObjectCounter = 0;
- pTVar1->GameState = GAME_STARTING;
- _Var3 = getpid();
- pTVar1->GameThreadPID = _Var3;
- return;
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void ExitSHM(void)
-
-{
- int result;
- int iVar1;
-
- SetErrorFunction((TErrorFunction *)0x0);
- SetPrintFunction((TPrintFunction *)0x0);
- if (SHM != (TSharedMemory *)0x0) {
- iVar1 = shmdt(SHM);
- if ((iVar1 == -1) && (VerboseOutput != false)) {
- puts(&DAT_080f1160);
- }
- SHM = (TSharedMemory *)0x0;
- }
- DeleteSHM();
- return;
-}
-
-
-
-void InitSHMExtern(bool Verbose)
-
-{
- VerboseOutput = Verbose;
- // try { // try from 0805706e to 08057072 has its CatchHandler @ 08057077
- AttachSHM();
- return;
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void ExitSHMExtern(void)
-
-{
- int result;
- int iVar1;
-
- if (SHM != (TSharedMemory *)0x0) {
- iVar1 = shmdt(SHM);
- if ((iVar1 == -1) && (VerboseOutput != false)) {
- puts(&DAT_080f1160);
- }
- SHM = (TSharedMemory *)0x0;
- }
- return;
-}
-
-
-
void __tcf_0(void *param_1)
{
diff --git a/reference/types.hh b/reference/types.hh
index d79cf0c..e66ea72 100644
--- a/reference/types.hh
+++ b/reference/types.hh
@@ -1,89 +1,4 @@
-struct Object {
- uint32 ObjectID;
-};
-
-struct TSkill {
- int (**_vptr.TSkill)(...); // VTABLE?
- int DAct;
- int MDAct;
- uint16 SkNr;
- TCreature *Master;
- int Act;
- int Max;
- int Min;
- int FactorPercent;
- int LastLevel;
- int NextLevel;
- int Delta;
- int Exp;
- int Cycle;
- int MaxCycle;
- int Count;
- int MaxCount;
- int AddLevel;
-};
-
-struct TSkillAdd {
- TSkill super_TSkill; // INHERITANCE?
-};
-struct TSkillHitpoints {
- TSkillAdd super_TSkillAdd; // INHERITANCE?
-};
-
-struct TSkillSoulpoints {
- TSkillAdd super_TSkillAdd; // INHERITANCE?
-};
-
-struct TSkillProbe {
- TSkill super_TSkill; // INHERITANCE?
-};
-
-struct TSkillMana {
- TSkillAdd super_TSkillAdd; // INHERITANCE?
-};
-
-struct TSkillGoStrength {
- TSkillAdd super_TSkillAdd; // INHERITANCE?
-};
-
-struct TSkillLight {
- TSkill super_TSkill; // INHERITANCE?
-};
-
-struct TSkillEnergy {
- TSkill super_TSkill; // INHERITANCE?
-};
-
-struct TSkillCarryStrength {
- TSkillAdd super_TSkillAdd; // INHERITANCE?
-};
-
-struct TSkillPoison {
- TSkill super_TSkill; // INHERITANCE?
-};
-
-struct TSkillBurning {
- TSkill super_TSkill; // INHERITANCE?
-};
-
-struct TSkillFed {
- TSkill super_TSkill; // INHERITANCE?
-};
-
-struct TSkillIllusion {
- TSkill super_TSkill; // INHERITANCE?
-};
-
-struct TSkillLevel {
- TSkill super_TSkill; // INHERITANCE?
-};
-
-struct TSkillBase {
- TSkill *Skills[25];
- TSkill *TimerList[25];
- uint16 FirstFreeTimer;
-};
struct TImpact {
int (**_vptr.TImpact)(...); // VTABLE?
@@ -145,142 +60,6 @@ struct TDamageImpact {
bool AllowDefense;
};
-struct TCombatEntry {
- uint32 ID;
- uint32 Damage;
- int TimeStamp;
-};
-
-struct TCombat {
- TCreature *Master;
- uint32 EarliestAttackTime;
- uint32 EarliestDefendTime;
- uint32 LastDefendTime;
- uint32 LatestAttackTime;
- uint32 AttackMode;
- uint32 ChaseMode;
- uint32 SecureMode;
- uint32 AttackDest;
- bool Following;
- Object Shield;
- Object Close;
- Object Missile;
- Object Throw;
- Object Wand;
- Object Ammo;
- bool Fist;
- uint32 CombatDamage;
- int ActCombatEntry;
- TCombatEntry CombatList[20];
- int LearningPoints;
-};
-
-struct TOutfit {
- int OutfitID;
- union{
- uint16 ObjectType;
- uint8 Colors[4];
- };
-};
-
-struct TCreature {
- int (**_vptr.TCreature)(...); // CREATURE VTABLE?
- TSkillBase super_TSkillBase; // INHERITANCE?
- TCombat Combat;
- uint32 ID;
- TCreature *NextHashEntry;
- uint32 NextChainCreature;
- char Name[31];
- char Murderer[31];
- TOutfit OrgOutfit;
- TOutfit Outfit;
- int startx;
- int starty;
- int startz;
- int posx;
- int posy;
- int posz;
- int Sex;
- int Race;
- int Direction;
- int Radius;
- CreatureType Type;
- bool IsDead;
- int LoseInventory;
- bool LoggingOut;
- bool LogoutAllowed;
- uint32 EarliestLogoutRound;
- uint32 EarliestProtectionZoneRound;
- uint32 EarliestYellRound;
- uint32 EarliestTradeChannelRound;
- uint32 EarliestSpellTime;
- uint32 EarliestMultiuseTime;
- uint32 EarliestWalkTime;
- uint32 LifeEndRound;
- TKnownCreature *FirstKnowingConnection;
- int SummonedCreatures;
- uint32 FireDamageOrigin;
- uint32 PoisonDamageOrigin;
- uint32 EnergyDamageOrigin;
- Object CrObject;
- vector<TToDoEntry> ToDoList;
- int ActToDo;
- int NrToDo;
- uint32 NextWakeup;
- bool Stop;
- bool LockToDo;
- uint8 Profession;
- TConnection *Connection;
-};
-
-
-struct TKnownCreature {
- KNOWNCREATURESTATE State;
- uint32 CreatureID;
- TKnownCreature *Next;
- TConnection *Connection;
-};
-
-struct TConnection {
- uint8 InData[2048];
- int InDataSize;
- bool SigIOPending;
- bool WaitingForACK;
- uint8 OutData[16384];
- uint8 field5_0x4806;
- uint8 field6_0x4807;
- int NextToSend;
- int NextToCommit;
- int NextToWrite;
- bool Overflow;
- bool WillingToSend;
- uint8 field12_0x4816;
- uint8 field13_0x4817;
- TConnection *NextSendingConnection;
- uint32 RandomSeed;
- CONNECTIONSTATE State;
- pid_t PID;
- int Socket;
- char IPAddress[16];
- TXTEASymmetricKey SymmetricKey;
- bool ConnectionIsOk;
- bool ClosingIsDelayed;
- uint8 field23_0x4852;
- uint8 field24_0x4853;
- uint32 TimeStamp;
- uint32 TimeStampAction;
- int TerminalType;
- int TerminalVersion;
- int TerminalOffsetX;
- int TerminalOffsetY;
- int TerminalWidth;
- int TerminalHeight;
- uint32 CharacterID;
- char Name[31];
- uint8 field35_0x4897;
- TKnownCreature KnownCreatureTable[150];
-};
-
struct TCircle {
int x[32];
int y[32];
@@ -300,59 +79,6 @@ struct TSpellList {
int Amount;
};
-struct TToDoEntry {
- ToDoType Code;
- union{
- struct{
- uint32 Time;
- } Wait;
-
- struct{
- int x;
- int y;
- int z;
- } Go;
-
- struct{
- int Direction;
- } Rotate;
-
- struct{
- uint32 Obj;
- int x;
- int y;
- int z;
- int Count;
- } Move;
-
- struct{
- uint32 Obj;
- uint32 Partner;
- } Trade;
-
- struct{
- uint32 Obj1;
- uint32 Obj2;
- int Dummy;
- } Use;
-
- struct{
- uint32 Obj;
- } Turn;
-
- struct{
- uint32 Text; // POINTER?
- int Mode;
- uint32 Addressee;
- bool CheckSpamming;
- } Talk;
-
- struct{
- int NewState;
- } ChangeState;
- };
-};
-
struct TXTEASymmetricKey {
int (**_vptr.TXTEASymmetricKey)(...); // VTABLE?
uint8 m_SymmetricKey[16];
@@ -405,20 +131,6 @@ struct TPreparedQuery {
char *Name;
};
-struct TSharedMemory {
- int Command;
- char CommandBuffer[256];
- ulong RoundNr;
- ulong ObjectCounter;
- ulong Errors;
- int PlayersOnline;
- int NewbiesOnline;
- int PrintBufferPosition;
- char PrintBuffer[200][128];
- enum GAMESTATE GameState;
- pid_t GameThreadPID;
-};
-
struct TPlayerIndexNode {
bool InternalNode;
};
@@ -539,16 +251,6 @@ struct listnode<storeunit<TWaitinglistEntry,_100>_> { // Original name: listnode
struct storeunit<TWaitinglistEntry,100> data;
};
-struct ObjectType {
- int TypeID;
-};
-
-struct TItemData {
- struct ObjectType Type;
- int Maximum;
- int Probability;
-};
-
struct TAttackWave {
int x;
int y;
@@ -564,16 +266,6 @@ struct TAttackWave {
struct vector<TItemData> ExtraItem;
};
-struct TSkillData {
- int Nr;
- int Actual;
- int Minimum;
- int Maximum;
- int NextLevel;
- int FactorPercent;
- int AddLevel;
-};
-
struct store<TWaitinglistEntry,100> {
struct list<storeunit<TWaitinglistEntry,_100>_> *Units;
union storeitem<TWaitinglistEntry> *firstFreeItem;
@@ -656,19 +348,7 @@ struct listIterator<storeunit<TWaitinglistEntry,_100>_> { // Original name: list
struct listnode<storeunit<TWaitinglistEntry,_100>_> *actNode;
};
-struct TSpellData {
- enum SpellShapeType Shape;
- int ShapeParam1;
- int ShapeParam2;
- int ShapeParam3;
- int ShapeParam4;
- enum SpellImpactType Impact;
- int ImpactParam1;
- int ImpactParam2;
- int ImpactParam3;
- int ImpactParam4;
- int Delay;
-};
+
struct storeunit<TNode,256> {
union storeitem<TNode> item[256];
@@ -734,14 +414,6 @@ struct list<storeunit<TNode,_256>_> { // Original name: list<storeunit<TNode, 25
struct listnode<storeunit<TNode,_256>_> *lastNode;
};
-struct TObjectType {
- char *Name;
- char *Description;
- uchar Flags[9];
- ulong Attributes[62];
- int AttributeOffsets[18];
-};
-
struct TCondition {
int Type;
ulong Text;
@@ -1207,53 +879,6 @@ struct TBehaviourDatabase {
int Behaviours;
};
-struct TMonster {
- struct TNonplayer super_TNonplayer;
- int Home;
- ulong Master;
- ulong Target;
-};
-
-struct TRaceData {
- char Name[30];
- char Article[3];
- struct TOutfit Outfit;
- struct ObjectType MaleCorpse;
- struct ObjectType FemaleCorpse;
- enum BloodType Blood;
- int ExperiencePoints;
- int FleeThreshold;
- int Attack;
- int Defend;
- int Armor;
- int Poison;
- int SummonCost;
- int LoseTarget;
- int Strategy[4];
- bool KickBoxes;
- bool KickCreatures;
- bool SeeInvisible;
- bool Unpushable;
- bool DistanceFighting;
- bool NoSummon;
- bool NoIllusion;
- bool NoConvince;
- bool NoBurning;
- bool NoPoison;
- bool NoEnergy;
- bool NoHit;
- bool NoLifeDrain;
- bool NoParalyze;
- int Skills;
- struct vector<TSkillData> Skill;
- int Talks;
- struct vector<long_unsigned_int> Talk;
- int Items;
- struct vector<TItemData> Item;
- int Spells;
- struct vector<TSpellData> Spell;
-};
-
struct TQueryManagerConnection {
int BufferSize;
uchar *Buffer;
diff --git a/src/config.cc b/src/config.cc
new file mode 100644
index 0000000..36917cb
--- /dev/null
+++ b/src/config.cc
@@ -0,0 +1,6 @@
+#include "main.hh"
+
+int Beat = 0;
+int DebugLevel = 0;
+
+//
diff --git a/src/connection.hh b/src/connection.hh
new file mode 100644
index 0000000..724ac91
--- /dev/null
+++ b/src/connection.hh
@@ -0,0 +1,56 @@
+#ifndef TIBIA_CONNECTION_HH_
+#define TIBIA_CONNECTION_HH_ 1
+
+#include "main.hh"
+#include "enums.hh"
+
+struct TConnection;
+
+struct TKnownCreature {
+ KNOWNCREATURESTATE State;
+ uint32 CreatureID;
+ TKnownCreature *Next;
+ TConnection *Connection;
+};
+
+struct TConnection {
+ uint8 InData[2048];
+ int InDataSize;
+ bool SigIOPending;
+ bool WaitingForACK;
+ uint8 OutData[16384];
+ uint8 field5_0x4806;
+ uint8 field6_0x4807;
+ int NextToSend;
+ int NextToCommit;
+ int NextToWrite;
+ bool Overflow;
+ bool WillingToSend;
+ uint8 field12_0x4816;
+ uint8 field13_0x4817;
+ TConnection *NextSendingConnection;
+ uint32 RandomSeed;
+ CONNECTIONSTATE State;
+ pid_t PID;
+ int Socket;
+ char IPAddress[16];
+ // TXTEASymmetricKey SymmetricKey; // TODO
+ bool ConnectionIsOk;
+ bool ClosingIsDelayed;
+ uint8 field23_0x4852;
+ uint8 field24_0x4853;
+ uint32 TimeStamp;
+ uint32 TimeStampAction;
+ int TerminalType;
+ int TerminalVersion;
+ int TerminalOffsetX;
+ int TerminalOffsetY;
+ int TerminalWidth;
+ int TerminalHeight;
+ uint32 CharacterID;
+ char Name[31];
+ uint8 field35_0x4897;
+ TKnownCreature KnownCreatureTable[150];
+};
+
+#endif // TIBIA_CONNECTION_HH_
diff --git a/src/containers.hh b/src/containers.hh
new file mode 100644
index 0000000..f249c81
--- /dev/null
+++ b/src/containers.hh
@@ -0,0 +1,338 @@
+#ifndef TIBIA_CONTAINERS_HH_
+#define TIBIA_CONTAINERS_HH_ 1
+
+#include "main.hh"
+
+// NOTE(fusion): What the actual fuck. This is an ever growing dynamic array
+// with each access through `operator()` growing it to make sure the requested
+// index is valid, even for negative indices.
+template<typename T>
+struct vector{
+ // REGULAR FUNCTIONS
+ // =========================================================================
+ vector(int min, int max, int block){
+ int space = (max - min) + 1;
+ if(space < 1){
+ error("vector: Ungueltige Feldgroesse %d bis %d.\n", min, max);
+ space = 1;
+ }
+
+ if(block < 0){
+ error("vector: Ungueltige Blockgroesse %d.\n", block);
+ block = 0;
+ }
+
+ this->min = min;
+ this->max = max;
+ this->start = min;
+ this->space = space;
+ this->block = block;
+ this->initialized = false;
+ this->entry = new T[this->space];
+ }
+
+ vector(int min, int max, int block, T init) : vector(min, max, block) {
+ this->initialized = true;
+ this->init = init;
+ for(int i = 0; i < this->space; i += 1){
+ this->entry[i] = init;
+ }
+ }
+
+ // TODO(fusion): Probably missing some inlined destructor?
+
+ T *at(int index){
+ // TODO(fusion): This is probably not the best way to achieve this.
+
+ while(index < this->start){
+ int increment = this->block;
+ if(increment == 0){
+ increment = this->space;
+ }
+
+ T *entry = new T[this->space + increment];
+ for(int i = this->min; i <= this->max; i += 1){
+ int old_index = i - this->start;
+ int new_index = old_index + increment;
+
+ // TODO(fusion): Do we actually need to swap elements here? I'm
+ // assuming some non-trivial structures that would invoke their
+ // destructors when `this->entry` gets deleted just below.
+ std::swap(entry[new_index], this->entry[old_index]);
+ }
+
+ if(this->entry != NULL){
+ delete[] this->entry;
+ }
+ this->entry = entry;
+ this->start -= increment;
+ this->space += increment;
+ }
+
+ while(index >= (this->start + this->space)){
+ int increment = this->block;
+ if(increment == 0){
+ increment = this->space;
+ }
+
+ T *entry = new[this->space + increment];
+ for(int i = this->min; i <= this->max; i += 1){
+ int old_index = i - this->start;
+ int new_index = old_index;
+
+ // TODO(fusion): Same as above.
+ std::swap(entry[new_index], this->entry[old_index]);
+ }
+
+ if(this->entry != NULL){
+ delete[] this->entry;
+ }
+ this->entry = entry;
+ this->space += increment;
+ }
+
+ while(index < this->min){
+ this->min -= 1;
+ if(this->initialized){
+ this->entry[this->min - this->start] = this->init;
+ }
+ }
+
+ while(index > this->max){
+ this->max += 1;
+ if(this->initialized){
+ this->entry[this->max - this->start] = this->init;
+ }
+ }
+
+ return &this->entry[index - this->start];
+ }
+
+ // DATA
+ // =========================================================================
+ int min;
+ int max;
+ int start;
+ int space;
+ int block;
+ bool initialized;
+ T init;
+ T *entry;
+};
+
+template<typename K, typename T>
+struct priority_queue_entry{
+ K Key;
+ T Data;
+};
+
+template<typename K, typename T>
+struct priority_queue{
+ // REGULAR FUNCTIONS
+ // =========================================================================
+ priority_queue(int capacity, int increment){
+ Entry = new vector<priority_queue_entry<K, T>>(1, capacity, increment);
+ Entries = 0;
+ }
+
+ // TODO(fusion): Probably missing some inlined destructor?
+
+ void insert(K Key, T *Data){
+ this->Entries += 1;
+ int CurrentIndex = this->Entries;
+ *this->Entry->at(CurrentIndex) = {Key, *Data};
+ while(CurrentIndex > 1){
+ int ParentIndex = CurrentIndex / 2;
+ priority_queue_entry<K, T> *Current = this->Entry->at(CurrentIndex);
+ priority_queue_entry<K, T> *Parent = this->Entry->at(ParentIndex);
+ if(Parent->Key <= Current->Key)
+ break;
+ std::swap(*Current, *Parent);
+ CurrentIndex = ParentIndex;
+ }
+ }
+
+ void deleteMin(void){
+ if(this->Entries < 1){
+ error("priority_queue::deleteMin: Warteschlange ist leer.\n");
+ return;
+ }
+
+ if(this->Entries > 1){
+ int CurrentIndex = 1;
+ int LastIndex = this->Entries;
+ std::swap(*this->Entry->at(CurrentIndex),
+ *this->Entry->at(LastIndex));
+
+ // TODO(fusion): This may be an oversight but the decompiled version
+ // checks in the loop below would INCLUDE `LastIndex`, which I assume
+ // is a bug? The first and last elements were just swapped and what
+ // was the first element in the queue is now at the end and should be
+ // considered "removed".
+ while(1){
+ int SmallestIndex = CurrentIndex * 2;
+ if(SmallestIndex >= LastIndex){
+ break;
+ }
+
+ priority_queue_entry<K, T> *Smallest = this->Entry->at(SmallestIndex);
+ if((SmallestIndex + 1) < LastIndex){
+ priority_queue_entry<K, T> *Other = this->Entry->at(SmallestIndex + 1);
+ if(Other->Key < Smallest->Key){
+ Smallest = Other;
+ SmallestIndex += 1;
+ }
+ }
+
+ priority_queue_entry<K, T> *Current = this->Entry->at(CurrentIndex);
+ if(Current->Key <= Smallest->Key){
+ break;
+ }
+
+ std::swap(*Current, *Smallest);
+ CurrentIndex = SmallestIndex;
+ }
+ }
+
+ this->Entries -= 1;
+ }
+
+ // DATA
+ // =========================================================================
+ vector<priority_queue_entry<K, T>> *Entry;
+ int Entries;
+};
+
+// TODO(fusion): We only use this structure two global queues:
+// priority_queue<uint32, uint32> ToDoQueue(5000, 1000);
+// priority_queue<uint32, TAttackWave*> AttackWaveQueue(100, 100);
+
+typedef<typename T>
+struct matrix{
+ // REGULAR FUNCTIONS
+ // =========================================================================
+ matrix(int xmin, int xmax, int ymin, int ymax){
+ int dx = (xmax - xmin) + 1;
+ int dy = (ymax - ymin) + 1;
+
+ if(dx < 1 || dy < 1){
+ error("matrix: Ungueltige Feldgroesse %d..%d, %d..%d.\n", xmin, xmax, ymin, ymax);
+
+ if(dx < 1){
+ dx = 1;
+ }
+
+ if(dy < 1){
+ dy = 1;
+ }
+ }
+
+ this->xmin = xmin;
+ this->ymin = ymin;
+ this->dx = dx;
+ this->dy = dy;
+ this->entry = new T[dx * dy];
+ }
+
+ matrix(int xmin, int xmax, int ymin, int ymax, T init) : matrix(xmin, xmax, ymin, ymax) {
+ int count = this->dx * this->dy;
+ for(int i = 0; i < count; i += 1){
+ this->entry[i] = init;
+ }
+ }
+
+ // TODO(fusion): Probably missing some inlined destructor?
+
+ T *at(int x, int y){
+ int xoffset = x - this->xmin;
+ int yoffset = y - this->ymin;
+ if(xoffset < 0 || xoffset >= this->dx || yoffset < 0 || yoffset >= this->dy){
+ error("matrix::operator(): Ungueltiger Index %d/%d.\n", x, y);
+ return &this->entry[0];
+ }else{
+ // TODO(fusion): Are we really storing this in row major order?
+ return &this->entry[yoffset * this->dx + xoffset];
+ }
+ }
+
+ // DATA
+ // =========================================================================
+ int xmin;
+ int ymin;
+ int dx;
+ int dy;
+ T *entry;
+};
+
+typedef<typename T>
+struct matrix3d{
+ // REGULAR FUNCTIONS
+ // =========================================================================
+ matrix3d(int xmin, int xmax, int ymin, int ymax, int zmin, int zmax){
+ int dx = (xmax - xmin) + 1;
+ int dy = (ymax - ymin) + 1;
+ int dz = (zmax - zmin) + 1;
+
+ if(dx < 1 || dy < 1 || dz < 1){
+ error("matrix3d: Ungueltige Feldgroesse %d..%d, %d..%d, %d..%d.\n",
+ xmin, xmax, ymin, ymax, zmin, zmax);
+
+ if(dx < 1){
+ dx = 1;
+ }
+
+ if(dy < 1){
+ dy = 1;
+ }
+
+ if(dz < 1){
+ dz = 1;
+ }
+ }
+
+ this->xmin = xmin;
+ this->ymin = ymin;
+ this->dx = dx;
+ this->dy = dy;
+ this->entry = new T[dx * dy];
+ }
+
+ matrix3d(int xmin, int xmax, int ymin, int ymax, int zmin, int zmax, T init)
+ : matrix(xmin, xmax, ymin, ymax, zmin, zmax) {
+ int count = this->dx * this->dy * this->dz;
+ for(int i = 0; i < count; i += 1){
+ this->entry[i] = init;
+ }
+ }
+
+ // TODO(fusion): Probably missing some inlined destructor?
+
+ T *at(int x, int y, int z){
+ int xoffset = x - this->xmin;
+ int yoffset = y - this->ymin;
+ int zoffset = z - this->zmin;
+ if(xoffset < 0 || xoffset >= this->dx
+ || yoffset < 0 || yoffset >= this->dy
+ || zoffset < 0 || zoffset >= this->dz){
+ error("matrix3d::operator(): Ungueltiger Index %d/%d/%d.\n", x, y, z);
+ return &this->entry[0];
+ }else{
+ // TODO(fusion): Same as `matrix::at` on the XY plane.
+ return &this->entry[zoffset * this->dx * this->dy
+ + yoffset * this->dx
+ + xoffset];
+ }
+ }
+
+ // DATA
+ // =========================================================================
+ int xmin;
+ int ymin;
+ int zmin;
+ int dx;
+ int dy;
+ int dz;
+ T *entry;
+};
+
+#endif //TIBIA_CONTAINERS_HH_ \ No newline at end of file
diff --git a/src/containers/matrix.hh b/src/containers/matrix.hh
deleted file mode 100644
index bf255ff..0000000
--- a/src/containers/matrix.hh
+++ /dev/null
@@ -1,132 +0,0 @@
-#ifndef TIBIA_MATRIX_HH_
-#define TIBIA_MATRIX_HH_ 1
-
-typedef<typename T>
-struct matrix{
- // REGULAR FUNCTIONS
- // =========================================================================
- matrix(int xmin, int xmax, int ymin, int ymax){
- int dx = (xmax - xmin) + 1;
- int dy = (ymax - ymin) + 1;
-
- if(dx < 1 || dy < 1){
- error("matrix: Ungueltige Feldgroesse %d..%d, %d..%d.\n", xmin, xmax, ymin, ymax);
-
- if(dx < 1){
- dx = 1;
- }
-
- if(dy < 1){
- dy = 1;
- }
- }
-
- this->xmin = xmin;
- this->ymin = ymin;
- this->dx = dx;
- this->dy = dy;
- this->entry = new T[dx * dy];
- }
-
- matrix(int xmin, int xmax, int ymin, int ymax, T init) : matrix(xmin, xmax, ymin, ymax) {
- int count = this->dx * this->dy;
- for(int i = 0; i < count; i += 1){
- this->entry[i] = init;
- }
- }
-
- // TODO(fusion): Probably missing some inlined destructor?
-
- T *at(int x, int y){
- int xoffset = x - this->xmin;
- int yoffset = y - this->ymin;
- if(xoffset < 0 || xoffset >= this->dx || yoffset < 0 || yoffset >= this->dy){
- error("matrix::operator(): Ungueltiger Index %d/%d.\n", x, y);
- return &this->entry[0];
- }else{
- // TODO(fusion): Are we really storing this in row major order?
- return &this->entry[yoffset * this->dx + xoffset];
- }
- }
-
- // DATA
- // =========================================================================
- int xmin;
- int ymin;
- int dx;
- int dy;
- T *entry;
-};
-
-typedef<typename T>
-struct matrix3d{
- // REGULAR FUNCTIONS
- // =========================================================================
- matrix3d(int xmin, int xmax, int ymin, int ymax, int zmin, int zmax){
- int dx = (xmax - xmin) + 1;
- int dy = (ymax - ymin) + 1;
- int dz = (zmax - zmin) + 1;
-
- if(dx < 1 || dy < 1 || dz < 1){
- error("matrix3d: Ungueltige Feldgroesse %d..%d, %d..%d, %d..%d.\n",
- xmin, xmax, ymin, ymax, zmin, zmax);
-
- if(dx < 1){
- dx = 1;
- }
-
- if(dy < 1){
- dy = 1;
- }
-
- if(dz < 1){
- dz = 1;
- }
- }
-
- this->xmin = xmin;
- this->ymin = ymin;
- this->dx = dx;
- this->dy = dy;
- this->entry = new T[dx * dy];
- }
-
- matrix3d(int xmin, int xmax, int ymin, int ymax, int zmin, int zmax, T init)
- : matrix(xmin, xmax, ymin, ymax, zmin, zmax) {
- int count = this->dx * this->dy * this->dz;
- for(int i = 0; i < count; i += 1){
- this->entry[i] = init;
- }
- }
-
- // TODO(fusion): Probably missing some inlined destructor?
-
- T *at(int x, int y, int z){
- int xoffset = x - this->xmin;
- int yoffset = y - this->ymin;
- int zoffset = z - this->zmin;
- if(xoffset < 0 || xoffset >= this->dx
- || yoffset < 0 || yoffset >= this->dy
- || zoffset < 0 || zoffset >= this->dz){
- error("matrix3d::operator(): Ungueltiger Index %d/%d/%d.\n", x, y, z);
- return &this->entry[0];
- }else{
- // TODO(fusion): Same as `matrix::at` on the XY plane.
- return &this->entry[zoffset * this->dx * this->dy
- + yoffset * this->dx
- + xoffset];
- }
- }
-
- // DATA
- // =========================================================================
- int xmin;
- int ymin;
- int zmin;
- int dx;
- int dy;
- int dz;
- T *entry;
-};
-
-#endif //TIBIA_MATRIX_HH_
diff --git a/src/containers/priority_queue.hh b/src/containers/priority_queue.hh
deleted file mode 100644
index b48353e..0000000
--- a/src/containers/priority_queue.hh
+++ /dev/null
@@ -1,94 +0,0 @@
-#ifndef TIBIA_PRIORITY_QUEUE_HH_
-#define TIBIA_PRIORITY_QUEUE_HH_ 1
-
-#include "main.hh"
-#include "vector.hh"
-
-template<typename K, typename T>
-struct priority_queue_entry{
- K Key;
- T Data;
-};
-
-template<typename K, typename T>
-struct priority_queue{
- // REGULAR FUNCTIONS
- // =========================================================================
- priority_queue(int capacity, int increment){
- Entry = new vector<priority_queue_entry<K, T>>(1, capacity, increment);
- Entries = 0;
- }
-
- // TODO(fusion): Probably missing some inlined destructor?
-
- void insert(K Key, T *Data){
- this->Entries += 1;
- int CurrentIndex = this->Entries;
- *this->Entry->at(CurrentIndex) = {Key, *Data};
- while(CurrentIndex > 1){
- int ParentIndex = CurrentIndex / 2;
- priority_queue_entry<K, T> *Current = this->Entry->at(CurrentIndex);
- priority_queue_entry<K, T> *Parent = this->Entry->at(ParentIndex);
- if(Parent->Key <= Current->Key)
- break;
- std::swap(*Current, *Parent);
- CurrentIndex = ParentIndex;
- }
- }
-
- void deleteMin(void){
- if(this->Entries < 1){
- error("priority_queue::deleteMin: Warteschlange ist leer.\n");
- return;
- }
-
- if(this->Entries > 1){
- int CurrentIndex = 1;
- int LastIndex = this->Entries;
- std::swap(*this->Entry->at(CurrentIndex),
- *this->Entry->at(LastIndex));
-
- // TODO(fusion): This may be an oversight but the decompiled version
- // checks in the loop below would INCLUDE `LastIndex`, which I assume
- // is a bug? The first and last elements were just swapped and what
- // was the first element in the queue is now at the end and should be
- // considered "removed".
- while(1){
- int SmallestIndex = CurrentIndex * 2;
- if(SmallestIndex >= LastIndex){
- break;
- }
-
- priority_queue_entry<K, T> *Smallest = this->Entry->at(SmallestIndex);
- if((SmallestIndex + 1) < LastIndex){
- priority_queue_entry<K, T> *Other = this->Entry->at(SmallestIndex + 1);
- if(Other->Key < Smallest->Key){
- Smallest = Other;
- SmallestIndex += 1;
- }
- }
-
- priority_queue_entry<K, T> *Current = this->Entry->at(CurrentIndex);
- if(Current->Key <= Smallest->Key){
- break;
- }
-
- std::swap(*Current, *Smallest);
- CurrentIndex = SmallestIndex;
- }
- }
-
- this->Entries -= 1;
- }
-
- // DATA
- // =========================================================================
- vector<priority_queue_entry<K, T>> *Entry;
- int Entries;
-};
-
-// TODO(fusion): We only use this structure two global queues:
-// priority_queue<uint32, uint32> ToDoQueue(5000, 1000);
-// priority_queue<uint32, TAttackWave*> AttackWaveQueue(100, 100);
-
-#endif //TIBIA_PRIORITY_QUEUE_HH_
diff --git a/src/containers/vector.hh b/src/containers/vector.hh
deleted file mode 100644
index 044ffe1..0000000
--- a/src/containers/vector.hh
+++ /dev/null
@@ -1,123 +0,0 @@
-#ifndef TIBIA_VECTOR_HH_
-#define TIBIA_VECTOR_HH_ 1
-
-#include "main.hh"
-
-// NOTE(fusion): What the actual fuck. This is an ever growing dynamic array
-// with each access through `operator()` growing it to make sure the requested
-// index is valid, even for negative indices.
-template<typename T>
-struct vector{
- // REGULAR FUNCTIONS
- // =========================================================================
- vector(int min, int max, int block){
- int space = (max - min) + 1;
- if(space < 1){
- error("vector: Ungueltige Feldgroesse %d bis %d.\n", min, max);
- space = 1;
- }
-
- if(block < 0){
- error("vector: Ungueltige Blockgroesse %d.\n", block);
- block = 0;
- }
-
- this->min = min;
- this->max = max;
- this->start = min;
- this->space = space;
- this->block = block;
- this->initialized = false;
- this->entry = new T[this->space];
- }
-
- vector(int min, int max, int block, T init) : vector(min, max, block) {
- this->initialized = true;
- this->init = init;
- for(int i = 0; i < this->space; i += 1){
- this->entry[i] = init;
- }
- }
-
- // TODO(fusion): Probably missing some inlined destructor?
-
- T *at(int index){
- // TODO(fusion): This is probably not the best way to achieve this.
-
- while(index < this->start){
- int increment = this->block;
- if(increment == 0){
- increment = this->space;
- }
-
- T *entry = new T[this->space + increment];
- for(int i = this->min; i <= this->max; i += 1){
- int old_index = i - this->start;
- int new_index = old_index + increment;
-
- // TODO(fusion): Do we actually need to swap elements here? I'm
- // assuming some non-trivial structures that would invoke their
- // destructors when `this->entry` gets deleted just below.
- std::swap(entry[new_index], this->entry[old_index]);
- }
-
- if(this->entry != NULL){
- delete[] this->entry;
- }
- this->entry = entry;
- this->start -= increment;
- this->space += increment;
- }
-
- while(index >= (this->start + this->space)){
- int increment = this->block;
- if(increment == 0){
- increment = this->space;
- }
-
- T *entry = new[this->space + increment];
- for(int i = this->min; i <= this->max; i += 1){
- int old_index = i - this->start;
- int new_index = old_index;
-
- // TODO(fusion): Same as above.
- std::swap(entry[new_index], this->entry[old_index]);
- }
-
- if(this->entry != NULL){
- delete[] this->entry;
- }
- this->entry = entry;
- this->space += increment;
- }
-
- while(index < this->min){
- this->min -= 1;
- if(this->initialized){
- this->entry[this->min - this->start] = this->init;
- }
- }
-
- while(index > this->max){
- this->max += 1;
- if(this->initialized){
- this->entry[this->max - this->start] = this->init;
- }
- }
-
- return &this->entry[index - this->start];
- }
-
- // DATA
- // =========================================================================
- int min;
- int max;
- int start;
- int space;
- int block;
- bool initialized;
- T init;
- T *entry;
-};
-
-#endif //TIBIA_VECTOR_HH_
diff --git a/src/creature.cc b/src/creature.cc
index f3acdb8..effac42 100644
--- a/src/creature.cc
+++ b/src/creature.cc
@@ -46,7 +46,7 @@ void CheckMana(TCreature *Creature, int ManaPoints, int SoulPoints, int Delay){
}
// NOTE(fusion): Maintain largest exhaust?
- int EarliestSpellTime = Delay + ServerMilliseconds;
+ uint32 EarliestSpellTime = Delay + ServerMilliseconds;
if(Creature->EarliestSpellTime < EarliestSpellTime){
Creature->EarliestSpellTime = EarliestSpellTime;
}
diff --git a/src/creature.hh b/src/creature.hh
index 8f0917a..2b19836 100644
--- a/src/creature.hh
+++ b/src/creature.hh
@@ -2,6 +2,8 @@
#define TIBIA_CREATURE_HH_ 1
#include "main.hh"
+#include "connection.hh"
+#include "containers.hh"
#include "skill.hh"
struct TCreature;
@@ -13,6 +15,12 @@ struct TCombatEntry{
};
struct TCombat{
+ // REGULAR FUNCTIONS
+ // =========================================================================
+ // TODO
+
+ // DATA
+ // =========================================================================
TCreature *Master;
uint32 EarliestAttackTime;
uint32 EarliestDefendTime;
@@ -36,6 +44,59 @@ struct TCombat{
int LearningPoints;
};
+struct TToDoEntry {
+ ToDoType Code;
+ union{
+ struct{
+ uint32 Time;
+ } Wait;
+
+ struct{
+ int x;
+ int y;
+ int z;
+ } Go;
+
+ struct{
+ int Direction;
+ } Rotate;
+
+ struct{
+ uint32 Obj;
+ int x;
+ int y;
+ int z;
+ int Count;
+ } Move;
+
+ struct{
+ uint32 Obj;
+ uint32 Partner;
+ } Trade;
+
+ struct{
+ uint32 Obj1;
+ uint32 Obj2;
+ int Dummy;
+ } Use;
+
+ struct{
+ uint32 Obj;
+ } Turn;
+
+ struct{
+ uint32 Text; // POINTER? Probably a reference from `AddDynamicString`?
+ int Mode;
+ uint32 Addressee;
+ bool CheckSpamming;
+ } Talk;
+
+ struct{
+ int NewState;
+ } ChangeState;
+ };
+};
+
struct TOutfit{
int OutfitID;
union{
diff --git a/src/enums.hh b/src/enums.hh
index 053a2ed..feb9775 100644
--- a/src/enums.hh
+++ b/src/enums.hh
@@ -12,6 +12,99 @@ enum CreatureType: int {
NPC = 2,
};
+enum CONNECTIONSTATE: int {
+ CONNECTION_FREE = 0,
+ CONNECTION_ASSIGNED = 1,
+ CONNECTION_CONNECTED = 2,
+ CONNECTION_LOGIN = 3,
+ CONNECTION_GAME = 4,
+ CONNECTION_DEAD = 5,
+ CONNECTION_LOGOUT = 6,
+ CONNECTION_DISCONNECTED = 7,
+};
+
+enum FLAG: int {
+ BANK = 0,
+ CLIP = 1,
+ BOTTOM = 2,
+ TOP = 3,
+ CONTAINER = 4,
+ CHEST = 5,
+ CUMULATIVE = 6,
+ USEEVENT = 7,
+ CHANGEUSE = 8,
+ FORCEUSE = 9,
+ MULTIUSE = 10,
+ DISTUSE = 11,
+ MOVEMENTEVENT = 12,
+ COLLISIONEVENT = 13,
+ SEPARATIONEVENT = 14,
+ KEY = 15,
+ KEYDOOR = 16,
+ NAMEDOOR = 17,
+ LEVELDOOR = 18,
+ QUESTDOOR = 19,
+ BED = 20,
+ FOOD = 21,
+ RUNE = 22,
+ INFORMATION = 23,
+ TEXT = 24,
+ WRITE = 25,
+ WRITEONCE = 26,
+ LIQUIDCONTAINER = 27,
+ LIQUIDSOURCE = 28,
+ LIQUIDPOOL = 29,
+ TELEPORTABSOLUTE = 30,
+ TELEPORTRELATIVE = 31,
+ UNPASS = 32,
+ UNMOVE = 33,
+ UNTHROW = 34,
+ UNLAY = 35,
+ AVOID = 36,
+ MAGICFIELD = 37,
+ RESTRICTLEVEL = 38,
+ RESTRICTPROFESSION = 39,
+ TAKE = 40,
+ HANG = 41,
+ HOOKSOUTH = 42,
+ HOOKEAST = 43,
+ ROTATE = 44,
+ DESTROY = 45,
+ CLOTHES = 46,
+ SKILLBOOST = 47,
+ PROTECTION = 48,
+ LIGHT = 49,
+ ROPESPOT = 50,
+ CORPSE = 51,
+ EXPIRE = 52,
+ EXPIRESTOP = 53,
+ WEAROUT = 54,
+ WEAPON = 55,
+ SHIELD = 56,
+ BOW = 57,
+ THROW = 58,
+ WAND = 59,
+ AMMO = 60,
+ ARMOR = 61,
+ HEIGHT = 62,
+ DISGUISE = 63,
+ SHOWDETAIL = 64,
+ SPECIALOBJECT = 65,
+};
+
+enum GAMESTATE: int {
+ GAME_STARTING = 0,
+ GAME_RUNNING = 1,
+ GAME_CLOSING = 2,
+ GAME_ENDING = 3,
+};
+
+enum KNOWNCREATURESTATE: int {
+ KNOWNCREATURE_FREE = 0,
+ KNOWNCREATURE_UPTODATE = 1,
+ KNOWNCREATURE_OUTDATED = 2
+};
+
// NOTE(fusion): Not in debug symbols.
enum PROFESSION: uint8 {
PROFESSION_NONE = 0,
@@ -202,7 +295,26 @@ enum Skill: int {
SKILL_SOUL = 22,
};
-enum TalkMode: int {
+enum SpellShapeType: int {
+ SHAPE_ACTOR = 0,
+ SHAPE_VICTIM = 1,
+ SHAPE_ORIGIN = 2,
+ SHAPE_DESTINATION = 3,
+ SHAPE_ANGLE = 4,
+};
+
+enum SpellImpactType: int {
+ IMPACT_DAMAGE = 0,
+ IMPACT_FIELD = 1,
+ IMPACT_HEALING = 2,
+ IMPACT_SPEED = 3,
+ IMPACT_DRUNKEN = 4,
+ IMPACT_STRENGTH = 5,
+ IMPACT_OUTFIT = 6,
+ IMPACT_SUMMON = 7,
+};
+
+enum TALK_MODE: int {
TALK_SAY = 1,
TALK_WHISPER = 2,
TALK_YELL = 3,
@@ -228,4 +340,88 @@ enum TalkMode: int {
TALK_FAILURE_MESSAGE = 23,
};
+enum ToDoType: int {
+ TDWait = 0,
+ TDGo = 1,
+ TDRotate = 2,
+ TDMove = 3,
+ TDTrade = 4,
+ TDUse = 5,
+ TDTurn = 6,
+ TDAttack = 7,
+ TDTalk = 8,
+ TDChangeState = 9,
+};
+
+enum TYPEATTRIBUTE: int {
+ WAYPOINTS = 0,
+ CAPACITY = 1,
+ CHANGETARGET = 2,
+ KEYDOORTARGET = 3,
+ NAMEDOORTARGET = 4,
+ LEVELDOORTARGET = 5,
+ QUESTDOORTARGET = 6,
+ NUTRITION = 7,
+ INFORMATIONTYPE = 8,
+ FONTSIZE = 9,
+ MAXLENGTH = 10,
+ MAXLENGTHONCE = 11,
+ SOURCELIQUIDTYPE = 12,
+ ABSTELEPORTEFFECT = 13,
+ RELTELEPORTDISPLACEMENT = 14,
+ RELTELEPORTEFFECT = 15,
+ AVOIDDAMAGETYPES = 16,
+ MINIMUMLEVEL = 17,
+ PROFESSIONS = 18,
+ WEIGHT = 19,
+ ROTATETARGET = 20,
+ DESTROYTARGET = 21,
+ BODYPOSITION = 22,
+ SKILLNUMBER = 23,
+ SKILLMODIFICATION = 24,
+ PROTECTIONDAMAGETYPES = 25,
+ DAMAGEREDUCTION = 26,
+ BRIGHTNESS = 27,
+ LIGHTCOLOR = 28,
+ CORPSETYPE = 29,
+ TOTALEXPIRETIME = 30,
+ EXPIRETARGET = 31,
+ TOTALUSES = 32,
+ WEAROUTTARGET = 33,
+ WEAPONTYPE = 34,
+ WEAPONATTACKVALUE = 35,
+ WEAPONDEFENDVALUE = 36,
+ SHIELDDEFENDVALUE = 37,
+ BOWRANGE = 38,
+ BOWAMMOTYPE = 39,
+ THROWRANGE = 40,
+ THROWATTACKVALUE = 41,
+ THROWDEFENDVALUE = 42,
+ THROWMISSILE = 43,
+ THROWSPECIALEFFECT = 44,
+ THROWEFFECTSTRENGTH = 45,
+ THROWFRAGILITY = 46,
+ WANDRANGE = 47,
+ WANDMANACONSUMPTION = 48,
+ WANDATTACKSTRENGTH = 49,
+ WANDATTACKVARIATION = 50,
+ WANDDAMAGETYPE = 51,
+ WANDMISSILE = 52,
+ AMMOTYPE = 53,
+ AMMOATTACKVALUE = 54,
+ AMMOMISSILE = 55,
+ AMMOSPECIALEFFECT = 56,
+ AMMOEFFECTSTRENGTH = 57,
+ ARMORVALUE = 58,
+ ELEVATION = 59,
+ DISGUISETARGET = 60,
+ MEANING = 61,
+};
+
+enum TWorldType: int {
+ NORMAL = 0,
+ NON_PVP = 1,
+ PVP_ENFORCED = 2,
+};
+
#endif //TIBIA_ENUMS_HH_
diff --git a/src/main.cc b/src/main.cc
index e616ce3..e7a5721 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -1,38 +1,563 @@
#include "main.hh"
+#include <signal.h>
+#include <sys/time.h>
+
+static bool BeADaemon = false;
+static bool Reboot = false;
+static bool SaveMapOn = false;
+
+static int SigAlarmCounter = 0;
+static int SigUsr1Counter = 0;
+
+static sighandler_t handler(int signr, sighandler_t sighandler){
+ struct sigaction act;
+ struct sigaction oldact;
+
+ act.sa_handler = sighandler;
+
+ // TODO(fusion): I feel we should probably use `sigfillset` specially for
+ // signals that share the same handler.
+ sigemptyset(&act.sa_mask);
+
+ // TODO(fusion): We had this weird logic in the decompiled version of this
+ // function but it looks like some GLIBC internal thing, since these values
+ // would mask signals 1020 and 1021 which don't really make sense.
+ //
+ //if(signr == SIGALRM){
+ // act.sa_mask.__val[0x1f] = 0x20000000;
+ //}else{
+ // act.sa_mask.__val[0x1f] = 0x10000000;
+ //}
+ //
+
+ if(sigaction(signr, &act, &oldact) == 0){
+ return oldact.sa_handler;
+ }else{
+ return SIG_ERR;
+ }
+}
+
+static void SigHupHandler(int signr){
+ // no-op (?)
+}
+
+static void SigAbortHandler(int signr){
+ print(1, "SigAbortHandler: schalte Writer-Thread ab.\n");
+ AbortWriter();
+}
+
+static void DefaultHandler(int signr){
+ print(1, "DefaultHandler: Beende Game-Server (SigNr. %d: %s).\n",
+ signr, sigdescr_np(signr));
+
+ handler(SIGINT, SIG_IGN);
+ handler(SIGQUIT, SIG_IGN);
+ handler(SIGTERM, SIG_IGN);
+ handler(SIGXCPU, SIG_IGN);
+ handler(SIGXFSZ, SIG_IGN);
+ handler(SIGPWR, SIG_IGN);
+
+ SaveMapOn = (signr == SIGQUIT) || (signr == SIGTERM) || (signr == SIGPWR);
+ if(signr == SIGTERM){
+ GetRealTime(&Hour, &Minute);
+ RebootTime = (Hour * 60 + Minute + 6) % 1440;
+ CloseGame();
+ }else{
+ EndGame();
+ }
+
+ Reboot = false;
+}
+
+// TODO(fusion): This function was exported in the binary but not referenced anywhere.
+static void ErrorHandler(int signr){
+ error("ErrorHandler: SigNr. %d: %s\n", signr, sigdescr_np(signr));
+ EndGame();
+ LogoutAllPlayers();
+ exit(1);
+}
+
+static void InitSignalHandler(void){
+ int count = 0;
+ count += (handler(SIGHUP, SigHupHandler) != SIG_ERR);
+ count += (handler(SIGINT, DefaultHandler) != SIG_ERR);
+ count += (handler(SIGQUIT, DefaultHandler) != SIG_ERR);
+ count += (handler(SIGABRT, SigAbortHandler) != SIG_ERR);
+ count += (handler(SIGUSR1, SIG_IGN) != SIG_ERR);
+ count += (handler(SIGUSR2, SIG_IGN) != SIG_ERR);
+ count += (handler(SIGPIPE, SIG_IGN) != SIG_ERR);
+ count += (handler(SIGALRM, SIG_IGN) != SIG_ERR);
+ count += (handler(SIGTERM, DefaultHandler) != SIG_ERR);
+ count += (handler(SIGSTKFLT, SIG_IGN) != SIG_ERR);
+ count += (handler(SIGCHLD, SIG_IGN) != SIG_ERR);
+ count += (handler(SIGTSTP, SIG_IGN) != SIG_ERR);
+ count += (handler(SIGTTIN, SIG_IGN) != SIG_ERR);
+ count += (handler(SIGTTOU, SIG_IGN) != SIG_ERR);
+ count += (handler(SIGURG, SIG_IGN) != SIG_ERR);
+ count += (handler(SIGXCPU, DefaultHandler) != SIG_ERR);
+ count += (handler(SIGXFSZ, DefaultHandler) != SIG_ERR);
+ count += (handler(SIGVTALRM, SIG_IGN) != SIG_ERR);
+ count += (handler(SIGWINCH, SIG_IGN) != SIG_ERR);
+ count += (handler(SIGPOLL, SIG_IGN) != SIG_ERR);
+ count += (handler(SIGPWR, DefaultHandler) != SIG_ERR);
+ print(1, "InitSignalHandler: %d Signalhandler eingerichtet (Soll=%d)\n", count, 0x1c);
+}
+
+static void ExitSignalHandler(void){
+ // no-op
+}
+
+static void SigAlarmHandler(int signr){
+ SigAlarmCounter += 1;
+
+ struct itimerval new_timer = {};
+ strict itimerval old_timer = {};
+ new_timer.it_value.tv_usec = Beat * 1000;
+ setitimer(ITIMER_REAL, &new_timer, &old_timer);
+}
+
+static void InitTime(void){
+ SigAlarmCounter = 0;
+ handler(SIGALRM, SigAlarmHandler);
+ SigAlarmHandler(SIGALARM);
+}
+
+static void ExitTime(void){
+ struct itimerval new_timer = {};
+ strict itimerval old_timer = {};
+ setitimer(ITIMER_REAL, &new_timer, &old_timer);
+ handler(SIGALRM, SIG_IGN);
+}
+
+static void UnlockGame(void){
+ // TODO(fusion): Probably use snprintf to format file name?
+ char FileName[4096];
+ strcpy(FileName, SAVEPATH);
+ strcat(FileName, "/game.pid");
+
+ std::ifstream InputFile(Filename, std::ios_base::in);
+ if(!InputFile.fail()){
+ int Pid;
+ InputFile >> Pid;
+
+ if(Pid == getpid()){
+ unlink(FileName);
+ }
+ }
+}
+
+static void LockGame(void){
+ // TODO(fusion): Probably use snprintf to format file name?
+ char FileName[4096];
+ strcpy(FileName, SAVEPATH);
+ strcat(FileName, "/game.pid");
+
+ {
+ std::ifstream InputFile(Filename, std::ios_base::in);
+ if(!InputFile.fail()){
+ int Pid;
+ InputFile >> Pid;
+ if(Pid != 0){
+ throw "Game-Server is already running, PID file exists.";
+ }
+ }
+ }
+
+ {
+ std::ofstream OutputFile(FileName, std::ios_base::out | std::ios_base::trunc);
+ OutputFile << (int)getpid();
+ }
+
+ atexit(UnlockGame);
+}
+
+void LoadWorldConfig(void){
#if 0
-// TODO(fusion): All globals should probably be packed into a `GlobalState`
-// structure to minimize collisions and bugs.
-struct GlobalState{
- // world state
- // creatures
- // items
- // etc...
-};
-
-GlobalState G = {};
+ // TODO(fusion): Whenever we implement query/database stuff.
+ TQueryManagerConnection Connection(0x4000);
+ if(Connection.WriteBuffer.Position < 0){
+ error("LoadWorldConfig: Kann nicht zum Query-Manager verbinden.\n");
+ throw "cannot connect to querymanager";
+ }
+
+ int HelpGameAddress[4];
+ int Ret = Connection.loadWorldConfig(&WorldType, &RebootTime, HelpGameAddress,
+ &Port, &MaxPlayers, &PremiumPlayerBuffer, &MaxNewbies, &PremiumNewbieBuffer);
+ if(Ret != 0){ // TODO(fusion): Maybe `Ret != QUERY_OK` or something?
+ error("LoadWorldConfig: Kann Konfigurationsdaten nicht holen.\n");
+ throw "cannot load world config";
+ }
+
+ // NOTE(fusion): Ugh...
+ snprintf(GameAddress, sizeof(GameAddress), "%d.%d.%d.%d",
+ HelpGameAddress[0], HelpGameAddress[1],
+ HelpGameAddress[2], HelpGameAddress[3]);
#endif
-// TODO(fusion): Probably current server time. Used for delays, timers, etc.
-int ServerMilliseconds = 0;
+ WorldType = NORMAL;
+ RebootTime = 6 * 60; // minutes
+ strcpy(GameAddress, "127.0.0.1"); // I KNOW
+ Port = 7171;
+ MaxPlayers = 1000;
+ PremiumPlayerBuffer = 100;
+ MaxNewbies = 200;
+ PremiumNewbieBuffer = 50;
+}
-void (*ErrorFunction)(const char*) = NULL;
+static void InitAll(void){
+ try{
+ //ReadConfig();
+ //SetQueryManagerLoginData(1, WorldName);
+ LoadWorldConfig();
+ InitSHM(!BeADaemon);
+ LockGame();
+ //InitLog("game");
+ srand(time(NULL));
+ InitSignalHandler();
+ //InitConnections();
+ //InitCommunication();
+ //InitStrings();
+ //InitWriter();
+ //InitReader();
+ //InitObjects();
+ //InitMap();
+ //InitInfo();
+ //InitMoveUse();
+ //InitMagic();
+ //InitCr();
+ //InitHouses();
+ InitTime();
+ //ApplyPatches();
+ }catch(const char *str){
+ error("Initialisierungsfehler: %s\n", str);
+ exit(EXIT_FAILURE);
+ }
+}
-void error(char *Text, ...){
- char s[1024];
+static void ExitAll(void){
+ // TODO(fusion): Probably missing some inlined empty `Exit*` functions here.
- va_list ap;
- va_start(ap, Text);
- vsnprintf(s, sizeof(s) - 1, Text, ap);
- va_end(ap);
+ EndGame();
+ ExitTime();
+ //ExitCr();
+ //ExitMagic();
+ //ExitMoveUse();
+ //ExitInfo();
+ //ExitHouses();
+ //ExitMap(SaveMapOn);
+ //ExitObjects();
+ //ExitReader();
+ //ExitWriter();
+ //ExitStrings();
+ //ExitCommunication();
+ //ExitConnections();
+ ExitSignalHandler();
+ ExitSHM();
+}
- if(ErrorFunction){
- ErrorFunction(s);
+static void ProcessCommand(void){
+ int Command = GetCommand();
+ if(Command != 0){
+ char *Buffer = GetCommandBuffer();
+ if(Command == 1){
+ if(Buffer != NULL){
+ BroadcastMessage(TALK_ADMIN_MESSAGE, "%s", Buffer);
+ }else{
+ error("ProcessCommand: Text für Broadcast ist NULL.\n");
+ }
+ }else{
+ error("ProcessCommand: Unbekanntes Kommando %d.\n", Command);
+ }
+
+ SetCommand(0, NULL);
+ }
+}
+
+static void AdvanceGame(int Delay){
+ static int CreatureTimeCounter = 0;
+ static int CronTimeCounter = 0;
+ static int SkillTimeCounter = 0;
+ static int OtherTimeCounter = 0;
+ static int OldAmbiente = -1;
+ static uint32 NextMinute = 30;
+ static bool Lag = false;
+
+ CreatureTimeCounter += Delay;
+ CronTimeCounter += Delay;
+ SkillTimeCounter += Delay;
+ OtherTimeCounter += Delay;
+
+ if(CreatureTimeCounter >= 1750){
+ CreatureTimeCounter -= 1000;
+ ProcessCreature();
+ }
+
+ if(CronTimeCounter >= 1500){
+ CronTimeCounter -= 1000;
+ ProcessCronSystem();
+ }
+
+ if(SkillTimeCounter >= 1250){
+ SkillTimeCounter -= 1000;
+ ProcessSkills();
+ }
+
+ if(OtherTimeCounter >= 1000){
+ OtherTimeCounter -= 1000;
+
+ RoundNr += 1;
+ SetRoundNr(RoundNr);
+
+ ProcessConnections();
+ ProcessMonsterhomes();
+ ProcessMonsterRaids();
+ ProcessCommunicationControl();
+ ProcessReaderThreadReplies(RefreshSector,SendMails);
+ ProcessWriterThreadReplies();
+ ProcessCommand();
+
+ // TODO(fusion): Shouldn't we be checking both brightness and color?
+ int Brightness, Color;
+ GetAmbiente(&Brightness, &Color);
+ if(OldAmbiente != Brightness){
+ OldAmbiente = Brightness;
+ TConnection *Connection = GetFirstConnection();
+ while(Connection != NULL){
+ // TODO(fusion): This is probably an inlined function that checks
+ // whether the connection is still going. The exact decompiled condition
+ // was `Connection->State - CONDITION_LOGIN < 4` but I think that's
+ // just a compiler optimization that wouldn't work properly on the
+ // decompiled version. That comparison in the disassembly is unsigned
+ // (`JBE`) but the enum is signed which would probably generate an
+ // invalid signed comparison (`JLE`).
+ //
+ // MOV EAX, dword ptr [Connection + Connection->State]
+ // SUB EAX, 0x3
+ // CMP EAX, 0x3
+ // JBE ... -> SendAmbiente(Connection)
+ //
+ if(Connection->State == CONNECTION_LOGIN
+ || Connection->State == CONNECTION_GAME
+ || Connection->State == CONNECTION_DEAD
+ || Connection->State == CONNECTION_LOGOUT){
+ SendAmbiente(Connection);
+ }
+ Connection = GetNextConnection();
+ }
+ }
+
+ if(RoundNr % 10 == 0){
+ NetLoadCheck();
+ }
+
+ if(RoundNr >= NextMinute){
+ int Hour, Minute;
+ GetRealTime(&Hour, &Minute);
+
+ RefreshCylinders();
+ if(Minute % 5 == 0){
+ CreatePlayerList(true);
+ }
+ if(Minute % 15 == 0){
+ SavePlayerDataOrder();
+ }
+ if(Minute == 0){
+ NetLoadSummary();
+ }
+ if(Minute == 55){
+ WriteKillStatistics();
+ }
+
+ int RealTime = Minute + Hour * 60;
+ if((RealTime + 5) % 1440 == RebootTime){
+ if(Reboot){
+ BroadcastMessage(TALK_ADMIN_MESSAGE,
+ "Server is saving game in 5 minutes.\nPlease come back in 10 minutes.");
+ }else{
+ BroadcastMessage(TALK_ADMIN_MESSAGE,
+ "Server is going down in 5 minutes.\nPlease log out.");
+ }
+ CloseGame();
+ }else if((RealTime + 3) % 1440 == RebootTime){
+ if(Reboot){
+ BroadcastMessage(TALK_ADMIN_MESSAGE,
+ "Server is saving game in 3 minutes.\nPlease come back in 10 minutes.");
+ }else{
+ BroadcastMessage(TALK_ADMIN_MESSAGE,
+ "Server is going down in 3 minutes.\nPlease log out.");
+ }
+ }else if((RealTime + 1) % 1440 == RebootTime){
+ if(Reboot){
+ BroadcastMessage(TALK_ADMIN_MESSAGE,
+ "Server is saving game in one minute.\nPlease log out.");
+ }else{
+ BroadcastMessage(TALK_ADMIN_MESSAGE,
+ "Server is going down in one minute.\nPlease log out.");
+ }
+ }else if(RealTime == RebootTime){
+ CloseGame();
+ LogoutAllPlayers();
+ SendAll();
+ if(Reboot){
+ RefreshMap();
+ }
+ SaveMap();
+ SaveMapOn = false;
+ EndGame();
+ }
+
+ NextMinute = GetRoundForNextMinute();
+ }
+ CleanupDynamicStrings();
+ }
+
+ if(Delay > Beat){
+ Log("lag", "Verzögerung %d msec.\n", Delay);
+ }
+
+ // TODO(fusion): Why would we delay creature movement yet another beat?
+ if(Delay < 1000){
+ MoveCreatures(Delay);
+ Lag = false;
}else{
- printf("%s", s);
+ if(!Lag && RoundNr > 10){
+ error("AdvanceGame: Keine Kreaturbewegung wegen Lag (Verzögerung: %d msec).\n", Delay);
+ }
+ Lag = true;
}
+
+ SendAll();
+}
+
+static void SigUsr1Handler(int signr){
+ SigUsr1Counter += 1;
+}
+
+static void LaunchGame(void){
+ SigUsr1Counter = 0;
+ handler(SIGUSR1, SigUsr1Handler);
+ StartGame();
+
+ print(1, "LaunchGame: Game-Server ist bereit (Pid=%d).\n", getpid());
+
+ // IMPORTANT(fusion): The whole design of the server is to run across a few
+ // different processes and communicate via shared memory and signals. Each
+ // of these processes are single threaded, meaning that signal handlers are
+ // executed concurrently on the SAME thread. You'd still require to synchronize
+ // access to large structures to avoid race conditions BUT accessing a few
+ // independent integers and booleans like we're doing with `SigAlarmCounter`,
+ // `SigUsr1Counter`, and `SaveMapOn` is perfectly safe.
+
+ SaveMapOn = true;
+ SigAlarmCounter = 0;
+ while(GameRunning()){
+ // TODO(fusion): `sigblock` and `sigpause` are deprecated in favour of
+ // `sigprocmask` and `sigsuspend`.
+ sigblock(sigmask(SIGUSR1));
+ while(SigUsr1Counter == 0 && SigAlarmCounter == 0){
+ sigpause(0);
+ }
+
+ if(SigUsr1Counter > 0){
+ SigUsr1Counter = 0;
+ ReceiveData();
+ }
+
+ int NumBeats = SigAlarmCounter;
+ if(NumBeats > 0){
+ SigAlarmCounter = 0;
+ AdvanceGame(NumBeats * Beat);
+ }
+ }
+
+ LogoutAllPlayers();
+}
+
+static bool DaemonInit(bool NoFork){
+ if(!NoFork){
+ pid_t Pid = fork();
+ if(Pid < 0){
+ return true;
+ }
+
+ if(Pid != 0){
+ exit(EXIT_SUCCESS);
+ }
+
+ setsid();
+ }
+
+ umask(0177);
+ chdir(SAVEPATH);
+
+ int OpenMax = sysconf(_SC_OPEN_MAX);
+ if(OpenMax < 0){
+ OpenMax = 1024;
+ }
+
+ for(int fd = 0; fd < OpenMax; fd += 1){
+ close(fd);
+ }
+
+ return false;
}
int main(int argc, char **argv){
+ bool NoFork = false;
+ BeADaemon = false;
+ Reboot = true;
+
+ for(int i = 1; i < argc; i += 1){
+ if(strcmp(argv[i], "daemon") == 0){
+ BeADaemon = true;
+ }else if(strcmp(argv[i], "nofork") == 0){
+ NoFork = true;
+ }
+ }
+
+ // TODO(fusion): It doesn't make sense for `DaemonInit` to even return here.
+ // It either exits the parent or child process, or let it run.
+ if(BeADaemon && DaemonInit(NoFork)){
+ return 2;
+ }
+
+ puts("Tibia Game-Server\n(c) by CIP Productions, 2003.\n");
+
+ InitAll();
+ atexit(ExitAll);
+
+ // TODO(fusion): The original binary does use exceptions but identifying
+ // try..catch blocks are not as straightforward as throw statements. I'll
+ // leave this one at the top level but we should come back to this problem
+ // once we identify all throw statements and how to roughly handle them.
+ try{
+ LaunchGame();
+ }catch(RESULT result){
+ error("main: Nicht abgefangene Exception %d.\n", result);
+ }catch(const char *str){
+ error("main: Nicht abgefangene Exception \"%s\".\n", str);
+ }catch(const std::exception &e){
+ error("main: Nicht abgefangene Exception %s.\n", e.what());
+ }catch(...){
+ error("main: Nicht abgefangene Exception unbekannten Typs.\n");
+ }
+
+ if(!Reboot){
+ print(1, "Beende Game-Server...\n");
+ }else{
+ UnlockGame();
+
+ char FileName[4096];
+ snprintf(FileName, sizeof(FileName), "%s/reboot-daily", BINPATH);
+ if(FileExists(FileName)){
+ ExitAll();
+ print(1, "Starte Game-Server neu...\n");
+ execv(FileName, argv);
+ }else{
+ print(1, "Reboot-Skript existiert nicht.\n");
+ }
+ }
+
return 0;
}
diff --git a/src/main.hh b/src/main.hh
index 0b0993c..287b59c 100644
--- a/src/main.hh
+++ b/src/main.hh
@@ -75,6 +75,64 @@ STATIC_ASSERT(sizeof(int) == 4);
# define ASSERT(expr) ((void)(expr))
#endif
+// TODO(fusion): We should re-implement the multi-process structure used by the
+// original code but only for reference. Making it compile on Windows shouldn't
+// be too difficult either. Overall this design is outdated and should be reviewed.
+// Nevertheless, we should focus on getting it working as intended, on the target
+// platform (which is Linux 32-bits) before attempting to refine it.
+STATIC_ASSERT(OS_LINUX);
+#include <sys/types.h>
+//
+
+// config.cc
+extern int Beat;
+
+// shm.cc
+void StartGame(void);
+void CloseGame(void);
+void EndGame(void);
+bool LoginAllowed(void);
+bool GameRunning(void);
+bool GameStarting(void);
+bool GameEnding(void);
+pid_t GetGameThreadPID(void);
+int GetPrintlogPosition(void);
+char *GetPrintlogLine(int Line);
+void IncrementObjectCounter(void);
+void DecrementObjectCounter(void);
+uint32 GetObjectCounter(void);
+void IncrementPlayersOnline(void);
+void DecrementPlayersOnline(void);
+int GetPlayersOnline(void);
+void IncrementNewbiesOnline(void);
+void DecrementNewbiesOnline(void);
+int GetNewbiesOnline(void);
+void SetRoundNr(uint32 RoundNr);
+uint32 GetRoundNr(void);
+void SetCommand(int Command, char *Text);
+int GetCommand(void);
+char *GetCommandBuffer(void);
+void InitSHM(bool Verbose);
+void ExitSHM(void);
+void InitSHMExtern(bool Verbose);
+void ExitSHMExtern(void);
+
+// time.cc
+extern uint32 RoundNr;
+extern uint32 ServerMilliseconds;
+void GetRealTime(int *Hour, int *Minute);
+void GetTime(int *Hour, int *Minute);
+void GetDate(int *Year, int *Cycle, int *Day);
+void GetAmbiente(int *Brightness, int *Color);
+uint32 GetRoundAtTime(int Hour, int Minute);
+uint32 GetRoundForNextMinute(void);
+
+// util.cc
+typedef void TErrorFunction(const char *Text);
+typedef void TPrintFunction(int Level, const char *Text);
+void SetErrorFunction(TErrorFunction *Function);
+void SetPrintFunction(TPrintFunction *Function);
void error(char *Text, ...) ATTR_PRINTF(1, 2);
+void print(int Level, char *Text, ...) ATTR_PRINTF(1, 2);
#endif //TIBIA_MAIN_HH_
diff --git a/src/map.hh b/src/map.hh
new file mode 100644
index 0000000..7bef02b
--- /dev/null
+++ b/src/map.hh
@@ -0,0 +1,26 @@
+#ifndef TIBIA_MAP_HH_
+#define TIBIA_MAP_HH_ 1
+
+#include "main.hh"
+
+// TODO(fusion): I'm not sure whether to put these.
+
+struct Object {
+ uint32 ObjectID;
+};
+
+constexpr Object NONE = {};
+
+struct ObjectType {
+ int TypeID;
+};
+
+struct TObjectType {
+ char *Name;
+ char *Description;
+ uint8 Flags[9];
+ uint32 Attributes[62];
+ int AttributeOffsets[18];
+};
+
+#endif //TIBIA_MAP_HH_ \ No newline at end of file
diff --git a/src/monster.hh b/src/monster.hh
new file mode 100644
index 0000000..7e18f48
--- /dev/null
+++ b/src/monster.hh
@@ -0,0 +1,88 @@
+#ifndef TIBIA_MONSTER_HH_
+#define TIBIA_MONSTER_HH_ 1
+
+#include "main.hh"
+#include "creature.hh"
+#include "containers.hh"
+#include "enums.hh"
+
+struct TSkillData {
+ int Nr;
+ int Actual;
+ int Minimum;
+ int Maximum;
+ int NextLevel;
+ int FactorPercent;
+ int AddLevel;
+};
+
+struct TItemData {
+ ObjectType Type;
+ int Maximum;
+ int Probability;
+};
+
+struct TSpellData {
+ SpellShapeType Shape;
+ int ShapeParam1;
+ int ShapeParam2;
+ int ShapeParam3;
+ int ShapeParam4;
+ SpellImpactType Impact;
+ int ImpactParam1;
+ int ImpactParam2;
+ int ImpactParam3;
+ int ImpactParam4;
+ int Delay;
+};
+
+struct TRaceData {
+ char Name[30];
+ char Article[3];
+ TOutfit Outfit;
+ ObjectType MaleCorpse;
+ ObjectType FemaleCorpse;
+ BloodType Blood;
+ int ExperiencePoints;
+ int FleeThreshold;
+ int Attack;
+ int Defend;
+ int Armor;
+ int Poison;
+ int SummonCost;
+ int LoseTarget;
+ int Strategy[4];
+ bool KickBoxes;
+ bool KickCreatures;
+ bool SeeInvisible;
+ bool Unpushable;
+ bool DistanceFighting;
+ bool NoSummon;
+ bool NoIllusion;
+ bool NoConvince;
+ bool NoBurning;
+ bool NoPoison;
+ bool NoEnergy;
+ bool NoHit;
+ bool NoLifeDrain;
+ bool NoParalyze;
+ int Skills;
+ vector<TSkillData> Skill;
+ int Talks;
+ vector<uint32> Talk; // POINTER? Probably a reference from `AddDynamicString`?
+ int Items;
+ vector<TItemData> Item;
+ int Spells;
+ vector<TSpellData> Spell;
+};
+
+#if 0
+// TODO(fusion):
+struct TMonster: TNonplayer {
+ int Home;
+ uint32 Master;
+ uint32 Target;
+};
+#endif
+
+#endif //TIBIA_MONSTER_HH_
diff --git a/src/player.hh b/src/player.hh
index b6009a1..0a3f583 100644
--- a/src/player.hh
+++ b/src/player.hh
@@ -3,6 +3,7 @@
#include "main.hh"
#include "creature.hh"
+#include "containers.hh"
struct TPlayerData {
uint32 CharacterID;
@@ -43,7 +44,7 @@ struct TPlayerData {
int InventorySize;
uint8 *Depot[9];
int DepotSize[9];
- ulong AccountID;
+ uint32 AccountID;
int Sex;
char Name[30];
uint8 Rights[12];
@@ -76,7 +77,7 @@ struct TPlayer: TCreature {
// DATA
// =========================================================================
//TCreature super_TCreature; // IMPLICIT
- ulong AccountID;
+ uint32 AccountID;
char Guild[31];
char Rank[31];
char Title[31];
@@ -98,10 +99,10 @@ struct TPlayer: TCreature {
uint8 SpellList[256];
int QuestValues[500];
Object OpenContainer[16];
- vector<long_unsigned_int> AttackedPlayers;
+ vector<uint32> AttackedPlayers;
int NumberOfAttackedPlayers;
bool Aggressor;
- vector<long_unsigned_int> FormerAttackedPlayers;
+ vector<uint32> FormerAttackedPlayers;
int NumberOfFormerAttackedPlayers;
bool FormerAggressor;
uint32 FormerLogoutRound;
diff --git a/src/shm.cc b/src/shm.cc
new file mode 100644
index 0000000..5cd4a52
--- /dev/null
+++ b/src/shm.cc
@@ -0,0 +1,385 @@
+#include "main.hh"
+
+// NOTE(fusion): This looks like an interface to external tools. Looking at the
+// `bin` directory this program was in, there are other programs that probably
+// use this interface to control certain aspects of the server. My previous
+// assumption that each connection was dispatched into its own process may not
+// be correct after all.
+
+struct TSharedMemory {
+ int Command;
+ char CommandBuffer[256];
+ uint32 RoundNr;
+ uint32 ObjectCounter;
+ uint32 Errors;
+ int PlayersOnline;
+ int NewbiesOnline;
+ int PrintBufferPosition;
+ char PrintBuffer[200][128];
+ GAMESTATE GameState;
+ pid_t GameThreadPID;
+};
+
+static TSharedMemory *SHM = NULL;
+static bool IsGameServer = false;
+static bool VerboseOutput = false;
+
+void StartGame(void){
+ if(SHM != NULL){
+ if(SHM->GameState == GAME_STARTING){
+ SHM->GameState = GAME_RUNNING;
+ }
+ }else{
+ error("StartGame: SharedMemory existiert nicht.\n");
+ }
+}
+
+void CloseGame(void){
+ if(SHM != NULL){
+ if(SHM->GameState == GAME_RUNNING){
+ SHM->GameState = GAME_CLOSING;
+ }
+ }else{
+ error("CloseGame: SharedMemory existiert nicht.\n");
+ }
+}
+
+void EndGame(void){
+ if(SHM != NULL){
+ SHM->GameState = GAME_ENDING;
+ }else{
+ error("EndGame: SharedMemory existiert nicht.\n");
+ }
+}
+
+bool LoginAllowed(void){
+ bool Result = false;
+ if(SHM != NULL){
+ Result = SHM->GameState == GAME_RUNNING;
+ }else{
+ error("IsLoginAllowed: SharedMemory existiert nicht.\n");
+ }
+ return Result;
+}
+
+bool GameRunning(void){
+ bool Result = false;
+ if(SHM != NULL){
+ Result = SHM->GameState == GAME_STARTING
+ || SHM->GameState == GAME_RUNNING
+ || SHM->GameState == GAME_CLOSING;
+ }else{
+ error("GameRunning: SharedMemory existiert nicht.\n");
+ }
+ return Result;
+}
+
+bool GameStarting(void){
+ bool Result = false;
+ if(SHM != NULL){
+ Result = SHM->GameState == GAME_STARTING;
+ }else{
+ error("GameStarting: SharedMemory existiert nicht.\n");
+ }
+ return Result;
+}
+
+bool GameEnding(void){
+ bool Result = false;
+ if(SHM != NULL){
+ Result = SHM->GameState == GAME_CLOSING
+ || SHM->GameState == GAME_ENDING;
+ }else{
+ error("GameEnding: SharedMemory existiert nicht.\n");
+ }
+ return Result;
+}
+
+pid_t GetGameThreadPID(void){
+ pid_t Pid = 0;
+ if(SHM != NULL){
+ Pid = SHM->GameThreadPID;
+ }
+ return Pid;
+}
+
+static void ErrorHandler(char *Text){
+ if(VerboseOutput){
+ printf("%s", Text);
+ }
+
+ if(SHM != NULL){
+ SHM->Errors += 1;
+ if(SHM->Errors <= 0x8000){
+ Log("error", Text);
+ if(SHM->Errors == 0x8000){
+ Log("error", "Zu viele Fehler. Keine weitere Protokollierung.\n");
+ }
+ }
+ }
+}
+
+static void PrintHandler(int Level, char *Text){
+ static Semaphore LogfileMutex(1);
+
+ if(Level > DebugLevel){
+ return;
+ }
+
+ if(VerboseOutput){
+ printf("%s", Text);
+ }
+
+ if(SHM != NULL){
+ // TODO(fusion): Does it even make sense to have this Semaphore here?
+ // It controls writes to the print buffer but reads outside this scope
+ // may be partial. But then, it doesn't seem like it is read anywhere
+ // else. Perhaps some external monitor tool, in which case do we even
+ // print from multiple threads?
+ LogfileMutex.down();
+ int Line = SHM->PrintBufferPosition;
+ char *Buffer = SHM->PrintBuffer[Line];
+ // TODO(fusion): Ughh...
+ strncpy(Buffer, Text, sizeof(SHM->PrintBuffer[0]) - 1);
+ Buffer[sizeof(SHM->PrintBuffer[0]) - 2] = 0;
+ if(Buffer[0] != 0){
+ usize TextLen = strlen(Buffer);
+ if(Buffer[TextLen - 1] != '\n'){
+ strcat(Buffer, "\n");
+ }
+ }
+ SHM->PrintBufferPosition = (Line + 1) % NARRAY(SHM->PrintBuffer);
+ LogfileMutex.up();
+ }
+}
+
+int GetPrintlogPosition(void){
+ int Result = 0;
+ if(SHM != NULL){
+ Result = SHM->PrintBufferPosition;
+ }
+ return Result;
+}
+
+char *GetPrintlogLine(int Line){
+ char *Result = NULL;
+ if(SHM != NULL && Line >= 0 && Line < NARRAY(SHM->PrintBuffer)){
+ Result = SHM->PrintBuffer[Line];
+ }
+ return Result;
+}
+
+void IncrementObjectCounter(void){
+ if(SHM != NULL){
+ SHM->ObjectCounter += 1;
+ }
+}
+
+void DecrementObjectCounter(void){
+ if(SHM != NULL){
+ SHM->ObjectCounter -= 1;
+ }
+}
+
+uint32 GetObjectCounter(void){
+ uint32 ObjectCounter = 0;
+ if(SHM != NULL){
+ ObjectCounter = SHM->ObjectCounter;
+ }
+ return ObjectCounter;
+}
+
+void IncrementPlayersOnline(void){
+ if(SHM != NULL){
+ SHM->PlayersOnline += 1;
+ }
+}
+
+void DecrementPlayersOnline(void){
+ if(SHM != NULL){
+ SHM->PlayersOnline -= 1;
+ }
+}
+
+int GetPlayersOnline(void){
+ int PlayersOnline = 0;
+ if(SHM != NULL){
+ PlayersOnline = SHM->PlayersOnline;
+ }
+ return PlayersOnline;
+}
+
+void IncrementNewbiesOnline(void){
+ if(SHM != NULL){
+ SHM->NewbiesOnline += 1;
+ }
+}
+
+void DecrementNewbiesOnline(void){
+ if(SHM != NULL){
+ SHM->NewbiesOnline -= 1;
+ }
+}
+
+int GetNewbiesOnline(void){
+ int NewbiesOnline = 0;
+ if(SHM != NULL){
+ NewbiesOnline = SHM->NewbiesOnline;
+ }
+ return NewbiesOnline;
+}
+
+void SetRoundNr(uint32 RoundNr){
+ if(SHM != NULL){
+ SHM->RoundNr = RoundNr;
+ }
+}
+
+uint32 GetRoundNr(void){
+ uint32 RoundNr = 0;
+ if(SHM != NULL){
+ RoundNr = SHM->RoundNr;
+ }
+ return RoundNr;
+}
+
+void SetCommand(int Command, char *Text){
+ if(SHM != NULL){
+ SHM->Command = Command;
+ if(Text == NULL){
+ SHM->CommandBuffer[0] = 0;
+ }else{
+ strncpy(SHM->CommandBuffer, sizeof(SHM->CommandBuffer), Text);
+ SHM->CommandBuffer[sizeof(SHM->CommandBuffer) - 1] = 0;
+ }
+ }
+}
+
+int GetCommand(void){
+ int Command = 0;
+ if(SHM != NULL){
+ Command = SHM->Command;
+ }
+ return Command;
+}
+
+char *GetCommandBuffer(void){
+ char *Buffer = NULL;
+ if(SHM != NULL && SHM->Command != 0){
+ Buffer = SHM->CommandBuffer;
+ }
+ return Buffer;
+}
+
+static bool DeleteSHM(void){
+ int SHMID = shmget(SHMKey, 0, 0);
+ if(SHMID == -1){
+ if(VerboseOutput){
+ puts("DeleteSHM: SharedMemory existiert nicht.");
+ }
+ return true;
+ }
+
+ if(shmctl(SHMID, IPC_RMID, NULL) == -1){
+ if(VerboseOutput){
+ // TODO(fusion): Include `errno` in the error message?
+ puts("DeleteSHM: Kann SharedMemory nicht löschen.");
+ }
+ return false;
+ }
+
+ return true;
+}
+
+static void CreateSHM(void){
+ bool Deleted = false;
+ while(true){
+ int SHMID = shmget(SHMKey, sizeof(TSharedMemory), IPC_CREAT | IPC_EXCL | 0777);
+ if(SHMID != -1){
+ return;
+ }
+
+ if(errno != EEXIST || Deleted){
+ if(VerboseOutput){
+ printf("CreateSHM: Kann SharedMemory nicht anlegen (Fehler %d).\n", errno);
+ }
+ throw "Cannot create SharedMemory";
+ }
+
+ if(!DeleteSHM()){
+ throw "Cannot delete SharedMemory";
+ }
+
+ Deleted = true;
+ }
+}
+
+static void AttachSHM(void){
+ int SHMID = shmget(SHMKey, sizeof(TSharedMemory), 0);
+ if(SHMID == -1){
+ if(VerboseOutput){
+ // TODO(fusion): Include `errno` in the error message?
+ puts("AttachSHM: Kann SharedMemory nicht fassen.");
+ }
+ SHM = NULL;
+ throw "Cannot get SharedMemory";
+ }
+
+ SHM = (TSharedMemory*)shmat(SHMID, NULL, 0);
+ if(SHM == (void*)-1){
+ if(VerboseOutput){
+ puts("AttachSHM: Kann SharedMemory nicht anbinden.");
+ }
+
+ SHM = NULL;
+ throw "Cannot attach SharedMemory";
+ }
+}
+
+static void DetachSHM(void){
+ if(SHM != NULL){
+ if(shmdt(SHM) == -1 && VerboseOutput){
+ puts("DetachSHM: Kann SharedMemory nicht löschen.");
+ }
+ SHM = NULL;
+ }
+}
+
+void InitSHM(bool Verbose){
+ IsGameServer = true;
+ VerboseOutput = Verbose;
+
+ CreateSHM();
+ AttachSHM();
+ SetErrorFunction(ErrorHandler);
+ SetPrintFunction(PrintHandler);
+
+ // NOTE(fusion): `CreateSHM` ensures a new shared memory segment is created
+ // and it should be always zero initialized as per the manual. Nevertheless
+ // the decompiled version was also clearing SHM, probably just in case.
+ memset(SHM, 0, sizeof(TSharedMemory));
+
+ strncpy(SHM->PrintBuffer[0], sizeof(SHM->PrintBuffer[0]),
+ "SHM initialized. System printing is working!\n");
+ SHM->PrintBuffer[0][sizeof(SHM->PrintBuffer[0]) - 1] = 0;
+
+ SHM->PrintBufferPosition = 1;
+ SHM->GameState = GAME_STARTING;
+ SHM->GameThreadPID = getpid();
+}
+
+void ExitSHM(void){
+ SetErrorFunction(NULL);
+ SetPrintFunction(NULL);
+ DetachSHM();
+ DeleteSHM();
+}
+
+void InitSHMExtern(bool Verbose){
+ VerboseOutput = Verbose;
+ AttachSHM();
+}
+
+void ExitSHMExtern(void){
+ DetachSHM();
+}
diff --git a/src/skill.cc b/src/skill.cc
index 629d935..6ca04ef 100644
--- a/src/skill.cc
+++ b/src/skill.cc
@@ -796,7 +796,7 @@ void TSkillSoulpoints::Event(int Range){
// TODO(fusion): Shouldn't this be the same as `Master->Skills[SKILL_SOUL]`?
// Not sure what's going on here.
if(!Master->IsDead){
- Master->Skills[SKILL_SOUL]->Set(Other->Act + 1);
+ Master->Skills[SKILL_SOUL]->Change(1);
}
}
@@ -1157,7 +1157,7 @@ bool TSkillBase::NewSkill(uint16 SkillNo, TCreature *Creature){
}
bool TSkillBase::SetSkills(int Race){
- if(Race < 0 || Race >= 512){
+ if(Race < 0 || Race >= NARRAY(RaceData)){
error("TSkillBase::SetSkills: Ungültige Rassennummer %d.\n", Race);
return false;
}
@@ -1237,7 +1237,7 @@ void TSkillBase::DelTimer(uint16 SkNr){
Skill->DelTimer();
int End = this->FirstFreeTimer;
- for(int Index = 0; Index < End; i += 1){
+ for(int Index = 0; Index < End; Index += 1){
if(Skill == this->TimerList[Index]){
// NOTE(fusion): A little swap and pop action.
End -= 1;
diff --git a/src/skill.hh b/src/skill.hh
index 9b54649..c3beff6 100644
--- a/src/skill.hh
+++ b/src/skill.hh
@@ -64,6 +64,7 @@ struct TSkill{
};
struct TSkillLevel: TSkill {
+ TSkillLevel(int SkNr, TCreature *Master) : TSkill(SkNr, Master) {}
void Increase(int Amount) override;
void Decrease(int Amount) override;
int GetExpForLevel(int Level) override;
@@ -71,6 +72,7 @@ struct TSkillLevel: TSkill {
};
struct TSkillProbe: TSkill {
+ TSkillProbe(int SkNr, TCreature *Master) : TSkill(SkNr, Master) {}
void Increase(int Amount) override;
void Decrease(int Amount) override;
int GetExpForLevel(int Level) override;
@@ -83,47 +85,57 @@ struct TSkillProbe: TSkill {
};
struct TSkillAdd: TSkill {
+ TSkillAdd(int SkNr, TCreature *Master) : TSkill(SkNr, Master) {}
void Advance(int Range) override;
};
struct TSkillHitpoints: TSkillAdd {
+ TSkillHitpoints(int SkNr, TCreature *Master) : TSkillAdd(SkNr, Master) {}
void Set(int Value) override;
};
struct TSkillMana: TSkillAdd {
+ TSkillMana(int SkNr, TCreature *Master) : TSkillAdd(SkNr, Master) {}
void Set(int Value) override;
};
struct TSkillGoStrength: TSkillAdd {
+ TSkillGoStrength(int SkNr, TCreature *Master) : TSkillAdd(SkNr, Master) {}
bool SetTimer(int Cycle, int Count, int MaxCount, int AdditionalValue) override;
void Event(int Range) override;
};
struct TSkillCarryStrength: TSkillAdd {
+ TSkillCarryStrength(int SkNr, TCreature *Master) : TSkillAdd(SkNr, Master) {}
void Set(int Value) override;
};
struct TSkillSoulpoints: TSkillAdd {
+ TSkillSoulpoints(int SkNr, TCreature *Master) : TSkillAdd(SkNr, Master) {}
void Set(int Value) override;
int TimerValue(void) override;
void Event(int Range) override;
};
struct TSkillFed: TSkill {
+ TSkillFed(int SkNr, TCreature *Master) : TSkill(SkNr, Master) {}
void Event(int Range) override;
};
struct TSkillLight: TSkill {
+ TSkillLight(int SkNr, TCreature *Master) : TSkill(SkNr, Master) {}
bool SetTimer(int Cycle, int Count, int MaxCount, int AdditionalValue) override;
void Event(int Range) override;
};
struct TSkillIllusion: TSkill {
+ TSkillIllusion(int SkNr, TCreature *Master) : TSkill(SkNr, Master) {}
bool SetTimer(int Cycle, int Count, int MaxCount, int AdditionalValue) override;
void Event(int Range) override;
};
struct TSkillPoison: TSkill {
+ TSkillPoison(int SkNr, TCreature *Master) : TSkill(SkNr, Master) {}
bool Process(void) override;
bool SetTimer(int Cycle, int Count, int MaxCount, int AdditionalValue) override;
void Event(int Range) override;
@@ -131,10 +143,12 @@ struct TSkillPoison: TSkill {
};
struct TSkillBurning: TSkill {
+ TSkillBurning(int SkNr, TCreature *Master) : TSkill(SkNr, Master) {}
void Event(int Range) override;
};
struct TSkillEnergy: TSkill {
+ TSkillEnergy(int SkNr, TCreature *Master) : TSkill(SkNr, Master) {}
void Event(int Range) override;
};
diff --git a/src/time.cc b/src/time.cc
new file mode 100644
index 0000000..89325ba
--- /dev/null
+++ b/src/time.cc
@@ -0,0 +1,96 @@
+#include "main.hh"
+
+// IMPORTANT(fusion): `RoundNr` is just the number of seconds since startup which
+// is why `GetRoundAtTime` and `GetRoundForNextMinute` straight up uses it as
+// seconds. It is incremented every 1 second inside `AdvanceGame`.
+uint32 RoundNr = 0;
+
+uint32 ServerMilliseconds = 0;
+
+// NOTE(fusion): This isn't strictly required because each server process is
+// single threaded and don't share static memory, which is what the result of
+// the regular `localtime` function uses.
+static struct tm GetLocalTimeTM(time_t timer){
+ struct tm result;
+#if COMPILER_MSVC
+ localtime_s(&result, &timer);
+#else
+ localtime_r(&timer, &result);
+#endif
+ return result;
+}
+
+void GetRealTime(int *Hour, int *Minute){
+ struct tm LocalTime = GetLocalTimeTM(time(NULL));
+ *Hour = LocalTime.tm_hour;
+ *Minute = LocalTime.tm_min;
+}
+
+void GetTime(int *Hour, int *Minute){
+ // NOTE(fusion): This maps each real time hour to a game time day.
+ struct tm LocalTime = GetLocalTimeTM(time(NULL));
+ int Time = LocalTime.tm_sec + LocalTime.tm_min * 60;
+ *Hour = (Time / 150);
+ *Minute = (Time % 150) * 2 / 5;
+}
+
+void GetDate(int *Year, int *Cycle, int *Day){
+ // NOTE(fusion): This maps each real time week to a game time year.
+ time_t RealTime = time(NULL);
+ struct tm LocalTime = GetLocalTimeTM(RealTime);
+ *Year = ((T / 86400) + 4) / 7
+ *Cycle = LocalTime.tm_wday;
+ *Day = LocalTime.tm_hour;
+}
+
+void GetAmbiente(int *Brightness, int *Color){
+ int Hour, Minute;
+ GetTime(&Hour, &Minute);
+
+ int Time = Minute + Hour * 60;
+ if(Time < 60){
+ *Brightness = 0x33;
+ *Color = 0xD7;
+ }else if(Time < 120){
+ *Brightness = 0x66;
+ *Color = 0xD7;
+ }else if(Time < 180){
+ *Brightness = 0x99;
+ *Color = 0xAD;
+ }else if(Time < 240){
+ *Brightness = 0xCC;
+ *Color = 0xAD;
+ }else if(Time <= 1200){
+ *Brightness = 0xFF;
+ *Color = 0xD7;
+ }else if(Time <= 1260){
+ *Brightness = 0xCC;
+ *Color = 0xD0;
+ }else if(Time <= 1320){
+ *Brightness = 0x99;
+ *Color = 0xD0;
+ }else if(Time <= 1380){
+ *Brightness = 0x66;
+ *Color = 0xD7;
+ }else{
+ *Brightness = 0x33;
+ *Color = 0xD7;
+ }
+}
+
+uint32 GetRoundAtTime(int Hour, int Minute){
+ struct tm LocalTime = GetLocalTimeTM(RealTime);
+ int SecondsToTime = (Hour - LocalTime.tm_hour) * 3600
+ + (Minute - LocalTime.tm_min) * 60
+ + (0 - LocalTime.tm_sec);
+ if(SecondsToTime < 0){
+ SecondsToTime += 86400;
+ }
+ return SecondsToTime + RoundNr;
+}
+
+uint32 GetRoundForNextMinute(void){
+ struct tm LocalTime = GetLocalTimeTM(RealTime);
+ int SecondsToNextMinute = 60 - LocalTime.tm_sec;
+ return SecondsToNextMinute + RoundNr + 30;
+}
diff --git a/src/util.cc b/src/util.cc
new file mode 100644
index 0000000..f2ebc48
--- /dev/null
+++ b/src/util.cc
@@ -0,0 +1,42 @@
+#include "util.hh"
+
+static void (*ErrorFunction)(const char *Text) = NULL;
+static void (*PrintFunction)(int Level, const char *Text) = NULL;
+
+void SetErrorFunction(TErrorFunction *Function){
+ ErrorFunction = Function;
+}
+
+void SetPrintFunction(TPrintFunction *Function){
+ PrintFunction = Function;
+}
+
+void error(char *Text, ...){
+ char s[1024];
+
+ va_list ap;
+ va_start(ap, Text);
+ vsnprintf(s, sizeof(s), Text, ap);
+ va_end(ap);
+
+ if(ErrorFunction){
+ ErrorFunction(s);
+ }else{
+ printf("%s", s);
+ }
+}
+
+void print(int Level, char *Text, ...){
+ char s[1024];
+
+ va_list ap;
+ va_start(ap, Text);
+ vsnprintf(s, sizeof(s), Text, ap);
+ va_end(ap);
+
+ if(PrintFunction){
+ PrintFunction(Level, s);
+ }else{
+ printf("%s", s);
+ }
+}