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

350 lines
9.3 KiB
C++

#include "stdafx.h"
//////////////////////////////////////////////////////////////////////////
#include <PacketStruct_AG.h>
#include <PacketStruct_CG.h>
#include <MapInfoParser.h>
#include "MatchInfoParser.h"
#include "ServerOptionParser.h"
//////////////////////////////////////////////////////////////////////////
#include <ServerSessions/ServerSessionManager.h>
#include <ServerSessions/ServerSessionEx.h>
#include <UserSessions/User.h>
#include <Zone/ZoneManager.h>
#include <Zone/LobbyRoom.h>
#include <Zone/CHuntingRoom.h>
#include <Zone/Village.h>
#include <AgentParty/AgentPartyManager.h>
_IMPL_POOL(CHuntingRoom)
CHuntingRoom::CHuntingRoom(void)
{
m_Link2ndPartyKey = 0;
}
CHuntingRoom::~CHuntingRoom(void)
{
}
BOOL CHuntingRoom::Process()
{
// 일정시간이 지난 유저 히스토리는 제거한다.
DWORD dwTimeDiff = 0; DWORD dwMaxTimeDiff = 24*3600000;
BASE_MatchInfo *pMatchInfo = MatchInfoParser::Instance()->GetMatchInfo( MATCH_ABUSE_JOINTIMES );
if( pMatchInfo ) dwMaxTimeDiff = pMatchInfo->m_dwMatchLimitTime;
for( PLAYER_HISTORY_ITER it = m_mapPlayerHistory.begin(); it != m_mapPlayerHistory.end(); )
{
PLAYER_HISTORY &PlayerInfo = (*it).second;
dwTimeDiff = GetTickCount() - PlayerInfo.m_dwJoinTime;
if( dwTimeDiff > dwMaxTimeDiff )
it = m_mapPlayerHistory.erase( it );
else
++it;
}
return RoomInterface::Process();
}
WORD CHuntingRoom::GetPlayerHistoryNum( DWORD dwGUID )
{
// m_mapPlayerHistory.count( dwGUID ); 이걸 사용하면 될건데 -_- 내가 왜 이랬을까? 이걸로 교체할려니 테스트 하기가 싫구나 ㅠㅜ
WORD wJoinCount = 0;
PLAYER_HISTORY_ITER FoundIt = m_mapPlayerHistory.find( dwGUID );
if( FoundIt != m_mapPlayerHistory.end() )
{
for( PLAYER_HISTORY_ITER it = FoundIt; it != m_mapPlayerHistory.end(); ++it )
{
PLAYER_HISTORY &PlayerInfo = (*it).second;
if( PlayerInfo.m_dwGUID == dwGUID )
wJoinCount++;
else
break;
}
}
return wJoinCount;
}
VOID CHuntingRoom::ReadyUser( User * pUser, eSEND_TYPE type, MAPCODE FieldCode, DWORD dwAreaID, WzVector * pwvStartPos, bool bFirstJoin )
{
const sMAPINFO *psMAPINFO = MapInfoParser::Instance()->FindMapInfo( GetMapCode() );
if( !dwAreaID )
{
if( !IsCompetition() )
dwAreaID = psMAPINFO->wStartAreaID;
else
dwAreaID = psMAPINFO->wStartAreaID2;
}
ZoneInterface::ReadyUser( pUser, type, FieldCode, dwAreaID, pwvStartPos, bFirstJoin );
}
RC::eROOM_RESULT CHuntingRoom::Migrate( KEYTYPE key, RoomInterface * pPreviousRoom, ServerSession * pServerSession )
{
if( pPreviousRoom->GetType() != eZONETYPE_CHUNTING && pPreviousRoom->GetType() != eZONETYPE_LOBBY )
return RC::RC_ROOM_INVALIDROOMTYPE;
RoomInterface::Migrate( key, pPreviousRoom, pServerSession );
// 현재 파티원 만큼 더 들어올 수 있다.(Dual Party)
SetLimitMaxUserNum( (BYTE)(pPreviousRoom->GetCurUserNum()*2) );
if( pPreviousRoom->GetType() == eZONETYPE_CHUNTING )
{
CHuntingRoom * pRoom = (CHuntingRoom *)pPreviousRoom;
SetAdditionalCHuntingInfo( pRoom->GetAdditionalCHuntingInfo() );
}
else
{
LobbyRoom * pRoom = (LobbyRoom *)pPreviousRoom;
SetAdditionalCHuntingInfo( pRoom->GetAdditionalCHuntingInfo() );
}
On_create();
// 릴레이 유저 등록
RelayUser( pPreviousRoom );
g_ZoneManager.ChangeBattlePlayersCount(this, GetNumberOfExpectedPlayers());
// 최초로 팀이 등장
BOOL bCompetitionStart = m_AdditionalInfo.m_Rule == eCOMPETITION_RULE_FREE_FOR_ALL;
EnterTeam( pPreviousRoom, bCompetitionStart );
return RC::RC_ROOM_SUCCESS;
}
VOID CHuntingRoom::EnterTeam( RoomInterface *pPreviousRoom, BOOL bCompetitionStart )
{
// (WAVERIX)(080726)(NOTE) 패킷부터 해서 현 시점 변경하면 좋아질 수 있는 루틴들이다.
// object key 가 검색의 효율성이 월등한 점...
// - 새로운 팀이 들어간다고 알린다.
MSG_AG_CHUNTING_ENTER_TEAM_CMD msgCMD;
msgCMD.m_RoomKey = GetKey();
msgCMD.m_byReadyPlayerNum = 0;
msgCMD.m_GuildGuid = 0;
User* const pPreviousMaster = pPreviousRoom->GetMaster();
if( pPreviousMaster )
msgCMD.m_GuildGuid = pPreviousMaster->GetSelectedCharGuildGuid();
DWORD userCount = 0;
const ZONE_USER_LIST& rList = pPreviousRoom->GetUserList();
FOREACH_CONTAINER( const ZONE_USER_LIST::value_type& rNode, rList, ZONE_USER_LIST )
{
User* const pUser = rNode.second;
msgCMD.m_UserKeyList[userCount] = pUser->GetUserKey();
++userCount;
if( CHUNTING_MAX_MEMBER_NUM <= userCount )
break;
}
ASSERT( (DWORD)rList.size() <= CHUNTING_MAX_MEMBER_NUM );
msgCMD.m_byReadyPlayerNum = (BYTE)userCount;
SendToLinkedServer( &msgCMD, msgCMD.GetSize() /*기껏 getsize만들어 놓고 안 사용하는 이유는? ㅋㅋ*/ );
// 경쟁모드 돌입. 다른 유저 출입불가.
SetCompetition( bCompetitionStart );
}
VOID CHuntingRoom::On_create()
{
RoomInterface::On_create();
// 경쟁모드 초기화
SetCompetition( FALSE );
m_bLinkedLobby = FALSE;
m_mapPlayerHistory.clear();
MSG_AG_ZONE_CHUNTION_CREATE_CMD msg;
msg.m_dwKey = GetMaster()->GetUserKey();
msg.m_MapCode = GetMapCode();
msg.m_RoomKey = GetKey();
memcpy( msg.m_pszRoomTitle, GetRoomTitle(), MAX_ROOMTITLE_LENGTH*sizeof(TCHAR) );
memcpy( msg.m_pszRoomPWD, GetRoomPWD(), MAX_ROOMPASSWORD_LENGTH*sizeof(TCHAR) );
msg.m_RoomInfo = *GetRoomInfo();
msg.m_AdditionalInfo = *GetAdditionalCHuntingInfo();
SendToLinkedServer( &msg, sizeof(msg) );
}
VOID CHuntingRoom::On_destroy()
{
if( !IsReusedServerSession() )
ServerSessionManager::Instance()->Decr_LOF_BattleServer( GetLinkedServer()->GetSessionIndex() );
RoomInterface::On_destroy();
m_Link2ndPartyKey = 0;
}
VOID CHuntingRoom::On_readyuser( User * pUser )
{
RoomInterface::On_readyuser(pUser);
pUser->SetZoneState( ePRS_BEFORE_ENTER_CHUNTING );
pUser->SetZoneKey( GetKey() );
pUser->SetZoneType( eZONETYPE_CHUNTING );
}
VOID CHuntingRoom::On_enteruser( User * pUser )
{
RoomInterface::On_enteruser(pUser);
pUser->SetZoneState( ePRS_AT_CHUNTING );
// User History 기록
PLAYER_HISTORY EnterUser;
EnterUser.m_dwGUID = pUser->GetUserGUID();
EnterUser.m_dwJoinTime = GetTickCount();
m_mapPlayerHistory.insert( PLAYER_HISTORY_PAIR( EnterUser.m_dwGUID, EnterUser ) );
}
VOID CHuntingRoom::On_leaveuser( User * pUser )
{
BOOL bMaster = GetMaster() == pUser;
RoomInterface::On_leaveuser(pUser);
// 최소 인원 제한에 맞지 않으면 방은 파기된다.
CheckMinLimitUser();
// 경쟁헌팅에 들어올 수 있는 인원은 현재인원의 2배이다.
SetLimitMaxUserNum( (BYTE)(GetCurUserNum()*2) );
// 링크된 로비의 최대인원을 바꾼후 유저들에게 알려준다.
LobbyRoom *pLobby = g_ZoneManager.FindCHuntingLobbyByCkey( GetKey() );
if( pLobby )
{
pLobby->SetLimitMaxUserNum( (BYTE)GetCurUserNum() );
MSG_CG_ZONE_CHUNTINGLOBBY_CHANGE_MAXUSER_CMD msg;
msg.m_byMaxLimitUser = (BYTE)GetCurUserNum();
pLobby->SendToAll( &msg, sizeof(msg) );
}
// 슈퍼방 아이템을 소지한 자가 없으면 슈퍼방 기능이 해제된다.
if(bMaster)
{
User* pNextMaster = RoomInterface::ChangeSpecialType(false, pUser);
if(pNextMaster)
{
AgentPartyManager::Instance()->ChangeMaster(pNextMaster->GetPartyState().GetPartyKey(),
pNextMaster->GetPlayerKey());
}
}
}
VOID CHuntingRoom::CheckMinLimitUser()
{
// 경쟁진행중에는 방이 파괴되지 않는다.
if( IsCompetition() ) return;
const sMAPINFO * pInfo = MapInfoParser::Instance()->FindMapInfo( GetMapCode() );
if( !pInfo ) return;
// 최소 인원 제한에 맞지 않으면 방은 파괴된다.
if( GetCurUserNum() >= pInfo->byMinUserNum ) return;
// 경쟁헌팅 멤버들을 모두 마을로 내보낸다.
ExpelAll();
// 링크된 로비의 멤버들을 모두 마을로 내보낸다.
LobbyRoom *pLobby = g_ZoneManager.FindCHuntingLobbyByCkey( GetKey() );
if( pLobby )
pLobby->ExpelAll();
}
VOID CHuntingRoom::ExpelAll()
{
const ZONE_USER_LIST& rList = GetUserList();
ZONE_USER_LIST::const_iterator it = rList.begin();
ZONE_USER_LIST::const_iterator itend= rList.end();
while( it!=itend )
{
User* const pUser = it->second;
++it;
Village* const pVillage = g_ZoneManager.FindVillage( pUser->GetSelectedCharMapCode() );
if( !pVillage )
continue;
CheckMoveZonePolicy* const pCheckMoveZonePolicy =
MoveZonePolicy<MZTF_CHUNTING_TO_VILLAGE>::AlignInfo(
pUser
//{ From | To }
, eZONETYPE_CHUNTING, eZONETYPE_VILLAGE // eZONETYPE
, GetKey(), pVillage->GetKey() // ZoneKey
);
const RC::eROOM_RESULT rt = g_ZoneManager.MoveZone( pCheckMoveZonePolicy, RoomArgument::GetEmpty() );
if( RC::RC_ROOM_SUCCESS == rt )
{
pUser->BeginTransaction( TR_LEAVE_CHUNTING_FOR_VILLAGE );
pUser->SetTRRoomKey( pVillage->GetKey() );
}
}
}
VOID CHuntingRoom::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();
rRoomInfo.m_AdditionalInfo = *GetAdditionalCHuntingInfo();
}
RC::eROOM_RESULT CHuntingRoom::_CanJoinEach( User* pUser, eZONEPUBLIC RoomPublic, TCHAR * pszRoomPWD )
{
// 카오상태 체크
if(!GetServerOptChaoStateUseZone( GetType()) && pUser->IsChaoState())
{
return RC::RC_ROOM_UNABLE_FUNCTION_FOR_CHAOSTATE;
}
// 경쟁중에는 다른 멤버가 들어올 수 없다.
if( IsCompetition() )
return RC::RC_ROOM_DOING_COMPETITION;
return RC::RC_ROOM_SUCCESS;
}
VOID CHuntingRoom::CompleteCompetition()
{
SetCompetition( FALSE );
// 경쟁이 종료된 후에 남은 유저수가 최소인원제한이 안되면 방이 파괴된다.
CheckMinLimitUser();
}