diff options
| author | fusion32 <marcopuzziello@gmail.com> | 2025-05-20 16:41:03 -0300 |
|---|---|---|
| committer | fusion32 <marcopuzziello@gmail.com> | 2025-05-20 16:41:03 -0300 |
| commit | 42be37f4ad99fc8580415fed89939e305d56193e (patch) | |
| tree | 41303aace3c214f925a43fec6a857f313196e38d | |
| parent | 7fe30185df21617cf44100f89db462cd4501050e (diff) | |
| download | game-42be37f4ad99fc8580415fed89939e305d56193e.tar.gz game-42be37f4ad99fc8580415fed89939e305d56193e.zip | |
implement `main.cc`, `shm.cc`, and `time.cc` + overall tweeks
| -rw-r--r-- | TODO.md | 1 | ||||
| -rw-r--r-- | reference/enums.hh | 378 | ||||
| -rw-r--r-- | reference/game.c | 1747 | ||||
| -rw-r--r-- | reference/types.hh | 377 | ||||
| -rw-r--r-- | src/config.cc | 6 | ||||
| -rw-r--r-- | src/connection.hh | 56 | ||||
| -rw-r--r-- | src/containers.hh | 338 | ||||
| -rw-r--r-- | src/containers/matrix.hh | 132 | ||||
| -rw-r--r-- | src/containers/priority_queue.hh | 94 | ||||
| -rw-r--r-- | src/containers/vector.hh | 123 | ||||
| -rw-r--r-- | src/creature.cc | 2 | ||||
| -rw-r--r-- | src/creature.hh | 61 | ||||
| -rw-r--r-- | src/enums.hh | 198 | ||||
| -rw-r--r-- | src/main.cc | 569 | ||||
| -rw-r--r-- | src/main.hh | 58 | ||||
| -rw-r--r-- | src/map.hh | 26 | ||||
| -rw-r--r-- | src/monster.hh | 88 | ||||
| -rw-r--r-- | src/player.hh | 9 | ||||
| -rw-r--r-- | src/shm.cc | 385 | ||||
| -rw-r--r-- | src/skill.cc | 6 | ||||
| -rw-r--r-- | src/skill.hh | 14 | ||||
| -rw-r--r-- | src/time.cc | 96 | ||||
| -rw-r--r-- | src/util.cc | 42 |
23 files changed, 1925 insertions, 2881 deletions
@@ -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); + } +} |
