From 3cc587ab8df80d42d9dab1a73a37701f565a3499 Mon Sep 17 00:00:00 2001 From: fusion32 Date: Sun, 15 Jun 2025 17:35:06 -0300 Subject: more work on `operate.cc` --- reference/game.c | 3241 ++++++++++------------------------------------------ reference/types.hh | 41 - src/connection.hh | 2 + src/containers.hh | 37 +- src/cr.hh | 3 + src/crmain.cc | 23 +- src/crplayer.cc | 1 + src/info.hh | 1 + src/main.cc | 3 +- src/objects.hh | 11 + src/operate.cc | 1025 ++++++++++++++++- src/operate.hh | 96 ++ src/stubs.hh | 38 +- 13 files changed, 1835 insertions(+), 2687 deletions(-) diff --git a/reference/game.c b/reference/game.c index 186295c..5fd4ee7 100644 --- a/reference/game.c +++ b/reference/game.c @@ -18375,2289 +18375,544 @@ void __static_initialization_and_destruction_0(int __initialize_p,int __priority return; } -void Use(ulong CreatureID,Object *Obj1,Object *Obj2,uchar Info) - -{ - bool bVar1; - bool bVar2; - ulong uVar3; - undefined4 *puVar4; - TCreature *pTVar5; - char *Text; - Object *this; - TCreature *cr; - int iStack_68; - uchar Info_local; - int x; - int y; - int z; - Object local_4c [4]; - Object local_3c [4]; - Object local_2c [7]; - - // try { // try from 080970b2 to 080978b7 has its CatchHandler @ 080978d3 - bVar1 = Object::exists(Obj1); - if (bVar1) { - bVar1 = false; - local_2c[0].ObjectID = NONE.ObjectID; - local_3c[0].ObjectID = NONE.ObjectID; - if ((Obj2->ObjectID != NONE.ObjectID) && (bVar2 = Object::exists(Obj2), !bVar2)) { - bVar1 = true; - } - if (!bVar1) { - local_3c[0] = (Object)Obj1->ObjectID; - CheckTopUseObject(CreatureID,local_3c); - local_3c[0] = (Object)Obj1->ObjectID; - bVar1 = ObjectAccessible(CreatureID,local_3c,1); - if (bVar1) { - bVar1 = false; - local_3c[0].ObjectID = NONE.ObjectID; - local_2c[0].ObjectID = NONE.ObjectID; - uVar3 = Obj2->ObjectID; - if (uVar3 != NONE.ObjectID) { - Object::getObjectType(local_2c); - bVar1 = ObjectType::getFlag((ObjectType *)local_2c,DISTUSE); - bVar1 = !bVar1; - uVar3 = Obj2->ObjectID; - } - if (bVar1) { - local_2c[0].ObjectID = uVar3; - CheckTopMultiuseObject(CreatureID,local_2c); - uVar3 = Obj2->ObjectID; - } - bVar1 = false; - local_3c[0].ObjectID = NONE.ObjectID; - local_2c[0].ObjectID = NONE.ObjectID; - if ((uVar3 != NONE.ObjectID) && - (local_2c[0].ObjectID = uVar3, bVar2 = ObjectAccessible(CreatureID,local_2c,1), - !bVar2)) { - bVar1 = true; - } - if (bVar1) { - Object::getObjectType(local_4c); - bVar1 = ObjectType::getFlag((ObjectType *)local_4c,DISTUSE); - if (!bVar1) goto LAB_0809780e; - pTVar5 = GetCreature(CreatureID); - if (pTVar5 == (TCreature *)0x0) { - Text = "Use: Verursachende Kreatur existiert nicht.\n"; - goto LAB_080977f2; - } - local_4c[0] = (Object)Obj2->ObjectID; - GetObjectCoordinates(local_4c,&stack0xffffff98,&x,&y); - if (y < pTVar5->posz) { - puVar4 = (undefined4 *)__cxa_allocate_exception(4); - *puVar4 = 0x17; - goto LAB_0809762d; - } - if (pTVar5->posz < y) { - puVar4 = (undefined4 *)__cxa_allocate_exception(4); - *puVar4 = 0x18; - goto LAB_0809762d; - } - bVar1 = ThrowPossible(pTVar5->posx,pTVar5->posy,pTVar5->posz,iStack_68,x,y,0); - if (!bVar1) { - puVar4 = (undefined4 *)__cxa_allocate_exception(4); - *puVar4 = 7; - goto LAB_0809762d; - } - } - Object::getObjectType(local_4c); - bVar1 = ObjectType::getFlag((ObjectType *)local_4c,CONTAINER); - if (bVar1) { - local_4c[0] = (Object)Obj1->ObjectID; - UseContainer(CreatureID,local_4c,Info); - return; - } - Object::getObjectType(local_4c); - bVar1 = ObjectType::getFlag((ObjectType *)local_4c,CHEST); - if (bVar1) { - local_4c[0] = (Object)Obj1->ObjectID; - UseChest(CreatureID,local_4c); - return; - } - Object::getObjectType(local_4c); - bVar1 = ObjectType::getFlag((ObjectType *)local_4c,LIQUIDCONTAINER); - if (bVar1) { - local_4c[0] = (Object)Obj2->ObjectID; - local_3c[0] = (Object)Obj1->ObjectID; - UseLiquidContainer(CreatureID,local_3c,local_4c); - return; - } - Object::getObjectType(local_4c); - bVar1 = ObjectType::getFlag((ObjectType *)local_4c,FOOD); - if (bVar1) { - local_4c[0] = (Object)Obj1->ObjectID; - UseFood(CreatureID,local_4c); - return; - } - Object::getObjectType(local_4c); - bVar1 = ObjectType::getFlag((ObjectType *)local_4c,WRITE); - if (!bVar1) { - Object::getObjectType(local_4c); - bVar1 = ObjectType::getFlag((ObjectType *)local_4c,WRITEONCE); - if (!bVar1) { - Object::getObjectType(local_4c); - bVar1 = ObjectType::getFlag((ObjectType *)local_4c,INFORMATION); - if (bVar1) { - local_4c[0] = (Object)Obj1->ObjectID; - UseAnnouncer(CreatureID,local_4c); - return; - } - Object::getObjectType(local_4c); - bVar1 = ObjectType::getFlag((ObjectType *)local_4c,RUNE); - if (bVar1) { - local_4c[0] = (Object)Obj2->ObjectID; - local_3c[0] = (Object)Obj1->ObjectID; - UseMagicItem(CreatureID,local_3c,local_4c); - return; - } - Object::getObjectType(local_4c); - bVar1 = ObjectType::getFlag((ObjectType *)local_4c,KEY); - if (bVar1) { - local_4c[0] = (Object)Obj2->ObjectID; - local_3c[0] = (Object)Obj1->ObjectID; - UseKeyDoor(CreatureID,local_3c,local_4c); - return; - } - Object::getObjectType(local_4c); - bVar1 = ObjectType::getFlag((ObjectType *)local_4c,NAMEDOOR); - if (bVar1) { - local_4c[0] = (Object)Obj1->ObjectID; - UseNameDoor(CreatureID,local_4c); - return; - } - Object::getObjectType(local_4c); - bVar1 = ObjectType::getFlag((ObjectType *)local_4c,LEVELDOOR); - if (bVar1) { - local_4c[0] = (Object)Obj1->ObjectID; - UseLevelDoor(CreatureID,local_4c); - return; - } - Object::getObjectType(local_4c); - bVar1 = ObjectType::getFlag((ObjectType *)local_4c,QUESTDOOR); - if (bVar1) { - local_4c[0] = (Object)Obj1->ObjectID; - UseQuestDoor(CreatureID,local_4c); - return; - } - bVar1 = false; - Object::getObjectType(local_4c); - bVar2 = ObjectType::getFlag((ObjectType *)local_4c,WEAPON); - if (bVar2) { - Object::getObjectType(local_4c); - uVar3 = ObjectType::getAttribute((ObjectType *)local_4c,WEAPONTYPE); - bVar2 = false; - if ((0 < (int)uVar3) && ((int)uVar3 < 4)) { - bVar2 = true; - } - if (bVar2) { - local_4c[0] = (Object)NONE.ObjectID; - local_3c[0].ObjectID = NONE.ObjectID; - if (Obj2->ObjectID != NONE.ObjectID) { - Object::getObjectType(local_3c); - bVar2 = ObjectType::getFlag((ObjectType *)local_3c,DESTROY); - if (bVar2) { - bVar1 = true; - } - } - } - } - if (bVar1) { - local_3c[0] = (Object)Obj2->ObjectID; - local_2c[0] = (Object)Obj1->ObjectID; - UseWeapon(CreatureID,local_2c,local_3c); - return; - } - Object::getObjectType(local_3c); - bVar1 = ObjectType::getFlag((ObjectType *)local_3c,CHANGEUSE); - if (bVar1) { - local_3c[0] = (Object)Obj1->ObjectID; - UseChangeObject(CreatureID,local_3c); - return; - } - Object::getObjectType(local_3c); - bVar1 = ObjectType::getFlag((ObjectType *)local_3c,USEEVENT); - if ((bVar1) && - (local_3c[0].ObjectID = NONE.ObjectID, Obj2->ObjectID == NONE.ObjectID)) - { - local_2c[0] = (Object)Obj1->ObjectID; - UseObject(CreatureID,local_2c); - return; - } - Object::getObjectType(local_2c); - bVar1 = ObjectType::getFlag((ObjectType *)local_2c,USEEVENT); - if (bVar1) { - local_2c[0] = (Object)Obj2->ObjectID; - z = Obj1->ObjectID; - UseObjects(CreatureID,(Object *)&z,local_2c); - return; - } - this = (Object *)&z; - Object::getObjectType(this); - bVar1 = ObjectType::getFlag((ObjectType *)this,TEXT); - if (bVar1) { - Object::getObjectType(this); - uVar3 = ObjectType::getAttribute((ObjectType *)this,FONTSIZE); - if (uVar3 == 1) { - z = Obj1->ObjectID; - goto LAB_080972e9; - } - } - puVar4 = (undefined4 *)__cxa_allocate_exception(4); - *puVar4 = 0x1d; - goto LAB_0809762d; - } - } - local_4c[0] = (Object)Obj1->ObjectID; - this = local_4c; -LAB_080972e9: - UseTextObject(CreatureID,this); - return; - } -LAB_0809780e: - puVar4 = (undefined4 *)__cxa_allocate_exception(4); - *puVar4 = 1; - goto LAB_0809762d; - } - Text = &DAT_081001e0; - } - else { - Text = &DAT_08100220; - } -LAB_080977f2: - error(Text); - puVar4 = (undefined4 *)__cxa_allocate_exception(4); - *puVar4 = 0xffffffff; -LAB_0809762d: - // WARNING: Subroutine does not return - __cxa_throw(puVar4,&RESULT::typeinfo,0); -} - - - -void Turn(ulong CreatureID,Object *Obj) - -{ - bool bVar1; - ulong _TypeID; - undefined4 *puVar2; - Object local_4c [4]; - Object local_3c [4]; - Object local_2c; - ObjectType NewType; - - // try { // try from 08097905 to 08097a4e has its CatchHandler @ 08097a63 - bVar1 = Object::exists(Obj); - if (bVar1) { - local_2c = (Object)Obj->ObjectID; - bVar1 = ObjectAccessible(CreatureID,&local_2c,1); - if (bVar1) { - Object::getObjectType(&local_2c); - bVar1 = ObjectType::getFlag((ObjectType *)&local_2c,ROTATE); - if (bVar1) { - Object::getObjectType(local_3c); - _TypeID = ObjectType::getAttribute((ObjectType *)local_3c,ROTATETARGET); - ObjectType::setTypeID((ObjectType *)&local_2c,_TypeID); - ObjectType::setTypeID((ObjectType *)local_3c,0); - if (local_2c.ObjectID == local_3c[0].ObjectID) { - Object::getObjectType(local_4c); - error(&DAT_08100260,local_4c[0].ObjectID); - } - ObjectType::setTypeID((ObjectType *)local_4c,local_2c.ObjectID); - local_3c[0] = (Object)Obj->ObjectID; - Change(local_3c,(ObjectType *)local_4c,0); - return; - } - puVar2 = (undefined4 *)__cxa_allocate_exception(4); - *puVar2 = 0x39; - } - else { - puVar2 = (undefined4 *)__cxa_allocate_exception(4); - *puVar2 = 1; - } - } - else { - error(&DAT_081002a0); - puVar2 = (undefined4 *)__cxa_allocate_exception(4); - *puVar2 = 0xffffffff; - } - // WARNING: Subroutine does not return - __cxa_throw(puVar2,&RESULT::typeinfo,0); -} - - - -// WARNING: Unknown calling convention -- yet parameter storage is locked - -void CreatePool(void) - -{ - bool bVar1; - undefined4 *puVar2; - Object *in_stack_00000004; - int *in_stack_00000008; - char *Text; - Object local_5c [4]; - ObjectType local_4c; - Object Help; - ObjectType local_3c [4]; - Object local_2c; - Object Obj; - - // try { // try from 08097a95 to 08097bba has its CatchHandler @ 08097c76 - bVar1 = Object::exists(in_stack_00000004); - if (bVar1) { - Object::getObjectType(&local_2c); - if (local_2c.ObjectID == 0) { - local_3c[0].TypeID = in_stack_00000004->ObjectID; - GetFirstContainerObject(&local_2c); - if (local_2c.ObjectID != NONE.ObjectID) { - do { - local_4c.TypeID = local_2c.ObjectID; - local_3c[0].TypeID = NONE.ObjectID; - Object::getNextObject(local_5c); - local_2c.ObjectID = local_5c[0].ObjectID; - local_3c[0].TypeID = local_5c[0].ObjectID; - Object::getObjectType(local_5c); - bVar1 = ObjectType::getFlag((ObjectType *)local_5c,BOTTOM); - if (bVar1) { - Object::getObjectType(local_5c); - bVar1 = ObjectType::getFlag((ObjectType *)local_5c,LIQUIDPOOL); - if (!bVar1) { - puVar2 = (undefined4 *)__cxa_allocate_exception(4); - *puVar2 = 4; - goto LAB_08097bef; - } - local_5c[0].ObjectID = local_4c.TypeID; - // try { // try from 08097bd3 to 08097bd7 has its CatchHandler @ 08097c30 - Delete(local_5c,-1); - } - } while (local_2c.ObjectID != NONE.ObjectID); - } - local_4c.TypeID = NONE.ObjectID; - local_3c[0].TypeID = NONE.ObjectID; - ObjectType::setTypeID(&local_4c,*in_stack_00000008); - local_3c[0].TypeID = in_stack_00000004->ObjectID; - Create(local_5c,local_3c,(ulong)&local_4c); - return; - } - Text = &DAT_081002e0; - } - else { - Text = &DAT_08100320; - } - error(Text); - puVar2 = (undefined4 *)__cxa_allocate_exception(4); - *puVar2 = 0xffffffff; -LAB_08097bef: - // WARNING: Subroutine does not return - // try { // try from 08097c02 to 08097c12 has its CatchHandler @ 08097c76 - __cxa_throw(puVar2,&RESULT::typeinfo,0); -} - - - -void EditText(ulong CreatureID,Object *Obj,char *Text) - -{ - bool bVar1; - TCreature *pTVar2; - size_t sVar3; - ulong uVar4; - char *pcVar5; - int iVar6; - undefined4 *puVar7; - TCreature *cr; - - // try { // try from 08097ca8 to 08097f12 has its CatchHandler @ 08097f30 - bVar1 = Object::exists(Obj); - if (bVar1) { - Object::getObjectType((Object *)&cr); - bVar1 = ObjectType::getFlag((ObjectType *)&cr,WRITE); - if (bVar1) { -LAB_08097cdf: - pTVar2 = GetCreature(CreatureID); - if (pTVar2 != (TCreature *)0x0) { - sVar3 = strlen(Text); - Object::getObjectType((Object *)&cr); - bVar1 = ObjectType::getFlag((ObjectType *)&cr,WRITE); - Object::getObjectType((Object *)&cr); - uVar4 = ObjectType::getAttribute((ObjectType *)&cr,!bVar1 + MAXLENGTH); - if (uVar4 <= sVar3) { - puVar7 = (undefined4 *)__cxa_allocate_exception(4); - *puVar7 = 0x28; - goto LAB_08097e92; - } - if (CreatureID != 0) { - cr = (TCreature *)Obj->ObjectID; - bVar1 = ObjectAccessible(CreatureID,(Object *)&cr,1); - if (!bVar1) { - puVar7 = (undefined4 *)__cxa_allocate_exception(4); - *puVar7 = 1; - goto LAB_08097e92; - } - } - uVar4 = Object::getAttribute(Obj,TEXTSTRING); - if ((uVar4 == 0) && (*Text != '\0')) { -LAB_08097dbf: - uVar4 = Object::getAttribute(Obj,TEXTSTRING); - DeleteDynamicString(uVar4); - cr = (TCreature *)Obj->ObjectID; - uVar4 = AddDynamicString(Text); - Change((Object *)&cr,TEXTSTRING,uVar4); - uVar4 = Object::getAttribute(Obj,EDITOR); - DeleteDynamicString(uVar4); - cr = (TCreature *)Obj->ObjectID; - uVar4 = AddDynamicString(pTVar2->Name); - Change((Object *)&cr,EDITOR,uVar4); - } - else { - uVar4 = Object::getAttribute(Obj,TEXTSTRING); - if (uVar4 != 0) { - uVar4 = Object::getAttribute(Obj,TEXTSTRING); - pcVar5 = GetDynamicString(uVar4); - iVar6 = strcmp(Text,pcVar5); - if (iVar6 != 0) goto LAB_08097dbf; - } - print(); - } - return; - } - pcVar5 = "EditText: Kreatur existiert nicht.\n"; - } - else { - Object::getObjectType((Object *)&cr); - bVar1 = ObjectType::getFlag((ObjectType *)&cr,WRITEONCE); - if (bVar1) { - uVar4 = Object::getAttribute(Obj,TEXTSTRING); - if (uVar4 == 0) goto LAB_08097cdf; - } - pcVar5 = "EditText: Objekt ist nicht beschreibbar.\n"; - } - } - else { - pcVar5 = &DAT_08100440; - } - error(pcVar5); - puVar7 = (undefined4 *)__cxa_allocate_exception(4); - *puVar7 = 0xffffffff; -LAB_08097e92: - // WARNING: Subroutine does not return - __cxa_throw(puVar7,&RESULT::typeinfo,0); -} - - - -Object CreateAtCreature(ulong CreatureID,ObjectType *Type,ulong Value) - -{ - bool bVar1; - bool bVar2; - bool bVar3; - TCreature *pTVar4; - undefined4 *puVar5; - int pos; - int iVar6; - ulong in_stack_00000010; - Object *Type_00; - Object *this; - bool local_61; - bool invert; - bool first; - TCreature *cr; - Object local_4c; - Object Obj; - Object local_3c [4]; - Object local_2c [7]; - - // try { // try from 08097f5f to 08097f63 has its CatchHandler @ 08098240 - pTVar4 = GetCreature((ulong)Type); - if (pTVar4 == (TCreature *)0x0) { - // try { // try from 08098159 to 08098187 has its CatchHandler @ 08098240 - error("GiveObjectToCreature: Kann Kreatur nicht finden.\n"); - puVar5 = (undefined4 *)__cxa_allocate_exception(4); - *puVar5 = 0xffffffff; - // WARNING: Subroutine does not return - __cxa_throw(puVar5,&RESULT::typeinfo,0); - } - // try { // try from 08097f7e to 08097fa3 has its CatchHandler @ 08098188 - ObjectType::setTypeID((ObjectType *)local_2c,*(int *)Value); - CheckWeight((ulong)Type,(ObjectType *)local_2c,in_stack_00000010,0); - local_61 = true; - iVar6 = 0; - // try { // try from 08097fb8 to 08097fbc has its CatchHandler @ 08098240 - bVar2 = ObjectType::getFlag((ObjectType *)Value,MOVEMENTEVENT); - while( true ) { - iVar6 = iVar6 + 1; - // try { // try from 08097fd2 to 08097fd6 has its CatchHandler @ 08098210 - GetBodyObject((ulong)&local_4c,(int)Type); - if ((local_61 != bVar2) && - (local_3c[0].ObjectID = NONE.ObjectID, local_4c.ObjectID == NONE.ObjectID)) { - ObjectType::setTypeID((ObjectType *)local_2c,*(int *)Value); - Type_00 = (Object *)&cr; - GetBodyContainer((ulong)Type_00,(int)Type); - this = local_2c; - goto LAB_080980b2; - } - bVar1 = false; - if (local_61 == bVar2) { - cr = (TCreature *)NONE.ObjectID; - local_3c[0].ObjectID = NONE.ObjectID; - if (local_4c.ObjectID != NONE.ObjectID) { - Object::getObjectType(local_3c); - bVar3 = ObjectType::getFlag((ObjectType *)local_3c,CONTAINER); - if (bVar3) { - bVar1 = true; - } - } - } - if (bVar1) break; - if (9 < iVar6) { - if (local_61 == false) { - // try { // try from 08098029 to 0809806b has its CatchHandler @ 08098240 - ObjectType::setTypeID((ObjectType *)&cr,*(int *)Value); - local_3c[0].ObjectID = (pTVar4->CrObject).ObjectID; - GetMapContainer(&local_4c); - Create((Object *)CreatureID,(ObjectType *)&local_4c,(ulong)&cr); - return (Object)CreatureID; - } - local_61 = false; - iVar6 = 0; - } - } - this = local_3c; - // try { // try from 0809808f to 08098131 has its CatchHandler @ 08098210 - ObjectType::setTypeID((ObjectType *)this,*(int *)Value); - Type_00 = local_2c; - local_2c[0].ObjectID = local_4c.ObjectID; -LAB_080980b2: - Create((Object *)CreatureID,(ObjectType *)Type_00,(ulong)this); - return (Object)CreatureID; -} - - - -void DeleteAtCreature(ulong CreatureID,ObjectType *Type,int Amount,ulong Data) - -{ - bool bVar1; - ulong uVar2; - undefined4 *puVar3; - Object *pOVar4; - ulong uVar5; - Object local_3c [4]; - Object local_2c; - Object Obj; - - if (0 < Amount) { - do { - // try { // try from 0809827c to 080983d5 has its CatchHandler @ 080983d6 - ObjectType::setTypeID((ObjectType *)local_3c,Type->TypeID); - uVar2 = CreatureID; - pOVar4 = local_3c; - uVar5 = Data; - GetInventoryObject((ulong)&local_2c,(ObjectType *)CreatureID,(ulong)local_3c); - local_3c[0].ObjectID = NONE.ObjectID; - if (local_2c.ObjectID == NONE.ObjectID) { - error("DeleteAtCreature: Kein Objekt gefunden.\n",uVar2,pOVar4,uVar5); - puVar3 = (undefined4 *)__cxa_allocate_exception(4); - *puVar3 = 0xffffffff; - // WARNING: Subroutine does not return - __cxa_throw(puVar3,&RESULT::typeinfo,0); - } - Object::getObjectType(local_3c); - bVar1 = ObjectType::getFlag((ObjectType *)local_3c,CUMULATIVE); - if ((bVar1) && (uVar2 = Object::getAttribute(&local_2c,AMOUNT), (int)uVar2 <= Amount)) { - uVar2 = Object::getAttribute(&local_2c,AMOUNT); - Amount = Amount - uVar2; - local_3c[0].ObjectID = local_2c.ObjectID; - Delete(local_3c,-1); - } - else { - Object::getObjectType(local_3c); - bVar1 = ObjectType::getFlag((ObjectType *)local_3c,CUMULATIVE); - if (bVar1) { - local_3c[0].ObjectID = local_2c.ObjectID; - uVar2 = Object::getAttribute(&local_2c,AMOUNT); - Change(local_3c,AMOUNT,uVar2 - Amount); - Amount = 0; - } - else { - local_3c[0].ObjectID = local_2c.ObjectID; - Delete(local_3c,-1); - Amount = Amount + -1; - } - } - } while (0 < Amount); - } - return; -} - - - -// WARNING: Unknown calling convention -- yet parameter storage is locked - -void ProcessCronSystem(void) - -{ - bool bVar1; - RESULT r_1; - ulong uVar2; - RESULT r; - Object local_5c [4]; - Object local_4c [4]; - ObjectType local_3c; - ObjectType Dest; - ulong local_2c; - Object Obj; - - while( true ) { - CronCheck(); - local_3c.TypeID = NONE.ObjectID; - if (local_2c == NONE.ObjectID) break; - // try { // try from 08098422 to 080984f7 has its CatchHandler @ 08098508 - Object::getObjectType(local_4c); - uVar2 = ObjectType::getAttribute((ObjectType *)local_4c,EXPIRETARGET); - ObjectType::setTypeID(&local_3c,uVar2); - Object::getObjectType(local_4c); - bVar1 = ObjectType::getFlag((ObjectType *)local_4c,CONTAINER); - if (bVar1) { - ObjectType::setTypeID((ObjectType *)local_4c,0); - if ((local_3c.TypeID == local_4c[0].ObjectID) || - (bVar1 = ObjectType::getFlag(&local_3c,CONTAINER), !bVar1)) { - uVar2 = 0; - } - else { - uVar2 = ObjectType::getAttribute(&local_3c,CAPACITY); - } - Empty(local_5c,uVar2); - } - ObjectType::setTypeID((ObjectType *)local_5c,local_3c.TypeID); - local_4c[0].ObjectID = local_2c; - Change(local_4c,(ObjectType *)local_5c,0); - } - return; -} - - - -bool SectorRefreshable(int SectorX,int SectorY,int SectorZ) - -{ - int iVar1; - ulong id; - TCreature *pTVar2; - undefined1 local_3c [4]; - TFindCreatures SearchPlayers; - - TFindCreatures::TFindCreatures - ((TFindCreatures *)local_3c,0x1f,0x1f,SectorX * 0x20 + 0x10,SectorY * 0x20 + 0x10,1); -LAB_08098600: - do { - while( true ) { - id = TFindCreatures::getNext((TFindCreatures *)local_3c); - if (id == 0) { - return true; - } - pTVar2 = GetCreature(id); - if (pTVar2 != (TCreature *)0x0) break; - error("SectorRefreshable: Kreatur existiert nicht.\n"); - } - iVar1 = pTVar2->posz; - if (iVar1 < 8) { - if (SectorZ < 8) { - return false; - } - if (iVar1 < 8) goto LAB_08098600; - } - if ((SectorZ - iVar1) + 2U < 5) { - return false; - } - } while( true ); -} - - - -// WARNING: Unknown calling convention -- yet parameter storage is locked - -void RefreshSector(void) - -{ - bool bVar1; - bool bVar2; - ulong id; - TCreature *pTVar3; - TCreature *cr; - int in_stack_00000004; - int in_stack_00000008; - int in_stack_0000000c; - uchar *in_stack_00000010; - int in_stack_00000014; - Object *Obj_00; - Object *Con; - int x_00; - int iVar4; - int y_00; - Object *Ignore; - Object *pOStack_a8; - bool PositionOk; - int x; - int y; - int z; - Object local_8c [4]; - Object local_7c [4]; - Object local_6c; - Object Obj; - undefined1 local_5c [4]; - TFindCreatures SearchMonsters; - undefined1 local_2c [4]; - TReadBuffer Buffer; - - bVar1 = SectorRefreshable(in_stack_00000004,in_stack_00000008,in_stack_0000000c); - if (bVar1) { - TReadBuffer::TReadBuffer((TReadBuffer *)local_2c,in_stack_00000010,in_stack_00000014); - RefreshSector(in_stack_00000004,in_stack_00000008,in_stack_0000000c,(TReadStream *)local_2c) - ; - x_00 = in_stack_00000004 * 0x20 + 0x10; - y_00 = in_stack_00000008 * 0x20 + 0x10; - Con = (Object *)0x10; - Obj_00 = (Object *)0x10; - TFindCreatures::TFindCreatures((TFindCreatures *)local_5c,0x10,0x10,x_00,y_00,7); -LAB_08098700: - id = TFindCreatures::getNext((TFindCreatures *)local_5c); - if (id != 0) { - pTVar3 = GetCreature(id); - if (pTVar3 == (TCreature *)0x0) { - error("RefreshSector: Kreatur existiert nicht.\n",Obj_00,Con,x_00,y_00); - } - else { - iVar4 = pTVar3->posz; - if (iVar4 == in_stack_0000000c) { - bVar1 = true; - Obj_00 = (Object *)pTVar3->posx; - Con = (Object *)pTVar3->posy; - pOStack_a8 = Obj_00; - x = (int)Con; - y = iVar4; - GetFirstObject(); - x_00 = iVar4; - if (local_6c.ObjectID != NONE.ObjectID) { - do { - local_8c[0].ObjectID = NONE.ObjectID; - local_7c[0].ObjectID = NONE.ObjectID; - Object::getObjectType(local_8c); - x_00 = iVar4; - if (local_8c[0].ObjectID != 99) { - Object::getObjectType(local_8c); - bVar2 = ObjectType::getFlag((ObjectType *)local_8c,UNPASS); - x_00 = iVar4; - if (bVar2) { - bVar1 = false; - } - } - Obj_00 = &local_6c; - Object::getNextObject(local_7c); - local_6c.ObjectID = local_7c[0].ObjectID; - iVar4 = x_00; - } while (local_7c[0].ObjectID != NONE.ObjectID); - } - local_8c[0].ObjectID = NONE.ObjectID; - local_7c[0].ObjectID = NONE.ObjectID; - if (!bVar1) { - y_00 = 0; - // try { // try from 0809881e to 08098994 has its CatchHandler @ 08098a14 - bVar1 = SearchFreeField((int *)&stack0xffffff58,&x,&y,1,0,false); - if (bVar1) { - local_8c[0].ObjectID = NONE.ObjectID; - GetMapContainer((int)local_7c,(int)pOStack_a8,x); - z = (pTVar3->CrObject).ObjectID; - Ignore = local_8c; - Obj_00 = (Object *)&z; - Con = local_7c; - } - else { - if (pTVar3->Type != NPC) { - if (pTVar3->Type == MONSTER) { - Obj_00 = (Object *)&DAT_08100600; - Con = pOStack_a8; - x_00 = x; - y_00 = y; - print(); - if (pTVar3 != (TCreature *)0x0) { - (*pTVar3->_vptr_TCreature[1])(pTVar3); - } - } - else { - Obj_00 = pOStack_a8; - Con = (Object *)x; - x_00 = y; - error("Spieler auf [%d,%d,%d] ist von Refresh betroffen.\n", - pOStack_a8,x,y); - } - goto LAB_08098700; - } - print(); - Ignore = (Object *)&z; - z = NONE.ObjectID; - GetMapContainer((int)local_8c,pTVar3->startx,pTVar3->starty); - local_7c[0].ObjectID = (pTVar3->CrObject).ObjectID; - Obj_00 = local_7c; - Con = local_8c; - } - y_00 = 0; - x_00 = -1; - Move(0,Obj_00,Con,-1,false,Ignore); - } - } - } - goto LAB_08098700; - } - } - return; -} - - - -// WARNING: Removing unreachable block (ram,0x08098d29) -// WARNING: Unknown calling convention -- yet parameter storage is locked - -void RefreshMap(void) - -{ - byte b; - bool bVar1; - char cVar2; - int DataSize; - int iVar3; - byte *pbVar4; - int iVar5; - int iVar6; - int y; - TWriteStream *SectorY; - char *pcVar7; - undefined1 uVar8; - TWriteStream *__in_chrg; - char *Stream; - char *pcVar9; - int local_5040; - int z; - byte local_5029; - bool Refreshable; - int yy; - int xx; - int x; - TReadBuffer ReadBuffer; - TReadScriptFile Script; - TWriteStream local_102c; - char FileName [4096]; - TDynamicWriteBuffer HelpBuffer; - - __in_chrg = (TWriteStream *)0x10000; - TDynamicWriteBuffer::TDynamicWriteBuffer((TDynamicWriteBuffer *)(FileName + 0xffc),0x10000); - xx = SectorXMin; - iVar5 = SectorXMax; - iVar6 = SectorYMax; - if (SectorXMin <= SectorXMax) { - do { - iVar3 = SectorZMax; - SectorY = (TWriteStream *)SectorYMin; - if (SectorYMin <= iVar6) { - do { - local_5040 = SectorZMin; - if (SectorZMin <= iVar3) { - do { - __in_chrg = SectorY; - // try { // try from 08098afd to 08098b58 has its CatchHandler @ 08098dd0 - bVar1 = SectorRefreshable(xx,(int)SectorY,local_5040); - if (bVar1) { - Stream = (char *)&local_102c; - pcVar9 = ORIGMAPPATH; - __in_chrg = (TWriteStream *)&DAT_080f2af5; - sprintf(Stream,"%s/%04u-%04u-%02u.sec",ORIGMAPPATH,xx,SectorY, - local_5040); - bVar1 = FileExists(Stream); - if (bVar1) { - // try { // try from 08098b66 to 08098b6a has its CatchHandler @ 08098db6 - TReadScriptFile::TReadScriptFile - ((TReadScriptFile *)&ReadBuffer.Position); - // try { // try from 08098b78 to 08098d61 has its CatchHandler @ 08098d75 - TReadScriptFile::open - ((TReadScriptFile *)&ReadBuffer.Position,Stream, - (int)pcVar9); - local_5029 = 0; - yy = -1; - b = 0xff; - while (TReadScriptFile::nextToken - ((TReadScriptFile *)&ReadBuffer.Position), - ReadBuffer.Position != 0) { - if ((ReadBuffer.Position != 6) || - (cVar2 = TReadScriptFile::getSpecial - ((TReadScriptFile *) - &ReadBuffer.Position), cVar2 != ',')) - { - if (ReadBuffer.Position == 4) { - pbVar4 = TReadScriptFile::getBytesequence - ((TReadScriptFile *) - &ReadBuffer.Position); - yy = (int)*pbVar4; - b = pbVar4[1]; - Stream = (char *)0x3a; - TReadScriptFile::readSymbol - ((TReadScriptFile *)&ReadBuffer.Position, - ':'); - local_5029 = 0; - } - else if (ReadBuffer.Position == 1) { - uVar8 = yy == -1; - if ((bool)uVar8) { - Stream = "coordinate expected"; - TReadScriptFile::error - ((TReadScriptFile *) - &ReadBuffer.Position, - "coordinate expected"); - } - pcVar9 = TReadScriptFile::getIdentifier - ((TReadScriptFile *) - &ReadBuffer.Position); - iVar5 = 8; - pcVar7 = "refresh"; - do { - if (iVar5 == 0) break; - iVar5 = iVar5 + -1; - uVar8 = *pcVar9 == *pcVar7; - pcVar9 = pcVar9 + 1; - pcVar7 = pcVar7 + 1; - } while ((bool)uVar8); - if ((bool)uVar8) { - local_5029 = 1; - } - pcVar9 = TReadScriptFile::getIdentifier - ((TReadScriptFile *) - &ReadBuffer.Position); - iVar5 = 8; - pcVar7 = "content"; - do { - if (iVar5 == 0) break; - iVar5 = iVar5 + -1; - uVar8 = *pcVar9 == *pcVar7; - pcVar9 = pcVar9 + 1; - pcVar7 = pcVar7 + 1; - } while ((bool)uVar8); - if ((bool)uVar8) { - TReadScriptFile::readSymbol - ((TReadScriptFile *) - &ReadBuffer.Position,'='); - if (local_5029 != 0) { - TDynamicWriteBuffer::writeByte - ((TDynamicWriteBuffer *) - (FileName + 0xffc),(uchar)yy); - TDynamicWriteBuffer::writeByte - ((TDynamicWriteBuffer *) - (FileName + 0xffc),b); - } - Stream = FileName + 0xffc; - LoadObjects((TReadScriptFile *) - &ReadBuffer.Position, - (TWriteStream *)Stream, - (bool)(local_5029 ^ 1)); - } - } - } - } - TReadScriptFile::close - ((TReadScriptFile *)&ReadBuffer.Position,(int)Stream); - // try { // try from 08098d6b to 08098d6f has its CatchHandler @ 08098db6 - TReadScriptFile::~TReadScriptFile - ((TReadScriptFile *)&ReadBuffer.Position,(int)Stream); - __in_chrg = (TWriteStream *)Stream; - } - } - local_5040 = local_5040 + 1; - iVar3 = SectorZMax; - iVar6 = SectorYMax; - } while (local_5040 <= SectorZMax); - } - SectorY = (TWriteStream *)((int)&SectorY->_vptr_TWriteStream + 1); - iVar5 = SectorXMax; - } while ((int)SectorY <= iVar6); - } - xx = xx + 1; - } while (xx <= iVar5); - } - TDynamicWriteBuffer::~TDynamicWriteBuffer - ((TDynamicWriteBuffer *)(FileName + 0xffc),(int)__in_chrg); - return; -} - - - -// WARNING: Unknown calling convention -- yet parameter storage is locked - -void RefreshCylinders(void) - -{ - bool bVar1; - int iVar2; - int iVar3; - int z; - int iVar4; - int i; - int iVar5; - - if (0 < RefreshedCylinders) { - iVar5 = 0; - iVar2 = RefreshedCylinders; - iVar3 = SectorZMax; - do { - if (RefreshCylinders::RefreshX < SectorXMax) { - RefreshCylinders::RefreshX = RefreshCylinders::RefreshX + 1; - iVar4 = RefreshCylinders::RefreshY; - } - else { - RefreshCylinders::RefreshX = SectorXMin; - iVar4 = SectorYMin; - if (RefreshCylinders::RefreshY < SectorYMax) { - iVar4 = RefreshCylinders::RefreshY + 1; - } - } - RefreshCylinders::RefreshY = iVar4; - iVar4 = SectorZMin; - if (SectorZMin <= iVar3) { - do { - bVar1 = SectorRefreshable(RefreshCylinders::RefreshX,RefreshCylinders::RefreshY, - iVar4); - if (bVar1) { - LoadSectorOrder(RefreshCylinders::RefreshX,RefreshCylinders::RefreshY,iVar4) - ; - } - iVar4 = iVar4 + 1; - iVar2 = RefreshedCylinders; - iVar3 = SectorZMax; - } while (iVar4 <= SectorZMax); - } - iVar5 = iVar5 + 1; - } while (iVar5 < iVar2); - } - return; -} - - - -void ApplyPatch(int SectorX,int SectorY,int SectorZ,bool FullSector,TReadScriptFile *Script, - bool SaveHouses) - -{ - bool bVar1; - bool bVar2; - ulong id; - TCreature *this; - Object *Con; - Object *Con_00; - int x_00; - Object *Ignore; - bool PositionOk; - bool SaveHouses_local; - Object *pOStack_98; - bool FullSector_local; - int x; - int y; - int z; - Object local_7c [4]; - Object local_6c [4]; - ulong local_5c; - Object Obj; - undefined1 local_4c [4]; - TFindCreatures SearchMonsters; - - bVar1 = false; - if ((SectorXMin <= SectorX) && (SectorX <= SectorXMax)) { - bVar1 = true; - } - if (bVar1) { - bVar1 = false; - if ((SectorYMin <= SectorY) && (SectorY <= SectorYMax)) { - bVar1 = true; - } - if (bVar1) { - bVar1 = false; - if ((SectorZMin <= SectorZ) && (SectorZ <= SectorZMax)) { - bVar1 = true; - } - if (bVar1) { - // try { // try from 08098f53 to 08099069 has its CatchHandler @ 08099366 - PrepareHouseCleanup(); - PatchSector(SectorX,SectorY,SectorZ,FullSector,Script,SaveHouses); - FinishHouseCleanup(); - Con_00 = (Object *)0x10; - x_00 = SectorX * 0x20 + 0x10; - Con = (Object *)0x10; - TFindCreatures::TFindCreatures - ((TFindCreatures *)local_4c,0x10,0x10,x_00,SectorY * 0x20 + 0x10,7); -LAB_08098fc1: - id = TFindCreatures::getNext((TFindCreatures *)local_4c); - if (id != 0) { - this = GetCreature(id); - if (this == (TCreature *)0x0) { - error("ApplyPatch: Kreatur existiert nicht.\n",Con,Con_00,x_00); - } - else if (this->posz == SectorZ) { - bVar1 = true; - pOStack_98 = (Object *)this->posx; - x = this->posy; - y = this->posz; - GetFirstObject(); - if (local_5c != NONE.ObjectID) { - do { - local_7c[0].ObjectID = NONE.ObjectID; - local_6c[0].ObjectID = NONE.ObjectID; - Object::getObjectType(local_7c); - if (local_7c[0].ObjectID != 99) { - Object::getObjectType(local_7c); - bVar2 = ObjectType::getFlag((ObjectType *)local_7c,UNPASS); - if (bVar2) { - bVar1 = false; - } - } - Object::getNextObject(local_6c); - local_5c = local_6c[0].ObjectID; - } while (local_6c[0].ObjectID != NONE.ObjectID); - } - local_6c[0].ObjectID = NONE.ObjectID; - if (bVar1) { - local_7c[0].ObjectID = (this->CrObject).ObjectID; - Con = local_6c; - Con_00 = (Object *)x; - x_00 = y; - // try { // try from 080992bc to 0809931c has its CatchHandler @ 08099366 - GetMapContainer((int)Con,(int)pOStack_98,x); - MoveObject(local_7c,Con); - } - else { - local_7c[0].ObjectID = NONE.ObjectID; - // try { // try from 080990c4 to 0809926a has its CatchHandler @ 08099322 - bVar1 = SearchFreeField((int *)&stack0xffffff68,&x,&y,1,0,false); - if (bVar1) { - Con = local_6c; - local_7c[0].ObjectID = NONE.ObjectID; - local_6c[0].ObjectID = (this->CrObject).ObjectID; - Con_00 = (Object *)&z; - GetMapContainer((int)Con_00,(int)pOStack_98,x); - Ignore = local_7c; - } - else { - if (this->Type != NPC) { - if (this->Type == MONSTER) { - x_00 = x; - print(); - z = (this->CrObject).ObjectID; - Delete((Object *)&z,-1); - Con_00 = (Object *)0x0; - Con = (Object *)0x0; - TCreature::StartLogout(this,false,false); - } - else { - Con = pOStack_98; - Con_00 = (Object *)x; - x_00 = y; - error("Spieler auf [%d,%d,%d] ist von Patch betroffen.\n", - pOStack_98,x,y); - } - goto LAB_08098fc1; - } - print(); - Con_00 = local_6c; - z = NONE.ObjectID; - local_7c[0].ObjectID = (this->CrObject).ObjectID; - GetMapContainer((int)Con_00,this->startx,this->starty); - Ignore = (Object *)&z; - Con = local_7c; - } - x_00 = -1; - Move(0,Con,Con_00,-1,false,Ignore); - } - } - goto LAB_08098fc1; - } - } - } - } - return; -} - - - -// WARNING: Unknown calling convention -- yet parameter storage is locked - -void ApplyPatches(void) - -{ - bool bVar1; - DIR *__dirp; - dirent *pdVar2; - size_t sVar3; - int iVar4; - int iVar5; - dirent *DirEntry; - char *pcVar6; - undefined1 uVar7; - char *pcVar8; - char *pcVar9; - int local_5018; - int MaxPatch; - DIR *WorkDir; - int iStack_500c; - bool SaveHouses; - int x; - int y; - int z; - int nr; - TReadScriptFile Script; - char local_101c [4]; - char FileName [4096]; - - sprintf(local_101c,"%s/save-houses",SAVEPATH); - // try { // try from 080993ba to 08099525 has its CatchHandler @ 0809979b - bVar1 = FileExists(local_101c); - if (bVar1) { - print(); - unlink(local_101c); - } - __dirp = opendir(SAVEPATH); - if (__dirp == (DIR *)0x0) { - // try { // try from 08099746 to 08099763 has its CatchHandler @ 0809979b - error("ApplyPatches: Unterverzeichnis %s nicht gefunden.\n",SAVEPATH); - } - else { - local_5018 = -1; -LAB_080993f0: - pdVar2 = readdir(__dirp); - if (pdVar2 != (dirent *)0x0) { - pcVar9 = pdVar2->d_name; - sVar3 = strlen(pcVar9); - uVar7 = sVar3 == 4; - if (4 < sVar3) { - iVar5 = 5; - pcVar8 = pdVar2->d_name + (sVar3 - 4); - pcVar6 = ".pat"; - do { - if (iVar5 == 0) break; - iVar5 = iVar5 + -1; - uVar7 = *pcVar8 == *pcVar6; - pcVar8 = pcVar8 + 1; - pcVar6 = pcVar6 + 1; - } while ((bool)uVar7); - if ((bool)uVar7) { - iVar5 = sscanf(pcVar9,"%d.pat",&z); - uVar7 = iVar5 == 1; - if ((bool)uVar7) { - if (local_5018 < z) { - local_5018 = z; - } - goto LAB_080993f0; - } - } - sVar3 = strlen(pcVar9); - iVar5 = 5; - pcVar8 = pdVar2->d_name + (sVar3 - 4); - pcVar6 = ".sec"; - do { - if (iVar5 == 0) break; - iVar5 = iVar5 + -1; - uVar7 = *pcVar8 == *pcVar6; - pcVar8 = pcVar8 + 1; - pcVar6 = pcVar6 + 1; - } while ((bool)uVar7); - if (((bool)uVar7) && - (iVar5 = sscanf(pcVar9,"%d-%d-%d.sec",&stack0xffffaff4,&x,&y), iVar5 == 3)) { - iVar5 = y; - print(); - pcVar8 = SAVEPATH; - sprintf(local_101c,"%s/%s",SAVEPATH,pcVar9,iVar5); - TReadScriptFile::TReadScriptFile((TReadScriptFile *)&nr); - // try { // try from 08099533 to 08099578 has its CatchHandler @ 08099778 - TReadScriptFile::open((TReadScriptFile *)&nr,local_101c,(int)pcVar8); - iVar5 = x; - ApplyPatch(iStack_500c,x,y,true,(TReadScriptFile *)&nr,bVar1); - TReadScriptFile::close((TReadScriptFile *)&nr,iVar5); - unlink(local_101c); - // try { // try from 0809958a to 0809961a has its CatchHandler @ 0809979b - TReadScriptFile::~TReadScriptFile((TReadScriptFile *)&nr,iVar5); - } - } - goto LAB_080993f0; - } - iVar5 = 0; - closedir(__dirp); - if (-1 < local_5018) { - do { - pcVar9 = SAVEPATH; - sprintf(local_101c,"%s/%03d.pat",SAVEPATH,iVar5); - bVar1 = FileExists(local_101c); - if (bVar1) { - TReadScriptFile::TReadScriptFile((TReadScriptFile *)&nr); - // try { // try from 08099622 to 08099706 has its CatchHandler @ 08099778 - TReadScriptFile::open((TReadScriptFile *)&nr,local_101c,(int)pcVar9); - pcVar9 = TReadScriptFile::readIdentifier((TReadScriptFile *)&nr); - iVar4 = stricmp(pcVar9,"sector",-1); - if (iVar4 != 0) { - // try { // try from 0809972d to 08099731 has its CatchHandler @ 08099778 - TReadScriptFile::error((TReadScriptFile *)&nr,"Sector expected"); - } - iStack_500c = TReadScriptFile::readNumber((TReadScriptFile *)&nr); - TReadScriptFile::readSymbol((TReadScriptFile *)&nr,','); - x = TReadScriptFile::readNumber((TReadScriptFile *)&nr); - TReadScriptFile::readSymbol((TReadScriptFile *)&nr,','); - y = TReadScriptFile::readNumber((TReadScriptFile *)&nr); - print(); - iVar4 = x; - ApplyPatch(iStack_500c,x,y,false,(TReadScriptFile *)&nr,false); - TReadScriptFile::close((TReadScriptFile *)&nr,iVar4); - unlink(local_101c); - // try { // try from 08099718 to 0809971c has its CatchHandler @ 0809979b - TReadScriptFile::~TReadScriptFile((TReadScriptFile *)&nr,iVar4); - } - iVar5 = iVar5 + 1; - } while (iVar5 <= local_5018); - } - } - return; -} - - - -// WARNING: Unknown calling convention -- yet parameter storage is locked - -int GetNumberOfChannels(void) - -{ - return Channels; -} - - - -bool ChannelActive(int ChannelID) - -{ - TChannel *pTVar1; - bool bVar2; - - if ((ChannelID < 0) || (Channels <= ChannelID)) { - error(&DAT_080ffea0,ChannelID); - bVar2 = false; - } - else { - bVar2 = true; - if (7 < ChannelID) { - pTVar1 = vector::operator()(&Channel,ChannelID); - bVar2 = pTVar1->Moderator != 0; - } - } - return bVar2; -} - - - -bool ChannelAvailable(int ChannelID,ulong CharacterID) - -{ - TPlayer *pl; - TPlayer *pTVar1; - TChannel *pTVar2; - ulong *puVar3; - int i; - TChannel *C; - bool bVar4; - RIGHT Right; - - if ((ChannelID < 0) || (Channels <= ChannelID)) { - error(&DAT_080ffea0,ChannelID); - bVar4 = false; - } - else { - bVar4 = true; - if (7 < ChannelID) { - pTVar2 = vector::operator()(&Channel,ChannelID); - bVar4 = pTVar2->Moderator != 0; - } - } - if (!bVar4) { - return false; - } - pTVar1 = GetPlayer(CharacterID); - if (pTVar1 == (TPlayer *)0x0) { - error("ChannelAvailable: Spieler existiert nicht.\n"); - return false; - } - switch(ChannelID) { - case 0: - return pTVar1->Guild[0] != '\0'; - case 1: - case 3: - Right = READ_GAMEMASTER_CHANNEL; - break; - case 2: - Right = READ_TUTOR_CHANNEL; - break; - case 4: - case 5: - case 6: - case 7: - return true; - default: - if (ChannelID < 8) { - return false; - } - pTVar2 = vector::operator()(&Channel,ChannelID); - if (CharacterID == pTVar2->Moderator) { - return true; - } - i = 0; - if (pTVar2->InvitedPlayers < 1) { - return false; - } - do { - puVar3 = vector<>::operator()(&pTVar2->InvitedPlayer,i); - if (CharacterID == *puVar3) { - return true; - } - i = i + 1; - } while (i < pTVar2->InvitedPlayers); - return false; - } - bVar4 = CheckRight(CharacterID,Right); - return bVar4; -} - - - -char * GetChannelName(int ChannelID,ulong CharacterID) - -{ - TPlayer *pTVar1; - TChannel *pTVar2; - char *pcVar3; - bool bVar4; - - if ((ChannelID < 0) || (Channels <= ChannelID)) { - error(&DAT_080ffea0,ChannelID); - bVar4 = false; - } - else { - bVar4 = true; - if (7 < ChannelID) { - pTVar2 = vector::operator()(&Channel,ChannelID); - bVar4 = pTVar2->Moderator != 0; - } - } - if (!bVar4) { - return "Unknown"; - } - pTVar1 = GetPlayer(CharacterID); - if (pTVar1 == (TPlayer *)0x0) { - error("GetChannelName: Spieler existiert nicht.\n"); -LAB_080999fd: - pcVar3 = "Unknown"; - } - else { - switch(ChannelID) { - case 0: - pcVar3 = pTVar1->Guild; - break; - case 1: - pcVar3 = "Gamemaster"; - break; - case 2: - pcVar3 = "Tutor"; - break; - case 3: - pcVar3 = "Rule Violations"; - break; - case 4: - pcVar3 = "Game-Chat"; - break; - case 5: - pcVar3 = "Trade"; - break; - case 6: - pcVar3 = "RL-Chat"; - break; - case 7: - pcVar3 = "Help"; - break; - default: - if (7 < ChannelID) { - pTVar2 = vector::operator()(&Channel,ChannelID); - sprintf(GetChannelName::ChannelName,"%s\'s Channel",pTVar2->ModeratorName); - return GetChannelName::ChannelName; - } - error("GetChannelName: Unbenutzter Kanal %d.\n",ChannelID); - goto LAB_080999fd; - } - } - return pcVar3; -} - - - -bool ChannelSubscribed(int ChannelID,ulong CharacterID) - -{ - TChannel *pTVar1; - ulong *puVar2; - int i; - TChannel *C; - bool bVar3; - - if ((ChannelID < 0) || (Channels <= ChannelID)) { - error(&DAT_080ffea0,ChannelID); - bVar3 = false; - } - else { - bVar3 = true; - if (7 < ChannelID) { - pTVar1 = vector::operator()(&Channel,ChannelID); - bVar3 = pTVar1->Moderator != 0; - } - } - if (bVar3) { - i = 0; - pTVar1 = vector::operator()(&Channel,ChannelID); - if (0 < pTVar1->Subscribers) { - do { - puVar2 = vector<>::operator()(&pTVar1->Subscriber,i); - if (CharacterID == *puVar2) { - return true; - } - i = i + 1; - } while (i < pTVar1->Subscribers); - } - } - return false; -} - - - -ulong GetFirstSubscriber(int ChannelID) - -{ - int i; - TChannel *pTVar1; - ulong *puVar2; - TChannel *C; - ulong uVar3; - bool bVar4; - - if ((ChannelID < 0) || (Channels <= ChannelID)) { - error(&DAT_080ffea0,ChannelID); - bVar4 = false; - } - else { - bVar4 = true; - if (7 < ChannelID) { - pTVar1 = vector::operator()(&Channel,ChannelID); - bVar4 = pTVar1->Moderator != 0; - } - } - uVar3 = 0; - if (bVar4) { - CurrentChannelID = ChannelID; - CurrentSubscriberNumber = 0; - if ((ChannelID < 0) || (Channels <= ChannelID)) { - error(&DAT_080ffea0,ChannelID); - bVar4 = false; - } - else { - bVar4 = true; - if (7 < ChannelID) { - pTVar1 = vector::operator()(&Channel,ChannelID); - bVar4 = pTVar1->Moderator != 0; - } - } - uVar3 = 0; - if (bVar4) { - pTVar1 = vector::operator()(&Channel,CurrentChannelID); - i = CurrentSubscriberNumber; - if (CurrentSubscriberNumber < pTVar1->Subscribers) { - CurrentSubscriberNumber = CurrentSubscriberNumber + 1; - puVar2 = vector<>::operator()(&pTVar1->Subscriber,i); - uVar3 = *puVar2; - } - else { - uVar3 = 0; - } - } - } - return uVar3; -} - - - // WARNING: Unknown calling convention -- yet parameter storage is locked -ulong GetNextSubscriber(void) +int GetNumberOfChannels(void) { - int i; - TChannel *pTVar1; - ulong *puVar2; - TChannel *C; - ulong uVar3; - bool bVar4; - - if ((CurrentChannelID < 0) || (Channels <= CurrentChannelID)) { - error(&DAT_080ffea0,CurrentChannelID); - bVar4 = false; - } - else { - bVar4 = true; - if (7 < CurrentChannelID) { - pTVar1 = vector::operator()(&Channel,CurrentChannelID); - bVar4 = pTVar1->Moderator != 0; - } - } - uVar3 = 0; - if (bVar4) { - pTVar1 = vector::operator()(&Channel,CurrentChannelID); - i = CurrentSubscriberNumber; - if (CurrentSubscriberNumber < pTVar1->Subscribers) { - CurrentSubscriberNumber = CurrentSubscriberNumber + 1; - puVar2 = vector<>::operator()(&pTVar1->Subscriber,i); - uVar3 = *puVar2; - } - else { - uVar3 = 0; - } - } - return uVar3; + return Channels; } -bool MayOpenChannel(ulong CharacterID) +bool ChannelActive(int ChannelID) { - bool bVar1; - TChannel *pTVar2; - bool bVar3; - int i; - int i_00; + TChannel *pTVar1; + bool bVar2; - if (Channels < 0xffff) { - bVar1 = CheckRight(CharacterID,PREMIUM_ACCOUNT); - bVar3 = false; - if (bVar1) { - i_00 = 8; - if (8 < Channels) { - do { - pTVar2 = vector::operator()(&Channel,i_00); - if (pTVar2->Moderator == CharacterID) goto LAB_08099cfb; - i_00 = i_00 + 1; - } while (i_00 < Channels); - } - bVar3 = true; - } + if ((ChannelID < 0) || (Channels <= ChannelID)) { + error(&DAT_080ffea0,ChannelID); + bVar2 = false; } else { -LAB_08099cfb: - bVar3 = false; + bVar2 = true; + if (7 < ChannelID) { + pTVar1 = vector::operator()(&Channel,ChannelID); + bVar2 = pTVar1->Moderator != 0; + } } - return bVar3; + return bVar2; } -// WARNING: Variable defined which should be unmapped: pl - -void OpenChannel(ulong CharacterID) +bool ChannelAvailable(int ChannelID,ulong CharacterID) { - bool bVar1; - TPlayer *pTVar2; - TChannel *pTVar3; - ulong *puVar4; - undefined4 *puVar5; - int ChannelID; + TPlayer *pl; + TPlayer *pTVar1; + TChannel *pTVar2; + ulong *puVar3; int i; TChannel *C; - int i_00; - TPlayer *pl; + bool bVar4; + RIGHT Right; - // try { // try from 08099d75 to 08099ef2 has its CatchHandler @ 08099ef5 - pTVar2 = GetPlayer(CharacterID); - if (pTVar2 == (TPlayer *)0x0) { - error("OpenChannel: Kreatur %lu existiert nicht.\n",CharacterID); + if ((ChannelID < 0) || (Channels <= ChannelID)) { + error(&DAT_080ffea0,ChannelID); + bVar4 = false; } else { - if (Channels < 0xffff) { - bVar1 = CheckRight(CharacterID,PREMIUM_ACCOUNT); - if (bVar1) { - i = 8; - if (8 < Channels) { - do { - pTVar3 = vector::operator()(&Channel,i); - if (pTVar3->Moderator == CharacterID) goto LAB_08099e20; - i = i + 1; - } while (i < Channels); - } - i_00 = 8; - i = Channels; - if (8 < Channels) { - do { - pTVar3 = vector::operator()(&Channel,i_00); - if (pTVar3->Moderator == 0) { - i = i_00; - } - i_00 = i_00 + 1; - } while (i_00 < Channels); - } - if (i == Channels) { - Channels = i + 1; - } - pTVar3 = vector::operator()(&Channel,i); - pTVar3->Moderator = CharacterID; - strcpy(pTVar3->ModeratorName,(pTVar2->super_TCreature).Name); - puVar4 = vector<>::operator()(&pTVar3->Subscriber,0); - *puVar4 = CharacterID; - pTVar3->Subscribers = 1; - pTVar3->InvitedPlayers = 0; -LAB_08099e20: - SendOpenOwnChannel((pTVar2->super_TCreature).Connection,i); - return; - } - puVar5 = (undefined4 *)__cxa_allocate_exception(4); - *puVar5 = 0x33; - goto LAB_08099eab; + bVar4 = true; + if (7 < ChannelID) { + pTVar2 = vector::operator()(&Channel,ChannelID); + bVar4 = pTVar2->Moderator != 0; } - error(&DAT_081009a0); } - puVar5 = (undefined4 *)__cxa_allocate_exception(4); - *puVar5 = 0xffffffff; -LAB_08099eab: - // WARNING: Subroutine does not return - __cxa_throw(puVar5,&RESULT::typeinfo,0); -} - - - -void CloseChannel(int ChannelID) - -{ - TChannel *pTVar1; - - if ((ChannelID < 8) || (Channels <= ChannelID)) { - error(&DAT_08100a00,ChannelID); - } - else { - pTVar1 = vector::operator()(&Channel,ChannelID); - if (pTVar1->Moderator == 0) { - error("CloseChannel: Kanal ist schon geschlossen.\n"); - return; - } - pTVar1->Moderator = 0; + if (!bVar4) { + return false; } - return; -} - - - -// WARNING: Variable defined which should be unmapped: Opp - -void InviteToChannel(ulong CharacterID,char *Name) - -{ - bool bVar1; - TPlayer *pTVar2; - int iVar3; - ulong *puVar4; - undefined4 *puVar5; - TChannel *pTVar6; - char *pcVar7; - ulong OppID; - TChannel *pTVar8; - ulong uVar9; - TPlayer *pl; - int local_20; - int i_1; - TChannel *C; - int channel; - TPlayer *Opp; - - // try { // try from 08099f85 to 0809a218 has its CatchHandler @ 0809a220 - pTVar2 = GetPlayer(CharacterID); - if (pTVar2 == (TPlayer *)0x0) { - error("InviteToChannel: Kreatur %lu existiert nicht.\n",CharacterID); - return; + pTVar1 = GetPlayer(CharacterID); + if (pTVar1 == (TPlayer *)0x0) { + error("ChannelAvailable: Spieler existiert nicht.\n"); + return false; } - C = (TChannel *)0xffffffff; - pTVar8 = (TChannel *)0x8; - if (8 < Channels) { + switch(ChannelID) { + case 0: + return pTVar1->Guild[0] != '\0'; + case 1: + case 3: + Right = READ_GAMEMASTER_CHANNEL; + break; + case 2: + Right = READ_TUTOR_CHANNEL; + break; + case 4: + case 5: + case 6: + case 7: + return true; + default: + if (ChannelID < 8) { + return false; + } + pTVar2 = vector::operator()(&Channel,ChannelID); + if (CharacterID == pTVar2->Moderator) { + return true; + } + i = 0; + if (pTVar2->InvitedPlayers < 1) { + return false; + } do { - pTVar6 = vector::operator()(&Channel,(int)pTVar8); - if (pTVar6->Moderator == CharacterID) { - C = pTVar8; + puVar3 = vector<>::operator()(&pTVar2->InvitedPlayer,i); + if (CharacterID == *puVar3) { + return true; } - pTVar8 = (TChannel *)((int)&pTVar8->Moderator + 1); - } while ((int)pTVar8 < Channels); - } - if (C == (TChannel *)0xffffffff) { - return; + i = i + 1; + } while (i < pTVar2->InvitedPlayers); + return false; } - uVar9 = 0; - channel = 0; - bVar1 = CheckRight((pTVar2->super_TCreature).ID,READ_GAMEMASTER_CHANNEL); - iVar3 = IdentifyPlayer(Name,false,!bVar1,(TPlayer **)&channel); - if (iVar3 == -1) { - uVar9 = GetCharacterID(Name); - if (uVar9 == 0) { - puVar5 = (undefined4 *)__cxa_allocate_exception(4); - *puVar5 = 0x1a; -LAB_0809a19d: - // WARNING: Subroutine does not return - __cxa_throw(puVar5,&RESULT::typeinfo,0); - } + bVar4 = CheckRight(CharacterID,Right); + return bVar4; +} + + + +char * GetChannelName(int ChannelID,ulong CharacterID) + +{ + TPlayer *pTVar1; + TChannel *pTVar2; + char *pcVar3; + bool bVar4; + + if ((ChannelID < 0) || (Channels <= ChannelID)) { + error(&DAT_080ffea0,ChannelID); + bVar4 = false; } else { - if (-1 < iVar3) { - if (iVar3 == 0) { - uVar9 = *(ulong *)(channel + 0x208); - Name = (char *)(channel + 0x214); - } - goto LAB_0809a01f; - } - if (iVar3 != -2) goto LAB_0809a01f; - uVar9 = GetCharacterID(Name); - if (uVar9 == 0) { - puVar5 = (undefined4 *)__cxa_allocate_exception(4); - *puVar5 = 0x1c; - goto LAB_0809a19d; + bVar4 = true; + if (7 < ChannelID) { + pTVar2 = vector::operator()(&Channel,ChannelID); + bVar4 = pTVar2->Moderator != 0; } } - Name = GetCharacterName(Name); -LAB_0809a01f: - print(); - pTVar8 = vector::operator()(&Channel,(int)C); - if (CharacterID != uVar9) { - local_20 = 0; - iVar3 = pTVar8->InvitedPlayers; - if (0 < iVar3) { - do { - puVar4 = vector<>::operator()(&pTVar8->InvitedPlayer,local_20); - if (*puVar4 == uVar9) { - SendMessage((pTVar2->super_TCreature).Connection,0x16, - "%s has already been invited.",Name); - return; - } - local_20 = local_20 + 1; - iVar3 = pTVar8->InvitedPlayers; - } while (local_20 < iVar3); - } - puVar4 = vector<>::operator()(&pTVar8->InvitedPlayer,iVar3); - *puVar4 = uVar9; - pTVar8->InvitedPlayers = pTVar8->InvitedPlayers + 1; - SendMessage((pTVar2->super_TCreature).Connection,0x16,"%s has been invited.",Name); - if (channel != 0) { - pcVar7 = "his"; - if ((pTVar2->super_TCreature).Sex != 1) { - pcVar7 = "her"; + if (!bVar4) { + return "Unknown"; + } + pTVar1 = GetPlayer(CharacterID); + if (pTVar1 == (TPlayer *)0x0) { + error("GetChannelName: Spieler existiert nicht.\n"); +LAB_080999fd: + pcVar3 = "Unknown"; + } + else { + switch(ChannelID) { + case 0: + pcVar3 = pTVar1->Guild; + break; + case 1: + pcVar3 = "Gamemaster"; + break; + case 2: + pcVar3 = "Tutor"; + break; + case 3: + pcVar3 = "Rule Violations"; + break; + case 4: + pcVar3 = "Game-Chat"; + break; + case 5: + pcVar3 = "Trade"; + break; + case 6: + pcVar3 = "RL-Chat"; + break; + case 7: + pcVar3 = "Help"; + break; + default: + if (7 < ChannelID) { + pTVar2 = vector::operator()(&Channel,ChannelID); + sprintf(GetChannelName::ChannelName,"%s\'s Channel",pTVar2->ModeratorName); + return GetChannelName::ChannelName; } - SendMessage(*(TConnection **)(channel + 0x318),0x16, - "%s invites you to %s private chat channel.",(pTVar2->super_TCreature).Name, - pcVar7); + error("GetChannelName: Unbenutzter Kanal %d.\n",ChannelID); + goto LAB_080999fd; } } - return; + return pcVar3; } -// WARNING: Variable defined which should be unmapped: Opp - -void ExcludeFromChannel(ulong CharacterID,char *Name) +bool ChannelSubscribed(int ChannelID,ulong CharacterID) { - bool bVar1; - TPlayer *pTVar2; - int iVar3; - ulong *puVar4; - ulong *puVar5; - undefined4 *puVar6; - TChannel *pTVar7; - ulong OppID; - TChannel *pTVar8; - ulong CharacterID_00; + TChannel *pTVar1; + ulong *puVar2; int i; - int local_24; - int Position; TChannel *C; - int channel; - TPlayer *pl; - TPlayer *Opp; + bool bVar3; - // try { // try from 0809a258 to 0809a4fe has its CatchHandler @ 0809a504 - pTVar2 = GetPlayer(CharacterID); - if (pTVar2 == (TPlayer *)0x0) { - error("ExcludeFromChannel: Kreatur %lu existiert nicht.\n",CharacterID); + if ((ChannelID < 0) || (Channels <= ChannelID)) { + error(&DAT_080ffea0,ChannelID); + bVar3 = false; } else { - C = (TChannel *)0xffffffff; - pTVar8 = (TChannel *)0x8; - if (8 < Channels) { - do { - pTVar7 = vector::operator()(&Channel,(int)pTVar8); - if (pTVar7->Moderator == CharacterID) { - C = pTVar8; - } - pTVar8 = (TChannel *)((int)&pTVar8->Moderator + 1); - } while ((int)pTVar8 < Channels); + bVar3 = true; + if (7 < ChannelID) { + pTVar1 = vector::operator()(&Channel,ChannelID); + bVar3 = pTVar1->Moderator != 0; } - if (C != (TChannel *)0xffffffff) { - CharacterID_00 = 0; - pl = (TPlayer *)0x0; - bVar1 = CheckRight((pTVar2->super_TCreature).ID,READ_GAMEMASTER_CHANNEL); - iVar3 = IdentifyPlayer(Name,false,!bVar1,&pl); - if (iVar3 == -1) { - CharacterID_00 = GetCharacterID(Name); - if (CharacterID_00 == 0) { - puVar6 = (undefined4 *)__cxa_allocate_exception(4); - *puVar6 = 0x1a; -LAB_0809a484: - // WARNING: Subroutine does not return - __cxa_throw(puVar6,&RESULT::typeinfo,0); - } - } - else if (iVar3 < 0) { - if ((iVar3 == -2) && (CharacterID_00 = GetCharacterID(Name), CharacterID_00 == 0)) { - puVar6 = (undefined4 *)__cxa_allocate_exception(4); - *puVar6 = 0x1c; - goto LAB_0809a484; - } - } - else if (iVar3 == 0) { - CharacterID_00 = (pl->super_TCreature).ID; - Name = (pl->super_TCreature).Name; - } - print(); - pTVar8 = vector::operator()(&Channel,(int)C); - if (CharacterID != CharacterID_00) { - local_24 = -1; - iVar3 = pTVar8->InvitedPlayers; - i = 0; - if (0 < iVar3) { - do { - puVar4 = vector<>::operator()(&pTVar8->InvitedPlayer,i); - if (*puVar4 == CharacterID_00) { - local_24 = i; - } - i = i + 1; - iVar3 = pTVar8->InvitedPlayers; - } while (i < iVar3); - } - if (local_24 == -1) { - SendMessage((pTVar2->super_TCreature).Connection,0x16,"%s has not been invited." - ,Name); - } - else { - pTVar8->InvitedPlayers = iVar3 + -1; - puVar4 = vector<>::operator()(&pTVar8->InvitedPlayer,local_24); - puVar5 = vector<>::operator()(&pTVar8->InvitedPlayer,pTVar8->InvitedPlayers); - *puVar4 = *puVar5; - SendMessage((pTVar2->super_TCreature).Connection,0x16,"%s has been excluded.", - Name); - bVar1 = ChannelSubscribed((int)C,CharacterID_00); - if (bVar1) { - LeaveChannel((int)C,CharacterID_00,false); - SendCloseChannel((pl->super_TCreature).Connection,(int)C); - } + } + if (bVar3) { + i = 0; + pTVar1 = vector::operator()(&Channel,ChannelID); + if (0 < pTVar1->Subscribers) { + do { + puVar2 = vector<>::operator()(&pTVar1->Subscriber,i); + if (CharacterID == *puVar2) { + return true; } - } + i = i + 1; + } while (i < pTVar1->Subscribers); } } - return; + return false; } -bool JoinChannel(int ChannelID,ulong CharacterID) +ulong GetFirstSubscriber(int ChannelID) { - bool bVar1; - TChannel *pTVar2; - ulong *puVar3; - undefined4 *puVar4; + int i; + TChannel *pTVar1; + ulong *puVar2; TChannel *C; + ulong uVar3; + bool bVar4; if ((ChannelID < 0) || (Channels <= ChannelID)) { - // try { // try from 0809a550 to 0809a61d has its CatchHandler @ 0809a630 error(&DAT_080ffea0,ChannelID); - bVar1 = false; + bVar4 = false; } else { - bVar1 = true; + bVar4 = true; if (7 < ChannelID) { - pTVar2 = vector::operator()(&Channel,ChannelID); - bVar1 = pTVar2->Moderator != 0; + pTVar1 = vector::operator()(&Channel,ChannelID); + bVar4 = pTVar1->Moderator != 0; } } - if (bVar1) { - bVar1 = ChannelAvailable(ChannelID,CharacterID); - if (bVar1) { - pTVar2 = vector::operator()(&Channel,ChannelID); - bVar1 = ChannelSubscribed(ChannelID,CharacterID); - if (!bVar1) { - puVar3 = vector<>::operator()(&pTVar2->Subscriber,pTVar2->Subscribers); - *puVar3 = CharacterID; - pTVar2->Subscribers = pTVar2->Subscribers + 1; + uVar3 = 0; + if (bVar4) { + CurrentChannelID = ChannelID; + CurrentSubscriberNumber = 0; + if ((ChannelID < 0) || (Channels <= ChannelID)) { + error(&DAT_080ffea0,ChannelID); + bVar4 = false; + } + else { + bVar4 = true; + if (7 < ChannelID) { + pTVar1 = vector::operator()(&Channel,ChannelID); + bVar4 = pTVar1->Moderator != 0; + } + } + uVar3 = 0; + if (bVar4) { + pTVar1 = vector::operator()(&Channel,CurrentChannelID); + i = CurrentSubscriberNumber; + if (CurrentSubscriberNumber < pTVar1->Subscribers) { + CurrentSubscriberNumber = CurrentSubscriberNumber + 1; + puVar2 = vector<>::operator()(&pTVar1->Subscriber,i); + uVar3 = *puVar2; + } + else { + uVar3 = 0; } - return CharacterID == pTVar2->Moderator; } - puVar4 = (undefined4 *)__cxa_allocate_exception(4); - *puVar4 = 1; - } - else { - puVar4 = (undefined4 *)__cxa_allocate_exception(4); - *puVar4 = 0xffffffff; } - // WARNING: Subroutine does not return - __cxa_throw(puVar4,&RESULT::typeinfo,0); + return uVar3; } -// WARNING: Variable defined which should be unmapped: CharacterID_local +// WARNING: Unknown calling convention -- yet parameter storage is locked -void LeaveChannel(int ChannelID,ulong CharacterID,bool Close) +ulong GetNextSubscriber(void) { - vector<> *this; - TChannel *C_1; + int i; TChannel *pTVar1; ulong *puVar2; - TPlayer *pTVar3; - ulong *puVar4; - int i; - int iVar5; TChannel *C; - bool bVar6; - bool Close_local; - ulong CharacterID_local; + ulong uVar3; + bool bVar4; - if ((ChannelID < 0) || (Channels <= ChannelID)) { - error(&DAT_080ffea0,ChannelID); - bVar6 = false; + if ((CurrentChannelID < 0) || (Channels <= CurrentChannelID)) { + error(&DAT_080ffea0,CurrentChannelID); + bVar4 = false; } else { - bVar6 = true; - if (7 < ChannelID) { - pTVar1 = vector::operator()(&Channel,ChannelID); - bVar6 = pTVar1->Moderator != 0; + bVar4 = true; + if (7 < CurrentChannelID) { + pTVar1 = vector::operator()(&Channel,CurrentChannelID); + bVar4 = pTVar1->Moderator != 0; } } - if (bVar6) { - iVar5 = 0; - pTVar1 = vector::operator()(&Channel,ChannelID); - if (0 < pTVar1->Subscribers) { - this = &pTVar1->Subscriber; - do { - puVar2 = vector<>::operator()(this,iVar5); - if (CharacterID == *puVar2) { - pTVar1->Subscribers = pTVar1->Subscribers + -1; - puVar2 = vector<>::operator()(this,iVar5); - puVar4 = vector<>::operator()(this,pTVar1->Subscribers); - *puVar2 = *puVar4; - break; - } - iVar5 = iVar5 + 1; - } while (iVar5 < pTVar1->Subscribers); - } - if ((Close) && (CharacterID == pTVar1->Moderator)) { - iVar5 = 0; - if (0 < pTVar1->Subscribers) { - do { - puVar2 = vector<>::operator()(&pTVar1->Subscriber,iVar5); - pTVar3 = GetPlayer(*puVar2); - if (pTVar3 != (TPlayer *)0x0) { - SendCloseChannel((pTVar3->super_TCreature).Connection,ChannelID); - } - iVar5 = iVar5 + 1; - } while (iVar5 < pTVar1->Subscribers); - } - pTVar1->Subscribers = 0; + uVar3 = 0; + if (bVar4) { + pTVar1 = vector::operator()(&Channel,CurrentChannelID); + i = CurrentSubscriberNumber; + if (CurrentSubscriberNumber < pTVar1->Subscribers) { + CurrentSubscriberNumber = CurrentSubscriberNumber + 1; + puVar2 = vector<>::operator()(&pTVar1->Subscriber,i); + uVar3 = *puVar2; } - if ((7 < ChannelID) && (pTVar1->Subscribers == 0)) { - if (Channels <= ChannelID) { - error(&DAT_08100a00); - return; - } - pTVar1 = vector::operator()(&Channel,ChannelID); - if (pTVar1->Moderator == 0) { - error("CloseChannel: Kanal ist schon geschlossen.\n"); - return; - } - pTVar1->Moderator = 0; + else { + uVar3 = 0; } } - return; + return uVar3; } -void LeaveAllChannels(ulong CharacterID) +bool MayOpenChannel(ulong CharacterID) { - TChannel *pTVar1; - int ChannelID; + bool bVar1; + TChannel *pTVar2; + bool bVar3; int i; - bool bVar2; + int i_00; - i = 0; - if (0 < Channels) { - do { - if ((i < 0) || (Channels <= i)) { - error(&DAT_080ffea0,i); - bVar2 = false; - } - else { - bVar2 = true; - if (7 < i) { - pTVar1 = vector::operator()(&Channel,i); - bVar2 = pTVar1->Moderator != 0; - } - } - if (bVar2) { - LeaveChannel(i,CharacterID,false); + if (Channels < 0xffff) { + bVar1 = CheckRight(CharacterID,PREMIUM_ACCOUNT); + bVar3 = false; + if (bVar1) { + i_00 = 8; + if (8 < Channels) { + do { + pTVar2 = vector::operator()(&Channel,i_00); + if (pTVar2->Moderator == CharacterID) goto LAB_08099cfb; + i_00 = i_00 + 1; + } while (i_00 < Channels); } - i = i + 1; - } while (i < Channels); + bVar3 = true; + } } - return; + else { +LAB_08099cfb: + bVar3 = false; + } + return bVar3; } -// WARNING: Unknown calling convention -- yet parameter storage is locked +// WARNING: Variable defined which should be unmapped: pl -ulong LogCommunication(void) +void OpenChannel(ulong CharacterID) { - TStatement *pTVar1; - ulong uVar2; - TStatement *Statement; - ulong in_stack_00000004; - int in_stack_00000008; - int in_stack_0000000c; - char *in_stack_00000010; - char *Text; + bool bVar1; + TPlayer *pTVar2; + TChannel *pTVar3; + ulong *puVar4; + undefined4 *puVar5; + int ChannelID; + int i; + TChannel *C; + int i_00; + TPlayer *pl; - if (in_stack_00000010 == (char *)0x0) { - Text = "LogCommunication: Text ist NULL.\n"; + // try { // try from 08099d75 to 08099ef2 has its CatchHandler @ 08099ef5 + pTVar2 = GetPlayer(CharacterID); + if (pTVar2 == (TPlayer *)0x0) { + error("OpenChannel: Kreatur %lu existiert nicht.\n",CharacterID); } else { - if (in_stack_00000004 != 0) { - StatementID = StatementID + 1; - pTVar1 = fifo::append(&Statements); - pTVar1->StatementID = StatementID; - uVar2 = time((time_t *)0x0); - pTVar1->TimeStamp = uVar2; - pTVar1->CharacterID = in_stack_00000004; - pTVar1->Mode = in_stack_00000008; - pTVar1->Channel = in_stack_0000000c; - uVar2 = AddDynamicString(in_stack_00000010); - pTVar1->Reported = false; - pTVar1->Text = uVar2; - return StatementID; + if (Channels < 0xffff) { + bVar1 = CheckRight(CharacterID,PREMIUM_ACCOUNT); + if (bVar1) { + i = 8; + if (8 < Channels) { + do { + pTVar3 = vector::operator()(&Channel,i); + if (pTVar3->Moderator == CharacterID) goto LAB_08099e20; + i = i + 1; + } while (i < Channels); + } + i_00 = 8; + i = Channels; + if (8 < Channels) { + do { + pTVar3 = vector::operator()(&Channel,i_00); + if (pTVar3->Moderator == 0) { + i = i_00; + } + i_00 = i_00 + 1; + } while (i_00 < Channels); + } + if (i == Channels) { + Channels = i + 1; + } + pTVar3 = vector::operator()(&Channel,i); + pTVar3->Moderator = CharacterID; + strcpy(pTVar3->ModeratorName,(pTVar2->super_TCreature).Name); + puVar4 = vector<>::operator()(&pTVar3->Subscriber,0); + *puVar4 = CharacterID; + pTVar3->Subscribers = 1; + pTVar3->InvitedPlayers = 0; +LAB_08099e20: + SendOpenOwnChannel((pTVar2->super_TCreature).Connection,i); + return; + } + puVar5 = (undefined4 *)__cxa_allocate_exception(4); + *puVar5 = 0x33; + goto LAB_08099eab; } - Text = "LogCommunication: CharacterID ist Null.\n"; + error(&DAT_081009a0); } - error(Text); - return 0; + puVar5 = (undefined4 *)__cxa_allocate_exception(4); + *puVar5 = 0xffffffff; +LAB_08099eab: + // WARNING: Subroutine does not return + __cxa_throw(puVar5,&RESULT::typeinfo,0); } -ulong LogListener(ulong StatementID,TPlayer *pl) +void CloseChannel(int ChannelID) { - bool bVar1; - TListener *Listener; - TListener *pTVar2; - ulong uVar3; + TChannel *pTVar1; - uVar3 = 0; - if ((StatementID != 0) && (uVar3 = 0, pl != (TPlayer *)0x0)) { - bVar1 = CheckRight((pl->super_TCreature).ID,LOG_COMMUNICATION); - uVar3 = 0; - if (bVar1) { - pTVar2 = fifo::append(&Listeners); - pTVar2->StatementID = StatementID; - pTVar2->CharacterID = (pl->super_TCreature).ID; - uVar3 = StatementID; + if ((ChannelID < 8) || (Channels <= ChannelID)) { + error(&DAT_08100a00,ChannelID); + } + else { + pTVar1 = vector::operator()(&Channel,ChannelID); + if (pTVar1->Moderator == 0) { + error("CloseChannel: Kanal ist schon geschlossen.\n"); + return; } + pTVar1->Moderator = 0; } - return uVar3; + return; } -// WARNING: Restarted to delay deadcode elimination for space: ram -// WARNING: Unknown calling convention -- yet parameter storage is locked +// WARNING: Variable defined which should be unmapped: Opp -void ProcessCommunicationControl(void) +void InviteToChannel(ulong CharacterID,char *Name) { - time_t tVar1; - TListener *pTVar2; - TStatement *pTVar3; - uint local_3c; - ulong Limit; + bool bVar1; + TPlayer *pTVar2; + int iVar3; + ulong *puVar4; + undefined4 *puVar5; + TChannel *pTVar6; + char *pcVar7; + ulong OppID; + TChannel *pTVar8; + ulong uVar9; + TPlayer *pl; + int local_20; + int i_1; + TChannel *C; + int channel; + TPlayer *Opp; - tVar1 = time((time_t *)0x0); - while( true ) { - if (Statements.Head < Statements.Tail) { - pTVar3 = (TStatement *)0x0; - } - else { - pTVar3 = Statements.Entry + Statements.Tail % Statements.Size; - } - if ((pTVar3 == (TStatement *)0x0) || (tVar1 - 0x708U <= pTVar3->TimeStamp)) break; - DeleteDynamicString(pTVar3->Text); - if (Statements.Head < Statements.Tail) { - error("fifo::remove: Fifo ist leer.\n"); - } - else { - Statements.Tail = Statements.Tail + 1; - } + // try { // try from 08099f85 to 0809a218 has its CatchHandler @ 0809a220 + pTVar2 = GetPlayer(CharacterID); + if (pTVar2 == (TPlayer *)0x0) { + error("InviteToChannel: Kreatur %lu existiert nicht.\n",CharacterID); + return; } - if (Statements.Head < Statements.Tail) { - pTVar3 = (TStatement *)0x0; + C = (TChannel *)0xffffffff; + pTVar8 = (TChannel *)0x8; + if (8 < Channels) { + do { + pTVar6 = vector::operator()(&Channel,(int)pTVar8); + if (pTVar6->Moderator == CharacterID) { + C = pTVar8; + } + pTVar8 = (TChannel *)((int)&pTVar8->Moderator + 1); + } while ((int)pTVar8 < Channels); } - else { - pTVar3 = Statements.Entry + Statements.Tail % Statements.Size; + if (C == (TChannel *)0xffffffff) { + return; } - if (pTVar3 == (TStatement *)0x0) { - local_3c = 0; + uVar9 = 0; + channel = 0; + bVar1 = CheckRight((pTVar2->super_TCreature).ID,READ_GAMEMASTER_CHANNEL); + iVar3 = IdentifyPlayer(Name,false,!bVar1,(TPlayer **)&channel); + if (iVar3 == -1) { + uVar9 = GetCharacterID(Name); + if (uVar9 == 0) { + puVar5 = (undefined4 *)__cxa_allocate_exception(4); + *puVar5 = 0x1a; +LAB_0809a19d: + // WARNING: Subroutine does not return + __cxa_throw(puVar5,&RESULT::typeinfo,0); + } } else { - if (Statements.Head < Statements.Tail) { - pTVar3 = (TStatement *)0x0; + if (-1 < iVar3) { + if (iVar3 == 0) { + uVar9 = *(ulong *)(channel + 0x208); + Name = (char *)(channel + 0x214); + } + goto LAB_0809a01f; } - else { - pTVar3 = Statements.Entry + Statements.Tail % Statements.Size; + if (iVar3 != -2) goto LAB_0809a01f; + uVar9 = GetCharacterID(Name); + if (uVar9 == 0) { + puVar5 = (undefined4 *)__cxa_allocate_exception(4); + *puVar5 = 0x1c; + goto LAB_0809a19d; } - local_3c = pTVar3->StatementID; } - while( true ) { - if (Listeners.Head < Listeners.Tail) { - pTVar2 = (TListener *)0x0; - } - else { - pTVar2 = Listeners.Entry + Listeners.Tail % Listeners.Size; - } - if ((pTVar2 == (TListener *)0x0) || (local_3c <= pTVar2->StatementID)) break; - if (Listeners.Head < Listeners.Tail) { - error("fifo::remove: Fifo ist leer.\n"); + Name = GetCharacterName(Name); +LAB_0809a01f: + print(); + pTVar8 = vector::operator()(&Channel,(int)C); + if (CharacterID != uVar9) { + local_20 = 0; + iVar3 = pTVar8->InvitedPlayers; + if (0 < iVar3) { + do { + puVar4 = vector<>::operator()(&pTVar8->InvitedPlayer,local_20); + if (*puVar4 == uVar9) { + SendMessage((pTVar2->super_TCreature).Connection,0x16, + "%s has already been invited.",Name); + return; + } + local_20 = local_20 + 1; + iVar3 = pTVar8->InvitedPlayers; + } while (local_20 < iVar3); } - else { - Listeners.Tail = Listeners.Tail + 1; + puVar4 = vector<>::operator()(&pTVar8->InvitedPlayer,iVar3); + *puVar4 = uVar9; + pTVar8->InvitedPlayers = pTVar8->InvitedPlayers + 1; + SendMessage((pTVar2->super_TCreature).Connection,0x16,"%s has been invited.",Name); + if (channel != 0) { + pcVar7 = "his"; + if ((pTVar2->super_TCreature).Sex != 1) { + pcVar7 = "her"; + } + SendMessage(*(TConnection **)(channel + 0x318),0x16, + "%s invites you to %s private chat channel.",(pTVar2->super_TCreature).Name, + pcVar7); } } return; @@ -20665,510 +18920,268 @@ void ProcessCommunicationControl(void) -int GetCommunicationContext - (ulong CharacterID,ulong StatementID,int *NumberOfStatements, - vector<> **ReportedStatements) +// WARNING: Variable defined which should be unmapped: Opp + +void ExcludeFromChannel(ulong CharacterID,char *Name) { - int iVar1; - bool bVar2; - vector<> *pvVar3; - TReportedStatement *pTVar4; - TStatement *pTVar5; - char *pcVar6; - char *pcVar7; - uint uVar8; - uint uVar9; + bool bVar1; + TPlayer *pTVar2; + int iVar3; + ulong *puVar4; + ulong *puVar5; + undefined4 *puVar6; + TChannel *pTVar7; + ulong OppID; + TChannel *pTVar8; + ulong CharacterID_00; int i; - fifo *pfVar10; - char *pcVar11; - TListener *pTVar12; - int *piVar13; - bool bVar14; - char *pcVar15; - char *local_40; - int FreeSpace; - TStatement *pTStack_38; - bool StatementContained; - fifoIterator iter2; - int local_20; - fifo *local_1c; - fifoIterator iter; + int local_24; + int Position; + TChannel *C; + int channel; + TPlayer *pl; + TPlayer *Opp; - local_1c = &Statements; - iter.Fifo = (fifo *)Statements.Head; - while( true ) { - bVar2 = false; - if ((Statements.Tail <= (int)iter.Fifo) && ((int)iter.Fifo <= Statements.Head)) { - bVar2 = true; - } - if (bVar2) { - pTVar5 = Statements.Entry + (int)iter.Fifo % Statements.Size; - } - else { - pTVar5 = (TStatement *)0x0; - } - if (pTVar5 == (TStatement *)0x0) break; - bVar2 = false; - if ((Statements.Tail <= (int)iter.Fifo) && ((int)iter.Fifo <= Statements.Head)) { - bVar2 = true; - } - if (bVar2) { - pTVar5 = Statements.Entry + (int)iter.Fifo % Statements.Size; - } - else { - pTVar5 = (TStatement *)0x0; - } - if (pTVar5->StatementID == StatementID) break; - iter.Fifo = (fifo *)((int)&iter.Fifo[-1].Tail + 3); - } - bVar2 = false; - if ((Statements.Tail <= (int)iter.Fifo) && ((int)iter.Fifo <= Statements.Head)) { - bVar2 = true; - } - if (bVar2) { - pTStack_38 = Statements.Entry + (int)iter.Fifo % Statements.Size; - } - else { - pTStack_38 = (TStatement *)0x0; - } - if (pTStack_38 == (TStatement *)0x0) { - return 1; - } - if (CharacterID != 0) { -LAB_0809ac90: - if (pTStack_38->Reported != false) { - return 2; - } - bVar2 = false; - *NumberOfStatements = 0; - local_20 = 0x4000; - iter2.Position = MaxPlayers * 0x42 + 2; - piVar13 = &iter2.Position; - if (iter2.Position < 0x4001) { - piVar13 = &local_20; - } - local_40 = (char *)(*piVar13 + -0x11f); - pvVar3 = (vector<> *)operator_new(0x130); - pcVar15 = (char *)0x0; - // try { // try from 0809ad0a to 0809ad0e has its CatchHandler @ 0809b61f - vector<>::vector(pvVar3,0,100,100); - *ReportedStatements = pvVar3; - iter2.Fifo = (fifo *)Listeners.Tail; - local_1c = &Statements; - pfVar10 = &Statements; - iter.Fifo = (fifo *)Statements.Tail; -LAB_0809ad41: - bVar14 = false; - if ((pfVar10->Tail <= (int)iter.Fifo) && ((int)iter.Fifo <= pfVar10->Head)) { - bVar14 = true; - } - if (bVar14) { - pTVar5 = pfVar10->Entry + (int)iter.Fifo % pfVar10->Size; - } - else { - pTVar5 = (TStatement *)0x0; - } - if (pTVar5 == (TStatement *)0x0) goto LAB_0809b4bf; - bVar14 = false; - if ((pfVar10->Tail <= (int)iter.Fifo) && ((int)iter.Fifo <= pfVar10->Head)) { - bVar14 = true; - } - if (bVar14) { - pTVar5 = pfVar10->Entry + (int)iter.Fifo % pfVar10->Size; - } - else { - pTVar5 = (TStatement *)0x0; - } - bVar14 = false; - uVar9 = pTStack_38->TimeStamp; - if (((int)(uVar9 - 0xb4) <= (int)pTVar5->TimeStamp) && - ((int)pTVar5->TimeStamp <= (int)(uVar9 + 0x3c))) { - bVar14 = true; - } - if (!bVar14) goto LAB_0809ae99; - if ((int)local_40 < 1) { - bVar14 = false; - if ((pfVar10->Tail <= (int)iter.Fifo) && ((int)iter.Fifo <= pfVar10->Head)) { - bVar14 = true; - } - if (bVar14) { - pTVar5 = pfVar10->Entry + (int)iter.Fifo % pfVar10->Size; - } - else { - pTVar5 = (TStatement *)0x0; - } - if (uVar9 < pTVar5->TimeStamp) { - error(&DAT_08100c20); -LAB_0809b4bf: - if ((int)local_40 < 0) { - pcVar11 = (char *)0x0; - pcVar15 = (char *)-(int)local_40; - error(&DAT_08100ce0,pcVar15); - if (*NumberOfStatements < 1) { -LAB_0809b5c9: - if ((int)local_40 < 0) { - error("GetCommunicationContext: FreeSpace ist immer noch negativ (%d).\n" - ,local_40); - pcVar15 = local_40; - } - } - else { - do { - pcVar15 = pcVar11; - pTVar4 = vector<>::operator()(*ReportedStatements,(int)pcVar11); - if (pTVar4->StatementID != StatementID) { - pTVar4 = vector<>::operator()(*ReportedStatements,(int)pcVar11); - pTVar4->StatementID = 0; - pcVar15 = pcVar11; - pTVar4 = vector<>::operator()(*ReportedStatements,(int)pcVar11); - pcVar7 = pTVar4->Text; - do { - pcVar6 = pcVar7; - uVar8 = *(uint *)pcVar6 + 0xfefefeff & ~*(uint *)pcVar6; - uVar9 = uVar8 & 0x80808080; - pcVar7 = pcVar6 + 4; - } while (uVar9 == 0); - bVar14 = (uVar8 & 0x8080) == 0; - if (bVar14) { - uVar9 = uVar9 >> 0x10; - } - if (bVar14) { - pcVar7 = pcVar6 + 6; - } - local_40 = pcVar7 + (int)(local_40 + - (-(int)pTVar4->Text - - (uint)CARRY1((byte)uVar9,(byte)uVar9)) + - 0x2b); - } - pcVar11 = pcVar11 + 1; - if (*NumberOfStatements <= (int)pcVar11) goto LAB_0809b5c9; - } while ((int)local_40 < 0); - } - } - if (bVar2) { - pTStack_38->Reported = true; - return 0; - } - error("GetCommunicationContext: Statement ist nicht im Kontext enthalten.\n",pcVar15 - ); - pvVar3 = *ReportedStatements; - if (pvVar3 == (vector<> *)0x0) { - return 1; - } - if (pvVar3->entry != (TReportedStatement *)0x0) { - operator_delete__(pvVar3->entry); - } - operator_delete(pvVar3); - return 1; - } - } - if (CharacterID != 0) { - while( true ) { - bVar14 = false; - if ((Listeners.Tail <= (int)iter2.Fifo) && ((int)iter2.Fifo <= Listeners.Head)) { - bVar14 = true; - } - if (bVar14) { - pTVar12 = Listeners.Entry + (int)iter2.Fifo % Listeners.Size; - } - else { - pTVar12 = (TListener *)0x0; - } - if (pTVar12 == (TListener *)0x0) break; - bVar14 = false; - if ((Listeners.Tail <= (int)iter2.Fifo) && ((int)iter2.Fifo <= Listeners.Head)) { - bVar14 = true; - } - if (bVar14) { - pTVar12 = Listeners.Entry + (int)iter2.Fifo % Listeners.Size; - } - else { - pTVar12 = (TListener *)0x0; - } - bVar14 = false; - if ((pfVar10->Tail <= (int)iter.Fifo) && ((int)iter.Fifo <= pfVar10->Head)) { - bVar14 = true; - } - if (bVar14) { - pTVar5 = pfVar10->Entry + (int)iter.Fifo % pfVar10->Size; - } - else { - pTVar5 = (TStatement *)0x0; - } - if (pTVar5->StatementID <= pTVar12->StatementID) break; - iter2.Fifo = (fifo *)((int)&(iter2.Fifo)->Entry + 1); - } - do { - bVar14 = false; - if ((Listeners.Tail <= (int)iter2.Fifo) && ((int)iter2.Fifo <= Listeners.Head)) { - bVar14 = true; - } - if (bVar14) { - pTVar12 = Listeners.Entry + (int)iter2.Fifo % Listeners.Size; - } - else { - pTVar12 = (TListener *)0x0; - } - if (pTVar12 == (TListener *)0x0) goto LAB_0809b39a; - bVar14 = false; - if ((Listeners.Tail <= (int)iter2.Fifo) && ((int)iter2.Fifo <= Listeners.Head)) { - bVar14 = true; - } - if (bVar14) { - pTVar12 = Listeners.Entry + (int)iter2.Fifo % Listeners.Size; - } - else { - pTVar12 = (TListener *)0x0; - } - bVar14 = false; - if ((pfVar10->Tail <= (int)iter.Fifo) && ((int)iter.Fifo <= pfVar10->Head)) { - bVar14 = true; - } - if (bVar14) { - pTVar5 = pfVar10->Entry + (int)iter.Fifo % pfVar10->Size; - } - else { - pTVar5 = (TStatement *)0x0; - } - if (pTVar12->StatementID != pTVar5->StatementID) goto LAB_0809b39a; - bVar14 = false; - if ((Listeners.Tail <= (int)iter2.Fifo) && ((int)iter2.Fifo <= Listeners.Head)) { - bVar14 = true; - } - if (bVar14) { - pTVar12 = Listeners.Entry + (int)iter2.Fifo % Listeners.Size; - } - else { - pTVar12 = (TListener *)0x0; + // try { // try from 0809a258 to 0809a4fe has its CatchHandler @ 0809a504 + pTVar2 = GetPlayer(CharacterID); + if (pTVar2 == (TPlayer *)0x0) { + error("ExcludeFromChannel: Kreatur %lu existiert nicht.\n",CharacterID); + } + else { + C = (TChannel *)0xffffffff; + pTVar8 = (TChannel *)0x8; + if (8 < Channels) { + do { + pTVar7 = vector::operator()(&Channel,(int)pTVar8); + if (pTVar7->Moderator == CharacterID) { + C = pTVar8; } - if (pTVar12->CharacterID == CharacterID) goto LAB_0809b39a; - iter2.Fifo = (fifo *)((int)&(iter2.Fifo)->Entry + 1); - } while( true ); - } - bVar14 = false; - if ((pfVar10->Tail <= (int)iter.Fifo) && (bVar14 = true, pfVar10->Head < (int)iter.Fifo)) { - bVar14 = false; - } - if (bVar14) { - pTVar5 = pfVar10->Entry + (int)iter.Fifo % pfVar10->Size; - } - else { - pTVar5 = (TStatement *)0x0; + pTVar8 = (TChannel *)((int)&pTVar8->Moderator + 1); + } while ((int)pTVar8 < Channels); } - if (pTVar5->Mode != 5) { - bVar14 = false; - if ((pfVar10->Tail <= (int)iter.Fifo) && ((int)iter.Fifo <= pfVar10->Head)) { - bVar14 = true; + if (C != (TChannel *)0xffffffff) { + CharacterID_00 = 0; + pl = (TPlayer *)0x0; + bVar1 = CheckRight((pTVar2->super_TCreature).ID,READ_GAMEMASTER_CHANNEL); + iVar3 = IdentifyPlayer(Name,false,!bVar1,&pl); + if (iVar3 == -1) { + CharacterID_00 = GetCharacterID(Name); + if (CharacterID_00 == 0) { + puVar6 = (undefined4 *)__cxa_allocate_exception(4); + *puVar6 = 0x1a; +LAB_0809a484: + // WARNING: Subroutine does not return + __cxa_throw(puVar6,&RESULT::typeinfo,0); + } } - if (bVar14) { - pTVar5 = pfVar10->Entry + (int)iter.Fifo % pfVar10->Size; + else if (iVar3 < 0) { + if ((iVar3 == -2) && (CharacterID_00 = GetCharacterID(Name), CharacterID_00 == 0)) { + puVar6 = (undefined4 *)__cxa_allocate_exception(4); + *puVar6 = 0x1c; + goto LAB_0809a484; + } } - else { - pTVar5 = (TStatement *)0x0; + else if (iVar3 == 0) { + CharacterID_00 = (pl->super_TCreature).ID; + Name = (pl->super_TCreature).Name; } - if (pTVar5->Mode != 10) { - bVar14 = false; - if ((pfVar10->Tail <= (int)iter.Fifo) && ((int)iter.Fifo <= pfVar10->Head)) { - bVar14 = true; + print(); + pTVar8 = vector::operator()(&Channel,(int)C); + if (CharacterID != CharacterID_00) { + local_24 = -1; + iVar3 = pTVar8->InvitedPlayers; + i = 0; + if (0 < iVar3) { + do { + puVar4 = vector<>::operator()(&pTVar8->InvitedPlayer,i); + if (*puVar4 == CharacterID_00) { + local_24 = i; + } + i = i + 1; + iVar3 = pTVar8->InvitedPlayers; + } while (i < iVar3); } - if (bVar14) { - pTVar5 = pfVar10->Entry + (int)iter.Fifo % pfVar10->Size; + if (local_24 == -1) { + SendMessage((pTVar2->super_TCreature).Connection,0x16,"%s has not been invited." + ,Name); } else { - pTVar5 = (TStatement *)0x0; + pTVar8->InvitedPlayers = iVar3 + -1; + puVar4 = vector<>::operator()(&pTVar8->InvitedPlayer,local_24); + puVar5 = vector<>::operator()(&pTVar8->InvitedPlayer,pTVar8->InvitedPlayers); + *puVar4 = *puVar5; + SendMessage((pTVar2->super_TCreature).Connection,0x16,"%s has been excluded.", + Name); + bVar1 = ChannelSubscribed((int)C,CharacterID_00); + if (bVar1) { + LeaveChannel((int)C,CharacterID_00,false); + SendCloseChannel((pl->super_TCreature).Connection,(int)C); + } } - if (pTVar5->Mode != 0xc) goto LAB_0809ae99; } } - bVar14 = false; - if ((pfVar10->Tail <= (int)iter.Fifo) && ((int)iter.Fifo <= pfVar10->Head)) { - bVar14 = true; - } - if (bVar14) { - pTVar5 = pfVar10->Entry + (int)iter.Fifo % pfVar10->Size; - } - else { - pTVar5 = (TStatement *)0x0; + } + return; +} + + + +bool JoinChannel(int ChannelID,ulong CharacterID) + +{ + bool bVar1; + TChannel *pTVar2; + ulong *puVar3; + undefined4 *puVar4; + TChannel *C; + + if ((ChannelID < 0) || (Channels <= ChannelID)) { + // try { // try from 0809a550 to 0809a61d has its CatchHandler @ 0809a630 + error(&DAT_080ffea0,ChannelID); + bVar1 = false; + } + else { + bVar1 = true; + if (7 < ChannelID) { + pTVar2 = vector::operator()(&Channel,ChannelID); + bVar1 = pTVar2->Moderator != 0; } - if (pTStack_38->Channel != pTVar5->Channel) goto LAB_0809ae99; - goto LAB_0809aedf; } - iVar1 = pTStack_38->Mode; - if (((iVar1 == 5) || (iVar1 == 10)) || (iVar1 == 0xc)) { - bVar2 = false; - iVar1 = pTStack_38->Channel; - if ((3 < iVar1) && (iVar1 < 8)) { - bVar2 = true; + if (bVar1) { + bVar1 = ChannelAvailable(ChannelID,CharacterID); + if (bVar1) { + pTVar2 = vector::operator()(&Channel,ChannelID); + bVar1 = ChannelSubscribed(ChannelID,CharacterID); + if (!bVar1) { + puVar3 = vector<>::operator()(&pTVar2->Subscriber,pTVar2->Subscribers); + *puVar3 = CharacterID; + pTVar2->Subscribers = pTVar2->Subscribers + 1; + } + return CharacterID == pTVar2->Moderator; } - if ((bVar2) || (iVar1 == 2)) goto LAB_0809ac90; + puVar4 = (undefined4 *)__cxa_allocate_exception(4); + *puVar4 = 1; } - error(&DAT_08100bc0); - return 1; -LAB_0809b39a: - bVar14 = false; - if ((Listeners.Tail <= (int)iter2.Fifo) && ((int)iter2.Fifo <= Listeners.Head)) { - bVar14 = true; + else { + puVar4 = (undefined4 *)__cxa_allocate_exception(4); + *puVar4 = 0xffffffff; } - if (bVar14) { - pTVar12 = Listeners.Entry + (int)iter2.Fifo % Listeners.Size; + // WARNING: Subroutine does not return + __cxa_throw(puVar4,&RESULT::typeinfo,0); +} + + + +// WARNING: Variable defined which should be unmapped: CharacterID_local + +void LeaveChannel(int ChannelID,ulong CharacterID,bool Close) + +{ + vector<> *this; + TChannel *C_1; + TChannel *pTVar1; + ulong *puVar2; + TPlayer *pTVar3; + ulong *puVar4; + int i; + int iVar5; + TChannel *C; + bool bVar6; + bool Close_local; + ulong CharacterID_local; + + if ((ChannelID < 0) || (Channels <= ChannelID)) { + error(&DAT_080ffea0,ChannelID); + bVar6 = false; } else { - pTVar12 = (TListener *)0x0; - } - if (pTVar12 != (TListener *)0x0) { - bVar14 = false; - if ((Listeners.Tail <= (int)iter2.Fifo) && ((int)iter2.Fifo <= Listeners.Head)) { - bVar14 = true; - } - if (bVar14) { - pTVar12 = Listeners.Entry + (int)iter2.Fifo % Listeners.Size; - } - else { - pTVar12 = (TListener *)0x0; - } - bVar14 = false; - if ((pfVar10->Tail <= (int)iter.Fifo) && ((int)iter.Fifo <= pfVar10->Head)) { - bVar14 = true; - } - if (bVar14) { - pTVar5 = pfVar10->Entry + (int)iter.Fifo % pfVar10->Size; + bVar6 = true; + if (7 < ChannelID) { + pTVar1 = vector::operator()(&Channel,ChannelID); + bVar6 = pTVar1->Moderator != 0; } - else { - pTVar5 = (TStatement *)0x0; + } + if (bVar6) { + iVar5 = 0; + pTVar1 = vector::operator()(&Channel,ChannelID); + if (0 < pTVar1->Subscribers) { + this = &pTVar1->Subscriber; + do { + puVar2 = vector<>::operator()(this,iVar5); + if (CharacterID == *puVar2) { + pTVar1->Subscribers = pTVar1->Subscribers + -1; + puVar2 = vector<>::operator()(this,iVar5); + puVar4 = vector<>::operator()(this,pTVar1->Subscribers); + *puVar2 = *puVar4; + break; + } + iVar5 = iVar5 + 1; + } while (iVar5 < pTVar1->Subscribers); } - if (pTVar12->StatementID <= pTVar5->StatementID) { -LAB_0809aedf: - bVar14 = false; - pTVar4 = vector<>::operator()(*ReportedStatements,*NumberOfStatements); - if ((local_1c->Tail <= (int)iter.Fifo) && ((int)iter.Fifo <= local_1c->Head)) { - bVar14 = true; - } - if (bVar14) { - pTVar5 = local_1c->Entry + (int)iter.Fifo % local_1c->Size; - } - else { - pTVar5 = (TStatement *)0x0; - } - bVar14 = false; - pTVar4->StatementID = pTVar5->StatementID; - pTVar4 = vector<>::operator()(*ReportedStatements,*NumberOfStatements); - if ((local_1c->Tail <= (int)iter.Fifo) && ((int)iter.Fifo <= local_1c->Head)) { - bVar14 = true; - } - if (bVar14) { - pTVar5 = local_1c->Entry + (int)iter.Fifo % local_1c->Size; - } - else { - pTVar5 = (TStatement *)0x0; - } - bVar14 = false; - pTVar4->TimeStamp = pTVar5->TimeStamp; - pTVar4 = vector<>::operator()(*ReportedStatements,*NumberOfStatements); - if ((local_1c->Tail <= (int)iter.Fifo) && ((int)iter.Fifo <= local_1c->Head)) { - bVar14 = true; - } - if (bVar14) { - pTVar5 = local_1c->Entry + (int)iter.Fifo % local_1c->Size; - } - else { - pTVar5 = (TStatement *)0x0; - } - bVar14 = false; - pTVar4->CharacterID = pTVar5->CharacterID; - pTVar4 = vector<>::operator()(*ReportedStatements,*NumberOfStatements); - if ((local_1c->Tail <= (int)iter.Fifo) && ((int)iter.Fifo <= local_1c->Head)) { - bVar14 = true; - } - if (bVar14) { - pTVar5 = local_1c->Entry + (int)iter.Fifo % local_1c->Size; - } - else { - pTVar5 = (TStatement *)0x0; - } - bVar14 = false; - pTVar4->Mode = pTVar5->Mode; - pTVar4 = vector<>::operator()(*ReportedStatements,*NumberOfStatements); - if ((local_1c->Tail <= (int)iter.Fifo) && ((int)iter.Fifo <= local_1c->Head)) { - bVar14 = true; - } - if (bVar14) { - pTVar5 = local_1c->Entry + (int)iter.Fifo % local_1c->Size; - } - else { - pTVar5 = (TStatement *)0x0; - } - bVar14 = false; - pTVar4->Channel = pTVar5->Channel; - if ((local_1c->Tail <= (int)iter.Fifo) && ((int)iter.Fifo <= local_1c->Head)) { - bVar14 = true; + if ((Close) && (CharacterID == pTVar1->Moderator)) { + iVar5 = 0; + if (0 < pTVar1->Subscribers) { + do { + puVar2 = vector<>::operator()(&pTVar1->Subscriber,iVar5); + pTVar3 = GetPlayer(*puVar2); + if (pTVar3 != (TPlayer *)0x0) { + SendCloseChannel((pTVar3->super_TCreature).Connection,ChannelID); + } + iVar5 = iVar5 + 1; + } while (iVar5 < pTVar1->Subscribers); } - if (bVar14) { - pTVar5 = local_1c->Entry + (int)iter.Fifo % local_1c->Size; + pTVar1->Subscribers = 0; + } + if ((7 < ChannelID) && (pTVar1->Subscribers == 0)) { + if (Channels <= ChannelID) { + error(&DAT_08100a00); + return; } - else { - pTVar5 = (TStatement *)0x0; + pTVar1 = vector::operator()(&Channel,ChannelID); + if (pTVar1->Moderator == 0) { + error("CloseChannel: Kanal ist schon geschlossen.\n"); + return; } - if (pTVar5->Text == 0) { - pTVar4 = vector<>::operator()(*ReportedStatements,*NumberOfStatements); - pTVar4->Text[0] = '\0'; + pTVar1->Moderator = 0; + } + } + return; +} + + + +void LeaveAllChannels(ulong CharacterID) + +{ + TChannel *pTVar1; + int ChannelID; + int i; + bool bVar2; + + i = 0; + if (0 < Channels) { + do { + if ((i < 0) || (Channels <= i)) { + error(&DAT_080ffea0,i); + bVar2 = false; } else { - bVar14 = false; - if ((local_1c->Tail <= (int)iter.Fifo) && ((int)iter.Fifo <= local_1c->Head)) { - bVar14 = true; - } - if (bVar14) { - pTVar5 = local_1c->Entry + (int)iter.Fifo % local_1c->Size; - } - else { - pTVar5 = (TStatement *)0x0; + bVar2 = true; + if (7 < i) { + pTVar1 = vector::operator()(&Channel,i); + bVar2 = pTVar1->Moderator != 0; } - pcVar15 = GetDynamicString(pTVar5->Text); - pTVar4 = vector<>::operator()(*ReportedStatements,*NumberOfStatements); - strcpy(pTVar4->Text,pcVar15); - } - pcVar15 = (char *)*NumberOfStatements; - pTVar4 = vector<>::operator()(*ReportedStatements,(int)pcVar15); - pcVar11 = pTVar4->Text; - do { - pcVar7 = pcVar11; - uVar8 = *(uint *)pcVar7 + 0xfefefeff & ~*(uint *)pcVar7; - uVar9 = uVar8 & 0x80808080; - pcVar11 = pcVar7 + 4; - } while (uVar9 == 0); - if ((uVar8 & 0x8080) == 0) { - pcVar11 = pcVar7 + 6; - uVar9 = uVar9 >> 0x10; - } - bVar14 = false; - local_40 = local_40 + - (-0x2e - (int)(pcVar11 + - ((-3 - (uint)CARRY1((byte)uVar9,(byte)uVar9)) - - (int)pTVar4->Text))); - *NumberOfStatements = *NumberOfStatements + 1; - if ((local_1c->Tail <= (int)iter.Fifo) && ((int)iter.Fifo <= local_1c->Head)) { - bVar14 = true; - } - if (bVar14) { - pTVar5 = local_1c->Entry + (int)iter.Fifo % local_1c->Size; - } - else { - pTVar5 = (TStatement *)0x0; } - pfVar10 = local_1c; - if (pTVar5->StatementID == StatementID) { - bVar2 = true; + if (bVar2) { + LeaveChannel(i,CharacterID,false); } - } + i = i + 1; + } while (i < Channels); } -LAB_0809ae99: - iter.Fifo = (fifo *)((int)&(iter.Fifo)->Entry + 1); - goto LAB_0809ad41; + return; } - - TParty * GetParty(ulong Leader) { diff --git a/reference/types.hh b/reference/types.hh index f3ce69d..5b900e6 100644 --- a/reference/types.hh +++ b/reference/types.hh @@ -89,20 +89,6 @@ struct TWaitinglistEntry { bool Sleeping; }; -struct TReportedStatement { - ulong StatementID; - ulong TimeStamp; - ulong CharacterID; - int Mode; - int Channel; - char Text[256]; -}; - -struct TListener { - ulong StatementID; - ulong CharacterID; -}; - struct TDelayedMail { ulong CharacterID; int DepotNumber; @@ -122,29 +108,12 @@ struct TMonsterhome { int Timer; }; -struct TChannel { - ulong Moderator; - char ModeratorName[30]; - struct vector Subscriber; - int Subscribers; - struct vector InvitedPlayer; - int InvitedPlayers; -}; - struct THelpDepot { ulong CharacterID; struct Object Box; int DepotNr; }; -struct TParty { - ulong Leader; - struct vector Member; - int Members; - struct vector InvitedPlayer; - int InvitedPlayers; -}; - struct TMoveUseAction { enum ActionType Action; int Parameters[5]; @@ -169,16 +138,6 @@ struct THouseArea { int DepotNr; }; -struct TStatement { - ulong StatementID; - ulong TimeStamp; - ulong CharacterID; - int Mode; - int Channel; - ulong Text; - bool Reported; -}; - struct TDirectReplyData { ulong CharacterID; char Message[100]; diff --git a/src/connection.hh b/src/connection.hh index ec79a6e..44b7360 100644 --- a/src/connection.hh +++ b/src/connection.hh @@ -5,6 +5,7 @@ #include "enums.hh" struct TConnection; +struct TPlayer; struct TKnownCreature { KNOWNCREATURESTATE State; @@ -14,6 +15,7 @@ struct TKnownCreature { }; struct TConnection { + TPlayer *GetPlayer(void); void Logout(int Delay, bool StopFight); bool IsVisible(int x, int y, int z); diff --git a/src/containers.hh b/src/containers.hh index 85dcfde..f82159b 100644 --- a/src/containers.hh +++ b/src/containers.hh @@ -118,6 +118,14 @@ struct vector{ return &this->entry[index - this->start]; } + T copyAt(int index) const { + T Result = {}; + if(index >= this->start && index < (this->start + this->space)){ + Result = this->entry[index - this->start]; + } + return Result; + } + // DATA // ================= int min; @@ -466,7 +474,7 @@ struct fifo{ // TODO(fusion): We don't consider integer overflow at all. this->Head += 1; - return this->Entry[this->Head % this->Size]; + return &this->Entry[this->Head % this->Size]; } void remove(void){ @@ -478,6 +486,33 @@ struct fifo{ this->Tail += 1; } + int iterFirst(void){ + return this->Head; + } + + int iterLast(void){ + return this->Tail; + } + + T *iterNext(int *Position){ + if(*Position < this->Tail || this->Head < *Position){ + return NULL; + } + T *Result = &this->Entry[*Position % this->Size]; + *Position -= 1; + return Result; + } + + T *iterPrev(int *Position){ + if(*Position < this->Tail || this->Head < *Position){ + return NULL; + } + + T *Result = &this->Entry[*Position % this->Size]; + *Position += 1; + return Result; + } + // TODO(fusion): There is also a `fifoIterator` used a few times and it is // essentially iterating from `this->Head` towards `this->Tail`. All its // functions were inlined so I'm not sure it is needed. diff --git a/src/cr.hh b/src/cr.hh index a2206f4..32d0090 100644 --- a/src/cr.hh +++ b/src/cr.hh @@ -718,6 +718,9 @@ struct TPlayer: TCreature { void SetOpenContainer(int ContainerNr, Object Con); void RejectTrade(void); Object InspectTrade(bool OwnOffer, int Position); + int CheckForMuting(void); + int RecordTalk(void); + int RecordMessage(uint32 Addressee); // VIRTUAL FUNCTIONS // ================= diff --git a/src/crmain.cc b/src/crmain.cc index 7e0ab42..c6a8b74 100644 --- a/src/crmain.cc +++ b/src/crmain.cc @@ -719,9 +719,13 @@ int TCreature::Damage(TCreature *Attacker, int Damage, int DamageType){ GraphicalEffect(this->CrObject, HitEffect); TextualEffect(this->CrObject, TextColor, "%d", Damage); if(SplashLiquid != LIQUID_NONE){ - CreatePool(GetMapContainer(this->CrObject), - GetSpecialObject(BLOOD_SPLASH), - SplashLiquid); + try{ + CreatePool(GetMapContainer(this->CrObject), + GetSpecialObject(BLOOD_SPLASH), + SplashLiquid); + }catch(RESULT r){ + // TODO(fusion): Ignore? + } } } @@ -754,10 +758,15 @@ int TCreature::Damage(TCreature *Attacker, int Damage, int DamageType){ if(ObjType == AmuletOfLossType){ Log("game", "%s stirbt mit Amulett of Loss.\n", this->Name); this->LoseInventory = 0; - Delete(Obj, -1); - // TODO(fusion): Shouldn't we break here? We could also - // just check if there is an amulet of loss in the necklace - // container instead of iterating over all of them. + try{ + Delete(Obj, -1); + // TODO(fusion): Shouldn't we break here? We could also + // just check if there is an amulet of loss in the necklace + // container instead of iterating over all inventory. + }catch(RESULT r){ + error("TCreature::Damage: Exception %d beim Löschen von Objekt %d.\n", + r, AmuletOfLossType.TypeID); + } } } } diff --git a/src/crplayer.cc b/src/crplayer.cc index 5b87ec8..8d962fb 100644 --- a/src/crplayer.cc +++ b/src/crplayer.cc @@ -1,4 +1,5 @@ #include "cr.hh" +#include "info.hh" #include "stubs.hh" diff --git a/src/info.hh b/src/info.hh index 863c500..8972276 100644 --- a/src/info.hh +++ b/src/info.hh @@ -52,6 +52,7 @@ bool ThrowPossible(int OrigX, int OrigY, int OrigZ, int DestX, int DestY, int DestZ, int Power); void GetCreatureLight(uint32 CreatureID, int *Brightness, int *Color); int GetInventoryWeight(uint32 CreatureID); +bool CheckRight(uint32 CharacterID, RIGHT Right); bool CheckBanishmentRight(uint32 CharacterID, int Reason, int Action); const char *GetBanishmentReason(int Reason); void InitInfo(void); diff --git a/src/main.cc b/src/main.cc index bbdebf1..7a804e0 100644 --- a/src/main.cc +++ b/src/main.cc @@ -4,6 +4,7 @@ #include "map.hh" #include "magic.hh" #include "objects.hh" +#include "operate.hh" #include "stubs.hh" @@ -238,7 +239,7 @@ static void InitAll(void){ InitCr(); //InitHouses(); InitTime(); - //ApplyPatches(); + ApplyPatches(); }catch(const char *str){ error("Initialisierungsfehler: %s\n", str); exit(EXIT_FAILURE); diff --git a/src/objects.hh b/src/objects.hh index 3d312ac..05b094d 100644 --- a/src/objects.hh +++ b/src/objects.hh @@ -62,6 +62,17 @@ struct ObjectType { || this->getFlag(WAND); } + bool isCloseWeapon(void){ + if(!this->getFlag(WEAPON)){ + return false; + } + + int WeaponType = this->getAttribute(WEAPONTYPE); + return WeaponType == WEAPON_SWORD + || WeaponType == WEAPON_CLUB + || WeaponType == WEAPON_AXE; + } + ObjectType getDisguise(void){ if(this->getFlag(DISGUISE)){ return (int)this->getAttribute(DISGUISETARGET); diff --git a/src/operate.cc b/src/operate.cc index 1e1f9a6..2224ed4 100644 --- a/src/operate.cc +++ b/src/operate.cc @@ -4,6 +4,23 @@ #include "stubs.hh" +#include +#include + +static fifo Statements(1024); +static fifo Listeners(1024); + +static vector Channel(0, 18, 10); +static int Channels; +static int CurrentChannelID; +static int CurrentSubscriberNumber; + +static vector Party(0, 100, 50); +static int Parties; + +// World Operations +// ============================================================================= + // TODO(fusion): The radii parameters for `TFindCreatures` are commonly around // 16 and 14 for x and y respectively so there is probably some constant involved. // Also, since we're talking about radii, these values are quite large when you @@ -383,7 +400,9 @@ void CheckTopMultiuseObject(uint32 CreatureID, Object Obj){ Best = Help; } - if(HelpType.getFlag(FORCEUSE) || GetObjectPriority(Help) >= PRIORITY_CREATURE){ + if(HelpType.getFlag(FORCEUSE) + || GetObjectPriority(Help) == PRIORITY_CREATURE + || GetObjectPriority(Help) == PRIORITY_LOW){ break; } @@ -2145,6 +2164,14 @@ void Look(uint32 CreatureID, Object Obj){ } void Talk(uint32 CreatureID, int Mode, const char *Addressee, const char *Text, bool CheckSpamming){ + // TODO(fusion): `Text` was originally `char*`, but I wanted to improve + // string handling overall and modifying string parameters is a bad idea, + // specially when you don't know their capacity. + // It is only modified when a player uses `TALK_YELL` to make it upper + // case, which shouldn't be a problem, but if we plan to do any cleanup + // afterwards, we need to get this right from the beginning. + char YellBuffer[256]; + TCreature *Creature = GetCreature(CreatureID); if(Creature == NULL){ error("Talk: Übergebene Kreatur %d existiert nicht.\n", CreatureID); @@ -2217,11 +2244,9 @@ void Talk(uint32 CreatureID, int Mode, const char *Addressee, const char *Text, throw EXHAUSTED; } - // TODO(fusion): This would be valid if `Text` was `char*`, but I - // wanted to improve the quality of string handling and parameters - // across the board, and now we need some scratch buffer to actually - // modify the text. - strUpper(Text); + strcpy(YellBuffer, Text); + strUpper(YellBuffer); + Text = YellBuffer; } if(Mode == TALK_CHANNEL_CALL && Channel == 5){ @@ -2277,7 +2302,7 @@ void Talk(uint32 CreatureID, int Mode, const char *Addressee, const char *Text, } if(Mode == TALK_PRIVATE_MESSAGE){ - Muting = Player->RecordMessage(Receiver->ID); + int Muting = Player->RecordMessage(Receiver->ID); if(Muting > 0){ SendMessage(Player->Connection, TALK_FAILURE_MESSAGE, "You have addressed too many players. You are muted for %d second%s.", @@ -2320,7 +2345,7 @@ void Talk(uint32 CreatureID, int Mode, const char *Addressee, const char *Text, TFindCreatures Search(Radius, Radius, Creature->posx, Creature->posy, FIND_PLAYERS); while(true){ - uint32 SpectatorID = Search.findNext(); + uint32 SpectatorID = Search.getNext(); if(SpectatorID == 0){ break; } @@ -2413,8 +2438,8 @@ void Talk(uint32 CreatureID, int Mode, const char *Addressee, const char *Text, continue; } - // TODO(fusion): We should probably review this. What if both player - // guild names are empty? Is it checked elsewhere? + // TODO(fusion): We should probably review this. You'd assume creature + // should be a player when talking to any channel. if(Channel == 0 && (Creature->Type != PLAYER || strcmp(((TPlayer*)Creature)->Guild, Subscriber->Guild) != 0)){ continue; @@ -2449,3 +2474,983 @@ void Talk(uint32 CreatureID, int Mode, const char *Addressee, const char *Text, } } } + +void Use(uint32 CreatureID, Object Obj1, Object Obj2, uint8 Info){ + if(!Obj1.exists()){ + error("Use: Übergebenes Objekt Obj 1 existiert nicht.\n"); + throw ERROR; + } + + if(Obj2 != NONE && !Obj2.exists()){ + error("Use: Übergebenes Objekt Obj 2 existiert nicht.\n"); + throw ERROR; + } + + CheckTopUseObject(CreatureID, Obj1); + if(!ObjectAccessible(CreatureID, Obj1, 1)){ + throw NOTACCESSIBLE; + } + + ObjectType ObjType1 = Obj1.getObjectType(); + if(Obj2 != NONE){ + // TODO(fusion): Is this correct? + if(!ObjType1.getFlag(DISTUSE)){ + CheckTopMultiuseObject(CreatureID, Obj2); + } + + if(!ObjectAccessible(CreatureID, Obj2, 1)){ + if(!ObjType1.getFlag(DISTUSE)){ + throw NOTACCESSIBLE; + } + + TCreature *Creature = GetCreature(CreatureID); + if(Creature == NULL){ + error("Use: Verursachende Kreatur existiert nicht.\n"); + throw ERROR; + } + + int ObjX2, ObjY2, ObjZ2; + GetObjectCoordinates(Obj2, &ObjX2, &ObjY2, &ObjZ2); + if(Creature->posz > ObjZ2){ + throw UPSTAIRS; + }else if(Creature->posz < ObjZ2){ + throw DOWNSTAIRS; + } + + if(!ThrowPossible(Creature->posx, Creature->posy, Creature->posz, ObjX2, ObjY2, ObjZ2, 0)){ + throw CANNOTTHROW; + } + } + } + + if(ObjType1.getFlag(CONTAINER)){ + UseContainer(CreatureID, Obj1, Info); + }else if(ObjType1.getFlag(CHEST)){ + UseChest(CreatureID, Obj1); + }else if(ObjType1.getFlag(LIQUIDCONTAINER)){ + UseLiquidContainer(CreatureID, Obj1, Obj2); + }else if(ObjType1.getFlag(FOOD)){ + UseFood(CreatureID, Obj1); + }else if(ObjType1.getFlag(WRITE) || ObjType1.getFlag(WRITEONCE)){ + UseTextObject(CreatureID, Obj1); + }else if(ObjType1.getFlag(INFORMATION)){ + UseAnnouncer(CreatureID, Obj1); + }else if(ObjType1.getFlag(RUNE)){ + UseMagicItem(CreatureID, Obj1, Obj2); + }else if(ObjType1.getFlag(KEY)){ + UseKeyDoor(CreatureID, Obj1, Obj2); + }else if(ObjType1.getFlag(NAMEDOOR)){ + UseNameDoor(CreatureID, Obj1); + }else if(ObjType1.getFlag(LEVELDOOR)){ + UseLevelDoor(CreatureID, Obj1); + }else if(ObjType1.getFlag(QUESTDOOR)){ + UseQuestDoor(CreatureID, Obj1); + }else if(ObjType1.isCloseWeapon() + && Obj2 != NONE + && Obj2.getObjectType().getFlag(DESTROY)){ + UseWeapon(CreatureID, Obj1, Obj2); + }else if(ObjType1.getFlag(CHANGEUSE)){ + UseChangeObject(CreatureID, Obj1); + }else if(ObjType1.getFlag(USEEVENT)){ + if(Obj2 != NONE){ + UseObjects(CreatureID, Obj1, Obj2); + }else{ + UseObject(CreatureID, Obj1); + } + }else if(ObjType1.getFlag(TEXT) + && ObjType1.getAttribute(FONTSIZE) == 1){ + UseTextObject(CreatureID, Obj1); + }else{ + throw NOTUSABLE; + } +} + +void Turn(uint32 CreatureID, Object Obj){ + if(!Obj.exists()){ + error("Turn: Übergebenes Objekt existiert nicht.\n"); + throw ERROR; + } + + if(!ObjectAccessible(CreatureID, Obj, 1)){ + throw NOTACCESSIBLE; + } + + ObjectType ObjType = Obj.getObjectType(); + if(!ObjType.getFlag(ROTATE)){ + throw NOTTURNABLE; + } + + ObjectType RotateTarget = ObjType.getAttribute(ROTATETARGET); + if(RotateTarget == ObjType){ + error("Turn: Objekt %d wird durch Drehen zerstört.\n", ObjType.TypeID); + } + + Change(Obj, RotateTarget, 0); +} + +void CreatePool(Object Con, ObjectType Type, uint32 Value){ + if(!Con.exists()){ + error("CreatePool: Übergebener MapContainer existiert nicht.\n"); + throw ERROR; + } + + ObjectType ConType = Con.getObjectType(); + if(!ConType.isMapContainer()){ + error("CreatePool: Übergebenes Objekt ist kein MapContainer.\n"); + throw ERROR; + } + + // NOTE(fusion): There can be no liquid pools on fields with other BOTTOM + // objects, with the exception of other liquid pools, in which case the new + // liquid pool would replace the old one. + Object Help = GetFirstContainerObject(Con); + while(Help != NONE){ + Object Next = Help.getNextObject(); + ObjectType HelpType = Help.getObjectType(); + if(HelpType.getFlag(BOTTOM)){ + if(!HelpType.getFlag(LIQUIDPOOL)){ + throw NOROOM; + } + + try{ + Delete(Help, -1); + }catch(RESULT r){ + error("CreatePool: Exception %d beim Löschen des alten Pools.\n", r); + } + } + Help = Next; + } + + Create(Con, Type, Value); +} + +void EditText(uint32 CreatureID, Object Obj, const char *Text){ + if(!Obj.exists()){ + error("EditText: Übergebenes Objekt existiert nicht.\n"); + throw ERROR; + } + + ObjectType ObjType = Obj.getObjectType(); + if(!ObjType.getFlag(WRITE) && (!ObjType.getFlag(WRITEONCE) || Obj.getAttribute(TEXTSTRING) != 0)){ + error("EditText: Objekt ist nicht beschreibbar.\n"); + throw ERROR; + } + + TCreature *Creature = GetCreature(CreatureID); + if(Creature == NULL){ + error("EditText: Kreatur existiert nicht.\n"); + throw ERROR; + } + + int TextLength = (int)strlen(Text); + int MaxLength = (ObjType.getFlag(WRITE) + ? ObjType.getAttribute(MAXLENGTH) + : ObjType.getAttribute(MAXLENGTHONCE)); + if(TextLength >= MaxLength){ + throw TOOLONG; + } + + // TODO(fusion): Similar to maybe inlined function in `Look`. + // TODO(fusion): Same as in `Look`. `CreatureID` can't be zero here or we'd + // have already returned so its probably some inlined function. + if(CreatureID != 0 && !ObjectAccessible(CreatureID, Obj, 1)){ + throw NOTACCESSIBLE; + } + + uint32 ObjText = Obj.getAttribute(TEXTSTRING); + if((ObjText != 0 && strcmp(GetDynamicString(ObjText), Text) == 0) + || (ObjText == 0 && Text[0] == 0)){ + print(3, "Text hat sich nicht geändert.\n"); + return; + } + + DeleteDynamicString(ObjText); + Change(Obj, TEXTSTRING, AddDynamicString(Text)); + + DeleteDynamicString(Obj.getAttribute(EDITOR)); + Change(Obj, EDITOR, AddDynamicString(Creature->Name)); +} + +Object CreateAtCreature(uint32 CreatureID, ObjectType Type, uint32 Value){ + // TODO(fusion): Bruhh... + + TCreature *Creature = GetCreature(CreatureID); + if(Creature == NULL){ + // TODO(fusion): Different function name? + error("GiveObjectToCreature: Kann Kreatur nicht finden.\n"); + throw ERROR; + } + + try{ + CheckWeight(CreatureID, Type, Value, 0); + }catch(RESULT r){ + return Create(GetMapContainer(Creature->CrObject), Type, Value); + } + + Object Obj = NONE; + bool CheckContainers = Type.getFlag(MOVEMENTEVENT); + for(int i = 0; i < 2; i += 1){ + bool TooHeavy = false; + for(int Position = INVENTORY_FIRST; + Position <= INVENTORY_LAST; + Position += 1){ + try{ + Object BodyObj = GetBodyObject(CreatureID, Position); + if(CheckContainers){ + if(BodyObj != NONE && BodyObj.getObjectType().getFlag(CONTAINER)){ + Obj = Create(BodyObj, Type, Value); + break; + } + }else{ + if(BodyObj == NONE){ + Obj = Create(GetBodyContainer(CreatureID, Position), Type, Value); + break; + } + } + }catch(RESULT r){ + // TODO(fusion): Is this even possible if we're checking the + // weight before hand? + if(r == TOOHEAVY){ + TooHeavy = true; + break; + } + } + } + + if(Obj != NONE || TooHeavy){ + break; + } + + CheckContainers = !CheckContainers; + } + + if(Obj == NONE){ + Obj = Create(GetMapContainer(Creature->CrObject), Type, Value); + } + + return Obj; +} + +void DeleteAtCreature(uint32 CreatureID, ObjectType Type, int Amount, uint32 Value){ + while(Amount > 0){ + Object Obj = GetInventoryObject(CreatureID, Type, Value); + if(Obj == NONE){ + error("DeleteAtCreature: Kein Objekt gefunden.\n"); + throw ERROR; + } + + if(Type.getFlag(CUMULATIVE)){ + int ObjAmount = (int)Obj.getAttribute(AMOUNT); + if(ObjAmount < Amount){ + Delete(Obj, -1); + Amount -= ObjAmount; + }else{ + Change(Obj, AMOUNT, (ObjAmount - Amount)); + Amount = 0; + } + }else{ + Delete(Obj, -1); + Amount -= 1; + } + } +} + +void ProcessCronSystem(void){ + while(true){ + Object Obj = CronCheck(); + if(Obj == NONE){ + break; + } + + ObjectType ObjType = Obj.getObjectType(); + ObjectType ExpireTarget = ObjType.getAttribute(EXPIRETARGET); + if(ObjType.getFlag(CONTAINER)){ + int Remainder = 0; + if(!ExpireTarget.isMapContainer() && ExpireTarget.getFlag(CONTAINER)){ + Remainder = (int)ExpireTarget.getAttribute(CAPACITY); + } + + Empty(Obj, Remainder); + } + + Change(Obj, ExpireTarget, 0); + } +} + +bool SectorRefreshable(int SectorX, int SectorY, int SectorZ){ + // TODO(fusion): Have the sector size defined as a constant in `map.hh`? + //constexpr int SectorSize = 32; + int SearchRadiusX = 32 - 1; + int SearchRadiusY = 32 - 1; + int SearchCenterX = SectorX * 32 + (32 / 2); + int SearchCenterY = SectorY * 32 + (32 / 2); + TFindCreatures Search(SearchRadiusX, SearchRadiusY, SearchCenterX, SearchCenterY, FIND_PLAYERS); + while(true){ + uint32 CharacterID = Search.getNext(); + if(CharacterID == 0){ + break; + } + + TPlayer *Player = GetPlayer(CharacterID); + if(Player == NULL){ + error("SectorRefreshable: Kreatur existiert nicht.\n"); + continue; + } + + // TODO(fusion): Maybe an inlined function to check whether a player + // can see some floor. All floors above ground, when above ground. Or + // two floors up and down, when underground. + if(Player->posz <= 7){ + if(SectorZ <= 7){ + return false; + } + }else{ + if(std::abs(Player->posz - SectorZ) <= 2){ + return false; + } + } + } + + return true; +} + +void RefreshSector(int SectorX, int SectorY, int SectorZ, const uint8 *Data, int Count){ + if(!SectorRefreshable(SectorX, SectorY, SectorZ)){ + return; + } + + TReadBuffer Buffer(Data, Count); + RefreshSector(SectorX, SectorY, SectorZ, &Buffer); + + // TODO(fusion): This function is very similar to `ApplyPatch`. + int SearchRadiusX = 32 / 2; + int SearchRadiusY = 32 / 2; + int SearchCenterX = SectorX * 32 + (32 / 2); + int SearchCenterY = SectorY * 32 + (32 / 2); + TFindCreatures Search(SearchRadiusX, SearchRadiusY, SearchCenterX, SearchCenterY, FIND_ALL); + while(true){ + uint32 CreatureID = Search.getNext(); + if(CreatureID == 0){ + break; + } + + TCreature *Creature = GetCreature(CreatureID); + if(Creature == NULL){ + error("RefreshSector: Kreatur existiert nicht.\n"); + continue; + } + + if(Creature->posz != SectorZ){ + continue; + } + + bool FieldBlocked = false; + int FieldX = Creature->posx; + int FieldY = Creature->posy; + int FieldZ = Creature->posz; + Object Obj = GetFirstObject(FieldX, FieldY, FieldZ); + while(Obj != NONE){ + ObjectType ObjType = Obj.getObjectType(); + if(!ObjType.isCreatureContainer() && ObjType.getFlag(UNPASS)){ + FieldBlocked = true; + break; + } + Obj = Obj.getNextObject(); + } + + if(FieldBlocked){ + try{ + if(!SearchFreeField(&FieldX, &FieldY, &FieldZ, 1, 0, false)){ + if(Creature->Type == NPC){ + print(2, "NPC auf [%d,%d,%d] muß auf seinen Start zurückgesetzt werden.\n", FieldX, FieldY, FieldZ); + FieldX = Creature->startx; + FieldY = Creature->starty; + FieldZ = Creature->startz; + }else if(Creature->Type == MONSTER){ + print(2, "Monster auf [%d,%d,%d] muß gelöscht werden.\n", FieldX, FieldY, FieldZ); + delete Creature; + continue; + }else{ + error("Spieler auf [%d,%d,%d] ist von Refresh betroffen.\n", FieldX, FieldY, FieldZ); + continue; + } + } + + Object MapCon = GetMapContainer(FieldX, FieldY, FieldZ); + Move(0, Creature->CrObject, MapCon, -1, false, NONE); + }catch(RESULT r){ + error("RefreshSector: Exception %d beim Neusetzen des Monsters.\n", r); + } + } + } +} + +void RefreshMap(void){ + TDynamicWriteBuffer HelpBuffer(0x10000); + for(int SectorZ = SectorZMin; SectorZ <= SectorZMax; SectorZ += 1) + for(int SectorY = SectorYMin; SectorY <= SectorYMax; SectorY += 1) + for(int SectorX = SectorXMin; SectorX <= SectorXMax; SectorX += 1){ + if(!SectorRefreshable(SectorX, SectorY, SectorZ)){ + continue; + } + + char FileName[4096]; + snprintf(FileName, sizeof(FileName), "%s/%04u-%04u-%02u.sec", + ORIGMAPPATH, SectorX, SectorY, SectorZ); + if(!FileExists(FileName)){ + continue; + } + + bool Refreshable = false; + int OffsetX = -1; + int OffsetY = -1; + HelpBuffer.reset(); + try{ + TReadScriptFile Script; + Script.open(FileName); + while(true){ + Script.nextToken(); + if(Script.Token == ENDOFFILE){ + Script.close(); + break; + } + + if(Script.Token == SPECIAL && Script.getSpecial() == ','){ + continue; + } + + if(Script.Token == BYTES){ + uint8 *SectorOffset = Script.getBytesequence(); + OffsetX = (int)SectorOffset[0]; + OffsetY = (int)SectorOffset[1]; + Script.readSymbol(':'); + continue; + } + + // TODO(fusion): We don't enforce the token to be an identifier + // here as we do when loading any sector file in `map.cc`. + if(Script.Token == IDENTIFIER){ + if(OffsetX == -1 || OffsetY == -1){ + Script.error("coordinate expected"); + } + + const char *Identifier = Script.getIdentifier(); + if(strcmp(Identifier, "refresh") == 0){ + Refreshable = true; + }else if(strcmp(Identifier, "content") == 0){ + Script.readSymbol('='); + if(Refreshable){ + HelpBuffer.writeByte((uint8)OffsetX); + HelpBuffer.writeByte((uint8)OffsetY); + } + LoadObjects(&Script, &HelpBuffer, !Refreshable); + } + } + } + + if(HelpBuffer.Position > 0){ + TReadBuffer ReadBuffer(HelpBuffer.Data, HelpBuffer.Position); + RefreshSector(SectorX, SectorY, SectorZ, &ReadBuffer); + } + }catch(const char *str){ + error("RefreshMap: Fehler beim Bearbeiten der Datei (%s).\n", str); + } + } +} + +void RefreshCylinders(void){ + // TODO(fusion): `RefreshedCylinders` is the number of cylinders we attempt to + // refresh in this function, which is called every minute or so by `AdvanceGame`. + // We should probably rename it to something more clear. + + // TODO(fusion): This might be on purpose but `RefreshX` and `RefreshY` will be + // way below `SectorXMin` and `SectorYMin` the first N times this function is + // called and depending on the value of `RefreshedCylinders`, could take a few + // hours before we even start refreshing the map. + // If the intent is to delay refreshing cylinders until some time after startup, + // we should change how this function is called by `AdvanceGame` instead. + + static int RefreshX = -1; + static int RefreshY = -1; + for(int i = 0; i < RefreshedCylinders; i += 1){ + if(RefreshX < SectorXMax){ + RefreshX += 1; + }else{ + RefreshX = SectorXMin; + if(RefreshY < SectorYMax){ + RefreshY += 1; + }else{ + RefreshY = SectorYMin; + } + } + + for(int RefreshZ = SectorZMin; + RefreshZ <= SectorZMax; + RefreshZ += 1){ + if(SectorRefreshable(RefreshX, RefreshY, RefreshZ)){ + LoadSectorOrder(RefreshX, RefreshY, RefreshZ); + } + } + } +} + +void ApplyPatch(int SectorX, int SectorY, int SectorZ, + bool FullSector, TReadScriptFile *Script, bool SaveHouses){ + if(SectorX < SectorXMin || SectorX > SectorXMax + || SectorY < SectorYMin || SectorY > SectorYMax + || SectorZ < SectorZMin || SectorZ > SectorZMax){ + return; + } + + PrepareHouseCleanup(); + PatchSector(SectorX, SectorY, SectorZ, FullSector, Script, SaveHouses); + FinishHouseCleanup(); + + // TODO(fusion): Similar to `SectorRefreshable` but with a reduced radius. + int SearchRadiusX = 32 / 2; + int SearchRadiusY = 32 / 2; + int SearchCenterX = SectorX * 32 + (32 / 2); + int SearchCenterY = SectorY * 32 + (32 / 2); + TFindCreatures Search(SearchRadiusX, SearchRadiusY, SearchCenterX, SearchCenterY, FIND_ALL); + while(true){ + uint32 CreatureID = Search.getNext(); + if(CreatureID == 0){ + break; + } + + TCreature *Creature = GetCreature(CreatureID); + if(Creature == NULL){ + error("ApplyPatch: Kreatur existiert nicht.\n"); + continue; + } + + if(Creature->posz != SectorZ){ + continue; + } + + bool FieldBlocked = false; + int FieldX = Creature->posx; + int FieldY = Creature->posy; + int FieldZ = Creature->posz; + Object Obj = GetFirstObject(FieldX, FieldY, FieldZ); + while(Obj != NONE){ + ObjectType ObjType = Obj.getObjectType(); + if(!ObjType.isCreatureContainer() && ObjType.getFlag(UNPASS)){ + FieldBlocked = true; + break; + } + Obj = Obj.getNextObject(); + } + + if(!FieldBlocked){ + // TODO(fusion): Not sure why we're moving the creature to the same + // field, specially with `MoveObject`. Does `PatchSector` leave + // creatures on invalid indices? + Object MapCon = GetMapContainer(FieldX, FieldY, FieldZ); + MoveObject(Creature->CrObject, MapCon); + }else{ + try{ + if(!SearchFreeField(&FieldX, &FieldY, &FieldZ, 1, 0, false)){ + if(Creature->Type == NPC){ + print(2, "NPC auf [%d,%d,%d] muß auf seinen Start zurückgesetzt werden.\n", FieldX, FieldY, FieldZ); + FieldX = Creature->startx; + FieldY = Creature->starty; + FieldZ = Creature->startz; + }else if(Creature->Type == MONSTER){ + print(2, "Monster auf [%d,%d,%d] muß gelöscht werden.\n", FieldX, FieldY, FieldZ); + Delete(Creature->CrObject, -1); + Creature->StartLogout(false, false); + continue; + }else{ + error("Spieler auf [%d,%d,%d] ist von Patch betroffen.\n", FieldX, FieldY, FieldZ); + continue; + } + } + + Object MapCon = GetMapContainer(FieldX, FieldY, FieldZ); + Move(0, Creature->CrObject, MapCon, -1, false, NONE); + }catch(RESULT r){ + error("ApplyPatch: Exception %d beim Neusetzen des Monsters.\n", r); + } + } + } +} + +void ApplyPatches(void){ + // TODO(fusion): We don't handle any script exceptions in here which could + // lead to `PatchDir` being leaked. It may not be a problem overall because + // this function is only called at startup by `InitAll`. + + char FileName[4096]; + bool SaveHouses = false; + snprintf(FileName, sizeof(FileName), "%s/save-houses", SAVEPATH); + if(FileExists(FileName)){ + SaveHouses = true; + print(2, "Häuser werden nicht gepatcht.\n"); + unlink(FileName); + } + + DIR *PatchDir = opendir(SAVEPATH); + if(PatchDir == NULL){ + error("ApplyPatches: Unterverzeichnis %s nicht gefunden.\n", SAVEPATH); + return; + } + + int MaxPatch = -1; + while(dirent *DirEntry = readdir(PatchDir)){ + if(DirEntry->d_type != DT_REG){ + continue; + } + + const char *FileExt = findLast(DirEntry->d_name, '.'); + if(FileExt == NULL){ + continue; + } + + if(strcmp(FileExt, ".pat") == 0){ + int Patch; + if(sscanf(DirEntry->d_name, "%d.pat", &Patch) == 1){ + if(MaxPatch < Patch){ + MaxPatch = Patch; + } + } + }else if(strcmp(FileExt, ".sec") == 0){ + int SectorX, SectorY, SectorZ; + if(sscanf(DirEntry->d_name, "%d-%d-%d.sec", &SectorX, &SectorY, &SectorZ) == 3){ + print(2,"Patche kompletten Sektor %d/%d/%d ...\n", SectorX, SectorY, SectorZ); + snprintf(FileName, sizeof(FileName), "%s/%s", SAVEPATH, DirEntry->d_name); + + TReadScriptFile Script; + Script.open(FileName); + ApplyPatch(SectorX, SectorY, SectorZ, true, &Script, SaveHouses); + Script.close(); + unlink(FileName); + } + } + } + + closedir(PatchDir); + + for(int Patch = 0; Patch <= MaxPatch; Patch += 1){ + snprintf(FileName, sizeof(FileName), "%s/%03d.pat", SAVEPATH, Patch); + if(FileExists(FileName)){ + TReadScriptFile Script; + Script.open(FileName); + if(strcmp(Script.readIdentifier(), "sector") != 0){ + Script.error("Sector expected"); + } + + int SectorX = Script.readNumber(); + Script.readSymbol(','); + int SectorY = Script.readNumber(); + Script.readSymbol(','); + int SectorZ = Script.readNumber(); + + print(2, "Patche Teile von Sektor %d/%d/%d (Patch %d) ...\n", + SectorX, SectorY, SectorZ, Patch); + ApplyPatch(SectorX, SectorY, SectorZ, false, &Script, false); + Script.close(); + unlink(FileName); + } + } +} + +// Communication Logging +// ============================================================================= +uint32 LogCommunication(uint32 CreatureID, int Mode, int Channel, const char *Text){ + static uint32 StatementID = 0; + + if(Text == NULL){ + error("LogCommunication: Text ist NULL.\n"); + return 0; + } + + if(CreatureID == 0){ + error("LogCommunication: CharacterID ist Null.\n"); + return 0; + } + + StatementID += 1; + + TStatement *Statement = Statements.append(); + Statement->StatementID = StatementID; + Statement->TimeStamp = (uint32)time(NULL); + Statement->CharacterID = CreatureID; + Statement->Mode = Mode; + Statement->Channel = Channel; + Statement->Text = AddDynamicString(Text); + Statement->Reported = false; + return StatementID; +} + +uint32 LogListener(uint32 StatementID, TPlayer *Player){ + if(StatementID == 0 || Player == NULL + || !CheckRight(Player->ID, LOG_COMMUNICATION)){ + return 0; + } + + TListener *Listener = Listeners.append(); + Listener->StatementID = StatementID; + Listener->CharacterID = Player->ID; + return StatementID; +} + +void ProcessCommunicationControl(void){ + // NOTE(fusion): Remove statements older than 30 minutes. + int Now = (int)time(NULL); + uint32 Limit = 0; + while(true){ + TStatement *Statement = Statements.next(); + if(Statement == NULL || Now <= (Statement->TimeStamp + 1800)){ + if(Statement != NULL){ + Limit = Statement->StatementID; + } + break; + } + + DeleteDynamicString(Statement->Text); + Statements.remove(); + } + + // TODO(fusion): If there are no statements left we'll end up with `Limit` + // equal to zero which will prevent any listeners entry from being removed. + while(true){ + TListener *Listener = Listeners.next(); + if(Listener == NULL || Listener->StatementID >= Limit){ + break; + } + + Listeners.remove(); + } +} + +int GetCommunicationContext(uint32 CharacterID, uint32 StatementID, + int *NumberOfStatements, vector **ReportedStatements){ + TStatement *Statement = NULL; + int StatementsIter = Statements.iterFirst(); + while(true){ + Statement = Statements.iterNext(&StatementsIter); + if(Statement == NULL || Statement->StatementID == StatementID){ + break; + } + } + + if(Statement == NULL){ + return 1; // STATEMENT_UNKNOWN ? + } + + if(CharacterID == 0){ + bool ChannelMode = Statement->Mode == TALK_CHANNEL_CALL + || Statement->Mode == TALK_GAMEMASTER_CHANNELCALL + || Statement->Mode == TALK_HIGHLIGHT_CHANNELCALL; + + bool ReportableChannel = Statement->Channel == 2 // CHANNEL_TUTOR + || Statement->Channel == 4 // CHANNEL_GAME + || Statement->Channel == 5 // CHANNEL_TRADE + || Statement->Channel == 6 // CHANNEL_RLCHAT + || Statement->Channel == 7; // CHANNEL_HELP + + if(!ChannelMode || !ReportableChannel){ + error("GetCommunicationContext: Äußerung dürfte nicht gemeldet werden.\n"); + return 1; // STATEMENT_UNKNOWN ? + } + } + + if(Statement->Reported){ + return 2; // STATEMENT_ALREADY_REPORTED ? + } + + // TODO(fusion): `FreeSpace` limits the amount of data that is gathered. It + // seems to grow/shrink with the size of the text plus an extra 46 bytes for + // each statement entry. This flat memory overhead of 46 bytes could be some + // compilation/decompilation artifact so I've left it out for now. + // The end point of this data is `ProcessPunishmentOrder` which may record + // statements into the database so it may be related to that. + + bool StatementContained = false; + int FreeSpace = KB(16); + *NumberOfStatements = 0; + *ReportedStatements = new vector(0, 100, 100); + StatementsIter = Statements.iterLast(); + while(true){ + TStatement *Current = Statements.iterPrev(&StatementsIter); + if(Current == NULL){ + break; + } + + if(Current->TimeStamp < (Statement->TimeStamp - 180) + || Current->TimeStamp > (Statement->TimeStamp + 60)){ + continue; + } + + if(FreeSpace <= 0 && Current->TimeStamp > Statement->TimeStamp){ + error("GetCommunicationContext: Kontext wird zu groß. Schneide Ende ab.\n"); + break; + } + + if(CharacterID == 0){ + bool ChannelMode = Current->Mode == TALK_CHANNEL_CALL + || Current->Mode == TALK_GAMEMASTER_CHANNELCALL + || Current->Mode == TALK_HIGHLIGHT_CHANNELCALL; + if(!ChannelMode || Current->Channel != Statement->Channel){ + continue; + } + }else{ + // NOTE(fusion): Check if the character listened to the current statement. + TListener *Listener = NULL; + int ListenersIter = Listeners.iterLast(); + while(true){ + Listener = Listeners.iterPrev(&ListenersIter); + if(Listener == NULL + || Listener->StatementID > Current->StatementID + || (Listener->StatementID == Current->StatementID + && Listener->CharacterID == CharacterID)){ + break; + } + } + + if(Listener == NULL || Listener->StatementID != Current->StatementID){ + continue; + } + } + + TReportedStatement *Entry = (*ReportedStatements)->at(*NumberOfStatements); + Entry->StatementID = Current->StatementID; + Entry->TimeStamp = Current->TimeStamp; + Entry->CharacterID = Current->CharacterID; + Entry->Mode = Current->Mode; + Entry->Channel = Current->Channel; + if(Current->Text != 0){ + // TODO(fusion): OOF SIZE: Large. + strcpy(Entry->Text, GetDynamicString(Current->Text)); + }else{ + Entry->Text[0] = 0; + } + *NumberOfStatements += 1; + FreeSpace -= (int)strlen(Entry->Text); + + if(Current->StatementID == StatementID){ + StatementContained = true; + } + } + + if(FreeSpace < 0){ + error("GetCommunicationContext: Kontext wird um %d Bytes zu groß. Lösche Anfang.\n", -FreeSpace); + + for(int i = 0; i < *NumberOfStatements && FreeSpace < 0; i += 1){ + TReportedStatement *Entry = (*ReportedStatements)->at(i); + if(Entry->StatementID != StatementID){ + Entry->StatementID = 0; + FreeSpace += (int)strlen(Entry->Text); + } + } + + if(FreeSpace < 0){ + error("GetCommunicationContext: FreeSpace ist immer noch negativ (%d).\n", FreeSpace); + } + } + + if(!StatementContained){ + error("GetCommunicationContext: Statement ist nicht im Kontext enthalten.\n"); + delete *ReportedStatements; + *NumberOfStatements = 0; + *ReportedStatements = NULL; + return 1; // STATEMENT_UNKNOWN ? + } + + Statement->Reported = true; + return 0; // STATEMENT_REPORTED ? +} + +// Channel +// ============================================================================= +TChannel::TChannel(void) : Subscriber(0, 10, 10), InvitedPlayer(0, 10, 10) { + this->Moderator = 0; + this->ModeratorName[0] = 0; + this->Subscribers = 0; + this->InvitedPlayers = 0; +} + +TChannel::TChannel(const TChannel &Other) : TChannel() { + this->operator=(Other); +} + +void TChannel::operator=(const TChannel &Other){ + this->Subscribers = Other.Subscribers; + for(int i = 0; i < Other.Subscribers; i += 1){ + *this->Subscriber.at(i) = Other.Subscriber.copyAt(i); + } + + this->InvitedPlayers = Other.InvitedPlayers; + for(int i = 0; i < Other.InvitedPlayers; i += 1){ + *this->InvitedPlayer.at(i) = Other.InvitedPlayer.copyAt(i); + } +} + +bool ChannelActive(int ChannelID){ + if(ChannelID < 0 || ChannelID >= Channels){ + error("ChannelActive: Ungültige Kanalnummer %d.\n", ChannelID); + return false; + } + + return ChannelID <= 7 || Channel.at(ChannelID)->Moderator != 0; +} + +const char *GetChannelName(int ChannelID, uint32 CharacterID){ + static char ChannelName[40]; + + if(!ChannelActive(ChannelID)){ + return "Unknown"; + } + + TPlayer *Player = GetPlayer(CharacterID); + if(Player == NULL){ + error("GetChannelName: Spieler existiert nicht.\n"); + return "Unknown"; + } + + switch(ChannelID){ + case 0: return Player->Guild; + case 1: return "Gamemaster"; + case 2: return "Tutor"; + case 3: return "Rule Violations"; + case 4: return "Game-Chat"; + case 5: return "Trade"; + case 6: return "RL-Chat"; + case 7: return "Help"; + default:{ + if(ChannelID > 7){ + snprintf(ChannelName, sizeof(ChannelName), "%s\'s Channel", + Channel.at(ChannelID)->ModeratorName); + return ChannelName; + }else{ + error("GetChannelName: Unbenutzter Kanal %d.\n", ChannelID); + return "Unknown"; + } + } + } +} + +// Party +// ============================================================================= +TParty::TParty(void) : Member(0, 10, 10), InvitedPlayer(0, 10, 10) { + this->Leader = 0; + this->Members = 0; + this->InvitedPlayers = 0; +} + +TParty::TParty(const TParty &Other) : TParty() { + this->operator=(Other); +} + +void TParty::operator=(const TParty &Other){ + this->Members = Other.Members; + for(int i = 0; i < Other.Members; i += 1){ + *this->Member.at(i) = Other.Member.copyAt(i); + } + + this->InvitedPlayers = Other.InvitedPlayers; + for(int i = 0; i < Other.InvitedPlayers; i += 1){ + *this->InvitedPlayer.at(i) = Other.InvitedPlayer.copyAt(i); + } +} diff --git a/src/operate.hh b/src/operate.hh index 7d137fd..0c370a2 100644 --- a/src/operate.hh +++ b/src/operate.hh @@ -2,6 +2,8 @@ #define TIBIA_OPERATE_HH_ 1 #include "common.hh" +#include "containers.hh" +#include "cr.hh" #include "map.hh" enum : int { @@ -20,6 +22,74 @@ enum : int { OBJECT_MOVED = 3, }; +struct TChannel { + TChannel(void); + + // TODO(fusion): `TChannel` will primarily live inside the `Channel` vector, + // which needs to resize its internal array as needed. To resize, it needs + // to copy/swap elements, which would be impossible since `TChannel` itself + // owns a few vectors which were made NON-COPYABLE to prevent memory bugs. + // To fix this problem and allow `TChannel` to be copyable, we need to + // implement the copy constructor and assignment manually. They're annoying + // and expensive but should allow everything to compile again. + // This problem arises from the fact that our unconventional `vector` type + // has a weird interface but still manages its underlying memory. If we are + // to resolve this completely, we'd need to re-implement `vector` properly + // and preferably with move semantics (if we want to follow the C++ route, + // which we may not). + TChannel(const TChannel &Other); + void operator=(const TChannel &Other); + + // DATA + // ================= + uint32 Moderator; + char ModeratorName[30]; + vector Subscriber; + int Subscribers; + vector InvitedPlayer; + int InvitedPlayers; +}; + +struct TParty { + TParty(void); + + // TODO(fusion): Same as `TChannel`. + TParty(const TParty &Other); + void operator=(const TParty &Other); + + // DATA + // ================= + uint32 Leader; + vector Member; + int Members; + vector InvitedPlayer; + int InvitedPlayers; +}; + +struct TStatement { + uint32 StatementID; + int TimeStamp; + uint32 CharacterID; + int Mode; + int Channel; + uint32 Text; + bool Reported; +}; + +struct TListener { + uint32 StatementID; + uint32 CharacterID; +}; + +struct TReportedStatement { + uint32 StatementID; + int TimeStamp; + uint32 CharacterID; + int Mode; + int Channel; + char Text[256]; +}; + void AnnounceMovingCreature(uint32 CreatureID, Object Con); void AnnounceChangedCreature(uint32 CreatureID, int Type); void AnnounceChangedField(Object Obj, int Type); @@ -61,5 +131,31 @@ void GraphicalEffect(int x, int y, int z, int Type); void GraphicalEffect(Object Obj, int Type); void TextualEffect(Object Obj, int Color, const char *Format, ...) ATTR_PRINTF(3, 4); void Missile(Object Start, Object Dest, int Type); +void Look(uint32 CreatureID, Object Obj); +void Talk(uint32 CreatureID, int Mode, const char *Addressee, const char *Text, bool CheckSpamming); +void Use(uint32 CreatureID, Object Obj1, Object Obj2, uint8 Info); +void Turn(uint32 CreatureID, Object Obj); +void CreatePool(Object Con, ObjectType Type, uint32 Value); +void EditText(uint32 CreatureID, Object Obj, const char *Text); +Object CreateAtCreature(uint32 CreatureID, ObjectType Type, uint32 Value); +void DeleteAtCreature(uint32 CreatureID, ObjectType Type, int Amount, uint32 Value); + +void ProcessCronSystem(void); +bool SectorRefreshable(int SectorX, int SectorY, int SectorZ); +void RefreshSector(int SectorX, int SectorY, int SectorZ, const uint8 *Data, int Count); +void RefreshMap(void); +void RefreshCylinders(void); +void ApplyPatch(int SectorX, int SectorY, int SectorZ, + bool FullSector, TReadScriptFile *Script, bool SaveHouses); +void ApplyPatches(void); + +uint32 LogCommunication(uint32 CreatureID, int Mode, int Channel, const char *Text); +uint32 LogListener(uint32 StatementID, TPlayer *Player); +void ProcessCommunicationControl(void); +int GetCommunicationContext(uint32 CharacterID, uint32 StatementID, + int *NumberOfStatements, vector **ReportedStatements); + +uint32 GetFirstSubscriber(int Channel); +uint32 GetNextSubscriber(void); #endif //TIBIA_OPERATE_HH_ diff --git a/src/stubs.hh b/src/stubs.hh index cb06608..df270ff 100644 --- a/src/stubs.hh +++ b/src/stubs.hh @@ -19,14 +19,11 @@ extern void BroadcastMessage(int Mode, const char *Text, ...) ATTR_PRINTF(2, 3); extern void ChangeNPCState(TCreature *Npc, int NewState, bool Stimulus); extern void CharacterDeathOrder(TCreature *Creature, int OldLevel, uint32 Offender, const char *Remark, bool Unjustified); -extern bool CheckRight(uint32 CreatureID, RIGHT Right); extern void CleanHouseField(int x, int y, int z); extern void ConvinceMonster(TCreature *Master, TCreature *Slave); extern void ChallengeMonster(TCreature *Challenger, TCreature *Monster); -extern Object CreateAtCreature(uint32 CreatureID, ObjectType Type, uint32 Value); 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 GetExitPosition(uint16 HouseID, int *x, int *y, int *z); extern TConnection *GetFirstConnection(void); extern TConnection *GetNextConnection(void); @@ -39,22 +36,18 @@ extern void InitLog(const char *ProtocolName); extern void KickGuest(uint16 HouseID, TPlayer *Host, TPlayer *Guest); extern void KillStatisticsOrder(int NumberOfRaces, const char *RaceNames, int *KilledPlayers, int *KilledCreatures); extern bool LagDetected(void); -extern void LoadMonsterRaid(const char *FileName, int Start, - bool *Type, int *Date, int *Interval, int *Duration); +extern void LoadSectorOrder(int SectorX, int SectorY, int SectorZ); extern void Log(const char *ProtocolName, const char *Text, ...) ATTR_PRINTF(2, 3); extern void LogoutAllPlayers(void); extern void NetLoadCheck(void); extern void NetLoadSummary(void); -extern void ProcessCommunicationControl(void); +extern void PrepareHouseCleanup(void); +extern void FinishHouseCleanup(void); extern void ProcessConnections(void); -extern void ProcessCronSystem(void); extern void ProcessMonsterhomes(void); extern void ProcessReaderThreadReplies(TRefreshSectorFunction *RefreshSector, TSendMailsFunction *SendMails); extern void ProcessWriterThreadReplies(void); extern void ReceiveData(void); -extern void RefreshCylinders(void); -extern void RefreshMap(void); -extern void RefreshSector(int SectorX, int SectorY, int SectorZ, const uint8 *Data, int Size); extern void SavePlayerDataOrder(void); extern void SendAll(void); extern void SendAmbiente(TConnection *Connection); @@ -92,13 +85,32 @@ extern void SendPlayerSkills(TConnection *Connection); extern void SendPlayerState(TConnection *Connection, uint8 State); extern void SendResult(TConnection *Connection, RESULT r); extern void SendSnapback(TConnection *Connection); +extern void SendTalk(TConnection *Connection, uint32 StatementID, + const char *Sender, int Mode, const char *Text, int Data); +extern void SendTalk(TConnection *Connection, uint32 StatementID, + const char *Sender, int Mode, int Channel, const char *Text); +extern void SendTalk(TConnection *Connection, uint32 StatementID, + const char *Sender, int Mode, int x,int y,int z, const char *Text); extern void SendTradeOffer(TConnection *Connection, const char *Name, bool OwnOffer, Object Obj); extern void ShowGuestList(uint16 HouseID, TPlayer *Player, char *Buffer); extern void ShowSubownerList(uint16 HouseID, TPlayer *Player, char *Buffer); extern void ShowNameDoor(Object Door, TPlayer *Player, char *Buffer); -extern void Talk(uint32 CreatureID, int Mode, const char *Addressee, const char *Text, bool CheckSpamming); -extern void Turn(uint32 CreatureID, Object Obj); -extern void Use(uint32 CreatureID, Object Obj1, Object Object2, uint8 Info); + +// moveuse.cc +extern void UseContainer(uint32 CreatureID, Object Con, uint8 ContainerNr); +extern void UseChest(uint32 CreatureID, Object Chest); +extern void UseLiquidContainer(uint32 CreatureID, Object Obj, Object Dest); +extern void UseFood(uint32 CreatureID, Object Obj); +extern void UseTextObject(uint32 CreatureID, Object Obj); +extern void UseAnnouncer(uint32 CreatureID, Object Obj); +extern void UseKeyDoor(uint32 CreatureID, Object Key, Object Door); +extern void UseNameDoor(uint32 CreatureID, Object Door); +extern void UseLevelDoor(uint32 CreatureID, Object Door); +extern void UseQuestDoor(uint32 CreatureID, Object Door); +extern void UseWeapon(uint32 CreatureID, Object Weapon, Object Target); +extern void UseChangeObject(uint32 CreatureID, Object Obj); +extern void UseObject(uint32 CreatureID, Object Obj); +extern void UseObjects(uint32 CreatureID, Object Obj1, Object Obj2); extern void MovementEvent(Object Obj, Object Start, Object Dest); extern void CollisionEvent(Object Obj, Object Dest); extern void SeparationEvent(Object Obj, Object Start); -- cgit v1.2.3