Files
2022-10-26 12:25:11 +08:00

846 lines
29 KiB
C++

#include "stdafx.h"
#include "./LobbyRoom.h"
//==================================================================================================
#include <PacketStruct_AG.h>
#include <PacketStruct_CG.h>
#include <MapInfoParser.h>
#include <RequireFieldLevelInfoParser.h>
#include <ServerOptionParser.h>
#include <MatchInfoParser.h>
//==================================================================================================
#include <UserSessions/User.h>
#include "ZoneManager.h"
#include "CHuntingRoom.h"
#include "Village.h"
#include "ServerOptionParserEx.h"
#include <ProhibitionWordParser.h>
#include <AgentParty/AgentPartyManager.h>
#include <AgentParty/AgentParty.h>
//==================================================================================================
//==================================================================================================
//==================================================================================================
_IMPL_POOL(LobbyRoom);
//==================================================================================================
LobbyRoom::LobbyRoom(void)
{
}
LobbyRoom::~LobbyRoom(void)
{
}
VOID
LobbyRoom::On_create()
{
RoomInterface::On_create();
MSG_AG_ZONE_LOBBY_CREATE_CMD msg;
msg.m_dwKey = GetMaster()->GetUserKey();
msg.m_MapCode = GetMapCode();
msg.m_RoomKey = GetKey();
memcpy(msg.m_pszRoomTitle, GetRoomTitle(), MAX_ROOMTITLE_LENGTH);
memcpy(msg.m_pszRoomPWD, GetRoomPWD(), MAX_ROOMPASSWORD_LENGTH);
msg.m_RoomInfo = *GetRoomInfo(); //< 생성할 방 정보
SendToLinkedServer(&msg, sizeof(msg));
// 경쟁헌팅 링크 로비방이라면, 다시 링크를 걸지 못하도록 플래그를 셋팅한다.
if(GetLobbyType() == eZONETYPE_CHUNTING)
{
CHuntingRoom* pCHunting = g_ZoneManager.FindCHunting(m_AdditionalCHuntingExInfo.m_LinkHuntingKey);
if(pCHunting)
{
pCHunting->SetLinkedLobby(TRUE);
}
}
m_WaitTimer.SetTimer(0);
}
VOID
LobbyRoom::On_destroy()
{
// 경쟁헌팅 링크 로비방이라면, 다시 링크를 걸수 있도록 플래그를 셋팅한다.
if(GetLobbyType() == eZONETYPE_CHUNTING)
{
CHuntingRoom* pCHunting = g_ZoneManager.FindCHunting(m_AdditionalCHuntingExInfo.m_LinkHuntingKey);
if(pCHunting)
{
pCHunting->SetLinkedLobby(FALSE);
}
}
RoomInterface::On_destroy();
}
VOID
LobbyRoom::On_readyuser(User* pUser)
{
RoomInterface::On_readyuser(pUser);
pUser->SetZoneState(ePRS_BEFORE_ENTER_LOBBY);
pUser->SetZoneKey(GetKey());
pUser->SetZoneType(eZONETYPE_LOBBY);
// 팀배정
AssignTeam(pUser);
}
VOID
LobbyRoom::On_enteruser(User* pUser)
{
RoomInterface::On_enteruser(pUser);
pUser->SetZoneState(ePRS_AT_LOBBY);
}
VOID
LobbyRoom::On_leaveuser(User* pUser)
{
eZONETYPE eFromZoneType, eToZoneType;
DWORD ToLinkServerIndex;
pUser->GetMoveZoneType(eFromZoneType, eToZoneType, ToLinkServerIndex);
if(0 == GetUserNum())
{
SetRoomState(eROOMSTATE_DESTROY);
}
else if(BOOLEAN bMaster = GetMaster() == pUser)
{
if(eToZoneType != eZONETYPE_INSTANCE &&
eToZoneType != eZONETYPE_MISSION &&
eToZoneType != eZONETYPE_PVP && // (CHANGES) (WAVERIX) prevent change master in pvp
eToZoneType != eZONETYPE_CHUNTING)
{
// 방장이면 위임
VestUserWithMaster(GetFirstUser());
// 슈퍼방 아이템을 소지한 자가 없으면 슈퍼방 기능이 해제된다.
if(bMaster)
{
User* pNextMaster = RoomInterface::ChangeSpecialType(false, pUser);
if(pNextMaster)
{
AgentPartyManager::Instance()->ChangeMaster(pNextMaster->GetPartyState().GetPartyKey(),
pNextMaster->GetPlayerKey());
}
}
}
}
if (pUser->GetPartyState().IsPartyMember())
{
AgentPartyManager::Instance()->LeaveZone(pUser, this);
}
pUser->SetReady(FALSE); // 유저 초기화
// (CHANGES) Leave Lobby -> Enter PvP시에 팀 설정 초기화 방지 처리
if(eToZoneType != eZONETYPE_PVP)
pUser->SetTeam(0);
}
RC::eROOM_RESULT
LobbyRoom::ChangeMap(MAPCODE mapCode)
{
const sMAPINFO* pInfo = MapInfoParser::Instance()->FindMapInfo(mapCode);
if(pInfo == 0)
return RC::RC_ROOM_INVALID_MAPCODE;
MapGroup* pGroup = MapInfoParser::Instance()->GetMapGroup(pInfo->MapKind);
sMAPINFO* pChangingMapInfo = pGroup->GetMapInfoCode(mapCode);
if(pChangingMapInfo == 0)
return RC::RC_ROOM_INVALID_MAPCODE;
#ifdef __NA_000000_20070528_TAIWAN_GUILD_PVP
if(GetRoomInfo()->IsSpecialType(eROOM_SPECIAL_GUILD_PVP))
{
if(!pInfo->EntranceItemCode)
return RC::RC_ROOM_INVALID_MAPCODE;
}
#endif
SetMapCode(mapCode);
return RC::RC_ROOM_SUCCESS;
}
RC::eROOM_RESULT
LobbyRoom::CanCreate(User* pUser, MAPCODE mapCode, eZONETYPE eZoneType,
eZONEPUBLIC ePublic, BASE_ROOMINFO& IN baseRoomInfo, KEYTYPE linkHuntingKey)
{
// 길드 PVP 모드라면
#ifdef __NA_000000_20070528_TAIWAN_GUILD_PVP
if(baseRoomInfo.IsSpecialType(eROOM_SPECIAL_GUILD_PVP))
{
// 길드 소속 체크
if(!pUser->GetSelectedCharGuildGuid())
return RC::RC_ROOM_CANNOT_CREATE_ROOM_FOR_NO_GUILD;
// PVP가 가능한 맵인지 체크
const sMAPINFO* pInfo = MapInfoParser::Instance()->FindMapInfo(mapCode);
if(!pInfo)
return RC::RC_ROOM_INVALID_MAPCODE;
if(!pInfo->EntranceItemCode)
return RC::RC_ROOM_INVALID_MAPCODE;
// 입장권 수량 체크
if(pUser->GetItemOwnFlag().GetItemNum(eITEMTYPE_GUILD_PVP_ENTRANCE) < pInfo->EntranceItemCount)
return RC::RC_ROOM_SHORT_ENTRANCE_CARD_OF_GUILD_PVP;
}
#endif
//.// 카오 체크
if(!GetServerOptChaoStateUseZone(eZoneType) && pUser->IsChaoState())
{
return RC::RC_ROOM_UNABLE_FUNCTION_FOR_CHAOSTATE;
}
if(eZoneType == eZONETYPE_CHUNTING)
{
// 기존 경쟁헌팅방에 조인하는 로비 생성인 경우
if(linkHuntingKey)
{
CHuntingRoom* pCHunting = g_ZoneManager.FindCHunting(linkHuntingKey);
if(!pCHunting)
return RC::RC_ROOM_INVALID_CHUNTING_LINK_KEY;
// 이미 링크 로비방이 만들어 졌는지 체크
if(pCHunting->GetLinkedLobby())
return RC::RC_ROOM_ALREADY_EXIST_LINKED_LOBBY;
// 경쟁중인 헌팅방은 들어갈 수 없다.
if(pCHunting->IsCompetition())
return RC::RC_ROOM_DOING_COMPETITION;
// 들어오려는 파티원수가 경쟁헌팅방의 멤버수보다 적어야 한다.
if(AgentPartyManager::Instance()->GetMemberNum(pUser->GetPartyState().GetPartyKey()) > pCHunting->GetCurUserNum())
return RC::RC_ROOM_MEMBERNUM_OF_PARTY_IS_MANY;
}
}
else if(eZoneType == eZONETYPE_MISSION)
{
// 미션방을 최고 수치보다 높은지 체크.
if(baseRoomInfo.m_MaxLV > (pUser->GetSelectedCharLV() + MISSION_LEVEL_JOIN_OFFSET))
return RC::RC_ROOM_INVALID_LIMITLEVEL_FOR_ME;
}
return RoomInterface::CanCreate(pUser, mapCode, eZoneType, ePublic, baseRoomInfo);
}
RC::eROOM_RESULT
LobbyRoom::_CanJoinEach(User* pUser, eZONEPUBLIC RoomPublic, TCHAR* pszRoomPWD)
{
// 카오상태 체크
if(!GetServerOptChaoStateUseZone(GetType()) && pUser->IsChaoState())
{
return RC::RC_ROOM_UNABLE_FUNCTION_FOR_CHAOSTATE;
}
// (WAVERIX) (090522) (CHANGES)
//const sMAPINFO* pInfo = MapInfoParser::Instance()->FindMapInfo(GetMapCode());
const sMAPINFO* pInfo = GetMapInfo();
if(!pInfo) return RC::RC_ROOM_INVALID_MAPCODE;
return RC::RC_ROOM_SUCCESS;
}
BOOL
LobbyRoom::CanShowAtRoomList(User* pUser, eZONEPUBLIC RoomPublic, TCHAR* pszRoomPWD)
{
// 파티원들이 들어올 수 있도록 기다려준다.
if(!m_WaitTimer.IsExpired(FALSE))
return FALSE;
return RoomInterface::CanShowAtRoomList(pUser, RoomPublic, pszRoomPWD);
}
RC::eROOM_RESULT
LobbyRoom::Create(User* pUser, KEYTYPE key, MAPCODE mapCode,
eZONETYPE eLobbyType, eZONEPUBLIC ePublic, TCHAR* pszRoomTitle, TCHAR* pszRoomPWD,
BASE_ROOMINFO & IN baseRoomInfo,
ServerSession* pServerSession, KEYTYPE linkHuntingKey)
{
if(eLobbyType != eZONETYPE_HUNTING && eLobbyType != eZONETYPE_MISSION && eLobbyType != eZONETYPE_PVP && eLobbyType != eZONETYPE_CHUNTING)
return RC::RC_ROOM_INVALID_ROOM_TYPE;
// 제대로 된 미션, 헌팅, pVP맵 코드가 맞는지 체크
RC::eROOM_RESULT rt = CanCreate(pUser, mapCode, eLobbyType, ePublic, baseRoomInfo, linkHuntingKey);
// 유저 상태 검사
if(rt != RC::RC_ROOM_SUCCESS) return rt;
// 인자 유효성 검사
// PVP일경우 체크
if(eLobbyType == eZONETYPE_PVP)
{
// 10레벨이상
if(pUser->GetSelectedCharLV() < 10) return RC::RC_ROOM_NEED_CHAR_LEVEL_10_FOR_PVP;
}
// 미션의 경우 방장보다 10LV 이상은 못들어오게 한다.
else if(eLobbyType == eZONETYPE_MISSION)
{
if(baseRoomInfo.m_MaxLV > (pUser->GetSelectedCharLV()+MISSION_LEVEL_JOIN_OFFSET))
baseRoomInfo.m_MaxLV = pUser->GetSelectedCharLV() + MISSION_LEVEL_JOIN_OFFSET;
}
if (pszRoomTitle[0] == '\0') {
return RC::RC_ROOM_CANNOT_USE_ROOM_TITLE;
};
util::StrArrayForRoomTitle room_title;
_tcsncpy(room_title, pszRoomTitle, _countof(room_title));
room_title[_countof(room_title) - 1] = _T('\0');
if (ProhibitionWordParser::Instance()->CheckFilter(room_title) == false) {
return RC::RC_ROOM_CANNOT_USE_ROOM_TITLE;
};
// 정보 복사 -----------------------------------------------------
RoomInterface::Create(pUser, key, mapCode,
ePublic, pszRoomTitle, pszRoomPWD, baseRoomInfo, pServerSession);
SetLobbyType(eLobbyType);
// 부가정보 기본 값으로 셋팅
m_AdditionalRoomInfo.m_Difficulty = eHUNTING_MONSTER_DIFFICULT_EASY;
m_AdditionalRoomInfo.m_Bonus = eHUNTING_BONUS_TYPE_ITEM;
m_AdditionalPVPInfo.m_Rule = ePVP_RULE_10;
m_AdditionalPVPInfo.m_Mode = ePVP_PERSONAL_MODE;
m_AdditionalCHuntingExInfo.m_Difficulty = eHUNTING_MONSTER_DIFFICULT_EASY;
m_AdditionalCHuntingExInfo.m_Bonus = eHUNTING_BONUS_TYPE_ITEM;
m_AdditionalCHuntingExInfo.m_Rule = eCOMPETITION_RULE_DUAL_PARTY;
m_AdditionalCHuntingExInfo.m_Mode = eCOMPETITION_MODE_TIME_ATTACK;
m_AdditionalCHuntingExInfo.m_LinkHuntingKey = linkHuntingKey;
// 유저
eROOMSTATE_TYPE type = GetRoomState();
SetRoomState(eROOMSTATE_GENERNAL);
rt = CanJoin(pUser, GetZonePublic(), GetRoomPWD());
SetRoomState(type);
if(rt != RC::RC_ROOM_SUCCESS)
return rt;
// 최대인원수 제한을 기존 경쟁헌팅방과 같게한다.
CHuntingRoom* pCHunting = g_ZoneManager.FindCHunting(linkHuntingKey);
if(pCHunting)
{
SetLimitMaxUserNum((BYTE)pCHunting->GetCurUserNum());
SetAdditionalCHuntingInfo(const_cast<ADDITIONAL_CHUNTINGINFO*>(pCHunting->GetAdditionalCHuntingInfo()));
}
On_create();
return rt;
}
VOID
LobbyRoom::SerializeLoad(HUNTING_ROOMINFO & OUT rRoomInfo)
{
rRoomInfo.m_Key = GetKey();
rRoomInfo.m_MapCode = GetMapCode();
memcpy(rRoomInfo.m_pszRoomTitle, GetRoomTitle(), MAX_ROOMTITLE_LENGTH*sizeof(TCHAR));
rRoomInfo.m_byRoomPublic = GetZonePublic();
rRoomInfo.m_CurUserNum = (BYTE)GetCurUserNum();
rRoomInfo.m_MaxLimitUserNum = GetLimitMaxUserNum();
rRoomInfo.m_RoomInfo = *GetRoomInfo();
rRoomInfo.m_AdditionalInfo = *GetAdditionalInfo();
}
VOID
LobbyRoom::SerializeLoad(MISSION_ROOMINFO & OUT rRoomInfo)
{
ASSERT(GetLobbyType() == eZONETYPE_MISSION);
rRoomInfo.m_Key = GetKey();
rRoomInfo.m_MapCode = GetMapCode();
rRoomInfo.m_byRoomPublic = GetZonePublic();
memcpy(rRoomInfo.m_pszRoomTitle, GetRoomTitle(), MAX_ROOMTITLE_LENGTH*sizeof(TCHAR));
rRoomInfo.m_CurUserNum = (BYTE)GetUserNum();
rRoomInfo.m_MaxLimitUserNum = GetLimitMaxUserNum();
rRoomInfo.m_RoomInfo = *GetRoomInfo();
}
VOID
LobbyRoom::SerializeLoad(PVP_ROOMINFO & OUT rRoomInfo)
{
rRoomInfo.m_Key = GetKey();
rRoomInfo.m_MapCode = GetMapCode();
memcpy(rRoomInfo.m_pszRoomTitle, GetRoomTitle(), MAX_ROOMTITLE_LENGTH*sizeof(TCHAR));
rRoomInfo.m_byRoomPublic = GetZonePublic();
rRoomInfo.m_CurUserNum = (BYTE)GetUserNum();
rRoomInfo.m_MaxLimitUserNum = GetLimitMaxUserNum();
rRoomInfo.m_RoomInfo = *GetRoomInfo();
rRoomInfo.m_AdditionalPVPInfo = *GetAdditionalPVPInfo();
}
VOID
LobbyRoom::SerializeLoad(CHUNTING_ROOMINFO & OUT rRoomInfo)
{
rRoomInfo.m_Key = GetKey();
rRoomInfo.m_MapCode = GetMapCode();
memcpy(rRoomInfo.m_pszRoomTitle, GetRoomTitle(), MAX_ROOMTITLE_LENGTH*sizeof(TCHAR));
rRoomInfo.m_byRoomPublic = GetZonePublic();
rRoomInfo.m_CurUserNum = (BYTE)GetUserNum();
rRoomInfo.m_MaxLimitUserNum = GetLimitMaxUserNum();
rRoomInfo.m_RoomInfo = *GetRoomInfo();
memcpy(&rRoomInfo.m_AdditionalInfo, GetAdditionalCHuntingInfo(), sizeof(ADDITIONAL_CHUNTINGINFO));
}
BOOL
LobbyRoom::IsAllReady()
{
User* const pMaster = GetMaster();
const ZONE_USER_LIST& rList = GetUserList();
FOREACH_CONTAINER(const ZONE_USER_LIST::value_type& rNode, rList, ZONE_USER_LIST)
{
User* const pUser = rNode.second;
if(pMaster && (pMaster == pUser))
continue;
if(!pUser->IsReady())
return FALSE;
}
return TRUE;
}
BOOL
LobbyRoom::IsPrepareUserNum()
{
const sMAPINFO* pInfo = MapInfoParser::Instance()->FindMapInfo(GetMapCode());
if(!pInfo)
return FALSE;
// 최소인원 제한 체크
if(GetUserNum() < pInfo->byMinUserNum)
return FALSE;
// 최대인원 제한 체크
if(GetUserNum() > GetLimitMaxUserNum())
return FALSE;
if(GetLobbyType() == eZONETYPE_PVP && IsPVPTeamMode())
{ // 팀전
// (WAVERIX)(080726)(NOTE) 개인적인 의견일 지 모르겠지만, DEBUG|RELEASE WIN-WIN 정책을 사용하고자 하면
// const BYTE teamNo = pUser->GetTeam();와 같이 하는 편이 더 나을 것이다.
// 뭐, 팀의 규약이 기존과 같은 형태로 정했다면 할 수 없지만, GetTeam이라는 interface는 const 함수임을 우리는 알지만,
// 컴파일러는 알기 힘들다는 점과 더 나은 코드가 생성되기 힘들게 된다는 점을 알아두자.
// 팀 번호 1,2는 사람이 인식하는 코드라는 점에서... 뭐라 따지기는 힘들다. 극악이 아닌 이상 용인하는 편이 나을 듯.
const BYTE teamUpperbound = 3; // 0 is skip no
BYTE teams[teamUpperbound] = { 0, };
const ZONE_USER_LIST& rList = GetUserList();
FOREACH_CONTAINER(const ZONE_USER_LIST::value_type& rNode, rList, ZONE_USER_LIST)
{
User* const pUser = rNode.second;
const BYTE teamNo = pUser->GetTeam();
if(teamNo && teamNo<teamUpperbound) // team1, team2
++teams[teamNo];
}
return (teams[1] && teams[2]);
}
return TRUE;
}
VOID
LobbyRoom::AssignTeam(User* pTargetUser)
{
const BOOLEAN isPvPZone = GetLobbyType() == eZONETYPE_PVP;
const BOOLEAN isPvPTeamMode = !!IsPVPTeamMode();
const ZONE_USER_LIST& rList = GetUserList();
if(pTargetUser)
{
if(!(isPvPZone && isPvPTeamMode))
{
pTargetUser->SetTeam(0); // 0으로 초기화 한다... 문제 없는지 타전해 볼 것.
return;
}
const BYTE teamUpperbound = 3; // 0 is skip no
BYTE teams[teamUpperbound] = { 0, };
// 팀원이 이미 들어 있다.
FOREACH_CONTAINER(const ZONE_USER_LIST::value_type& rNode, rList, ZONE_USER_LIST)
{
User* const pUser = rNode.second;
const BYTE teamNo = pUser->GetTeam();
if(teamNo && teamNo<teamUpperbound) // team1, team2
++teams[teamNo];
}
const BYTE selectedTeam = (teams[1] > teams[2])
? 2
: 1
;
pTargetUser->SetTeam(selectedTeam);
}
else
{ // 팀 전...?
if(!isPvPZone)
return;
BYTE toggle = 0;
// (WAVERIX)(080726)(NOTE) - 흐음... 효율성 문제는 떠나서 가독성 문제는 따져봐야 할 듯...
// 내가 보기엔 그게 그거지만... 다른 사람의 눈에는 어캐 보이는 가... 모르겠다.
FOREACH_CONTAINER(const ZONE_USER_LIST::value_type& rNode, rList, ZONE_USER_LIST)
{
const BYTE selectedTeam = !isPvPTeamMode
? 0
: (!(toggle++ & 1)
? 1
: 2
)
;
User* const pUser = rNode.second;
pUser->SetTeam(selectedTeam);
}
}
}
User*
LobbyRoom::Get2ndTeamMaster()
{
User* pMaster = GetMaster();
if(!pMaster) return NULL;
const ZONE_USER_LIST& rList = GetUserList();
FOREACH_CONTAINER(const ZONE_USER_LIST::value_type& rNode, rList, ZONE_USER_LIST)
{
User* const pUser = rNode.second;
if(pUser->GetTeam() != pMaster->GetTeam())
return pUser;
}
return NULL;
}
BOOL
LobbyRoom::RecommendLevel(LEVELTYPE LV)
{
BYTE byDiff = 99;
switch(GetLobbyType())
{
case eZONETYPE_PVP: return RoomInterface::ValidLevel(LV);
case eZONETYPE_MISSION: break;
case eZONETYPE_HUNTING: byDiff = GetAdditionalInfo()->m_Difficulty; break;
default: return FALSE;
}
BASE_RequireFieldLevelInfo* pFieldLVInfo = RequireFieldLevelInfoParser::Instance()->GetRequireFieldLevelInfo(GetMapCode(), byDiff);
if(!pFieldLVInfo) return FALSE;
if(pFieldLVInfo->m_wMinlv <= LV && LV <= pFieldLVInfo->m_wMaxlv)
return TRUE;
return FALSE;
}
VOID
LobbyRoom::Invite(User* pUser)
{
switch(GetLobbyType())
{
case eZONETYPE_HUNTING:
{
MSG_CG_ZONE_HUNTINGLOBBY_JOIN_CMD cmsg;
SerializeLoad(cmsg.m_RoomInfo);
if(GetZonePublic() == eZONEPUBLIC_PRIVATE)
memcpy(cmsg.m_pszRoomPWD, GetRoomPWD(), MAX_ROOMPASSWORD_LENGTH);
pUser->SendPacket(&cmsg, cmsg.GetSize());
}
break;
case eZONETYPE_MISSION:
{
MSG_CG_ZONE_MISSIONLOBBY_JOIN_CMD cmsg;
SerializeLoad(cmsg.m_RoomInfo);
if(GetZonePublic() == eZONEPUBLIC_PRIVATE)
memcpy(cmsg.m_pszRoomPWD, GetRoomPWD(), MAX_ROOMPASSWORD_LENGTH);
pUser->SendPacket(&cmsg, cmsg.GetSize());
}
break;
case eZONETYPE_PVP:
{
MSG_CG_ZONE_PVPLOBBY_JOIN_CMD cmsg;
SerializeLoad(cmsg.m_RoomInfo);
if(GetZonePublic() == eZONEPUBLIC_PRIVATE)
memcpy(cmsg.m_pszRoomPWD, GetRoomPWD(), MAX_ROOMPASSWORD_LENGTH);
pUser->SendPacket(&cmsg, cmsg.GetSize());
}
break;
case eZONETYPE_CHUNTING:
{
MSG_CG_ZONE_CHUNTINGLOBBY_JOIN_CMD cmsg;
SerializeLoad(cmsg.m_RoomInfo);
if(GetZonePublic() == eZONEPUBLIC_PRIVATE)
memcpy(cmsg.m_pszRoomPWD, GetRoomPWD(), MAX_ROOMPASSWORD_LENGTH);
pUser->SendPacket(&cmsg, cmsg.GetSize());
}
break;
}
}
VOID
LobbyRoom::ExpelAll()
{
// (WAVERIX)(080726)(NOTE)
// VAssistX or VStudio 쪽의 인식 패턴의 문제일까...? 아래와 같이 하는 게 brace 분석에 문제가 없다.
const ZONE_USER_LIST& rList = GetUserList();
ZONE_USER_LIST::const_iterator it = rList.begin(),
itend = rList.end();
while(it != itend)
{
User* const pUser = it->second;
++it;
MAPCODE mapCode = pUser->GetSelectedCharMapCode();
ZoneInterface* pZone = g_ZoneManager.FindStaticZone(mapCode);
if(pZone == 0)
continue;
BOOLEAN isAcceptable = pZone->GetType() == eZONETYPE_VILLAGE ||
pZone->GetMapCode() == HardCode::MAPCODE_for_TUTORIAL_FIELD;
if(isAcceptable == 0)
continue;
//const sMAPINFO* pMAPINFO = MapInfoParser::Instance()->FindMapInfo(mapCode);
//if(!((eZONETYPE_VILLAGE == pMAPINFO->byMKind) || (eZONETYPE_TUTORIAL_FIELD == pMAPINFO->byMKind)))
// continue;
// 로비 나감 CMD
LeaveUser(pUser, eSEND_CMD, eZONETYPE_VILLAGE, pZone->GetLinkedServerIndex());
// 마을 들어감 CMD
pZone->ReadyUser(pUser, eSEND_CMD);
// 로비에서 나간다 패킷 보냄
MSG_CG_ZONE_LOBBY_LEAVE_ACK msg;
pUser->SendPacket(&msg, sizeof(msg));
}
}
BOOL
LobbyRoom::CheckAbusing(CHuntingRoom* pCHuntingRoom)
{
if(!pCHuntingRoom)
return FALSE;
BYTE byLimitCount = 5;
BASE_MatchInfo* pMatchInfo = MatchInfoParser::Instance()->GetMatchInfo(MATCH_ABUSE_JOINTIMES);
if(pMatchInfo) byLimitCount = pMatchInfo->m_byMatchLimitCount;
const ZONE_USER_LIST& rList = GetUserList();
FOREACH_CONTAINER(const ZONE_USER_LIST::value_type& rNode, rList, ZONE_USER_LIST)
{
User* const pUser = rNode.second;
// 같은 방에 특정시간에 특정회수 이상의 조인을 막는다.
// (WAVERIX)(080726)(NOTE) 뭔지 모르지만 흥미가 생기게 만든다. 나중에 이 주석을 보면 어떻게 구현했는지 살펴보자.
const WORD wJoinCount = pCHuntingRoom->GetPlayerHistoryNum(pUser->GetUserGUID());
if(wJoinCount > byLimitCount)
return TRUE;
}
return FALSE;
}
#ifdef __NA_000000_20070528_TAIWAN_GUILD_PVP
RC::eROOM_RESULT
LobbyRoom::CanMigrateToChunting()
{
// 이 함수는.. 실제로는 GUILD PVP 체크 함수이다...
// 따라서 길드 PVP가 아니면 넘어 가는 것을 한다.
if(!GetRoomInfo()->IsSpecialType(eROOM_SPECIAL_GUILD_PVP))
return RC::RC_ROOM_SUCCESS;
// 길드 PVP에서는 서바이벌 모드를 지원하지 않는다.
if(GetAdditionalCHuntingInfo()->m_Mode == eCOMPETITION_MODE_SURVIVAL)
return RC::RC_ROOM_INVALID_MODE_VALUE;
// 길드 PVP가 가능한 맵인지 체크
const sMAPINFO* pInfo = GetMapInfo();
if(pInfo == 0) // (WAVERIX) 이 시점에는 이미 선행 검사가 되었으리라 생각되지만...
return RC::RC_ROOM_INVALID_MAPCODE;
if(pInfo->EntranceItemCode == 0)
return RC::RC_ROOM_INVALID_MAPCODE;
// DualParty Rule인지 체크
if(m_AdditionalCHuntingExInfo.m_Rule != eCOMPETITION_RULE_DUAL_PARTY)
return RC::RC_ROOM_INVALID_RULE_VALUE;
if(ServerOptionParserEx::Instance()->GetServerOption().m_byGuildPVPUserCount != GetUserNum())
return RC::RC_ROOM_CANNOT_CREATE_ROOM_FOR_LIMIT_USER;
const ZONE_USER_LIST& rList = GetUserList();
FOREACH_CONTAINER(const ZONE_USER_LIST::value_type& rNode, rList, ZONE_USER_LIST)
{
User* const pUser = rNode.second;
const RC::eROOM_RESULT ret = CanJoinGuildPVP(pUser);
if(ret != RC::RC_ROOM_SUCCESS)
return ret;
}
return RC::RC_ROOM_SUCCESS;
}
#endif
BOOL
LobbyRoom::ChangeRoomTitle(const TCHAR* pszRoomTitle)
{
if (pszRoomTitle[0] == '\0') {
return false;
};
util::StrArrayForRoomTitle room_title;
_tcsncpy(room_title, pszRoomTitle, _countof(room_title));
room_title[_countof(room_title) - 1] = _T('\0');
if (ProhibitionWordParser::Instance()->CheckFilter(room_title) == false) {
return false;
};
SetRoomTitle(room_title);
return true;
}
// CHANGES: f110608.6L, this method added to reply against CG_ZONE_LOBBY_REQUEST_INFO_SYN
bool LobbyRoom::SendLobbyInfoForRequest(User* requester) const
{
uint8_t shared_buffer[max(sizeof(MSG_CG_ZONE_LOBBY_MISSION_REQUEST_INFO_ACK),
max(sizeof(MSG_CG_ZONE_LOBBY_CHUNTING_REQUEST_INFO_ACK),
max(sizeof(MSG_CG_ZONE_LOBBY_PVP_REQUEST_INFO_ACK), 0)))];
switch (m_LobbyType)
{
case eZONETYPE_MISSION:
if (MSG_CG_ZONE_LOBBY_MISSION_REQUEST_INFO_ACK* const msg_ack =
new (shared_buffer) MSG_CG_ZONE_LOBBY_MISSION_REQUEST_INFO_ACK)
{
msg_ack->m_MapCode = this->GetMapCode();
msg_ack->m_NonBlockNum = this->GetLimitMaxUserNum();
//
const ns_functor::LobbyChangedStatusNotificationFilter filter;
msg_ack->m_Count = this->GetListMemberInfo(
filter.GetRedirectedArray(msg_ack->m_dwReadyPlayerKey), requester);
//
requester->SendPacket(msg_ack, msg_ack->GetSize());
};
break;
//case eZONETYPE_HUNTING: <- don't support anymore since ... when is this type removed?
case eZONETYPE_PVP:
if (MSG_CG_ZONE_LOBBY_PVP_REQUEST_INFO_ACK* const msg_ack =
new (shared_buffer) MSG_CG_ZONE_LOBBY_PVP_REQUEST_INFO_ACK)
{
msg_ack->m_MapCode = this->GetMapCode();
msg_ack->m_AdditionalPVPInfo = this->m_AdditionalPVPInfo;
msg_ack->m_NonBlockNum = this->GetLimitMaxUserNum();
//
const ns_functor::PvPLobbyChangedStatusNotificationFilter filter;
msg_ack->m_Count = this->GetListMemberInfo(// no checked requester
filter.GetRedirectedArray(msg_ack->m_PlayerInfo), NULL);
//
requester->SendPacket(msg_ack, msg_ack->GetSize());
if (this->IsPVPTeamMode())
{
MSG_CG_ZONE_LOBBY_PVP_INFO_BRD msg_brd;
msg_brd.m_dwPlayerKey = requester->GetPlayerKey();
msg_brd.m_Team = requester->GetTeam();
this->SendToAll(&msg_brd, sizeof(msg_brd), requester->GetUserKey());
};
};
break;
case eZONETYPE_CHUNTING:
if (MSG_CG_ZONE_LOBBY_CHUNTING_REQUEST_INFO_ACK* const msg_ack =
new (shared_buffer) MSG_CG_ZONE_LOBBY_CHUNTING_REQUEST_INFO_ACK)
{
msg_ack->m_MapCode = this->GetMapCode();
msg_ack->m_AdditionalCHuntingInfo = this->m_AdditionalCHuntingExInfo;
msg_ack->m_NonBlockNum = this->GetLimitMaxUserNum();
const ns_functor::LobbyChangedStatusNotificationFilter filter;
msg_ack->m_Count = this->GetListMemberInfo(
filter.GetRedirectedArray(msg_ack->m_dwReadyPlayerKey), requester);
//
requester->SendPacket(msg_ack, msg_ack->GetSize());
};
break;
default:
SUNLOG(eCRITICAL_LOG, _T("|["__FUNCTION__"]|斤口=unexpected lobby type %d|"),
m_LobbyType);
return false;
};
return true;
}
//==================================================================================================
//==================================================================================================
//==================================================================================================
// CHANGES: f110609.3L, it added to make shared part data.
// returns: number of aligned information
uint8_t LobbyRoom::GetListMemberInfo(
ns_functor::LobbyChangedStatusNotificationFilter::MemberInfoArray& result_array,
User* requester) const
{
const ns_functor::LobbyChangedStatusNotificationFilter filter;
BOOST_STATIC_ASSERT(_countof(result_array) == MAX_PARTYMEMBER_NUM);
uint16_t* dest_it = result_array;
int number_of_aligned = 0;
//
const ZONE_USER_LIST& user_list = GetUserList();
FOREACH_CONTAINER(const ZONE_USER_LIST::value_type& node, user_list, ZONE_USER_LIST)
{
User* const user = node.second;
if (filter.Check(user, requester) == false) {
continue;
};
//
*dest_it = static_cast<uint16_t>(user->GetPlayerKey());
++dest_it;
//
number_of_aligned = static_cast<int>(dest_it - result_array);
if (number_of_aligned >= _countof(result_array)) {
break;
}
};
return static_cast<uint8_t>(number_of_aligned);
}
uint8_t LobbyRoom::GetListMemberInfo(
ns_functor::PvPLobbyChangedStatusNotificationFilter::MemberInfoArray& result_array,
User* requester) const
{
__TOUCHED(requester);
const ns_functor::PvPLobbyChangedStatusNotificationFilter filter;
BOOST_STATIC_ASSERT(_countof(result_array) == MAX_PARTYMEMBER_NUM);
PVP_LOBBY_INFO* dest_it = result_array;
int number_of_aligned = 0;
//
const ZONE_USER_LIST& user_list = GetUserList();
FOREACH_CONTAINER(const ZONE_USER_LIST::value_type& node, user_list, ZONE_USER_LIST)
{
User* const user = node.second;
// no checked requester
if (filter.Check(user, NULL) == false) {
continue;
};
//
dest_it->m_Team = user->GetTeam();
dest_it->m_Ready = (user->IsReady() != false);
dest_it->m_dwPlayerKey = static_cast<uint16_t>(user->GetPlayerKey());
++dest_it;
//
number_of_aligned = static_cast<uint8_t>(dest_it - result_array);
if (number_of_aligned >= _countof(result_array)) {
break;
}
};
return static_cast<uint8_t>(number_of_aligned);
}
//==================================================================================================
//==================================================================================================
//==================================================================================================