From 5bdedeecea69a5892e3ce8854e85f78537cf7ca4 Mon Sep 17 00:00:00 2001 From: fusion32 Date: Sun, 15 Jun 2025 22:25:12 -0300 Subject: channel functions --- reference/game.c | 807 ------------------------------------------------------ src/containers.hh | 2 + src/operate.cc | 391 +++++++++++++++++++++++++- src/operate.hh | 32 ++- src/stubs.hh | 4 + 5 files changed, 427 insertions(+), 809 deletions(-) diff --git a/reference/game.c b/reference/game.c index 5fd4ee7..6b71785 100644 --- a/reference/game.c +++ b/reference/game.c @@ -18375,813 +18375,6 @@ void __static_initialization_and_destruction_0(int __initialize_p,int __priority 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 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; -} - - - -bool MayOpenChannel(ulong CharacterID) - -{ - bool bVar1; - TChannel *pTVar2; - bool bVar3; - int i; - int i_00; - - 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; - } - } - else { -LAB_08099cfb: - bVar3 = false; - } - return bVar3; -} - - - -// WARNING: Variable defined which should be unmapped: pl - -void OpenChannel(ulong CharacterID) - -{ - bool bVar1; - TPlayer *pTVar2; - TChannel *pTVar3; - ulong *puVar4; - undefined4 *puVar5; - int ChannelID; - int i; - TChannel *C; - int i_00; - TPlayer *pl; - - // 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 (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; - } - 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; - } - 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; - } - 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); - } - if (C == (TChannel *)0xffffffff) { - return; - } - 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 (-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; - } - } - 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"; - } - SendMessage(*(TConnection **)(channel + 0x318),0x16, - "%s invites you to %s private chat channel.",(pTVar2->super_TCreature).Name, - pcVar7); - } - } - return; -} - - - -// WARNING: Variable defined which should be unmapped: Opp - -void ExcludeFromChannel(ulong CharacterID,char *Name) - -{ - bool bVar1; - TPlayer *pTVar2; - int iVar3; - ulong *puVar4; - ulong *puVar5; - undefined4 *puVar6; - TChannel *pTVar7; - ulong OppID; - TChannel *pTVar8; - ulong CharacterID_00; - int i; - int local_24; - int Position; - TChannel *C; - int channel; - TPlayer *pl; - TPlayer *Opp; - - // 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; - } - pTVar8 = (TChannel *)((int)&pTVar8->Moderator + 1); - } while ((int)pTVar8 < Channels); - } - 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); - } - } - } - } - } - 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 (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; - } - 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); -} - - - -// 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 { - bVar6 = true; - if (7 < ChannelID) { - pTVar1 = vector::operator()(&Channel,ChannelID); - bVar6 = 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; - } - 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; - } - } - 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 { - bVar2 = true; - if (7 < i) { - pTVar1 = vector::operator()(&Channel,i); - bVar2 = pTVar1->Moderator != 0; - } - } - if (bVar2) { - LeaveChannel(i,CharacterID,false); - } - i = i + 1; - } while (i < Channels); - } - return; -} - TParty * GetParty(ulong Leader) { diff --git a/src/containers.hh b/src/containers.hh index f82159b..ecbe6be 100644 --- a/src/containers.hh +++ b/src/containers.hh @@ -122,6 +122,8 @@ struct vector{ T Result = {}; if(index >= this->start && index < (this->start + this->space)){ Result = this->entry[index - this->start]; + }else if(this->initialized){ + Result = this->init; } return Result; } diff --git a/src/operate.cc b/src/operate.cc index 2224ed4..7d18a94 100644 --- a/src/operate.cc +++ b/src/operate.cc @@ -3387,6 +3387,10 @@ void TChannel::operator=(const TChannel &Other){ } } +int GetNumberOfChannels(void){ + return Channels; +} + bool ChannelActive(int ChannelID){ if(ChannelID < 0 || ChannelID >= Channels){ error("ChannelActive: Ungültige Kanalnummer %d.\n", ChannelID); @@ -3396,6 +3400,44 @@ bool ChannelActive(int ChannelID){ return ChannelID <= 7 || Channel.at(ChannelID)->Moderator != 0; } +bool ChannelAvailable(int ChannelID, uint32 CharacterID){ + if(!ChannelActive(ChannelID)){ + return false; + } + + TPlayer *Player = GetPlayer(CharacterID); + if(Player == NULL){ + error("ChannelAvailable: Spieler existiert nicht.\n"); + return false; + } + + switch(ChannelID){ + case 0: return Player->Guild[0] != 0; + case 1: return CheckRight(Player->ID, READ_GAMEMASTER_CHANNEL); + case 2: return CheckRight(Player->ID, READ_TUTOR_CHANNEL); + case 3: return CheckRight(Player->ID, READ_GAMEMASTER_CHANNEL); + case 4: return true; + case 5: return true; + case 6: return true; + case 7: return true; + default:{ + if(ChannelID > 7){ + TChannel *Chan = Channel.at(ChannelID); + if(Chan->Moderator == CharacterID){ + return true; + } + + for(int i = 0; i < Chan->InvitedPlayers; i += 1){ + if(*Chan->InvitedPlayer.at(i) == CharacterID){ + return true; + } + } + } + return false; + } + } +} + const char *GetChannelName(int ChannelID, uint32 CharacterID){ static char ChannelName[40]; @@ -3410,7 +3452,7 @@ const char *GetChannelName(int ChannelID, uint32 CharacterID){ } switch(ChannelID){ - case 0: return Player->Guild; + case 0: return Player->Guild; case 1: return "Gamemaster"; case 2: return "Tutor"; case 3: return "Rule Violations"; @@ -3431,6 +3473,353 @@ const char *GetChannelName(int ChannelID, uint32 CharacterID){ } } +bool ChannelSubscribed(int ChannelID, uint32 CharacterID){ + if(!ChannelActive(ChannelID)){ + return false; + } + + TChannel *Chan = Channel.at(ChannelID); + for(int i = 0; i < Chan->Subscribers; i += 1){ + if(*Chan->Subscriber.at(i) == CharacterID){ + return true; + } + } + + return false; +} + +// TODO(fusion): This could have been a simple for loop? +uint32 GetFirstSubscriber(int ChannelID){ + CurrentChannelID = ChannelID; + CurrentSubscriberNumber = 0; + return GetNextSubscriber(); +} + +uint32 GetNextSubscriber(void){ + if(!ChannelActive(CurrentChannelID)){ + return 0; + } + + uint32 Subscriber = 0; + TChannel *Chan = Channel.at(CurrentChannelID); + if(CurrentSubscriberNumber < Chan->Subscribers){ + Subscriber = *Chan->Subscriber.at(CurrentSubscriberNumber); + CurrentSubscriberNumber += 1; + } + + return Subscriber; +} + +bool MayOpenChannel(uint32 CharacterID){ + if(Channels >= 0xFFFF){ + return false; + } + + if(!CheckRight(CharacterID, PREMIUM_ACCOUNT)){ + return false; + } + + // NOTE(fusion): Check if character is already moderator of any non-public channel. + for(int ChannelID = 8; ChannelID < Channels; ChannelID += 1){ + if(Channel.at(ChannelID)->Moderator == CharacterID){ + return false; + } + } + + return true; +} + +void OpenChannel(uint32 CharacterID){ + TPlayer *Player = GetPlayer(CharacterID); + if(Player == NULL){ + error("OpenChannel: Kreatur %u existiert nicht.\n", CharacterID); + throw ERROR; + } + + // TODO(fusion): Shouldn't we scan for a free channel before returning here? + if(Channels >= 0xFFFF){ + error("OpenChannel: Zu viele Kanäle.\n"); + throw ERROR; + } + + if(!CheckRight(CharacterID, PREMIUM_ACCOUNT)){ + throw NOPREMIUMACCOUNT; + } + + // NOTE(fusion): Check if character already has an open channel. + for(int ChannelID = 8; ChannelID < Channels; ChannelID += 1){ + if(Channel.at(ChannelID)->Moderator == CharacterID){ + SendOpenOwnChannel(Player->Connection, ChannelID); + return; + } + } + + // NOTE(fusion): Assign free channel to character. + int ChannelID = 8; + while(ChannelID < Channels){ + if(Channel.at(ChannelID)->Moderator == 0){ + break; + } + ChannelID += 1; + } + + if(ChannelID == Channels){ + Channels += 1; + } + + TChannel *Chan = Channel.at(ChannelID); + Chan->Moderator = CharacterID; + strcpy(Chan->ModeratorName, Player->Name); + *Chan->Subscriber.at(0) = CharacterID; + Chan->Subscribers = 1; + Chan->InvitedPlayers = 0; + SendOpenOwnChannel(Player->Connection, ChannelID); +} + +void CloseChannel(int ChannelID){ + if(ChannelID <= 7 || ChannelID >= Channels){ + error("CloseChannel: Ungültige ChannelID %d.\n", ChannelID); + return; + } + + TChannel *Chan = Channel.at(ChannelID); + if(Chan->Moderator == 0){ + error("CloseChannel: Kanal ist schon geschlossen.\n"); + return; + } + + Chan->Moderator = 0; +} + +void InviteToChannel(uint32 CharacterID, const char *Name){ + TPlayer *Player = GetPlayer(CharacterID); + if(Player == NULL){ + error("InviteToChannel: Kreatur %u existiert nicht.\n", CharacterID); + return; + } + + int ChannelID = 8; + while(ChannelID < Channels){ + if(Channel.at(ChannelID)->Moderator == CharacterID){ + break; + } + ChannelID += 1; + } + + if(ChannelID >= Channels){ + return; + } + + TPlayer *Other = NULL; + uint32 OtherID = 0; + bool IgnoreGamemasters = !CheckRight(Player->ID, READ_GAMEMASTER_CHANNEL); + switch(IdentifyPlayer(Name, false, IgnoreGamemasters, &Other)){ + case 0:{ // PLAYERFOUND ? + OtherID = Other->ID; + Name = Other->Name; + break; + } + + case -1:{ // PLAYERNOTONLINE ? + OtherID = GetCharacterID(Name); + if(OtherID == 0){ + throw PLAYERNOTEXISTING; + } + + Name = GetCharacterName(Name); + break; + } + + case -2:{ // NAMEAMBIGUOUS ? + OtherID = GetCharacterID(Name); + if(OtherID == 0){ + throw NAMEAMBIGUOUS; + } + + Name = GetCharacterName(Name); + break; + } + + default:{ + // TODO(fusion): This wasn't here but I don't think `IdentifyPlayer` + // can return anything else than 0, -1, and -2 anyways. + error("InviteToChannel: Ungültiger Rückgabewert von IdentifyPlayer.\n"); + throw ERROR; + } + } + + print(3, "Lade Spieler %s (%u) in Private Channel ein.\n", Name, OtherID); + if(CharacterID != OtherID){ + TChannel *Chan = Channel.at(ChannelID); + for(int i = 0; i < Chan->InvitedPlayers; i += 1){ + if(*Chan->InvitedPlayer.at(i) == OtherID){ + SendMessage(Player->Connection, TALK_INFO_MESSAGE, + "%s has already been invited.", Name); + return; + } + } + + *Chan->InvitedPlayer.at(Chan->InvitedPlayers) = OtherID; + Chan->InvitedPlayers += 1; + + SendMessage(Player->Connection, TALK_INFO_MESSAGE, + "%s has been invited.", Name); + + if(Other != NULL){ + SendMessage(Other->Connection, TALK_INFO_MESSAGE, + "%s invites you to %s private chat channel.", + Player->Name, (Player->Sex == 1 ? "his" : "her")); + } + } +} + +void ExcludeFromChannel(uint32 CharacterID, const char *Name){ + TPlayer *Player = GetPlayer(CharacterID); + if(Player == NULL){ + error("ExcludeFromChannel: Kreatur %u existiert nicht.\n", CharacterID); + return; + } + + int ChannelID = 8; + while(ChannelID < Channels){ + if(Channel.at(ChannelID)->Moderator == CharacterID){ + break; + } + ChannelID += 1; + } + + if(ChannelID >= Channels){ + return; + } + + // TODO(fusion): Why don't we call `GetCharacterName` as we do in + // `InviteToChannel`, when the player is not found? + TPlayer *Other = NULL; + uint32 OtherID = 0; + bool IgnoreGamemasters = !CheckRight(Player->ID, READ_GAMEMASTER_CHANNEL); + switch(IdentifyPlayer(Name, false, IgnoreGamemasters, &Other)){ + case 0:{ // PLAYERFOUND ? + OtherID = Other->ID; + Name = Other->Name; + break; + } + + case -1:{ // PLAYERNOTONLINE ? + OtherID = GetCharacterID(Name); + if(OtherID == 0){ + throw PLAYERNOTEXISTING; + } + break; + } + + case -2:{ // NAMEAMBIGUOUS ? + OtherID = GetCharacterID(Name); + if(OtherID == 0){ + throw NAMEAMBIGUOUS; + } + break; + } + + default:{ + // TODO(fusion): Same as `InviteToChannel`. + error("ExcludeFromChannel: Ungültiger Rückgabewert von IdentifyPlayer.\n"); + throw ERROR; + } + } + + print(3, "Schließe Spieler %s (%u) aus Private Channel aus.\n", Name, OtherID); + if(CharacterID != OtherID){ + bool Removed = false; + TChannel *Chan = Channel.at(ChannelID); + for(int i = 0; i < Chan->InvitedPlayers; i += 1){ + if(*Chan->InvitedPlayer.at(i) == OtherID){ + // NOTE(fusion): A little swap and pop action. + Chan->InvitedPlayers -= 1; + *Chan->InvitedPlayer.at(i) = *Chan->InvitedPlayer.at(Chan->InvitedPlayers); + Removed = true; + break; + } + } + + if(!Removed){ + SendMessage(Player->Connection, TALK_INFO_MESSAGE, + "%s has not been invited.", Name); + }else{ + SendMessage(Player->Connection, TALK_INFO_MESSAGE, + "%s has been excluded.", Name); + if(ChannelSubscribed(ChannelID, OtherID)){ + LeaveChannel(ChannelID, OtherID, false); + + // TODO(fusion): We didn't check if `Other` was NULL here. It + // seems that the player destructor will call `LeaveAllChannels` + // to make sure a player is only subscribed if it is still valid. + // Nevertheless, this check should become invisible to the branch + // predictor and it's always best to be safe. + if(Other != NULL){ + SendCloseChannel(Other->Connection, ChannelID); + } + } + } + } +} + +bool JoinChannel(int ChannelID, uint32 CharacterID){ + if(!ChannelActive(ChannelID)){ + throw ERROR; + } + + if(!ChannelAvailable(ChannelID, CharacterID)){ + throw NOTACCESSIBLE; + } + + TChannel *Chan = Channel.at(ChannelID); + if(!ChannelSubscribed(ChannelID, CharacterID)){ + *Chan->Subscriber.at(Chan->Subscribers) = CharacterID; + Chan->Subscribers += 1; + } + + return CharacterID == Chan->Moderator; +} + +void LeaveChannel(int ChannelID, uint32 CharacterID, bool Close){ + if(!ChannelActive(ChannelID)){ + return; + } + + TChannel *Chan = Channel.at(ChannelID); + for(int i = 0; i < Chan->Subscribers; i += 1){ + if(*Chan->Subscriber.at(i) == CharacterID){ + // NOTE(fusion): A little swap and pop action. + Chan->Subscribers -= 1; + *Chan->Subscriber.at(i) = *Chan->Subscriber.at(Chan->Subscribers); + break; + } + } + + if(Close && CharacterID == Chan->Moderator){ + for(int i = 0; i < Chan->Subscribers; i += 1){ + uint32 SubscriberID = *Chan->Subscriber.at(i); + TPlayer *Subscriber = GetPlayer(SubscriberID); + if(Subscriber != NULL){ + SendCloseChannel(Subscriber->Connection, ChannelID); + } + } + Chan->Subscribers = 0; + } + + if(ChannelID > 7 && Chan->Subscribers == 0){ + CloseChannel(ChannelID); + } +} + +void LeaveAllChannels(uint32 CharacterID){ + for(int ChannelID = 0; ChannelID < Channels; ChannelID += 1){ + if(ChannelActive(ChannelID)){ + LeaveChannel(ChannelID, CharacterID, false); + } + } +} + // Party // ============================================================================= TParty::TParty(void) : Member(0, 10, 10), InvitedPlayer(0, 10, 10) { diff --git a/src/operate.hh b/src/operate.hh index 0c370a2..4942569 100644 --- a/src/operate.hh +++ b/src/operate.hh @@ -22,6 +22,23 @@ enum : int { OBJECT_MOVED = 3, }; +// TODO(fusion): Use these? +enum : int { + CHANNEL_GUILD = 0, + CHANNEL_GAMEMASTER = 1, + CHANNEL_TUTOR = 2, + CHANNEL_RULEVIOLATIONS = 3, + CHANNEL_GAMECHAT = 4, + CHANNEL_TRADE = 5, + CHANNEL_RLCHAT = 6, + CHANNEL_HELP = 7, + + CHANNEL_PUBLIC_FIRST = 0, + CHANNEL_PUBLIC_LAST = 7, + CHANNEL_PRIVATE_FIRST = 8, + CHANNEL_PRIVATE_LAST = 0xFFFF, +}; + struct TChannel { TChannel(void); @@ -155,7 +172,20 @@ void ProcessCommunicationControl(void); int GetCommunicationContext(uint32 CharacterID, uint32 StatementID, int *NumberOfStatements, vector **ReportedStatements); -uint32 GetFirstSubscriber(int Channel); +int GetNumberOfChannels(void); +bool ChannelActive(int ChannelID); +bool ChannelAvailable(int ChannelID, uint32 CharacterID); +const char *GetChannelName(int ChannelID, uint32 CharacterID); +bool ChannelSubscribed(int ChannelID, uint32 CharacterID); +uint32 GetFirstSubscriber(int ChannelID); uint32 GetNextSubscriber(void); +bool MayOpenChannel(uint32 CharacterID); +void OpenChannel(uint32 CharacterID); +void CloseChannel(int ChannelID); +void InviteToChannel(uint32 CharacterID, const char *Name); +void ExcludeFromChannel(uint32 CharacterID, const char *Name); +bool JoinChannel(int ChannelID, uint32 CharacterID); +void LeaveChannel(int ChannelID, uint32 CharacterID, bool Close); +void LeaveAllChannels(uint32 CharacterID); #endif //TIBIA_OPERATE_HH_ diff --git a/src/stubs.hh b/src/stubs.hh index df270ff..bb68d1d 100644 --- a/src/stubs.hh +++ b/src/stubs.hh @@ -24,6 +24,8 @@ extern void ConvinceMonster(TCreature *Master, TCreature *Slave); extern void ChallengeMonster(TCreature *Challenger, TCreature *Monster); extern TCreature *CreateMonster(int Race, int x, int y, int z, int Home, uint32 Master, bool ShowEffect); extern void CreatePlayerList(bool Online); +extern uint32 GetCharacterID(const char *Name); +extern const char *GetCharacterName(const char *Name); extern void GetExitPosition(uint16 HouseID, int *x, int *y, int *z); extern TConnection *GetFirstConnection(void); extern TConnection *GetNextConnection(void); @@ -53,6 +55,7 @@ extern void SendAll(void); extern void SendAmbiente(TConnection *Connection); extern void SendClearTarget(TConnection *Connection); extern void SendContainer(TConnection *Connection, int ContainerNr); +extern void SendCloseChannel(TConnection *Connection, int ChannelID); extern void SendCloseContainer(TConnection *Connection, int ContainerNr); extern void SendCloseTrade(TConnection *Connection); extern void SendCreatureHealth(TConnection *Connection, uint32 CreatureID); @@ -80,6 +83,7 @@ extern void SendMails(TPlayerData *PlayerData); extern void SendMarkCreature(TConnection *Connection, uint32 CreatureID, int Color); extern void SendMessage(TConnection *Connection, int Mode, const char *Text, ...) ATTR_PRINTF(3, 4); extern void SendMoveCreature(TConnection *Connection, uint32 CreatureID, int x, int y, int z); +extern void SendOpenOwnChannel(TConnection *Connection, int Channel); extern void SendPlayerData(TConnection *Connection); extern void SendPlayerSkills(TConnection *Connection); extern void SendPlayerState(TConnection *Connection, uint8 State); -- cgit v1.2.3