aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorfusion32 <marcopuzziello@gmail.com>2025-06-07 23:52:37 -0300
committerfusion32 <marcopuzziello@gmail.com>2025-06-07 23:52:37 -0300
commit0590a5f1b3e0ffe295d7894a16b9d8aff3fae586 (patch)
tree6a340a2d415185f3634c2206e00e630bea998474
parent3d7fcfc4a6a1fc7016145b39596775bcd32be5c1 (diff)
downloadgame-0590a5f1b3e0ffe295d7894a16b9d8aff3fae586.tar.gz
game-0590a5f1b3e0ffe295d7894a16b9d8aff3fae586.zip
implement monster raids
-rw-r--r--TODO.md6
-rw-r--r--reference/game.c974
-rw-r--r--reference/types.hh15
-rw-r--r--src/containers.hh22
-rw-r--r--src/cr.hh32
-rw-r--r--src/crmain.cc420
-rw-r--r--src/objects.cc2
-rw-r--r--src/stubs.hh4
8 files changed, 463 insertions, 1012 deletions
diff --git a/TODO.md b/TODO.md
index 12dc857..50b2e97 100644
--- a/TODO.md
+++ b/TODO.md
@@ -1,11 +1,5 @@
## TODO NEXT
- CRACT.CC
-- CRMAIN.CC
- - TCreature::CreatureMoveStimulus
- - FINDCREATURES
- - KILL STATS
- - RACE
- - RAIDS
- CRPLAYER.CC, CRNONPL.CC
- HOUSES.CC
- INFO.CC
diff --git a/reference/game.c b/reference/game.c
index f0a4f51..0a5a2e5 100644
--- a/reference/game.c
+++ b/reference/game.c
@@ -29623,980 +29623,6 @@ void __static_initialization_and_destruction_0(int __initialize_p,int __priority
return;
}
-// DWARF original prototype: void TAttackWave(TAttackWave * this)
-
-void __thiscall TAttackWave::TAttackWave(TAttackWave *this)
-
-{
- vector<TItemData>::vector(&this->ExtraItem,1,5,5);
- this->x = 0;
- this->y = 0;
- this->z = 0;
- this->Spread = 0;
- this->Race = -1;
- this->MinCount = 0;
- this->MaxCount = 0;
- this->Radius = 0x7fffffff;
- this->Lifetime = 0;
- this->Message = 0;
- this->ExtraItems = 0;
- return;
-}
-
-
-
-// DWARF original prototype: void TAttackWave(TAttackWave * this)
-
-void __thiscall TAttackWave::TAttackWave(TAttackWave *this)
-
-{
- vector<TItemData>::vector(&this->ExtraItem,1,5,5);
- this->x = 0;
- this->y = 0;
- this->z = 0;
- this->Spread = 0;
- this->Race = -1;
- this->MinCount = 0;
- this->MaxCount = 0;
- this->Radius = 0x7fffffff;
- this->Lifetime = 0;
- this->Message = 0;
- this->ExtraItems = 0;
- return;
-}
-
-
-
-// DWARF original prototype: void ~TAttackWave(TAttackWave * this, int __in_chrg)
-
-void __thiscall TAttackWave::~TAttackWave(TAttackWave *this,int __in_chrg)
-
-{
- TItemData *pTVar1;
-
- if (this->Message != 0) {
- DeleteDynamicString(this->Message);
- }
- pTVar1 = (this->ExtraItem).entry;
- if (pTVar1 == (TItemData *)0x0) {
- return;
- }
- operator_delete__(pTVar1);
- return;
-}
-
-
-
-// DWARF original prototype: void ~TAttackWave(TAttackWave * this, int __in_chrg)
-
-void __thiscall TAttackWave::~TAttackWave(TAttackWave *this,int __in_chrg)
-
-{
- TItemData *pTVar1;
-
- if (this->Message != 0) {
- DeleteDynamicString(this->Message);
- }
- pTVar1 = (this->ExtraItem).entry;
- if (pTVar1 == (TItemData *)0x0) {
- return;
- }
- operator_delete__(pTVar1);
- return;
-}
-
-
-
-void LoadMonsterRaid(char *FileName,int Start,bool *Type,int *Date,int *Interval,int *Duration)
-
-{
- TReadScriptFile *pTVar1;
- bool bVar2;
- char cVar3;
- char *pcVar4;
- char *pcVar5;
- TAttackWave *this;
- TItemData *this_00;
- ulong uVar6;
- undefined4 *puVar7;
- int End;
- int iVar8;
- int iVar9;
- char *pcVar10;
- undefined1 uVar11;
- char *in_stack_ffffbfac;
- int Delay;
- TAttackWave *AttackWave;
- ObjectType local_402c [4];
- char local_401c [4];
- char Ident [30];
- TReadScriptFile Script;
-
- if (FileName == (char *)0x0) {
- pcVar4 = "LoadMonsterRaid: Dateiname ist NULL.\n";
-LAB_080a45c3:
- // try { // try from 080a45c3 to 080a45f1 has its CatchHandler @ 080a4636
- error(pcVar4);
- puVar7 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar7 = "cannot load monster raid";
- // WARNING: Subroutine does not return
- __cxa_throw(puVar7,char_const*::typeinfo,0);
- }
- uVar11 = Start == 0;
- if (Start < 0) {
- if ((((Type == (bool *)0x0) || (Date == (int *)0x0)) || (Interval == (int *)0x0)) ||
- (uVar11 = Duration == (int *)0x0, (bool)uVar11)) {
- pcVar4 = &DAT_08102420;
- goto LAB_080a45c3;
- }
- *Date = 0;
- *Interval = 0;
- *Duration = 0;
- }
- else {
- in_stack_ffffbfac = FileName;
- // try { // try from 080a3d82 to 080a3d94 has its CatchHandler @ 080a4636
- print();
- }
- TReadScriptFile::TReadScriptFile((TReadScriptFile *)(Ident + 0x1c));
- pTVar1 = (TReadScriptFile *)(Ident + 0x1c);
- // try { // try from 080a3da2 to 080a3ebd has its CatchHandler @ 080a4630
- TReadScriptFile::open(pTVar1,FileName,(int)in_stack_ffffbfac);
- TReadScriptFile::nextToken(pTVar1);
- pcVar4 = TReadScriptFile::getIdentifier(pTVar1);
- iVar8 = 0xc;
- pcVar5 = "description";
- do {
- if (iVar8 == 0) break;
- iVar8 = iVar8 + -1;
- uVar11 = *pcVar4 == *pcVar5;
- pcVar4 = pcVar4 + 1;
- pcVar5 = pcVar5 + 1;
- } while ((bool)uVar11);
- if ((bool)uVar11) {
- TReadScriptFile::readSymbol((TReadScriptFile *)(Ident + 0x1c),'=');
- TReadScriptFile::readString((TReadScriptFile *)(Ident + 0x1c));
- TReadScriptFile::nextToken((TReadScriptFile *)(Ident + 0x1c));
- }
- pcVar4 = TReadScriptFile::getIdentifier((TReadScriptFile *)(Ident + 0x1c));
- iVar8 = 5;
- pcVar5 = "type";
- do {
- if (iVar8 == 0) break;
- iVar8 = iVar8 + -1;
- uVar11 = *pcVar4 == *pcVar5;
- pcVar4 = pcVar4 + 1;
- pcVar5 = pcVar5 + 1;
- } while ((bool)uVar11);
- if (!(bool)uVar11) {
- TReadScriptFile::error((TReadScriptFile *)(Ident + 0x1c),"type expected");
- }
- TReadScriptFile::readSymbol((TReadScriptFile *)(Ident + 0x1c),'=');
- TReadScriptFile::readIdentifier((TReadScriptFile *)(Ident + 0x1c));
- uVar11 = Start == 0;
- if (Start < 0) {
- pcVar4 = TReadScriptFile::getIdentifier((TReadScriptFile *)(Ident + 0x1c));
- iVar8 = 8;
- pcVar5 = "bigraid";
- do {
- if (iVar8 == 0) break;
- iVar8 = iVar8 + -1;
- uVar11 = *pcVar4 == *pcVar5;
- pcVar4 = pcVar4 + 1;
- pcVar5 = pcVar5 + 1;
- } while ((bool)uVar11);
- *Type = (bool)uVar11;
- }
- TReadScriptFile::readIdentifier((TReadScriptFile *)(Ident + 0x1c));
- pcVar4 = TReadScriptFile::getIdentifier((TReadScriptFile *)(Ident + 0x1c));
- iVar8 = 5;
- pcVar5 = "date";
- do {
- if (iVar8 == 0) break;
- iVar8 = iVar8 + -1;
- uVar11 = *pcVar4 == *pcVar5;
- pcVar4 = pcVar4 + 1;
- pcVar5 = pcVar5 + 1;
- } while ((bool)uVar11);
- if ((bool)uVar11) {
- pcVar4 = (char *)0x3d;
- TReadScriptFile::readSymbol((TReadScriptFile *)(Ident + 0x1c),'=');
- TReadScriptFile::readNumber((TReadScriptFile *)(Ident + 0x1c));
- uVar11 = Start == 0;
- if (-1 < Start) goto LAB_080a3e84;
- iVar8 = TReadScriptFile::getNumber((TReadScriptFile *)(Ident + 0x1c));
- }
- else {
- pcVar4 = TReadScriptFile::getIdentifier((TReadScriptFile *)(Ident + 0x1c));
- iVar8 = 9;
- pcVar5 = "interval";
- do {
- if (iVar8 == 0) break;
- iVar8 = iVar8 + -1;
- uVar11 = *pcVar4 == *pcVar5;
- pcVar4 = pcVar4 + 1;
- pcVar5 = pcVar5 + 1;
- } while ((bool)uVar11);
- if (!(bool)uVar11) {
- pcVar4 = "date or interval expected";
- TReadScriptFile::error((TReadScriptFile *)(Ident + 0x1c),"date or interval expected");
- goto LAB_080a3e84;
- }
- pcVar4 = (char *)0x3d;
- TReadScriptFile::readSymbol((TReadScriptFile *)(Ident + 0x1c),'=');
- TReadScriptFile::readNumber((TReadScriptFile *)(Ident + 0x1c));
- uVar11 = Start == 0;
- if (-1 < Start) goto LAB_080a3e84;
- iVar8 = TReadScriptFile::getNumber((TReadScriptFile *)(Ident + 0x1c));
- Date = Interval;
- }
- *Date = iVar8;
-LAB_080a3e84:
- pcVar5 = TReadScriptFile::readIdentifier((TReadScriptFile *)(Ident + 0x1c));
- iVar8 = 6;
- pcVar10 = "delay";
- do {
- if (iVar8 == 0) break;
- iVar8 = iVar8 + -1;
- uVar11 = *pcVar5 == *pcVar10;
- pcVar5 = pcVar5 + 1;
- pcVar10 = pcVar10 + 1;
- } while ((bool)uVar11);
- if (!(bool)uVar11) {
- pcVar4 = "delay expected";
- TReadScriptFile::error((TReadScriptFile *)(Ident + 0x1c),"delay expected");
- }
- do {
- if (unique0x100007f5 != 1) {
- TReadScriptFile::close((TReadScriptFile *)(Ident + 0x1c),(int)pcVar4);
- // try { // try from 080a3ec7 to 080a3ecb has its CatchHandler @ 080a4636
- TReadScriptFile::~TReadScriptFile((TReadScriptFile *)(Ident + 0x1c),(int)pcVar4);
- return;
- }
- pcVar4 = (char *)0x3d;
- // try { // try from 080a3eea to 080a3f08 has its CatchHandler @ 080a4630
- TReadScriptFile::readSymbol((TReadScriptFile *)(Ident + 0x1c),'=');
- iVar8 = TReadScriptFile::readNumber((TReadScriptFile *)(Ident + 0x1c));
- this = (TAttackWave *)operator_new(0x54);
- // try { // try from 080a3f0e to 080a3f12 has its CatchHandler @ 080a45fb
- TAttackWave::TAttackWave(this);
- // try { // try from 080a3f22 to 080a4573 has its CatchHandler @ 080a4630
- while (TReadScriptFile::nextToken((TReadScriptFile *)(Ident + 0x1c)), stack0xffffc004 != 0)
- {
- uVar11 = stack0xffffc004 == 1;
- if (!(bool)uVar11) {
- pcVar4 = "identifier expected";
- TReadScriptFile::error((TReadScriptFile *)(Ident + 0x1c),"identifier expected");
- }
- pcVar5 = TReadScriptFile::getIdentifier((TReadScriptFile *)(Ident + 0x1c));
- iVar9 = 6;
- pcVar10 = "delay";
- do {
- if (iVar9 == 0) break;
- iVar9 = iVar9 + -1;
- uVar11 = *pcVar5 == *pcVar10;
- pcVar5 = pcVar5 + 1;
- pcVar10 = pcVar10 + 1;
- } while ((bool)uVar11);
- if ((bool)uVar11) break;
- pcVar4 = TReadScriptFile::getIdentifier((TReadScriptFile *)(Ident + 0x1c));
- strcpy(local_401c,pcVar4);
- pcVar4 = (char *)0x3d;
- TReadScriptFile::readSymbol((TReadScriptFile *)(Ident + 0x1c),'=');
- iVar9 = 9;
- pcVar5 = local_401c;
- pcVar10 = "location";
- do {
- if (iVar9 == 0) break;
- iVar9 = iVar9 + -1;
- uVar11 = *pcVar5 == *pcVar10;
- pcVar5 = pcVar5 + 1;
- pcVar10 = pcVar10 + 1;
- } while ((bool)uVar11);
- if ((bool)uVar11) {
- TReadScriptFile::readString((TReadScriptFile *)(Ident + 0x1c));
- }
- iVar9 = 9;
- pcVar5 = local_401c;
- pcVar10 = "position";
- do {
- if (iVar9 == 0) break;
- iVar9 = iVar9 + -1;
- uVar11 = *pcVar5 == *pcVar10;
- pcVar5 = pcVar5 + 1;
- pcVar10 = pcVar10 + 1;
- } while ((bool)uVar11);
- if ((bool)uVar11) {
- pcVar4 = (char *)this;
- TReadScriptFile::readCoordinate((TReadScriptFile *)(Ident + 0x1c));
- }
- iVar9 = 7;
- pcVar5 = local_401c;
- pcVar10 = "spread";
- do {
- if (iVar9 == 0) break;
- iVar9 = iVar9 + -1;
- uVar11 = *pcVar5 == *pcVar10;
- pcVar5 = pcVar5 + 1;
- pcVar10 = pcVar10 + 1;
- } while ((bool)uVar11);
- if ((bool)uVar11) {
- iVar9 = TReadScriptFile::readNumber((TReadScriptFile *)(Ident + 0x1c));
- this->Spread = iVar9;
- }
- iVar9 = 5;
- pcVar5 = local_401c;
- pcVar10 = "race";
- do {
- if (iVar9 == 0) break;
- iVar9 = iVar9 + -1;
- uVar11 = *pcVar5 == *pcVar10;
- pcVar5 = pcVar5 + 1;
- pcVar10 = pcVar10 + 1;
- } while ((bool)uVar11);
- if ((bool)uVar11) {
- iVar9 = TReadScriptFile::readNumber((TReadScriptFile *)(Ident + 0x1c));
- this->Race = iVar9;
- bVar2 = false;
- if ((0 < this->Race) && (this->Race < 0x200)) {
- bVar2 = true;
- }
- uVar11 = !bVar2;
- if ((bool)uVar11) {
- pcVar4 = "illegal race number";
- TReadScriptFile::error((TReadScriptFile *)(Ident + 0x1c),"illegal race number");
- }
- }
- iVar9 = 6;
- pcVar5 = local_401c;
- pcVar10 = "count";
- do {
- if (iVar9 == 0) break;
- iVar9 = iVar9 + -1;
- uVar11 = *pcVar5 == *pcVar10;
- pcVar5 = pcVar5 + 1;
- pcVar10 = pcVar10 + 1;
- } while ((bool)uVar11);
- if ((bool)uVar11) {
- TReadScriptFile::readSymbol((TReadScriptFile *)(Ident + 0x1c),'(');
- iVar9 = TReadScriptFile::readNumber((TReadScriptFile *)(Ident + 0x1c));
- this->MinCount = iVar9;
- pTVar1 = (TReadScriptFile *)(Ident + 0x1c);
- TReadScriptFile::readSymbol(pTVar1,',');
- iVar9 = TReadScriptFile::readNumber(pTVar1);
- this->MaxCount = iVar9;
- pcVar4 = (char *)0x29;
- TReadScriptFile::readSymbol(pTVar1,')');
- if (this->MaxCount < this->MinCount) {
- pcVar4 = "mincount greater than maxcount";
- TReadScriptFile::error(pTVar1,"mincount greater than maxcount");
- }
- uVar11 = this->MinCount == 0;
- if ((this->MinCount < 0) || (uVar11 = this->MaxCount == 0, this->MaxCount < 1)) {
- pcVar4 = "illegal number of monsters";
- TReadScriptFile::error
- ((TReadScriptFile *)(Ident + 0x1c),"illegal number of monsters");
- }
- }
- iVar9 = 7;
- pcVar5 = local_401c;
- pcVar10 = "radius";
- do {
- if (iVar9 == 0) break;
- iVar9 = iVar9 + -1;
- uVar11 = *pcVar5 == *pcVar10;
- pcVar5 = pcVar5 + 1;
- pcVar10 = pcVar10 + 1;
- } while ((bool)uVar11);
- if ((bool)uVar11) {
- iVar9 = TReadScriptFile::readNumber((TReadScriptFile *)(Ident + 0x1c));
- this->Radius = iVar9;
- }
- iVar9 = 9;
- pcVar5 = local_401c;
- pcVar10 = "lifetime";
- do {
- if (iVar9 == 0) break;
- iVar9 = iVar9 + -1;
- uVar11 = *pcVar5 == *pcVar10;
- pcVar5 = pcVar5 + 1;
- pcVar10 = pcVar10 + 1;
- } while ((bool)uVar11);
- if ((bool)uVar11) {
- iVar9 = TReadScriptFile::readNumber((TReadScriptFile *)(Ident + 0x1c));
- this->Lifetime = iVar9;
- }
- iVar9 = 8;
- pcVar5 = local_401c;
- pcVar10 = "message";
- do {
- if (iVar9 == 0) break;
- iVar9 = iVar9 + -1;
- uVar11 = *pcVar5 == *pcVar10;
- pcVar5 = pcVar5 + 1;
- pcVar10 = pcVar10 + 1;
- } while ((bool)uVar11);
- if ((bool)uVar11) {
- pcVar5 = TReadScriptFile::readString((TReadScriptFile *)(Ident + 0x1c));
- uVar6 = AddDynamicString(pcVar5);
- this->Message = uVar6;
- }
- iVar9 = 10;
- pcVar5 = local_401c;
- pcVar10 = "inventory";
- do {
- if (iVar9 == 0) break;
- iVar9 = iVar9 + -1;
- uVar11 = *pcVar5 == *pcVar10;
- pcVar5 = pcVar5 + 1;
- pcVar10 = pcVar10 + 1;
- } while ((bool)uVar11);
- if ((bool)uVar11) {
- TReadScriptFile::readSymbol((TReadScriptFile *)(Ident + 0x1c),'{');
- do {
- TReadScriptFile::readSymbol((TReadScriptFile *)(Ident + 0x1c),'(');
- iVar9 = this->ExtraItems + 1;
- this->ExtraItems = iVar9;
- this_00 = vector<TItemData>::operator()(&this->ExtraItem,iVar9);
- iVar9 = TReadScriptFile::readNumber((TReadScriptFile *)(Ident + 0x1c));
- ObjectType::setTypeID((ObjectType *)&AttackWave,iVar9);
- ObjectType::setTypeID(&this_00->Type,(int)AttackWave);
- ObjectType::setTypeID(local_402c,(this_00->Type).TypeID);
- TReadScriptFile::readSymbol((TReadScriptFile *)(Ident + 0x1c),',');
- iVar9 = TReadScriptFile::readNumber((TReadScriptFile *)(Ident + 0x1c));
- this_00->Maximum = iVar9;
- TReadScriptFile::readSymbol((TReadScriptFile *)(Ident + 0x1c),',');
- iVar9 = TReadScriptFile::readNumber((TReadScriptFile *)(Ident + 0x1c));
- this_00->Probability = iVar9;
- pcVar4 = (char *)0x29;
- TReadScriptFile::readSymbol((TReadScriptFile *)(Ident + 0x1c),')');
- cVar3 = TReadScriptFile::readSpecial((TReadScriptFile *)(Ident + 0x1c));
- } while (cVar3 != '}');
- }
- }
- if (this->x == 0) {
- pcVar4 = "position expected";
- TReadScriptFile::error((TReadScriptFile *)(Ident + 0x1c),"position expected");
- }
- if (this->Race == -1) {
- pcVar4 = "race expected";
- TReadScriptFile::error((TReadScriptFile *)(Ident + 0x1c),"race expected");
- }
- if (this->MaxCount == 0) {
- pcVar4 = "count expected";
- TReadScriptFile::error((TReadScriptFile *)(Ident + 0x1c),"count expected");
- }
- if (Start < 0) {
- iVar9 = iVar8 + this->Lifetime;
- if (this->Lifetime == 0) {
- iVar9 = iVar8 + 0xe10;
- }
- if (*Duration < iVar9) {
- *Duration = iVar9;
- }
- if (this != (TAttackWave *)0x0) {
- TAttackWave::~TAttackWave(this,(int)pcVar4);
- operator_delete(this);
- }
- }
- else {
- pcVar4 = (char *)(Start + iVar8);
- priority_queue<>::insert(&AttackWaveQueue);
- }
- } while( true );
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void LoadMonsterRaids(void)
-
-{
- char *__s;
- dirent *DirEntry;
- time_t tVar1;
- DIR *__dirp;
- dirent *pdVar2;
- size_t sVar3;
- long lVar4;
- undefined4 *puVar5;
- int iVar6;
- char *s;
- int iVar7;
- char *pcVar8;
- byte *pbVar9;
- bool bVar10;
- bool bVar11;
- int BigRaidDuration;
- int TieBreaker;
- DIR *WorkDir;
- time_t Now;
- int iStack_2030;
- bool BigRaid;
- int Date;
- int Interval;
- int Duration;
- int Hour;
- int Minute;
- char FileName [4096];
- char BigRaidName [4096];
-
- tVar1 = time((time_t *)0x0);
- // try { // try from 080a4681 to 080a4a1b has its CatchHandler @ 080a4a20
- GetRealTime(&Duration,&Hour);
- iVar7 = (((RebootTime - (Hour + Duration * 0x3c)) + 0x5a0) % 0x5a0) * 0x3c;
- __dirp = opendir(MONSTERPATH);
- if (__dirp == (DIR *)0x0) {
- error("LoadMonsterRaids: Unterverzeichnis %s nicht gefunden.\n",MONSTERPATH);
- puVar5 = (undefined4 *)__cxa_allocate_exception(4);
- *puVar5 = "Cannot load monster raids";
- // WARNING: Subroutine does not return
- __cxa_throw(puVar5,char_const*::typeinfo,0);
- }
- FileName[0xffc] = '\0';
- BigRaidDuration = -1;
- do {
- do {
- pdVar2 = readdir(__dirp);
- if (pdVar2 == (dirent *)0x0) {
- closedir(__dirp);
- if (FileName[0xffc] != '\0') {
- lVar4 = random();
- LoadMonsterRaid(FileName + 0xffc,lVar4 + RoundNr,(bool *)0x0,(int *)0x0,
- (int *)0x0,(int *)0x0);
- }
- return;
- }
- __s = pdVar2->d_name;
- sVar3 = strlen(__s);
- bVar10 = sVar3 < 4;
- bVar11 = sVar3 == 4;
- } while (sVar3 < 5);
- iVar6 = 4;
- pcVar8 = __s + (sVar3 - 4);
- pbVar9 = &DAT_080fe05c;
- do {
- if (iVar6 == 0) break;
- iVar6 = iVar6 + -1;
- bVar10 = (byte)*pcVar8 < *pbVar9;
- bVar11 = *pcVar8 == *pbVar9;
- pcVar8 = pcVar8 + 1;
- pbVar9 = pbVar9 + 1;
- } while (bVar11);
- if ((!bVar10 && !bVar11) == bVar10) {
- sprintf((char *)&Minute,"%s/%s",MONSTERPATH,__s);
- LoadMonsterRaid((char *)&Minute,-1,(bool *)((int)&Now + 3),&stack0xffffdfd0,&Date,
- &Interval);
- print();
- if (0 < iStack_2030) {
- bVar10 = false;
- if ((tVar1 <= iStack_2030) && (bVar10 = true, tVar1 + iVar7 < iStack_2030)) {
- bVar10 = false;
- }
- if ((bVar10) &&
- (LoadMonsterRaid((char *)&Minute,(iStack_2030 + RoundNr) - tVar1,(bool *)0x0,
- (int *)0x0,(int *)0x0,(int *)0x0), Now._3_1_ != '\0')) {
- FileName[0xffc] = '\0';
- BigRaidDuration = 100;
- }
- }
- if (((iStack_2030 == 0) && (Interval <= iVar7)) && (lVar4 = random(), lVar4 < iVar7)) {
- if (Now._3_1_ == '\0') {
- lVar4 = random();
- LoadMonsterRaid((char *)&Minute,lVar4 + RoundNr,(bool *)0x0,(int *)0x0,
- (int *)0x0,(int *)0x0);
- }
- else {
- lVar4 = random();
- if (BigRaidDuration < lVar4) {
- strcpy(FileName + 0xffc,(char *)&Minute);
- BigRaidDuration = lVar4;
- }
- }
- }
- }
- } while( true );
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void ProcessMonsterRaids(void)
-
-{
- ulong uVar1;
- undefined4 uVar2;
- int iVar3;
- TAttackWave *pTVar4;
- int iVar5;
- ulong *puVar6;
- bool bVar7;
- long lVar8;
- long lVar9;
- TItemData *pTVar10;
- TCreature *pTVar11;
- char *pcVar12;
- priority_queue_entry<> *ppVar13;
- int Count;
- TAttackWave *AttackWave;
- ulong *puVar14;
- int i;
- int i_1;
- int iVar15;
- undefined1 local_cc [36];
- int local_a8;
- int j;
- int Repeat;
- int Amount;
- TCreature *cr;
- int Monsters;
- TCreature___0_ *Monster;
- uint local_8c;
- ulong ExecutionRound;
- int posx;
- int posy;
- int posz;
- Object Obj;
- ulong local_6c [4];
- ulong local_5c [4];
- ulong local_4c [4];
- ulong local_3c [4];
- ulong local_2c;
- Object Bag;
-
- puVar6 = (ulong *)local_cc;
- do {
- puVar14 = puVar6;
- if (AttackWaveQueue.Entries == 0) {
- return;
- }
- puVar14[1] = 1;
- *puVar14 = (ulong)AttackWaveQueue.Entry;
- puVar14[-1] = 0x80a5040;
- ppVar13 = vector<>::operator()((vector<> *)*puVar14,puVar14[1]);
- local_8c = ppVar13->Key;
- puVar14[1] = 1;
- *puVar14 = (ulong)AttackWaveQueue.Entry;
- puVar14[-1] = 0x80a505d;
- ppVar13 = vector<>::operator()((vector<> *)*puVar14,puVar14[1]);
- pTVar4 = ppVar13->Data;
- if (RoundNr < local_8c) {
- return;
- }
- Monster = (TCreature___0_ *)puVar14;
- *puVar14 = (ulong)&AttackWaveQueue;
- puVar14[-1] = 0x80a4a87;
- priority_queue<>::deleteMin((priority_queue<> *)*puVar14);
- uVar1 = pTVar4->Race;
- *puVar14 = 2;
- puVar14[1] = (ulong)"Angriff von Monstern der Rasse %d.\n";
- puVar14[2] = uVar1;
- puVar14[-1] = 0x80a4aa2;
- print();
- if (pTVar4->Message != 0) {
- *puVar14 = pTVar4->Message;
- puVar14[-1] = 0x80a5006;
- pcVar12 = GetDynamicString(*puVar14);
- *puVar14 = 0x13;
- puVar14[2] = (ulong)pcVar12;
- puVar14[1] = (ulong)&DAT_08102a6c;
- puVar14[-1] = 0x80a501e;
- BroadcastMessage(*puVar14,(char *)puVar14[1]);
- }
- puVar14[1] = pTVar4->MaxCount;
- *puVar14 = pTVar4->MinCount;
- puVar14[-1] = 0x80a4abf;
- lVar8 = random();
- cr = (TCreature *)0x0;
- iVar5 = -(lVar8 * 4 + 0xfU & 0xfffffff0);
- Monsters = (int)puVar14 + iVar5 + 0x1c;
- if (0 < lVar8) {
- do {
- *(int *)((int)puVar14 + iVar5 + 4) = pTVar4->Spread;
- *(int *)((int)puVar14 + iVar5) = -pTVar4->Spread;
- *(undefined4 *)((int)puVar14 + iVar5 + -4) = 0x80a4b14;
- lVar9 = random();
- ExecutionRound = lVar9 + pTVar4->x;
- *(int *)((int)puVar14 + iVar5 + 4) = pTVar4->Spread;
- *(int *)((int)puVar14 + iVar5) = -pTVar4->Spread;
- *(undefined4 *)((int)puVar14 + iVar5 + -4) = 0x80a4b32;
- lVar9 = random();
- posx = lVar9 + pTVar4->y;
- posy = pTVar4->z;
- *(undefined4 *)((int)puVar14 + iVar5 + 0x14) = 0;
- *(undefined4 *)((int)puVar14 + iVar5 + 0x10) = 0;
- *(undefined4 *)((int)puVar14 + iVar5 + 0xc) = 1;
- *(int **)((int)puVar14 + iVar5 + 8) = &posy;
- *(int **)((int)puVar14 + iVar5 + 4) = &posx;
- *(ulong **)((int)puVar14 + iVar5) = &ExecutionRound;
- *(undefined4 *)((int)puVar14 + iVar5 + -4) = 0x80a4b6e;
- bVar7 = SearchFreeField(*(int **)((int)puVar14 + iVar5),
- *(int **)((int)puVar14 + iVar5 + 4),
- *(int **)((int)puVar14 + iVar5 + 8),
- *(int *)((int)puVar14 + iVar5 + 0xc),
- *(ushort *)((int)puVar14 + iVar5 + 0x10),
- *(bool *)((int)puVar14 + iVar5 + 0x14));
- if (bVar7) {
- *(int *)((int)puVar14 + iVar5 + 8) = posy;
- *(int *)((int)puVar14 + iVar5 + 4) = posx;
- *(ulong *)((int)puVar14 + iVar5) = ExecutionRound;
- *(undefined4 *)((int)puVar14 + iVar5 + -4) = 0x80a4f6c;
- bVar7 = IsProtectionZone();
- if (!bVar7) {
- *(undefined4 *)((int)puVar14 + iVar5 + 0x18) = 1;
- *(undefined4 *)((int)puVar14 + iVar5 + 0x14) = 0;
- *(undefined4 *)((int)puVar14 + iVar5 + 0x10) = 0;
- *(int *)((int)puVar14 + iVar5 + 0xc) = posy;
- *(int *)((int)puVar14 + iVar5 + 8) = posx;
- *(ulong *)((int)puVar14 + iVar5 + 4) = ExecutionRound;
- *(int *)((int)puVar14 + iVar5) = pTVar4->Race;
- *(undefined4 *)((int)puVar14 + iVar5 + -4) = 0x80a4faf;
- pTVar11 = CreateMonster(*(int *)((int)puVar14 + iVar5),
- *(int *)((int)puVar14 + iVar5 + 4),
- *(int *)((int)puVar14 + iVar5 + 8),
- *(int *)((int)puVar14 + iVar5 + 0xc),
- *(int *)((int)puVar14 + iVar5 + 0x10),
- *(ulong *)((int)puVar14 + iVar5 + 0x14),
- *(bool *)((int)puVar14 + iVar5 + 0x18));
- *(TCreature **)(Monsters + (int)cr * 4) = pTVar11;
- if (pTVar11 != (TCreature *)0x0) {
- if (pTVar4->Lifetime != 0) {
- pTVar11->LifeEndRound = pTVar4->Lifetime + RoundNr;
- }
- *(int *)(*(int *)(Monsters + (int)cr * 4) + 0x288) = pTVar4->Radius;
- cr = (TCreature *)((int)&cr->_vptr_TCreature + 1);
- }
- }
- }
- lVar8 = lVar8 + -1;
- } while (lVar8 != 0);
- }
- iVar15 = 1;
- if (0 < pTVar4->ExtraItems) {
- do {
- if ((int)cr < 1) break;
- *(int *)((int)puVar14 + iVar5 + 4) = iVar15;
- *(vector<TItemData> **)((int)puVar14 + iVar5) = &pTVar4->ExtraItem;
- *(undefined4 *)((int)puVar14 + iVar5 + -4) = 0x80a4b9c;
- pTVar10 = vector<TItemData>::operator()
- (*(vector<TItemData> **)((int)puVar14 + iVar5),
- *(int *)((int)puVar14 + iVar5 + 4));
- *(undefined4 *)((int)puVar14 + iVar5) = 0;
- *(undefined4 *)((int)puVar14 + iVar5 + 4) = 999;
- *(undefined4 *)((int)puVar14 + iVar5 + -4) = 0x80a4bb2;
- lVar8 = random();
- pTVar11 = cr;
- if (lVar8 <= pTVar10->Probability) {
- *(undefined4 *)((int)puVar14 + iVar5) = 0;
- *(undefined1 **)((int)puVar14 + iVar5 + 4) =
- (undefined1 *)((int)&pTVar11[-1].Connection + 3);
- *(undefined4 *)((int)puVar14 + iVar5 + -4) = 0x80a4bff;
- lVar8 = random();
- Amount = *(int *)(Monsters + lVar8 * 4);
- *(undefined4 *)((int)puVar14 + iVar5 + 8) = 3;
- uVar2 = *(undefined4 *)(Amount + 0x208);
- *(ulong **)((int)puVar14 + iVar5) = &local_2c;
- *(undefined4 *)((int)puVar14 + iVar5 + 4) = uVar2;
- *(undefined4 *)((int)puVar14 + iVar5 + -4) = 0x80a4c31;
- GetBodyObject(*(ulong *)((int)puVar14 + iVar5),
- *(int *)((int)puVar14 + iVar5 + 4));
- local_3c[0] = NONE.ObjectID;
- if (local_2c == NONE.ObjectID) {
- *(undefined4 *)((int)puVar14 + iVar5 + 4) = 0xe;
- *(ulong **)((int)puVar14 + iVar5) = local_6c;
- // try { // try from 080a4c4f to 080a4c9d has its CatchHandler @ 080a506a
- *(undefined4 *)((int)puVar14 + iVar5 + -4) = 0x80a4c54;
- GetSpecialObject(*(SPECIALMEANING *)((int)puVar14 + iVar5));
- *(undefined4 *)((int)puVar14 + iVar5 + 8) = 3;
- *(undefined4 *)((int)puVar14 + iVar5 + 4) = *(undefined4 *)(Amount + 0x208);
- *(int **)((int)puVar14 + iVar5) = &posz;
- *(undefined4 *)((int)puVar14 + iVar5 + -4) = 0x80a4c7a;
- GetBodyContainer(*(ulong *)((int)puVar14 + iVar5),
- *(int *)((int)puVar14 + iVar5 + 4));
- *(undefined4 *)((int)puVar14 + iVar5 + 0xc) = 0;
- *(ulong **)((int)puVar14 + iVar5 + 8) = local_6c;
- *(int **)((int)puVar14 + iVar5 + 4) = &posz;
- *(ulong **)((int)puVar14 + iVar5) = local_5c;
- *(undefined4 *)((int)puVar14 + iVar5 + -4) = 0x80a4c9e;
- Create(*(Object **)((int)puVar14 + iVar5),
- *(ObjectType **)((int)puVar14 + iVar5 + 4),
- *(ulong *)((int)puVar14 + iVar5 + 8));
- local_2c = local_5c[0];
- local_4c[0] = local_5c[0];
- }
- iVar3 = pTVar10->Maximum;
- *(undefined4 *)((int)puVar14 + iVar5) = 1;
- *(int *)((int)puVar14 + iVar5 + 4) = iVar3;
- *(undefined4 *)((int)puVar14 + iVar5 + -4) = 0x80a4cbd;
- Repeat = random();
- *(int *)((int)puVar14 + iVar5 + 0xc) = (pTVar10->Type).TypeID;
- iVar3 = Repeat;
- *(undefined4 *)((int)puVar14 + iVar5) = 2;
- *(char **)((int)puVar14 + iVar5 + 4) = "Verteile %d Objekte vom Typ %d.\n";
- *(int *)((int)puVar14 + iVar5 + 8) = iVar3;
- *(undefined4 *)((int)puVar14 + iVar5 + -4) = 0x80a4ce7;
- print();
- j = 1;
- *(undefined4 *)((int)puVar14 + iVar5 + 4) = 6;
- *(TItemData **)((int)puVar14 + iVar5) = pTVar10;
- *(undefined4 *)((int)puVar14 + iVar5 + -4) = 0x80a4d02;
- bVar7 = ObjectType::getFlag(*(ObjectType **)((int)puVar14 + iVar5),
- *(FLAG *)((int)puVar14 + iVar5 + 4));
- iVar3 = Repeat;
- if (!bVar7) {
- Repeat = 0;
- j = iVar3;
- }
- local_a8 = 0;
- if (0 < j) {
- do {
- posz = 0;
- *(undefined4 *)((int)puVar14 + iVar5 + 4) = 0x37;
- *(TItemData **)((int)puVar14 + iVar5) = pTVar10;
- *(undefined4 *)((int)puVar14 + iVar5 + -4) = 0x80a4d4b;
- bVar7 = ObjectType::getFlag(*(ObjectType **)((int)puVar14 + iVar5),
- *(FLAG *)((int)puVar14 + iVar5 + 4));
- if (bVar7) {
-LAB_080a4d67:
- iVar3 = (pTVar10->Type).TypeID;
- *(ulong **)((int)puVar14 + iVar5) = local_4c;
- *(int *)((int)puVar14 + iVar5 + 4) = iVar3;
- // try { // try from 080a4d73 to 080a4d9e has its CatchHandler @ 080a50b2
- *(undefined4 *)((int)puVar14 + iVar5 + -4) = 0x80a4d78;
- ObjectType::setTypeID
- (*(ObjectType **)((int)puVar14 + iVar5),
- *(int *)((int)puVar14 + iVar5 + 4));
- local_3c[0] = local_2c;
- *(undefined4 *)((int)puVar14 + iVar5 + 0xc) = 0;
- *(ulong **)((int)puVar14 + iVar5 + 8) = local_4c;
- *(ulong **)((int)puVar14 + iVar5 + 4) = local_3c;
- *(ulong **)((int)puVar14 + iVar5) = local_5c;
- *(undefined4 *)((int)puVar14 + iVar5 + -4) = 0x80a4d9f;
- Create(*(Object **)((int)puVar14 + iVar5),
- *(ObjectType **)((int)puVar14 + iVar5 + 4),
- *(ulong *)((int)puVar14 + iVar5 + 8));
- }
- else {
- *(undefined4 *)((int)puVar14 + iVar5 + 4) = 0x38;
- *(TItemData **)((int)puVar14 + iVar5) = pTVar10;
- *(undefined4 *)((int)puVar14 + iVar5 + -4) = 0x80a4d5f;
- bVar7 = ObjectType::getFlag(*(ObjectType **)((int)puVar14 + iVar5),
- *(FLAG *)((int)puVar14 + iVar5 + 4));
- if (bVar7) goto LAB_080a4d67;
- *(undefined4 *)((int)puVar14 + iVar5 + 4) = 0x39;
- *(TItemData **)((int)puVar14 + iVar5) = pTVar10;
- *(undefined4 *)((int)puVar14 + iVar5 + -4) = 0x80a4e88;
- bVar7 = ObjectType::getFlag(*(ObjectType **)((int)puVar14 + iVar5),
- *(FLAG *)((int)puVar14 + iVar5 + 4));
- if (bVar7) goto LAB_080a4d67;
- *(undefined4 *)((int)puVar14 + iVar5 + 4) = 0x3a;
- *(TItemData **)((int)puVar14 + iVar5) = pTVar10;
- *(undefined4 *)((int)puVar14 + iVar5 + -4) = 0x80a4ea0;
- bVar7 = ObjectType::getFlag(*(ObjectType **)((int)puVar14 + iVar5),
- *(FLAG *)((int)puVar14 + iVar5 + 4));
- if (bVar7) goto LAB_080a4d67;
- *(undefined4 *)((int)puVar14 + iVar5 + 4) = 0x3b;
- *(TItemData **)((int)puVar14 + iVar5) = pTVar10;
- *(undefined4 *)((int)puVar14 + iVar5 + -4) = 0x80a4eb8;
- bVar7 = ObjectType::getFlag(*(ObjectType **)((int)puVar14 + iVar5),
- *(FLAG *)((int)puVar14 + iVar5 + 4));
- if (bVar7) goto LAB_080a4d67;
- *(undefined4 *)((int)puVar14 + iVar5 + 4) = 0x36;
- *(TItemData **)((int)puVar14 + iVar5) = pTVar10;
- *(undefined4 *)((int)puVar14 + iVar5 + -4) = 0x80a4ed0;
- bVar7 = ObjectType::getFlag(*(ObjectType **)((int)puVar14 + iVar5),
- *(FLAG *)((int)puVar14 + iVar5 + 4));
- if (bVar7) goto LAB_080a4d67;
- *(undefined4 *)((int)puVar14 + iVar5 + 4) = 0x34;
- *(TItemData **)((int)puVar14 + iVar5) = pTVar10;
- *(undefined4 *)((int)puVar14 + iVar5 + -4) = 0x80a4ee8;
- bVar7 = ObjectType::getFlag(*(ObjectType **)((int)puVar14 + iVar5),
- *(FLAG *)((int)puVar14 + iVar5 + 4));
- if (bVar7) goto LAB_080a4d67;
- *(undefined4 *)((int)puVar14 + iVar5 + 4) = 0x35;
- *(TItemData **)((int)puVar14 + iVar5) = pTVar10;
- *(undefined4 *)((int)puVar14 + iVar5 + -4) = 0x80a4f00;
- bVar7 = ObjectType::getFlag(*(ObjectType **)((int)puVar14 + iVar5),
- *(FLAG *)((int)puVar14 + iVar5 + 4));
- if (bVar7) goto LAB_080a4d67;
- iVar3 = (pTVar10->Type).TypeID;
- *(ulong **)((int)puVar14 + iVar5) = local_4c;
- *(int *)((int)puVar14 + iVar5 + 4) = iVar3;
- *(undefined4 *)((int)puVar14 + iVar5 + -4) = 0x80a4f19;
- ObjectType::setTypeID
- (*(ObjectType **)((int)puVar14 + iVar5),
- *(int *)((int)puVar14 + iVar5 + 4));
- iVar3 = Repeat;
- *(ulong **)((int)puVar14 + iVar5 + 8) = local_4c;
- *(int *)((int)puVar14 + iVar5 + 0xc) = iVar3;
- *(undefined4 *)((int)puVar14 + iVar5 + 4) =
- *(undefined4 *)(Amount + 0x208);
- *(ulong **)((int)puVar14 + iVar5) = local_5c;
- *(undefined4 *)((int)puVar14 + iVar5 + -4) = 0x80a4f45;
- CreateAtCreature(*(ulong *)((int)puVar14 + iVar5),
- *(ObjectType **)((int)puVar14 + iVar5 + 4),
- *(ulong *)((int)puVar14 + iVar5 + 8));
- }
- posz = local_5c[0];
- local_6c[0] = local_5c[0];
- *(int **)((int)puVar14 + iVar5 + 4) = &posz;
- *(ulong **)((int)puVar14 + iVar5) = local_6c;
- *(undefined4 *)((int)puVar14 + iVar5 + -4) = 0x80a4dbd;
- Object::getContainer(*(Object **)((int)puVar14 + iVar5));
- *(ulong **)((int)puVar14 + iVar5 + 4) = local_6c;
- *(ulong **)((int)puVar14 + iVar5) = local_5c;
- *(undefined4 *)((int)puVar14 + iVar5 + -4) = 0x80a4dd2;
- Object::getObjectType(*(Object **)((int)puVar14 + iVar5));
- if (local_5c[0] == 0) {
- uVar2 = *(undefined4 *)(Amount + 0x280);
- *(undefined **)((int)puVar14 + iVar5) = &DAT_081025a0;
- *(undefined4 *)((int)puVar14 + iVar5 + 4) = uVar2;
- *(undefined4 *)((int)puVar14 + iVar5 + -4) = 0x80a4e5a;
- error(*(char **)((int)puVar14 + iVar5));
- local_5c[0] = posz;
- *(undefined4 *)((int)puVar14 + iVar5 + 4) = 0xffffffff;
- *(ulong **)((int)puVar14 + iVar5) = local_5c;
- *(undefined4 *)((int)puVar14 + iVar5 + -4) = 0x80a4e73;
- Delete(*(Object **)((int)puVar14 + iVar5),
- *(int *)((int)puVar14 + iVar5 + 4));
- }
- local_a8 = local_a8 + 1;
- } while (local_a8 < j);
- }
- local_6c[0] = local_2c;
- *(ulong **)((int)puVar14 + iVar5 + 4) = local_6c;
- *(int **)((int)puVar14 + iVar5) = &posz;
- *(undefined4 *)((int)puVar14 + iVar5 + -4) = 0x80a4e0c;
- GetFirstContainerObject(*(Object **)((int)puVar14 + iVar5));
- local_5c[0] = NONE.ObjectID;
- if (posz == NONE.ObjectID) {
- local_4c[0] = local_2c;
- *(undefined4 *)((int)puVar14 + iVar5 + 4) = 0xffffffff;
- *(ulong **)((int)puVar14 + iVar5) = local_4c;
- *(undefined4 *)((int)puVar14 + iVar5 + -4) = 0x80a4e39;
- Delete(*(Object **)((int)puVar14 + iVar5),*(int *)((int)puVar14 + iVar5 + 4)
- );
- }
- }
- iVar15 = iVar15 + 1;
- } while (iVar15 <= pTVar4->ExtraItems);
- }
- puVar6 = (ulong *)Monster;
- if (pTVar4 != (TAttackWave *)0x0) {
- *(TAttackWave **)((int)puVar14 + iVar5) = pTVar4;
- *(undefined4 *)((int)puVar14 + iVar5 + -4) = 0x80a4bde;
- TAttackWave::~TAttackWave
- (*(TAttackWave **)((int)puVar14 + iVar5),*(int *)((int)puVar14 + iVar5 + 4));
- *(TAttackWave **)((int)puVar14 + iVar5) = pTVar4;
- *(undefined4 *)((int)puVar14 + iVar5 + -4) = 0x80a4be6;
- operator_delete(*(void **)((int)puVar14 + iVar5));
- puVar6 = (ulong *)Monster;
- }
- } while( true );
-}
-
void __tcf_0(void *param_1)
{
diff --git a/reference/types.hh b/reference/types.hh
index c711831..f3ce69d 100644
--- a/reference/types.hh
+++ b/reference/types.hh
@@ -89,21 +89,6 @@ struct TWaitinglistEntry {
bool Sleeping;
};
-struct TAttackWave {
- int x;
- int y;
- int z;
- int Spread;
- int Race;
- int MinCount;
- int MaxCount;
- int Radius;
- int Lifetime;
- ulong Message;
- int ExtraItems;
- struct vector<TItemData> ExtraItem;
-};
-
struct TReportedStatement {
ulong StatementID;
ulong TimeStamp;
diff --git a/src/containers.hh b/src/containers.hh
index ba7e3cd..85dcfde 100644
--- a/src/containers.hh
+++ b/src/containers.hh
@@ -3,11 +3,21 @@
#include "common.hh"
+// NOTE(fusion): All containers are automatically managed by their constructors
+// and destructors, meaning raw copies could result in memory corruption through
+// double frees, use after frees, etc... To avoid that, we need to make them all
+// non copyable.
+#define NONCOPYABLE(Type) \
+ Type(const Type &Other) = delete; \
+ void operator=(const Type &Other) = delete;
+
// 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{
+ NONCOPYABLE(vector)
+
vector(int min, int max, int block){
int space = (max - min) + 1;
if(space < 1){
@@ -128,6 +138,8 @@ struct priority_queue_entry{
template<typename K, typename T>
struct priority_queue{
+ NONCOPYABLE(priority_queue)
+
priority_queue(int capacity, int increment){
Entry = new vector<priority_queue_entry<K, T>>(1, capacity, increment);
Entries = 0;
@@ -205,6 +217,8 @@ struct priority_queue{
template<typename T>
struct matrix{
+ NONCOPYABLE(matrix)
+
matrix(int xmin, int xmax, int ymin, int ymax){
int dx = (xmax - xmin) + 1;
int dy = (ymax - ymin) + 1;
@@ -273,6 +287,8 @@ struct matrix{
template<typename T>
struct matrix3d{
+ NONCOPYABLE(matrix3d)
+
matrix3d(int xmin, int xmax, int ymin, int ymax, int zmin, int zmax){
int dx = (xmax - xmin) + 1;
int dy = (ymax - ymin) + 1;
@@ -351,6 +367,8 @@ struct listnode{
template<typename T>
struct list{
+ NONCOPYABLE(list)
+
list(void){
firstNode = NULL;
lastNode = NULL;
@@ -409,6 +427,8 @@ struct list{
template<typename T>
struct fifo{
+ NONCOPYABLE(fifo)
+
fifo(int InitialSize){
ASSERT(InitialSize > 0);
this->Entry = new T[InitialSize];
@@ -490,6 +510,8 @@ struct storeunit{
// It is also known as a slab allocator.
template<typename T, usize N>
struct store{
+ NONCOPYABLE(store)
+
store(void){
this->Units = new list<storeunit<T, N>>;
this->firstFreeItem = NULL;
diff --git a/src/cr.hh b/src/cr.hh
index ff96e88..e82b17b 100644
--- a/src/cr.hh
+++ b/src/cr.hh
@@ -154,6 +154,28 @@ struct TPlayerData {
int NumberOfMutings;
};
+// TAttackWave
+// =============================================================================
+struct TAttackWave {
+ TAttackWave(void);
+ ~TAttackWave(void);
+
+ // DATA
+ // =================
+ int x;
+ int y;
+ int z;
+ int Spread;
+ int Race;
+ int MinCount;
+ int MaxCount;
+ int Radius;
+ int Lifetime;
+ uint32 Message;
+ int ExtraItems;
+ vector<TItemData> ExtraItem;
+};
+
// TSkillBase
// =============================================================================
struct TSkill{
@@ -722,8 +744,6 @@ struct TPlayer: TCreature {
// =============================================================================
#define MAX_RACES 512
extern TRaceData RaceData[MAX_RACES];
-extern int KilledCreatures[MAX_RACES];
-extern int KilledPlayers[MAX_RACES];
extern priority_queue<uint32, uint32> ToDoQueue;
bool IsCreaturePlayer(uint32 CreatureID);
@@ -752,9 +772,15 @@ bool GetRaceNoParalyze(int Race);
int GetRaceSummonCost(int Race);
int GetRacePoison(int Race);
bool GetRaceUnpushable(int Race);
-
TOutfit ReadOutfit(TReadScriptFile *Script);
void WriteOutfit(TReadScriptFile *Script, TOutfit Outfit);
+void LoadRace(const char *FileName);
+void LoadRaces(void);
+
+void LoadMonsterRaid(const char *FileName, int Start,
+ bool *Type, int *Date, int *Interval, int *Duration);
+void LoadMonsterRaids(void);
+void ProcessMonsterRaids(void);
// crskill.cc
// =============================================================================
diff --git a/src/crmain.cc b/src/crmain.cc
index 48d31be..5d0f2f3 100644
--- a/src/crmain.cc
+++ b/src/crmain.cc
@@ -5,18 +5,20 @@
#include "stubs.hh"
-TRaceData RaceData[MAX_RACES];
-int KilledCreatures[MAX_RACES];
-int KilledPlayers[MAX_RACES];
+#include <dirent.h>
+#include <time.h>
+TRaceData RaceData[MAX_RACES];
priority_queue<uint32, uint32> ToDoQueue(5000, 1000);
-//priority_queue<uint32, TAttackWave*> AttackWaveQueue(100, 100);
static uint32 NextCreatureID;
static int FirstFreeCreature;
static TCreature *HashList[1000];
static matrix<uint32> *FirstChainCreature;
static vector<TCreature*> CreatureList(0, 10000, 1000);
+static priority_queue<uint32, TAttackWave*> AttackWaveQueue(100, 100);
+static int KilledCreatures[MAX_RACES];
+static int KilledPlayers[MAX_RACES];
// TFindCreatures
// =============================================================================
@@ -1332,10 +1334,11 @@ TOutfit ReadOutfit(TReadScriptFile *Script){
memcpy(Outfit.Colors, Script->readBytesequence(), sizeof(Outfit.Colors));
}
Script->readSymbol(')');
+ return Outfit;
}
// TODO(fusion): Probably move this somewhere else?
-void WriteOutfit(TReadScriptFile *Script, TOutfit Outfit){
+void WriteOutfit(TWriteScriptFile *Script, TOutfit Outfit){
Script->writeText("(");
Script->writeNumber(Outfit.OutfitID);
Script->writeText(",");
@@ -1361,7 +1364,7 @@ void LoadRace(const char *FileName){
Script.readSymbol('=');
int RaceNumber = Script.readNumber();
- if(!IsRaceValid(Race)){
+ if(!IsRaceValid(RaceNumber)){
Script.error("illegal race number");
}
@@ -1389,7 +1392,7 @@ void LoadRace(const char *FileName){
}else if(strcmp(Identifier, "article") == 0){
strcpy(Race->Article, Script.readString());
}else if(strcmp(Identifier, "outfit") == 0){
- Race->Outfit = ReadOutfit(Script);
+ Race->Outfit = ReadOutfit(&Script);
}else if(strcmp(Identifier, "corpse") == 0){
int CorpseTypeID = Script.readNumber();
Race->MaleCorpse = CorpseTypeID;
@@ -1512,10 +1515,10 @@ void LoadRace(const char *FileName){
}else if(strcmp(Identifier, "inventory") == 0){
Script.readSymbol('{');
do{
- Script.readSymbol('(');
// NOTE(fusion): Items are indexed from 1.
Race->Items += 1;
TItemData *ItemData = Race->Item.at(Race->Items);
+ Script.readSymbol('(');
ItemData->Type = Script.readNumber();
Script.readSymbol(',');
ItemData->Maximum = Script.readNumber();
@@ -1526,6 +1529,7 @@ void LoadRace(const char *FileName){
}else if(strcmp(Identifier, "spells") == 0){
Script.readSymbol('{');
do{
+ // NOTE(fusion): Spells are indexed from 1.
Race->Spells += 1;
TSpellData *SpellData = Race->Spell.at(Race->Spells);
@@ -1636,7 +1640,7 @@ void LoadRace(const char *FileName){
}else if(strcmp(SpellImpact, "outfit") == 0){
SpellData->Impact = IMPACT_OUTFIT;
Script.readSymbol('(');
- TOutfit Outfit = ReadOutfit(Script);
+ TOutfit Outfit = ReadOutfit(&Script);
SpellData->ImpactParam1 = Outfit.OutfitID;
SpellData->ImpactParam2 = (int)Outfit.PackedData;
Script.readSymbol(',');
@@ -1665,7 +1669,7 @@ void LoadRace(const char *FileName){
}
}while(Script.readSpecial() != '}');
}else{
- Script.error("unknown race field");
+ Script.error("unknown race property");
}
}
}
@@ -1697,7 +1701,401 @@ void LoadRaces(void){
// Monster Raid
// =============================================================================
-void LoadMonsterRaids(void); //TODO
+TAttackWave::TAttackWave(void) :
+ ExtraItem(1, 5, 5)
+{
+ this->x = 0;
+ this->y = 0;
+ this->z = 0;
+ this->Spread = 0;
+ this->Race = -1;
+ this->MinCount = 0;
+ this->MaxCount = 0;
+ this->Radius = INT_MAX;
+ this->Lifetime = 0;
+ this->Message = 0;
+ this->ExtraItems = 0;
+}
+
+TAttackWave::~TAttackWave(void){
+ if(this->Message != 0){
+ DeleteDynamicString(this->Message);
+ }
+}
+
+void LoadMonsterRaid(const char *FileName, int Start,
+ bool *Type, int *Date, int *Interval, int *Duration){
+ if(FileName == NULL){
+ error("LoadMonsterRaid: Dateiname ist NULL.\n");
+ throw "cannot load monster raid";
+ }
+
+ // TODO(fusion): The original function would only write to these output
+ // variables when `Start` was negative. Instead, we assign dummy variables
+ // if any of the pointers is NULL to allow for any reads and writes while
+ // loading the raid.
+ bool DummyType;
+ int DummyDate;
+ int DummyInterval;
+ int DummyDuration;
+ if(Type == NULL) { Type = &DummyType; }
+ if(Date == NULL) { Date = &DummyDate; }
+ if(Interval == NULL) { Interval = &DummyInterval; }
+ if(Duration == NULL) { Duration = &DummyDuration; }
+
+ *Type = false;
+ *Date = 0;
+ *Interval = 0;
+ *Duration = 0;
+
+ if(Start >= 0){
+ print(1, "Plane Raid %s ein für Runde %d.\n", FileName, Start);
+ }
+
+ // NOTE(fusion): We expect the first few attributes describing the raid to
+ // be in an exact order, followed by attack waves. Attack wave attributes
+ // don't need to be in any specific order but specifying `Delay` will wrap
+ // the previous wave (if any) and start a new one.
+
+ TReadScriptFile Script;
+ Script.open(FileName);
+
+ // NOTE(fusion): Optional `Description` attribute.
+ Script.nextToken();
+ if(strcmp(Script.getIdentifier(), "description") == 0){
+ Script.readSymbol('=');
+ Script.readString();
+ Script.nextToken();
+ }
+
+ if(strcmp(Script.getIdentifier(), "type") == 0){
+ // NOTE(fusion): The type can be either "BigRaid" or "SmallRaid" so it uses
+ // a boolean for `Type` to tell whether it is a big raid or not. It could be
+ // renamed to `BigRaid` or something.
+ Script.readSymbol('=');
+ *Type = (strcmp(Script.readIdentifier(), "bigraid") == 0);
+ }else{
+ Script.error("type expected");
+ }
+
+ Script.nextToken();
+ if(strcmp(Script.getIdentifier(), "date") == 0){
+ Script.readSymbol('=');
+ *Date = Script.getNumber();
+ }else if(strcmp(Script.getIdentifier(), "interval") == 0){
+ Script.readSymbol('=');
+ *Interval = Script.getNumber();
+ }else{
+ Script.error("date or interval expected");
+ }
+
+ Script.nextToken();
+ while(Script.Token != ENDOFFILE){
+ if(strcmp(Script.getIdentifier(), "delay") == 0){
+ Script.error("delay expected");
+ }
+
+ Script.readSymbol('=');
+ int Delay = Script.readNumber();
+ TAttackWave *Wave = new TAttackWave;
+ while(true){
+ Script.nextToken();
+ if(Script.Token == ENDOFFILE){
+ break;
+ }
+
+ if(strcmp(Script.getIdentifier(), "delay") == 0){
+ break;
+ }
+
+ char Identifier[MAX_IDENT_LENGTH];
+ strcpy(Identifier, Script.getIdentifier());
+ Script.readSymbol('=');
+ if(strcmp(Identifier, "location") == 0){
+ Script.readString();
+ }else if(strcmp(Identifier, "position") == 0){
+ Script.readCoordinate(&Wave->x, &Wave->y, &Wave->z);
+ }else if(strcmp(Identifier, "spread") == 0){
+ Wave->Spread = Script.readNumber();
+ }else if(strcmp(Identifier, "race") == 0){
+ Wave->Race = Script.readNumber();
+ if(!IsRaceValid(Wave->Race)){
+ Script.error("illegal race number");
+ }
+ }else if(strcmp(Identifier, "count") == 0){
+ Script.readSymbol('(');
+ Wave->MinCount = Script.readNumber();
+ Script.readSymbol(',');
+ Wave->MaxCount = Script.readNumber();
+ Script.readSymbol(')');
+
+ if(Wave->MaxCount < Wave->MinCount){
+ Script.error("mincount greater than maxcount");
+ }
+
+ if(Wave->MinCount < 0 || Wave->MaxCount < 1){
+ Script.error("illegal number of monsters");
+ }
+ }else if(strcmp(Identifier, "radius") == 0){
+ Wave->Radius = Script.readNumber();
+ }else if(strcmp(Identifier, "lifetime") == 0){
+ Wave->Lifetime = Script.readNumber();
+ }else if(strcmp(Identifier, "message") == 0){
+ Wave->Message = AddDynamicString(Script.readString());
+ }else if(strcmp(Identifier, "inventory") == 0){
+ Script.readSymbol('{');
+ do{
+ // NOTE(fusion): Items are indexed from 1.
+ Wave->ExtraItems += 1;
+ TItemData *ItemData = Wave->ExtraItem.at(Wave->ExtraItems);
+ Script.readSymbol('(');
+ ItemData->Type = Script.readNumber();
+ Script.readSymbol(',');
+ ItemData->Maximum = Script.readNumber();
+ Script.readSymbol(',');
+ ItemData->Probability = Script.readNumber();
+ Script.readSymbol(')');
+ }while(Script.readSpecial() != '}');
+ }else{
+ Script.error("unknown attack wave property");
+ }
+ }
+
+ if(Wave->x == 0){
+ Script.error("position expected");
+ }
+
+ if(Wave->Race == -1){
+ Script.error("race expected");
+ }
+
+ if(Wave->MaxCount == 0){
+ Script.error("count expected");
+ }
+
+ int WaveEnd = Delay + (Wave->Lifetime != 0 ? Wave->Lifetime : 3600);
+ if(*Duration < WaveEnd){
+ *Duration = WaveEnd;
+ }
+
+ if(Start >= 0){
+ AttackWaveQueue.insert(Start + Delay, Wave);
+ }else{
+ delete Wave;
+ }
+ }
+
+ Script.close();
+}
+
+void LoadMonsterRaids(void){
+ DIR *MonsterDir = opendir(MONSTERPATH);
+ if(MonsterDir == NULL){
+ error("LoadMonsterRaids: Unterverzeichnis %s nicht gefunden.\n", MONSTERPATH);
+ throw "Cannot load monster raids";
+ }
+
+ // TODO(fusion): The `Date` attribute used by raid files is a unix timestamp
+ // which is usually what `time(NULL)` returns. This should work fine until
+ // 2038 when the timestamp value exceeds the capacity of a 32-bit signed
+ // integer.
+ int Now = (int)std::min<time_t>(time(NULL), INT_MAX);
+
+ int Hour, Minute;
+ GetRealTime(&Hour, &Minute);
+
+ int SecondsToReboot = (RebootTime - (Hour * 60 + Minute)) * 60;
+ if(SecondsToReboot < 0){
+ SecondsToReboot += 86400;
+ }
+
+ char BigRaidName[4096];
+ int BigRaidDuration = 0;
+ int BigRaidTieBreaker = -1;
+
+ char FileName[4096];
+ while(dirent *DirEntry = readdir(MonsterDir)){
+ const char *FileExt = findLast(DirEntry->d_name, '.');
+ if(FileExt != NULL && strcmp(FileExt, ".evt") == 0){
+ snprintf(FileName, sizeof(FileName), "%s/%s", MONSTERPATH, DirEntry->d_name);
+
+ bool BigRaid;
+ int Date, Interval, Duration;
+ LoadMonsterRaid(FileName, -1, &BigRaid, &Date, &Interval, &Duration);
+ print(1, "Raid %s: Date %d, Interval %d, Duration %d\n",
+ FileName, Date, Interval, Duration);
+
+ if(Date > 0){
+ if(Now <= Date && Date <= (Now + SecondsToReboot)){
+ int Start = RoundNr + (Date - Now);
+ LoadMonsterRaid(FileName, Start, NULL, NULL, NULL, NULL);
+ if(BigRaid){
+ BigRaidName[0] = 0;
+ BigRaidDuration = 0;
+ BigRaidTieBreaker = 100;
+ }
+ }
+ }else if(Duration <= SecondsToReboot){
+ // NOTE(fusion): `Interval` specifies an average raid interval
+ // in seconds. With this function being called at startup, usually
+ // after a reboot, we can expect `SecondsToReboot` to be close to
+ // a day very regularly. Meaning we can approximate the condition
+ // below to `random(1, AverageIntervalDays) == 1` which hopefully
+ // makes more sense.
+ if(random(0, Interval - 1) < SecondsToReboot){
+ if(!BigRaid){
+ int Start = RoundNr + random(0, SecondsToReboot - Duration);
+ LoadMonsterRaid(FileName, Start, NULL, NULL, NULL, NULL);
+ }else{
+ int TieBreaker = random(0, 99);
+ if(TieBreaker > BigRaidTieBreaker){
+ strcpy(BigRaidName, FileName);
+ BigRaidDuration = Duration;
+ BigRaidTieBreaker = TieBreaker;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ closedir(MonsterDir);
+
+ if(BigRaidName[0] != 0){
+ int Start = RoundNr + random(0, SecondsToReboot - BigRaidDuration);
+ LoadMonsterRaid(BigRaidName, Start, NULL, NULL, NULL, NULL);
+ }
+}
+
+void ProcessMonsterRaids(void){
+ while(AttackWaveQueue.Entries > 0){
+ auto Entry = *AttackWaveQueue.Entry->at(1);
+ uint32 ExecutionRound = Entry.Key;
+ TAttackWave *Wave = Entry.Data;
+ if(ExecutionRound > RoundNr){
+ break;
+ }
+
+ AttackWaveQueue.deleteMin();
+ print(2, "Angriff von Monstern der Rasse %d.\n", Wave->Race);
+ if(Wave->Message != 0){
+ BroadcastMessage(TALK_EVENT_MESSAGE, "%s", GetDynamicString(Wave->Message));
+ }
+
+ int NumSpawned = 0;
+ TCreature *Spawned[64] = {};
+
+ // NOTE(fusion): The original function would use `alloca` to allocate the
+ // buffer for spawned creatures. Inspecting some raid files, the maximum
+ // count I could find was 40. I don't think it is realistic for this number
+ // to get much higher, mostly because you can always split a large wave
+ // into multiple smaller ones, and because going crazy with alloca could
+ // cause the stack to blow up.
+ int Count = random(Wave->MinCount, Wave->MaxCount);
+ if(Count > NARRAY(Spawned)){
+ Count = NARRAY(Spawned);
+ }
+
+ for(int i = 0; i < Count; i += 1){
+ int SpawnX = Wave->x + random(-Wave->Spread, Wave->Spread);
+ int SpawnY = Wave->y + random(-Wave->Spread, Wave->Spread);
+ int SpawnZ = Wave->z;
+ if(!SearchFreeField(&SpawnX, &SpawnY, &SpawnZ, 1, 0, false)
+ || IsProtectionZone(SpawnX, SpawnY, SpawnZ)){
+ continue;
+ }
+
+ TCreature *Creature = CreateMonster(Wave->Race, SpawnX, SpawnY, SpawnZ, 0, 0, true);
+ if(Creature != NULL){
+ Creature->Radius = Wave->Radius;
+ if(Wave->Lifetime != 0){
+ Creature->LifeEndRound = RoundNr + Wave->Lifetime;
+ }
+
+ Spawned[NumSpawned] = Creature;
+ NumSpawned += 1;
+ }
+ }
+
+ if(NumSpawned > 0){
+ int ExtraItems = Wave->ExtraItems;
+ for(int i = 1; i <= ExtraItems; i += 1){
+ TItemData *ItemData = Wave->ExtraItem.at(i);
+ if(random(0, 999) > ItemData->Probability){
+ continue;
+ }
+
+ TCreature *Creature = Spawned[random(0, NumSpawned - 1)];
+ Object Bag = GetBodyObject(Creature->ID, 3); // BAG ?
+ if(Bag == NONE){
+ try{
+ Bag = Create(GetBodyContainer(Creature->ID, 3),
+ GetSpecialObject(INVENTORY_CONTAINER),
+ 0);
+ }catch(RESULT r){
+ error("ProcessMonsterRaids: Exception %d bei Rasse %d"
+ " beim Erstellen des Rucksacks.\n", r, Wave->Race);
+ continue;
+ }
+ }
+
+ ObjectType ItemType = ItemData->Type;
+ int Amount = random(1, ItemData->Maximum);
+ int Repeat = 1;
+ if(!ItemType.getFlag(CUMULATIVE)){
+ Repeat = Amount;
+ Amount = 0;
+ }
+
+ print(2, "Verteile %d Objekte vom Typ %d.\n", Amount, ItemType.TypeID);
+ for(int j = 0; j < Repeat; j += 1){
+ // TODO(fusion): What's the difference between using `Create`
+ // and `CreateAtCreature` here? Maybe it checks carry strength,
+ // but then why? Don't they have some check to make sure items
+ // are not dropped onto the map? This is very confusing and
+ // using exception handlers all over the place doesn't help
+ // either.
+ Object Item = NONE;
+ try{
+ // TODO(fusion): Possibly an inlined function to check for
+ // weapons or equipment?
+ if(ItemType.getFlag(WEAPON)
+ || ItemType.getFlag(SHIELD)
+ || ItemType.getFlag(BOW)
+ || ItemType.getFlag(THROW)
+ || ItemType.getFlag(WAND)
+ || ItemType.getFlag(WEAROUT)
+ || ItemType.getFlag(EXPIRE)
+ || ItemType.getFlag(EXPIRESTOP)){
+ Item = Create(Bag, ItemType, 0);
+ }else{
+ Item = CreateAtCreature(Creature->ID, ItemType, Amount);
+ }
+ }catch(RESULT r){
+ error("ProcessMonsterRaids: Exception %d bei Rasse %d, ggf."
+ " CarryStrength erhöhen.\n", r, Wave->Race);
+ break;
+ }
+
+ if(Item.getContainer().getObjectType().isMapContainer()){
+ error("ProcessMonsterRaids: Objekt fällt auf die Karte."
+ " CarryStrength für Rasse %d erhöhen.\n", Wave->Race);
+ Delete(Item, -1);
+ // TODO(fusion): Should probably stop this inner loop here.
+ }
+ }
+
+ // NOTE(fusion): `Bag` could be empty if we failed to add any
+ // items to it in the loop above.
+ if(GetFirstContainerObject(Bag) == NONE){
+ Delete(Bag, -1);
+ }
+ }
+ }
+
+ delete Wave;
+ }
+}
// Initialization
// =============================================================================
diff --git a/src/objects.cc b/src/objects.cc
index 51171f0..198a11d 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -576,7 +576,7 @@ static void LoadObjects(void){
}
}
}else{
- Script.error("Unknown object type field");
+ Script.error("Unknown object type property");
}
}
}
diff --git a/src/stubs.hh b/src/stubs.hh
index 3495a59..d936ab5 100644
--- a/src/stubs.hh
+++ b/src/stubs.hh
@@ -28,12 +28,13 @@ extern void ChallengeMonster(TCreature *Challenger, TCreature *Monster);
extern int CountInventoryObjects(uint32 CreatureID, ObjectType Type, uint32 Value);
extern Object Create(Object Con, ObjectType Type, uint32 Value);
extern Object CreateAtCreature(uint32 CreatureID, ObjectType Type, uint32 Value);
-extern void CreateMonster(int Race, int x, int y, int z, int Home, uint32 Master, bool ShowEffect);
+extern TCreature *CreateMonster(int Race, int x, int y, int z, int Home, uint32 Master, bool ShowEffect);
extern void CreatePlayerList(bool Online);
extern void CreatePool(Object Con, ObjectType Type, uint32 Value);
extern void Delete(Object Obj, int Count);
extern bool FieldPossible(int x, int y, int z, int FieldType);
extern Object GetBodyObject(uint32 CreatureID, int Position);
+extern Object GetBodyContainer(uint32 CreatureID, int Position);
extern void GetExitPosition(uint16 HouseID, int *x, int *y, int *z);
extern TConnection *GetFirstConnection(void);
extern TConnection *GetNextConnection(void);
@@ -62,7 +63,6 @@ extern void ProcessCommunicationControl(void);
extern void ProcessConnections(void);
extern void ProcessCronSystem(void);
extern void ProcessMonsterhomes(void);
-extern void ProcessMonsterRaids(void);
extern void ProcessReaderThreadReplies(TRefreshSectorFunction *RefreshSector, TSendMailsFunction *SendMails);
extern void ProcessWriterThreadReplies(void);
extern void ReceiveData(void);