Restructure repository to include all source folders
Move git root from Client/ to src/ to track all source code: - Client: Game client source (moved to Client/Client/) - Server: Game server source - GameTools: Development tools - CryptoSource: Encryption utilities - database: Database scripts - Script: Game scripts - rylCoder_16.02.2008_src: Legacy coder tools - GMFont, Game: Additional resources 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,251 @@
|
||||
#include "stdafx.h"
|
||||
#include "Airship.h"
|
||||
|
||||
#include <Skill/SkillTable.h>
|
||||
#include <Skill/SkillMgr.h>
|
||||
|
||||
#include <Utility/Math/Math.h>
|
||||
|
||||
#include <Item/ItemFactory.h>
|
||||
|
||||
#include <Map/FieldMap/CellManager.h>
|
||||
#include <Map/DuelMap/DuelCellManager.h>
|
||||
|
||||
#include <Network/Packet/WrapPacket.h>
|
||||
#include <Network/Packet/PacketCommand.h>
|
||||
#include <Network/Packet/PacketStruct/ServerInfo.h>
|
||||
|
||||
#include <Network/Dispatch/GameClient/GameClientDispatch.h>
|
||||
#include <Network/Dispatch/GameClient/SendCharItem.h>
|
||||
#include <Network/Dispatch/GameClient/SendCharCastle.h>
|
||||
#include <Network/Dispatch/GameClient/SendCharAttack.h>
|
||||
#include <Network/Dispatch/DBAgent/DBAgentDispatch.h>
|
||||
#include <Network/Dispatch/DBAgent/DBAgentRequest.h>
|
||||
|
||||
#include <Network/ClientSocket/ClientConstants.h>
|
||||
|
||||
|
||||
CAirship::CAirship(MonsterCreateInfo& MonsterCreate, unsigned long dwOwnerID, unsigned char cNation,
|
||||
unsigned long dwHP, unsigned short wObjectType, unsigned char cState,
|
||||
unsigned char cUpgradeStep)
|
||||
: CSiegeArms(MonsterCreate, dwOwnerID, cNation, dwHP, wObjectType, cState, cUpgradeStep)
|
||||
{
|
||||
std::fill_n(&m_dwPassengerCID[0], int(Siege::AIRSHIP_PASSENGER_NUM), 0);
|
||||
}
|
||||
|
||||
CAirship::~CAirship()
|
||||
{
|
||||
}
|
||||
|
||||
bool CAirship::Dead(CAggresiveCreature* pOffencer)
|
||||
{
|
||||
if (NULL == pOffencer) return false;
|
||||
if (STATE_ID_DIE == m_nCurrentState) return false;
|
||||
|
||||
m_CreatureStatus.m_nNowHP = 0;
|
||||
m_dwLastBehaviorTick = m_dwLastTime = CPulse::GetInstance().GetLastTick();
|
||||
m_lCurrentFrame = FPS;
|
||||
m_bAttacking = false;
|
||||
m_bCasting = false;
|
||||
|
||||
// 타고 있던 캐릭터는 죽는다.
|
||||
CCharacter* lpRider = NULL;
|
||||
if (m_dwRiderCID)
|
||||
{
|
||||
lpRider = CCreatureManager::GetInstance().GetCharacter(m_dwRiderCID);
|
||||
if ( lpRider )
|
||||
{
|
||||
lpRider->GetOff();
|
||||
lpRider->Kill(pOffencer);
|
||||
}
|
||||
|
||||
m_dwRiderCID = 0;
|
||||
}
|
||||
|
||||
for (int i=0; i<Siege::AIRSHIP_PASSENGER_NUM; ++i)
|
||||
{
|
||||
lpRider = CCreatureManager::GetInstance().GetCharacter(m_dwPassengerCID[i]);
|
||||
if ( lpRider )
|
||||
{
|
||||
lpRider->GetOff();
|
||||
lpRider->Kill(pOffencer);
|
||||
}
|
||||
|
||||
m_dwPassengerCID[i] = 0;
|
||||
}
|
||||
|
||||
// 크리쳐 매니져에서 삭제 (해당 셀에서도 삭제한다.)
|
||||
CCreatureManager::GetInstance().DeleteCreature(m_dwCID);
|
||||
|
||||
// 중계 서버로 패킷 전송
|
||||
GET_SINGLE_DISPATCH(lpDBAgentDispatch, CDBAgentDispatch, CDBAgentDispatch::GetDispatchTable());
|
||||
if (lpDBAgentDispatch)
|
||||
{
|
||||
return GameClientSendPacket::SendCharSiegeArmsCmdToDBAgent(lpDBAgentDispatch->GetSendStream(), 0, m_dwCID,
|
||||
0, PktSiegeArmsCmd::SIEGE_DESTROY_ARMS,
|
||||
PktSiegeArmsCmd::NO_SERVER_ERR);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void CAirship::MoveTo(const Position& NewPosition)
|
||||
{
|
||||
CSiegeObject::MoveTo(NewPosition);
|
||||
|
||||
for (int i=0; i<Siege::AIRSHIP_PASSENGER_NUM; ++i)
|
||||
{
|
||||
if (0 != m_dwPassengerCID[i])
|
||||
{
|
||||
CCharacter* lpPassenger = CCreatureManager::GetInstance().GetCharacter(m_dwPassengerCID[i]);
|
||||
if (lpPassenger)
|
||||
{
|
||||
lpPassenger->MoveTo(NewPosition, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char CAirship::IsRider(unsigned long dwCID) const
|
||||
{
|
||||
if (m_dwRiderCID == dwCID)
|
||||
{
|
||||
return Siege::RIDER_FOR_OWNER;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i=0; i<Siege::AIRSHIP_PASSENGER_NUM; ++i)
|
||||
{
|
||||
if (dwCID == m_dwPassengerCID[i])
|
||||
{
|
||||
return Siege::RIDER_FOR_PASSENGER;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Siege::NOT_RIDER;
|
||||
}
|
||||
|
||||
bool CAirship::Ride(unsigned long dwCID)
|
||||
{
|
||||
if (dwCID == m_dwOwnerID)
|
||||
{
|
||||
return CSiegeArms::Ride(dwCID);
|
||||
}
|
||||
else if (Siege::NOT_RIDER == IsRider(dwCID))
|
||||
{
|
||||
CCharacter* lpRider = CCreatureManager::GetInstance().GetCharacter(dwCID);
|
||||
if (lpRider)
|
||||
{
|
||||
for (int i=0; i<Siege::AIRSHIP_PASSENGER_NUM; ++i)
|
||||
{
|
||||
if (0 == m_dwPassengerCID[i] && 0 != m_cNation && m_cNation == lpRider->GetNation())
|
||||
{
|
||||
m_dwPassengerCID[i] = dwCID;
|
||||
lpRider->Ride(m_dwCID);
|
||||
lpRider->SkillClear();
|
||||
|
||||
// Ride 함수 자체에서 클라이언트에게 패킷을 보내준다.
|
||||
PktSiegeArmsCmd pktSAC;
|
||||
pktSAC.m_dwCID = GetOwnerID();
|
||||
pktSAC.m_dwArmsID = m_dwCID;
|
||||
pktSAC.m_cState = m_cState;
|
||||
pktSAC.m_dwValue = dwCID;
|
||||
pktSAC.m_cSubCmd = PktSiegeArmsCmd::SIEGE_RIDE_ARMS;
|
||||
|
||||
char* szPacket = reinterpret_cast<char *>(&pktSAC);
|
||||
if (PacketWrap::WrapCrypt(szPacket, sizeof(PktSiegeArmsCmd), CmdSiegeArmsCmd, 0, 0))
|
||||
{
|
||||
SendToRange(Siege::BROADCAST_RADIUS, szPacket, sizeof(PktSiegeArmsCmd), CmdSiegeArmsCmd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CAirship::GetOff(unsigned long dwCID)
|
||||
{
|
||||
if (dwCID == m_dwRiderCID)
|
||||
{
|
||||
return CSiegeArms::GetOff(dwCID);
|
||||
}
|
||||
else if (Siege::NOT_RIDER != IsRider(dwCID))
|
||||
{
|
||||
CCharacter* lpRider = CCreatureManager::GetInstance().GetCharacter(dwCID);
|
||||
if (lpRider)
|
||||
{
|
||||
for (int i=0; i<Siege::AIRSHIP_PASSENGER_NUM; ++i)
|
||||
{
|
||||
if (dwCID == m_dwPassengerCID[i])
|
||||
{
|
||||
m_dwPassengerCID[i] = 0;
|
||||
lpRider->GetOff();
|
||||
|
||||
// GetOff 함수 자체에서 클라이언트에게 패킷을 보내준다.
|
||||
PktSiegeArmsCmd pktSAC;
|
||||
pktSAC.m_dwCID = GetOwnerID();
|
||||
pktSAC.m_dwArmsID = m_dwCID;
|
||||
pktSAC.m_cState = m_cState;
|
||||
pktSAC.m_dwValue = dwCID;
|
||||
pktSAC.m_cSubCmd = PktSiegeArmsCmd::SIEGE_GETOFF_ARMS;
|
||||
|
||||
char* szPacket = reinterpret_cast<char *>(&pktSAC);
|
||||
if (PacketWrap::WrapCrypt(szPacket, sizeof(PktSiegeArmsCmd), CmdSiegeArmsCmd, 0, 0))
|
||||
{
|
||||
SendToRange(Siege::BROADCAST_RADIUS, szPacket, sizeof(PktSiegeArmsCmd), CmdSiegeArmsCmd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CAirship::AllGetOff()
|
||||
{
|
||||
// 주인이 타고 있으면, 주인부터 내린다.
|
||||
if (0 != m_dwRiderCID)
|
||||
{
|
||||
GetOff(m_dwRiderCID);
|
||||
}
|
||||
|
||||
// 손님 내리기
|
||||
for (int i=0; i<Siege::AIRSHIP_PASSENGER_NUM; ++i)
|
||||
{
|
||||
if (0 != m_dwPassengerCID[i])
|
||||
{
|
||||
GetOff(m_dwPassengerCID[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CAirship::GetRiders(unsigned long* pRiders) const
|
||||
{
|
||||
CSiegeObject::GetRiders(pRiders);
|
||||
|
||||
std::copy( &m_dwPassengerCID[0], &m_dwPassengerCID[ Siege::AIRSHIP_PASSENGER_NUM ], &pRiders[1] );
|
||||
}
|
||||
|
||||
unsigned char CAirship::GetRiderNum() const
|
||||
{
|
||||
unsigned char cRiderNum = CSiegeObject::GetRiderNum();
|
||||
|
||||
for (int i=0; i<Siege::AIRSHIP_PASSENGER_NUM; ++i)
|
||||
{
|
||||
if (0 != m_dwPassengerCID[i])
|
||||
{
|
||||
++cRiderNum;
|
||||
}
|
||||
}
|
||||
|
||||
return cRiderNum;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
#ifndef _AIRSHIP_OBJECT_H_
|
||||
#define _AIRSHIP_OBJECT_H_
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Creature/Siege/SiegeArms.h>
|
||||
|
||||
using namespace Siege;
|
||||
|
||||
|
||||
class CAirship : public CSiegeArms
|
||||
{
|
||||
public:
|
||||
virtual ~CAirship();
|
||||
|
||||
// CSkillMonster 의 기능
|
||||
void NormalBehavior(unsigned long dwTick) { }
|
||||
void AttackBehavior(unsigned long dwTick) { }
|
||||
void SearchPlayer(void) { }
|
||||
|
||||
bool Dead(CAggresiveCreature* pOffencer);
|
||||
void MoveTo(const Position& NewPosition);
|
||||
|
||||
// 드랍쉽은 아래 함수의 구현이 없다.
|
||||
bool AttackCID(CCharacter* lpRideChar, AtType attackType, AtNode& attackNode, unsigned short& wError) { return false; }
|
||||
bool Attack(AtType attackType, unsigned char cDefenderNum, CAggresiveCreature** ppDefenders,
|
||||
unsigned char* cDefenserJudges, unsigned short* wDefenserMPHeal) { return false; }
|
||||
bool MissileAttack(AtType attackType, float fDir, float nRange, float fAngle, char cTargetType) { return false; }
|
||||
|
||||
// Rider 관련 정보
|
||||
unsigned char IsRider(unsigned long dwCID) const; // 해당 캐릭터가 병기에 탑승해 있는가?
|
||||
bool Ride(unsigned long dwCID); // 병기 탑승
|
||||
bool GetOff(unsigned long dwCID); // 병기 내림 (중계 서버로 패킷 전송)
|
||||
void AllGetOff(); // 병기에서 모두 내림 (패킷 전송)
|
||||
|
||||
void GetRiders( unsigned long* pRiders ) const;
|
||||
unsigned char GetRiderNum() const;
|
||||
|
||||
private:
|
||||
CAirship(MonsterCreateInfo& MonsterCreate, unsigned long dwOwnerID, unsigned char cNation,
|
||||
unsigned long dwHP, unsigned short wObjectType, unsigned char cState, unsigned char cUpgradeStep);
|
||||
|
||||
|
||||
unsigned long m_dwPassengerCID[Siege::AIRSHIP_PASSENGER_NUM]; // 승객 CID
|
||||
|
||||
friend class CSiegeObjectMgr;
|
||||
};
|
||||
|
||||
#endif _AIRSHIP_OBJECT_H_
|
||||
@@ -0,0 +1,136 @@
|
||||
#include "stdafx.h"
|
||||
#include "BroadCastSiegeObjectData.h"
|
||||
|
||||
|
||||
BroadCastSiege::CSiegeObjectData::CSiegeObjectData() :
|
||||
m_dwCID(0), m_dwUpdateDataFlag(0)
|
||||
{
|
||||
memset( &m_OwershipInfo, 0, sizeof( sOwnerShipInfo ) );
|
||||
memset( &m_StateInfo, 0, sizeof( sStateInfo ) );
|
||||
memset( &m_HPInfo, 0, sizeof( sHPInfo ) );
|
||||
memset( &m_PosInfo, 0, sizeof( sPosInfo ) );
|
||||
memset( &m_MaterialInfo, 0, sizeof( sMaterialInfo ) );
|
||||
memset( &m_RiderInfo, 0, sizeof( sRiderInfo ) );
|
||||
|
||||
m_PosInfo.m_NetworkPos.Initialize( 0, 0, 0, 0, 0 );
|
||||
}
|
||||
|
||||
BroadCastSiege::CSiegeObjectData::~CSiegeObjectData()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
const void
|
||||
BroadCastSiege::CSiegeObjectData::GetRiders( unsigned long* pRiders ) const
|
||||
{
|
||||
std::copy( &m_RiderInfo.m_dwRiderID[0], &m_RiderInfo.m_dwRiderID[Siege::AIRSHIP_RIDER_NUM ], pRiders );
|
||||
}
|
||||
|
||||
const bool
|
||||
BroadCastSiege::CSiegeObjectData::IsSameRiders( unsigned long* pRiders ) const
|
||||
{
|
||||
for ( int i=0; i<Siege::AIRSHIP_RIDER_NUM; ++i )
|
||||
{
|
||||
if ( m_RiderInfo.m_dwRiderID[i] != pRiders[i] )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
BroadCastSiege::CSiegeObjectData::SetRiders( unsigned long* pRiders )
|
||||
{
|
||||
std::copy( &pRiders[0], &pRiders[ Siege::AIRSHIP_RIDER_NUM ], m_RiderInfo.m_dwRiderID );
|
||||
}
|
||||
|
||||
void
|
||||
BroadCastSiege::CSiegeObjectData::ClearRiders()
|
||||
{
|
||||
std::fill_n( &m_RiderInfo.m_dwRiderID[0], int( Siege::AIRSHIP_RIDER_NUM ), 0 );
|
||||
}
|
||||
|
||||
// ===================================================================================
|
||||
// Data 처리 함수
|
||||
void
|
||||
BroadCastSiege::CSiegeObjectData::ClearData()
|
||||
{
|
||||
memset( &m_OwershipInfo, 0, sizeof( sOwnerShipInfo ) );
|
||||
memset( &m_StateInfo, 0, sizeof( sStateInfo ) );
|
||||
memset( &m_HPInfo, 0, sizeof( sHPInfo ) );
|
||||
memset( &m_PosInfo, 0, sizeof( sPosInfo ) );
|
||||
memset( &m_MaterialInfo, 0, sizeof( sMaterialInfo ) );
|
||||
memset( &m_RiderInfo, 0, sizeof( sRiderInfo ) );
|
||||
|
||||
m_PosInfo.m_NetworkPos.Initialize( 0, 0, 0, 0, 0 );
|
||||
m_dwCID = m_dwUpdateDataFlag = 0;
|
||||
}
|
||||
|
||||
//! 버퍼와 버퍼 길이를 인자로 받아서 데이터를 업데이트한다.
|
||||
//! 리턴시에 버퍼 길이에, 사용한 버퍼 길이를 넣어 준다.
|
||||
//! 리턴값은 성공/실패 여부를 리턴한다.
|
||||
bool
|
||||
BroadCastSiege::CSiegeObjectData::UpdateData( unsigned long dwCID, const char* szData, int& iBufferSize_InOut )
|
||||
{
|
||||
// 데이터 순서는 다음과 같다.
|
||||
// UpdateFlag( 4 byte )
|
||||
// 기본 소유 정보 ( 3 * 4 + 1 byte = 13 byte )
|
||||
// 상태 정보 ( 6 byte )
|
||||
// HP 정보 ( 2 * 4 byte = 8 byte )
|
||||
// 위치 정보 ( 12 byte )
|
||||
// 자재 정보 ( 1 byte )
|
||||
// 탑승자 정보 ( 10 * 4 byte = 40 byte )
|
||||
// Total -> 84 byte
|
||||
|
||||
unsigned long dwUpdateFlag = 0;
|
||||
|
||||
const char* szDataPos = szData;
|
||||
const int iBufferSize = iBufferSize_InOut;
|
||||
if ( iBufferSize < sizeof(unsigned long) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update Flag 읽어오기
|
||||
COPY_AND_ADVANCE_SRC( &dwUpdateFlag, szDataPos, sizeof(unsigned long) );
|
||||
|
||||
// 읽어온 UpdateFlag로, 필요한 데이터의 양을 추산한다. 데이터 양이 부족하면 에러를 뱉는다.
|
||||
int iEstimateBufferSize = EstimateBufferSize( dwUpdateFlag );
|
||||
|
||||
if ( iBufferSize < iEstimateBufferSize )
|
||||
{
|
||||
// 버퍼 크기가 추산한 길이보다 작은 경우는 실패.
|
||||
return false;
|
||||
}
|
||||
|
||||
// 데이터 복사. 순서 바뀌면 죽는다!!.
|
||||
m_dwCID = dwCID;
|
||||
|
||||
if ( dwUpdateFlag & DELTA_OWNERSHIP ) { COPY_AND_ADVANCE_SRC( &m_OwershipInfo, szDataPos, sizeof( sOwnerShipInfo ) ); }
|
||||
if ( dwUpdateFlag & DELTA_STATE ) { COPY_AND_ADVANCE_SRC( &m_StateInfo, szDataPos, sizeof( sStateInfo ) ); }
|
||||
if ( dwUpdateFlag & DELTA_HP ) { COPY_AND_ADVANCE_SRC( &m_HPInfo, szDataPos, sizeof( sHPInfo ) ); }
|
||||
if ( dwUpdateFlag & DELTA_POS ) { COPY_AND_ADVANCE_SRC( &m_PosInfo, szDataPos, sizeof( sPosInfo ) ); }
|
||||
if ( dwUpdateFlag & DELTA_MATERIAL ) { COPY_AND_ADVANCE_SRC( &m_MaterialInfo, szDataPos, sizeof( sMaterialInfo ) ); }
|
||||
if ( dwUpdateFlag & DELTA_RIDER ) { COPY_AND_ADVANCE_SRC( &m_RiderInfo, szDataPos, sizeof( sRiderInfo ) ); }
|
||||
|
||||
iBufferSize_InOut = static_cast<int>( szDataPos - szData );
|
||||
// SetDataFlag(Broadcast2nd::CHARDATA_CHANGED);
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
BroadCastSiege::CSiegeObjectData::EstimateBufferSize( unsigned long dwUpdateFlag )
|
||||
{
|
||||
int iEstimateBufferSize = 0;
|
||||
|
||||
if ( dwUpdateFlag & DELTA_OWNERSHIP ) { iEstimateBufferSize += sizeof( sOwnerShipInfo ); }
|
||||
if ( dwUpdateFlag & DELTA_STATE ) { iEstimateBufferSize += sizeof( sStateInfo ); }
|
||||
if ( dwUpdateFlag & DELTA_HP ) { iEstimateBufferSize += sizeof( sHPInfo ); }
|
||||
if ( dwUpdateFlag & DELTA_POS ) { iEstimateBufferSize += sizeof( sPosInfo ); }
|
||||
if ( dwUpdateFlag & DELTA_MATERIAL ) { iEstimateBufferSize += sizeof( sMaterialInfo ); }
|
||||
if ( dwUpdateFlag & DELTA_RIDER ) { iEstimateBufferSize += sizeof( sRiderInfo ); }
|
||||
|
||||
return iEstimateBufferSize;
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
#ifndef __BROADCAST_SIEGEOBJECT_DATA_H__
|
||||
#define __BROADCAST_SIEGEOBJECT_DATA_H__
|
||||
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
|
||||
#include <Network/Packet/PacketStruct/CharMovePacket.h>
|
||||
#include <Creature/Siege/SiegeConstants.h>
|
||||
|
||||
//! 본 파일은 서버/클라이언트가 전부 사용하는 파일이다.
|
||||
//! 공성 오브젝트 데이터 중 클라이언트가 꼭 알아야 할 내용들을 담고 있다.
|
||||
|
||||
namespace BroadCastSiege
|
||||
{
|
||||
inline void COPY_AND_ADVANCE_SRC( void* dst, const char*& src, size_t size )
|
||||
{
|
||||
memcpy( dst, src, size ); src += size;
|
||||
}
|
||||
|
||||
inline void COPY_AND_ADVANCE_DST( char*& dst, const void* src, size_t size )
|
||||
{
|
||||
memcpy( dst, src, size ); dst += size;
|
||||
}
|
||||
|
||||
#define FLOAT_EPSILON 0.001
|
||||
|
||||
// Update Data Flag
|
||||
enum SiegeDeltaInfo
|
||||
{
|
||||
DELTA_OWNERSHIP = 1 << 0, // dwCampOrCastleID, OwnerID, GID, cNation
|
||||
DELTA_STATE = 1 << 1, // wObjectType, cState, cSubState, cUpgradeStep, cUpgradeType
|
||||
DELTA_HP = 1 << 2, // HP 정보
|
||||
DELTA_POS = 1 << 3, // fDir, Pos
|
||||
DELTA_MATERIAL = 1 << 4, // cMaterial
|
||||
DELTA_RIDER = 1 << 5, // dwRiderCID[]
|
||||
};
|
||||
|
||||
enum Const
|
||||
{
|
||||
// UpdateFlag ( 4 byte )
|
||||
// OwnerShipInfo ( 13 byte )
|
||||
// StateInfo( 6 byte )
|
||||
// HPInfo ( 8 byte )
|
||||
// PosInfo ( 12 byte )
|
||||
// MaterialInfo ( 1 byte )
|
||||
// RiderInfo ( 40 byte )
|
||||
// Total : 84 byte
|
||||
MAX_SIEGEOBJECT_DATA_SIZE = 120,
|
||||
MAX_SIEGEBROADCAST_BUFFER_SIZE = 160 // sizeof(PktNewSiegeBroadCast) + MAX_SIEGEOBJECT_DATA_SIZE
|
||||
};
|
||||
|
||||
enum BroadCastType
|
||||
{
|
||||
BROADCAST_ALL_DATA = 1, // 모든 데이터 전송
|
||||
BROADCAST_DELTA_DATA = 2, // 변경된 데이터 전송
|
||||
BROADCAST_DELETE_DATA = 3 // 해당 크리쳐 삭제 데이터 전송
|
||||
};
|
||||
|
||||
// 소유 정보 (성ID, 길드 요새ID, 소유자CID), 길드ID
|
||||
struct sOwnerShipInfo
|
||||
{
|
||||
unsigned long m_dwCampOrCastleID;
|
||||
unsigned long m_dwOwnerCID;
|
||||
unsigned long m_dwGID;
|
||||
unsigned char m_cNation;
|
||||
};
|
||||
|
||||
// 공성 오브젝트 상태 정보
|
||||
struct sStateInfo
|
||||
{
|
||||
unsigned short m_wObjectType;
|
||||
unsigned char m_cState;
|
||||
unsigned char m_cSubState;
|
||||
unsigned char m_cUpgradeStep;
|
||||
unsigned char m_cUpgradeType;
|
||||
};
|
||||
|
||||
// HP 정보
|
||||
struct sHPInfo
|
||||
{
|
||||
unsigned long m_dwNowHP;
|
||||
unsigned long m_dwMaxHP;
|
||||
};
|
||||
|
||||
// 위치 정보
|
||||
struct sPosInfo
|
||||
{
|
||||
float m_fDefaultDir;
|
||||
CNetworkPos m_NetworkPos;
|
||||
};
|
||||
|
||||
// 자재 정보
|
||||
struct sMaterialInfo
|
||||
{
|
||||
unsigned char m_cMaterial;
|
||||
};
|
||||
|
||||
// 탑승자 정보
|
||||
struct sRiderInfo
|
||||
{
|
||||
unsigned long m_dwRiderID[Siege::AIRSHIP_RIDER_NUM];
|
||||
};
|
||||
|
||||
|
||||
// =============================================================================================
|
||||
// SiegeObject Data
|
||||
class CSiegeObjectData
|
||||
{
|
||||
public:
|
||||
CSiegeObjectData();
|
||||
~CSiegeObjectData();
|
||||
|
||||
// ===================================================================================
|
||||
// Get 함수
|
||||
const unsigned long GetCID() const { return m_dwCID; }
|
||||
|
||||
const sOwnerShipInfo& GetOwnerShipInfo() const { return m_OwershipInfo; }
|
||||
const unsigned long GetCastleID() const { return m_OwershipInfo.m_dwCampOrCastleID; }
|
||||
const unsigned long GetCampID() const { return m_OwershipInfo.m_dwCampOrCastleID; }
|
||||
const unsigned long GetOwnerCID() const { return m_OwershipInfo.m_dwOwnerCID; }
|
||||
const unsigned long GetGID() const { return m_OwershipInfo.m_dwGID; }
|
||||
const unsigned char GetNation() const { return m_OwershipInfo.m_cNation; }
|
||||
|
||||
const sStateInfo& GetStateInfo() const { return m_StateInfo; }
|
||||
const unsigned short GetObjectType() const { return m_StateInfo.m_wObjectType; }
|
||||
const unsigned char GetState() const { return m_StateInfo.m_cState; }
|
||||
const unsigned char GetSubState() const { return m_StateInfo.m_cSubState; }
|
||||
const unsigned char GetUpgradeType() const { return m_StateInfo.m_cUpgradeType; }
|
||||
const unsigned char GetUpgradeStep() const { return m_StateInfo.m_cUpgradeStep; }
|
||||
|
||||
const sHPInfo& GetHPInfo() const { return m_HPInfo; }
|
||||
const unsigned long GetNowHP() const { return m_HPInfo.m_dwNowHP; }
|
||||
const unsigned long GetMaxHP() const { return m_HPInfo.m_dwMaxHP; }
|
||||
|
||||
const sPosInfo& GetPosInfo() const { return m_PosInfo; }
|
||||
const float GetDefaultDir() const { return m_PosInfo.m_fDefaultDir; }
|
||||
const CNetworkPos& GetNetworkPos() const { return m_PosInfo.m_NetworkPos; }
|
||||
|
||||
const sMaterialInfo& GetMaterialInfo() const { return m_MaterialInfo; }
|
||||
const unsigned char GetMaterialNum() const { return m_MaterialInfo.m_cMaterial; }
|
||||
|
||||
const sRiderInfo& GetRiderInfo() const { return m_RiderInfo; }
|
||||
const void GetRiders( unsigned long* pPassenger ) const;
|
||||
const bool IsSameRiders( unsigned long * pPassenger ) const;
|
||||
|
||||
// ===================================================================================
|
||||
// Set 함수
|
||||
void SetOwnerShipInfo( const sOwnerShipInfo& info ) { m_OwershipInfo = info; }
|
||||
void SetCastleID( unsigned long dwCastleID ) { m_OwershipInfo.m_dwCampOrCastleID = dwCastleID; }
|
||||
void SetCampID( unsigned long dwCampID ) { m_OwershipInfo.m_dwCampOrCastleID = dwCampID; }
|
||||
void SetOwnerCID( unsigned long dwOwnerCID ) { m_OwershipInfo.m_dwOwnerCID = dwOwnerCID; }
|
||||
void SetGID( unsigned long dwGID ) { m_OwershipInfo.m_dwGID = dwGID; }
|
||||
void SetNation( unsigned char cNation ) { m_OwershipInfo.m_cNation = cNation; }
|
||||
|
||||
void SetStateInfo( const sStateInfo& info ) { m_StateInfo = info; }
|
||||
void SetObjectType( unsigned short wType ) { m_StateInfo.m_wObjectType = wType; }
|
||||
void SetState( unsigned char cState ) { m_StateInfo.m_cState = cState; }
|
||||
void SetSubState( unsigned char cSubState ) { m_StateInfo.m_cSubState = cSubState; }
|
||||
void SetUpgradeType( unsigned char cType ) { m_StateInfo.m_cUpgradeType = cType; }
|
||||
void SetUpgradeStep( unsigned char cStep ) { m_StateInfo.m_cUpgradeStep = cStep; }
|
||||
|
||||
void SetHPInfo( const sHPInfo& info ) { m_HPInfo = info; }
|
||||
void SetNowHP( unsigned long dwNowHP ) { m_HPInfo.m_dwNowHP = dwNowHP; }
|
||||
void SetMaxHP( unsigned long dwMaxHP ) { m_HPInfo.m_dwMaxHP = dwMaxHP; }
|
||||
|
||||
void SetPosInfo( const sPosInfo& info ) { m_PosInfo = info; }
|
||||
void SetDefaultDir( float fDir ) { m_PosInfo.m_fDefaultDir = fDir; }
|
||||
void SetNetworkPos( const CNetworkPos& pos) { m_PosInfo.m_NetworkPos = pos; }
|
||||
|
||||
void SetMaterialInfo( const sMaterialInfo& info ) { m_MaterialInfo = info; }
|
||||
void SetMaterialNum( unsigned char cMaterial ) { m_MaterialInfo.m_cMaterial = cMaterial; }
|
||||
|
||||
void SetRiderInfo( const sRiderInfo& info ) { m_RiderInfo = info; }
|
||||
void SetRiders( unsigned long* pPassenger );
|
||||
void ClearRiders();
|
||||
|
||||
// ===================================================================================
|
||||
// Data 처리 함수
|
||||
void ClearData();
|
||||
|
||||
//! 버퍼와 버퍼 길이를 인자로 받아서 데이터를 업데이트한다.
|
||||
//! 리턴시에 버퍼 길이에, 사용한 버퍼 길이를 넣어 준다.
|
||||
//! 리턴값은 성공/실패 여부를 리턴한다.
|
||||
bool UpdateData( unsigned long dwCID, const char* szData, int& iBufferSize_InOut );
|
||||
static int EstimateBufferSize( unsigned long dwUpdateFlag );
|
||||
|
||||
// ===================================================================================
|
||||
// Data Flag 관련 함수
|
||||
void SetUpdateDataFlag( unsigned long dwFlag ) { m_dwUpdateDataFlag |= dwFlag; }
|
||||
bool HasUpdateDataFlag( unsigned long dwFlag ) { return 0 != (m_dwUpdateDataFlag & dwFlag); }
|
||||
void ResetUpdateDataFlag( unsigned long dwFlag ) { m_dwUpdateDataFlag &= ~dwFlag; }
|
||||
void ClearUpdateDataFlag() { m_dwUpdateDataFlag = 0; }
|
||||
|
||||
unsigned long GetDataFlag() const { return m_dwUpdateDataFlag; }
|
||||
|
||||
private:
|
||||
|
||||
unsigned long m_dwCID;
|
||||
|
||||
sOwnerShipInfo m_OwershipInfo;
|
||||
sStateInfo m_StateInfo;
|
||||
sHPInfo m_HPInfo;
|
||||
sPosInfo m_PosInfo;
|
||||
sMaterialInfo m_MaterialInfo;
|
||||
sRiderInfo m_RiderInfo;
|
||||
|
||||
unsigned long m_dwUpdateDataFlag;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif __BROADCAST_SIEGEOBJECT_DATA_H__
|
||||
602
Server/RylServerProject/RylGameLibrary/Creature/Siege/Camp.cpp
Normal file
602
Server/RylServerProject/RylGameLibrary/Creature/Siege/Camp.cpp
Normal file
@@ -0,0 +1,602 @@
|
||||
#include "stdafx.h"
|
||||
#include "Camp.h"
|
||||
|
||||
#include <Community/Guild/Guild.h>
|
||||
#include <Community/Guild/GuildMgr.h>
|
||||
|
||||
#include <Skill/SkillTable.h>
|
||||
#include <Skill/SkillMgr.h>
|
||||
|
||||
#include <Utility/Math/Math.h>
|
||||
|
||||
#include <Item/Item.h>
|
||||
#include <Item/ItemFactory.h>
|
||||
|
||||
#include <Map/FieldMap/CellManager.h>
|
||||
#include <Map/DuelMap/DuelCellManager.h>
|
||||
|
||||
#include <Network/Packet/WrapPacket.h>
|
||||
#include <Network/Packet/PacketCommand.h>
|
||||
#include <Network/Packet/PacketStruct/ServerInfo.h>
|
||||
|
||||
#include <Network/Dispatch/GameClient/GameClientDispatch.h>
|
||||
#include <Network/Dispatch/GameClient/SendCharItem.h>
|
||||
#include <Network/Dispatch/GameClient/SendCharCastle.h>
|
||||
#include <Network/Dispatch/GameClient/SendCharAttack.h>
|
||||
#include <Network/Dispatch/DBAgent/DBAgentDispatch.h>
|
||||
#include <Network/Dispatch/DBAgent/DBAgentRequest.h>
|
||||
|
||||
#include <Network/ClientSocket/ClientConstants.h>
|
||||
|
||||
CCamp::CCamp(MonsterCreateInfo& MonsterCreate, unsigned long dwCampID, unsigned long dwGID,
|
||||
unsigned long dwHP, unsigned short wObjectType, unsigned char cState,
|
||||
unsigned char cSubState, unsigned char cUpgradeStep, unsigned char cMaterial,
|
||||
unsigned char cSiegeCount, const CampRight& campRight, bool bFullHP)
|
||||
: CSiegeObject(MonsterCreate, dwCampID, dwGID, dwHP, wObjectType, cState, cSubState, cUpgradeStep, cMaterial, cSiegeCount, bFullHP),
|
||||
m_CampRight(campRight), m_dwLastAttackedTick(0), m_dwCmdSenderCID(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CCamp::~CCamp()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CCamp::NormalBehavior(unsigned long dwTick)
|
||||
{
|
||||
// 선공 처리
|
||||
if (NULL == m_lpTarget && true == m_MonsterInfo.m_bFirstAttack)
|
||||
{
|
||||
SearchPlayer();
|
||||
}
|
||||
}
|
||||
|
||||
void CCamp::AttackBehavior(unsigned long dwTick)
|
||||
{
|
||||
PERFORMANCE_CHECK(FunctionTimingCheck)
|
||||
|
||||
// 구축중, 구축 취소중, 파괴되었으면 공격할 수 없다.
|
||||
if (Siege::DEVELOPING == m_cState ||
|
||||
Siege::CANCELING == m_cState ||
|
||||
Siege::DESTROYED == m_cState)
|
||||
{
|
||||
CancelTarget();
|
||||
return;
|
||||
}
|
||||
|
||||
// 마법 캐스팅 중일때는.. 아무런 다른 행동을 해서는 안된다.
|
||||
if (true == m_bCasting)
|
||||
{
|
||||
CastingAttackAction();
|
||||
return;
|
||||
}
|
||||
|
||||
m_lpTarget = m_Threat.GetTarget();
|
||||
if (NULL == m_lpTarget ||
|
||||
(m_lpTarget && true == m_lpTarget->GetEnchantInfo().GetFlag(Skill::SpellID::Hide)))
|
||||
{
|
||||
CancelTarget();
|
||||
return;
|
||||
}
|
||||
|
||||
const float fDY = fabs(m_lpTarget->GetCurrentPos().m_fPointY - GetCurrentPos().m_fPointY);
|
||||
const float fDX = m_lpTarget->GetCurrentPos().m_fPointX - GetCurrentPos().m_fPointX;
|
||||
const float fDZ = m_lpTarget->GetCurrentPos().m_fPointZ - GetCurrentPos().m_fPointZ;
|
||||
const float fDistance = sqrtf((fDX * fDX) + (fDZ * fDZ));
|
||||
|
||||
|
||||
// 거리 체크
|
||||
if (fDistance > Siege::CAMP_ATTACK_RANGE || 0 == m_lpTarget->GetStatus().m_nNowHP)
|
||||
{
|
||||
CancelTarget();
|
||||
return;
|
||||
}
|
||||
|
||||
if (0 >= m_lCurrentFrame)
|
||||
{
|
||||
// 공격 범위 밖이다.
|
||||
if (true == SkillAttack()) // 스킬 공격을 사용하는가 체크
|
||||
{
|
||||
SkillAttackAction();
|
||||
}
|
||||
|
||||
if (false == m_bAttacking)
|
||||
{
|
||||
m_lCurrentFrame = m_MotionInfo.m_dwFrame;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 공격 범위 안이다.
|
||||
if (false == m_bAttacking)
|
||||
{
|
||||
if (true == SkillAttack()) // 스킬 공격을 사용하는가 체크
|
||||
{
|
||||
SkillAttackAction();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 방향을 고정시켜둔다.
|
||||
m_MotionInfo.m_fDirection = 0;
|
||||
}
|
||||
|
||||
void CCamp::SearchPlayer(void)
|
||||
{
|
||||
// TODO : 해상도 조절을 통해 float 계산을 없애보자.
|
||||
if (NULL == m_CellPos.m_lpCell)
|
||||
{
|
||||
ERRLOG1(g_Log, "CID:0X%08 공성 오브젝트가 셀 범위 밖에 있습니다.", m_dwCID);
|
||||
return;
|
||||
}
|
||||
|
||||
CCell* pCell = NULL;
|
||||
CCharacter* pTempTarget = NULL;
|
||||
CCharacter* pCurrentTarget = NULL;
|
||||
|
||||
const float fSquareSearchRange = (float)(Siege::CAMP_ATTACK_RANGE * Siege::CAMP_ATTACK_RANGE);
|
||||
|
||||
for (int nCellCount = 0; nCellCount < CCell::CONNECT_NUM; ++nCellCount)
|
||||
{
|
||||
pCell = m_CellPos.m_lpCell->GetConnectCell(nCellCount);
|
||||
if (NULL == pCell || false == pCell->IsCharacter())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
pTempTarget = pCell->GetFirstCharacter();
|
||||
|
||||
while (NULL != pTempTarget)
|
||||
{
|
||||
const float fDistY = fabs(pTempTarget->GetCurrentPos().m_fPointY - GetCurrentPos().m_fPointY);
|
||||
|
||||
if (pTempTarget->GetStatus().m_nNowHP > 0 && EnemyCheck::EC_ENEMY == IsEnemy(pTempTarget))
|
||||
{
|
||||
if (false == pTempTarget->GetEnchantInfo().GetFlag(Skill::SpellID::Stealth) &&
|
||||
false == pTempTarget->GetEnchantInfo().GetFlag(Skill::SpellID::Invincible) &&
|
||||
false == pTempTarget->GetEnchantInfo().GetFlag(Skill::SpellID::Hide))
|
||||
{
|
||||
const float fDX = pTempTarget->GetCurrentPos().m_fPointX - GetCurrentPos().m_fPointX;
|
||||
const float fDZ = pTempTarget->GetCurrentPos().m_fPointZ - GetCurrentPos().m_fPointZ;
|
||||
|
||||
const float fDistance = (fDX * fDX) + (fDZ * fDZ);
|
||||
|
||||
if (fDistance < fSquareSearchRange)
|
||||
{
|
||||
pCurrentTarget = pTempTarget;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pTempTarget = pCell->GetNextCharacter();
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL != pCurrentTarget)
|
||||
{
|
||||
m_Threat.AddToThreatList(pCurrentTarget, 1);
|
||||
m_nCurrentState = CFSM::GetInstance().StateTransition(m_nCurrentState, INPUT_ID_SEEN_PLAYER);
|
||||
}
|
||||
}
|
||||
|
||||
bool CCamp::Attack(AtType attackType, unsigned char cDefenderNum, CAggresiveCreature** ppDefenders, unsigned char* cDefenserJudges, unsigned short* wDefenserMPHeal)
|
||||
{
|
||||
return CSkillMonster::Attack(attackType, cDefenderNum, ppDefenders, cDefenserJudges, wDefenserMPHeal);
|
||||
}
|
||||
|
||||
bool CCamp::Dead(CAggresiveCreature* pOffencer)
|
||||
{
|
||||
if (STATE_ID_DIE == m_nCurrentState) { return false; }
|
||||
|
||||
m_CreatureStatus.m_nNowHP = 0;
|
||||
m_dwLastBehaviorTick = m_dwLastTime = CPulse::GetInstance().GetLastTick();
|
||||
m_lCurrentFrame = FPS;
|
||||
m_bAttacking = false;
|
||||
m_bCasting = false;
|
||||
|
||||
m_nCurrentState = CFSM::GetInstance().StateTransition(m_nCurrentState, INPUT_ID_ZERO_HP);
|
||||
|
||||
// 크리쳐 매니져에서 삭제 (해당 셀에서도 삭제한다.)
|
||||
CCreatureManager::GetInstance().DeleteCreature(m_dwCID);
|
||||
|
||||
// 중계 서버로 패킷 전송
|
||||
GET_SINGLE_DISPATCH(lpDBAgentDispatch, CDBAgentDispatch, CDBAgentDispatch::GetDispatchTable());
|
||||
if (lpDBAgentDispatch)
|
||||
{
|
||||
if ( pOffencer )
|
||||
{
|
||||
DETLOG3(g_Log, "길드 요새 이벤트 로그 : 파괴된 요새 아이디(0x%08x), 파괴한 캐릭터 아이디(0x%08x), 파괴한 길드 아이디(0x%08x)",
|
||||
GetCampID(), pOffencer->GetCID(), pOffencer->GetGID());
|
||||
|
||||
return GameClientSendPacket::SendCharCampCmdToDBAgent(lpDBAgentDispatch->GetSendStream(), pOffencer->GetCID(), GetCampID(),
|
||||
pOffencer->GetGID(), 0, PktCampCmd::CAMP_DESTROY, PktBase::NO_SERVER_ERR);
|
||||
}
|
||||
else
|
||||
{
|
||||
return GameClientSendPacket::SendCharCampCmdToDBAgent(lpDBAgentDispatch->GetSendStream(), 0, GetCampID(),
|
||||
0, 0, PktCampCmd::CAMP_DESTROY, PktBase::NO_SERVER_ERR);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool CCamp::ToStarterKit(bool bFullMaterial)
|
||||
{
|
||||
// 아이템 생성
|
||||
Item::CItem* lpItem = Item::CItemFactory::GetInstance().CreateItem(Item::EtcItemID::CAMP_KIT_ID);
|
||||
if (NULL == lpItem)
|
||||
{
|
||||
ERRLOG0(g_Log, "길드 요새 생성 스타트킷 아이템 생성에 실패했습니다.");
|
||||
return false;
|
||||
}
|
||||
|
||||
CGuild* lpGuild = Guild::CGuildMgr::GetInstance().GetGuild(m_dwGID);
|
||||
if (NULL != lpGuild)
|
||||
{
|
||||
Guild::MemberInfo MasterInfo = lpGuild->GetMaster();
|
||||
unsigned long dwMasterID = MasterInfo.m_dwCID;
|
||||
CCharacter* lpCharacter = CCreatureManager::GetInstance().GetCharacter( dwMasterID );
|
||||
|
||||
if (NULL != lpCharacter)
|
||||
{
|
||||
if (false == lpCharacter->GiveItem(lpItem))
|
||||
{
|
||||
ERRLOG0(g_Log, "길드 요새 생성 스타트킷을 돌려주는데 실패하였습니다.");
|
||||
|
||||
DELETE_ITEM(lpItem);
|
||||
return false;
|
||||
}
|
||||
|
||||
// GievItem 으로 스택된 경우
|
||||
if (lpItem->IsSet(Item::DetailData::STACKABLE) && 0 == lpItem->GetNumOrDurability())
|
||||
{
|
||||
DELETE_ITEM(lpItem);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 바닥에 아이템 떨어뜨리기
|
||||
CCell::ItemInfo itemInfo;
|
||||
GetCellPos().m_lpCell->SetItem(GetCurrentPos(), lpItem, 0, 0, CCell::NONE, itemInfo);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// 길드 요새 파괴시 길드 마스터에게 돈을 돌려준다. (로그인해있을때만)
|
||||
// (로그아웃해 있을 때는 중계 서버에서 돈을 돌려주는 처리를 한다.)
|
||||
void CCamp::AddGoldToMaster(unsigned long dwGold)
|
||||
{
|
||||
CGuild* lpGuild = Guild::CGuildMgr::GetInstance().GetGuild(m_dwGID);
|
||||
|
||||
if (lpGuild)
|
||||
{
|
||||
Guild::MemberInfo& MasterInfo = lpGuild->GetMaster();
|
||||
CCharacter* lpMaster = CCreatureManager::GetInstance().GetCharacter( MasterInfo.m_dwCID );
|
||||
|
||||
if (lpMaster)
|
||||
{
|
||||
lpMaster->AddGold(dwGold, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 길드 요새 구축 완료
|
||||
bool CCamp::Build(unsigned char cUpgradeStep)
|
||||
{
|
||||
m_cState = Siege::COMPLETE;
|
||||
|
||||
UpdateObjectInfo();
|
||||
|
||||
// 해당 진지가 있는 반경 5셀 이내에 전송
|
||||
PktCampCmd pktCC;
|
||||
pktCC.m_dwCID = m_dwCID;
|
||||
pktCC.m_dwCampID = GetCampID();
|
||||
pktCC.m_cState = m_cState;
|
||||
pktCC.m_dwValue1 = 0;
|
||||
pktCC.m_dwValue2 = 0;
|
||||
pktCC.m_cSubCmd = PktCampCmd::CAMP_BUILD_COMPLETE;
|
||||
|
||||
char* szPacket = reinterpret_cast<char *>(&pktCC);
|
||||
if (PacketWrap::WrapCrypt(szPacket, sizeof(PktCampCmd), CmdCampCmd, 0, 0))
|
||||
{
|
||||
// Vincent - 브로드 캐스트 테스트 코드
|
||||
//SendToRadiusCell(szPacket, sizeof(PktCampCmd), CmdCampCmd);
|
||||
//SendToRange(Siege::BROADCAST_RADIUS, szPacket, sizeof(PktCampCmd), CmdCampCmd);
|
||||
// Vincent - 모든 캐릭터에게 전송해야 라지맵 정보가 제대로 갱신된다.
|
||||
CCreatureManager::GetInstance().SendAllCharacter(szPacket, sizeof(PktCampCmd), CmdCampCmd);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CCamp::Cancel()
|
||||
{
|
||||
const int MAX_BUFFER = sizeof(PktCampCmd);
|
||||
char szBuffer[MAX_BUFFER];
|
||||
|
||||
PktCampCmd* lpPktCC = reinterpret_cast<PktCampCmd*>(szBuffer);
|
||||
|
||||
lpPktCC->m_dwCID = m_dwCID;
|
||||
lpPktCC->m_dwCampID = GetCampID();
|
||||
lpPktCC->m_cState = Siege::DESTROYED;
|
||||
lpPktCC->m_dwValue1 = 0;
|
||||
lpPktCC->m_dwValue2 = 0;
|
||||
lpPktCC->m_cSubCmd = PktCampCmd::CAMP_DESTROY;
|
||||
|
||||
if (true == PacketWrap::WrapCrypt(szBuffer, MAX_BUFFER, CmdCampCmd, 0 ,0))
|
||||
{
|
||||
CCreatureManager::GetInstance().SendAllCharacter(szBuffer, MAX_BUFFER, CmdCampCmd);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 길드 요새 업그레이드 완료
|
||||
bool CCamp::Upgrade(unsigned char cUpgradeStep)
|
||||
{
|
||||
m_cState = Siege::COMPLETE;
|
||||
m_cUpgradeStep = cUpgradeStep;
|
||||
|
||||
UpdateObjectInfo(Siege::UPGRADE_HP);
|
||||
|
||||
// 해당 진지가 있는 반경 5셀 이내에 전송
|
||||
PktCampCmd pktCC;
|
||||
pktCC.m_dwCID = m_dwCID;
|
||||
pktCC.m_dwCampID = GetCampID();
|
||||
pktCC.m_cState = m_cState;
|
||||
pktCC.m_dwValue1 = m_cUpgradeStep;
|
||||
pktCC.m_dwValue2 = 0;
|
||||
pktCC.m_cSubCmd = PktCampCmd::CAMP_UPGRADE_COMPLETE;
|
||||
|
||||
char* szPacket = reinterpret_cast<char *>(&pktCC);
|
||||
if (PacketWrap::WrapCrypt(szPacket, sizeof(PktCampCmd), CmdCampCmd, 0, 0))
|
||||
{
|
||||
// Vincent - 브로드 캐스트 테스트 코드
|
||||
//SendToRadiusCell(szPacket, sizeof(PktCampCmd), CmdCampCmd);
|
||||
SendToRange(Siege::BROADCAST_RADIUS, szPacket, sizeof(PktCampCmd), CmdCampCmd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 길드 요새 수리 완료
|
||||
bool CCamp::Repair(unsigned short wRepairHP)
|
||||
{
|
||||
m_cState = Siege::COMPLETE;
|
||||
UpdateObjectInfo(Siege::REPAIR_HP, wRepairHP);
|
||||
|
||||
// 해당 진지가 있는 반경 5셀 이내에 전송
|
||||
PktCampCmd pktCC;
|
||||
pktCC.m_dwCID = m_dwCID;
|
||||
pktCC.m_dwCampID = GetCampID();
|
||||
pktCC.m_cState = m_cState;
|
||||
pktCC.m_dwValue1 = m_CreatureStatus.m_nNowHP;
|
||||
pktCC.m_dwValue2 = 0;
|
||||
pktCC.m_cSubCmd = PktCampCmd::CAMP_REPAIR_COMPLETE;
|
||||
|
||||
char* szPacket = reinterpret_cast<char *>(&pktCC);
|
||||
if (PacketWrap::WrapCrypt(szPacket, sizeof(PktCampCmd), CmdCampCmd, 0, 0))
|
||||
{
|
||||
// Vincent - 브로드 캐스트 테스트 코드
|
||||
//SendToRadiusCell(szPacket, sizeof(PktCampCmd), CmdCampCmd);
|
||||
SendToRange(Siege::BROADCAST_RADIUS, szPacket, sizeof(PktCampCmd), CmdCampCmd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CCamp::Destroy(unsigned long dwOffencerGID)
|
||||
{
|
||||
const int MAX_BUFFER = sizeof(PktCampCmd);
|
||||
char szBuffer[MAX_BUFFER];
|
||||
|
||||
PktCampCmd* lpPktCC = reinterpret_cast<PktCampCmd*>(szBuffer);
|
||||
|
||||
lpPktCC->m_dwCID = m_dwCID;
|
||||
lpPktCC->m_dwCampID = GetCampID();
|
||||
lpPktCC->m_cState = Siege::DESTROYED;
|
||||
lpPktCC->m_dwValue1 = 0;
|
||||
lpPktCC->m_dwValue2 = 0;
|
||||
lpPktCC->m_cSubCmd = PktCampCmd::CAMP_DESTROY;
|
||||
|
||||
if (true == PacketWrap::WrapCrypt(szBuffer, MAX_BUFFER, CmdCampCmd, 0 ,0))
|
||||
{
|
||||
CCreatureManager::GetInstance().SendAllCharacter(szBuffer, MAX_BUFFER, CmdCampCmd);
|
||||
|
||||
// 자재 드랍
|
||||
CCell* lpCell = CCellManager::GetInstance().GetCell(0,
|
||||
static_cast<unsigned long>(GetCurrentPos().m_fPointX),
|
||||
static_cast<unsigned long>(GetCurrentPos().m_fPointY),
|
||||
static_cast<unsigned long>(GetCurrentPos().m_fPointZ));
|
||||
|
||||
if (NULL == lpCell)
|
||||
{
|
||||
ERRLOG4(g_Log, "CampID:0x%08x 자재를 드랍할 길드 요새의 위치가 이상합니다. X:%.1f, Y:%.1f, Z:%.1f",
|
||||
GetCampID(), GetCurrentPos().m_fPointX, GetCurrentPos().m_fPointY, GetCurrentPos().m_fPointZ);
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned char cAmount = m_cMaterial + Siege::GetUpgradeMaterialNum(m_wObjectType) * m_cUpgradeStep / 2;
|
||||
while (cAmount > 0)
|
||||
{
|
||||
Item::CItem* lpMaterial = Item::CItemFactory::GetInstance().CreateItem(Item::EtcItemID::SIEGE_MATERIAL_ID);
|
||||
if (NULL == lpMaterial)
|
||||
{
|
||||
ERRLOG0(g_Log, "공성 병기 제작용 자재 아이템 생성에 실패했습니다.");
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned char cMaxNum = lpMaterial->GetMaxNumOrDurability();
|
||||
if (cAmount < cMaxNum)
|
||||
{
|
||||
lpMaterial->SetNumOrDurability(cAmount);
|
||||
cMaxNum = cAmount;
|
||||
cAmount = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
lpMaterial->SetNumOrDurability(cMaxNum);
|
||||
cAmount -= cMaxNum;
|
||||
}
|
||||
|
||||
CCell::ItemInfo itemInfo;
|
||||
|
||||
lpCell->SetItem(GetCurrentPos(), lpMaterial, 0, dwOffencerGID,
|
||||
(0 == dwOffencerGID) ? CCell::NONE : CCell::GUILD, itemInfo);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool CCamp::ChangeType(unsigned short wChangeType)
|
||||
{
|
||||
m_cState = Siege::COMPLETE;
|
||||
|
||||
// 해당 진지가 있는 반경 5셀 이내에 전송
|
||||
PktCampCmd pktCC;
|
||||
pktCC.m_dwCID = m_dwCID;
|
||||
pktCC.m_dwCampID = GetCampID();
|
||||
pktCC.m_cState = m_cState;
|
||||
pktCC.m_dwValue1 = wChangeType;
|
||||
pktCC.m_dwValue2 = 0;
|
||||
pktCC.m_cSubCmd = PktCampCmd::CAMP_CHANGE_COMPLETE;
|
||||
|
||||
char* szPacket = reinterpret_cast<char *>(&pktCC);
|
||||
if (PacketWrap::WrapCrypt(szPacket, sizeof(PktCampCmd), CmdCampCmd, 0, 0))
|
||||
{
|
||||
// Vincent - 브로드 캐스트 테스트 코드
|
||||
//SendToRadiusCell(szPacket, sizeof(PktCampCmd), CmdCampCmd);
|
||||
SendToRange(Siege::BROADCAST_RADIUS, szPacket, sizeof(PktCampCmd), CmdCampCmd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// 길드 요새 정보 업데이트
|
||||
bool CCamp::Update(unsigned char cState, unsigned long dwValue1, unsigned long dwValue2, unsigned long dwNoValue, unsigned char cSubCmd)
|
||||
{
|
||||
m_cState = cState;
|
||||
|
||||
UpdateObjectInfo();
|
||||
|
||||
// 해당 진지가 있는 반경 5셀 이내에 전송
|
||||
PktCampCmd pktCC;
|
||||
pktCC.m_dwCID = m_dwCID;
|
||||
pktCC.m_dwCampID = GetCampID();
|
||||
pktCC.m_cState = m_cState;
|
||||
pktCC.m_dwValue1 = dwValue1;
|
||||
pktCC.m_dwValue2 = dwValue2;
|
||||
pktCC.m_cSubCmd = cSubCmd;
|
||||
|
||||
// 자재 소모를 필요로한 명령은 남은 자재의 갯수를 보내준다.
|
||||
switch (cSubCmd)
|
||||
{
|
||||
case PktCampCmd::CAMP_UPGRADE:
|
||||
{
|
||||
m_cUpgradeStep = static_cast<unsigned char>(dwValue1);
|
||||
pktCC.m_dwValue2 = m_cMaterial;
|
||||
}
|
||||
break;
|
||||
|
||||
case PktCampCmd::CAMP_REPAIR:
|
||||
case PktCampCmd::CAMP_CHANGE_TYPE:
|
||||
{
|
||||
pktCC.m_dwValue2 = m_cMaterial;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
char* szPacket = reinterpret_cast<char *>(&pktCC);
|
||||
if (PacketWrap::WrapCrypt(szPacket, sizeof(PktCampCmd), CmdCampCmd, 0, 0))
|
||||
{
|
||||
// Vincent - 브로드 캐스트 테스트 코드
|
||||
//SendToRadiusCell(szPacket, sizeof(PktCampCmd), CmdCampCmd);
|
||||
SendToRange(Siege::BROADCAST_RADIUS, szPacket, sizeof(PktCampCmd), CmdCampCmd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CCamp::SetRight(CampRight campRight)
|
||||
{
|
||||
m_CampRight = campRight;
|
||||
|
||||
// 해당 길드의 길드원들에게 전송
|
||||
Guild::CGuild* lpGuild = Guild::CGuildMgr::GetInstance().GetGuild(GetGID());
|
||||
if (lpGuild)
|
||||
{
|
||||
PktCampRight pktCR;
|
||||
pktCR.m_dwCID = m_dwCID;
|
||||
pktCR.m_dwCampID = GetCampID();
|
||||
pktCR.m_CampRight = m_CampRight;
|
||||
|
||||
char* szPacket = reinterpret_cast<char *>(&pktCR);
|
||||
if (PacketWrap::WrapCrypt(szPacket, sizeof(PktCampRight), CmdCampRight, 0, 0))
|
||||
{
|
||||
lpGuild->SendAllMember(szPacket, sizeof(PktCampRight), CmdCampRight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CCamp::CheckRight(unsigned char cRightType, unsigned long dwCID, unsigned long dwGID)
|
||||
{
|
||||
Guild::CGuild* lpGuild = Guild::CGuildMgr::GetInstance().GetGuild(m_dwGID);
|
||||
if (lpGuild)
|
||||
{
|
||||
if (m_CampRight.Check(cRightType, lpGuild->GetTitle(dwCID)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void CCamp::SendAttackedMessage()
|
||||
{
|
||||
unsigned long dwNowTime = timeGetTime();
|
||||
if ( dwNowTime - m_dwLastAttackedTick >= Siege::CAMP_ATTACKED_INTERVAL )
|
||||
{
|
||||
// 중계 서버로 패킷 전송
|
||||
GET_SINGLE_DISPATCH(lpDBAgentDispatch, CDBAgentDispatch, CDBAgentDispatch::GetDispatchTable());
|
||||
if (lpDBAgentDispatch)
|
||||
{
|
||||
if (IsWorldWeapon())
|
||||
{
|
||||
GameClientSendPacket::SendCharCampMessageToDBAgent(lpDBAgentDispatch->GetSendStream(), GetCampID(),
|
||||
PktCampMessage::MSGCMD_WEAPON_ATTACKED, PktBase::NO_SERVER_ERR);
|
||||
}
|
||||
else
|
||||
{
|
||||
GameClientSendPacket::SendCharCampMessageToDBAgent(lpDBAgentDispatch->GetSendStream(), GetCampID(),
|
||||
PktCampMessage::MSGCMD_ATTACKED, PktBase::NO_SERVER_ERR);
|
||||
}
|
||||
}
|
||||
|
||||
m_dwLastAttackedTick = dwNowTime;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unsigned long CCamp::GetRepairGold() const
|
||||
{
|
||||
int nDiffHP = m_CreatureStatus.m_StatusInfo.m_nMaxHP - m_CreatureStatus.m_nNowHP;
|
||||
return nDiffHP * Siege::CAMP_REPAIR_GOLD_PER_HP;
|
||||
}
|
||||
|
||||
73
Server/RylServerProject/RylGameLibrary/Creature/Siege/Camp.h
Normal file
73
Server/RylServerProject/RylGameLibrary/Creature/Siege/Camp.h
Normal file
@@ -0,0 +1,73 @@
|
||||
#ifndef _CAMP_OBJECT_H_
|
||||
#define _CAMP_OBJECT_H_
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Creature/Siege/SiegeObject.h>
|
||||
#include <Creature/Siege/SiegeConstants.h>
|
||||
|
||||
using namespace Siege;
|
||||
|
||||
|
||||
class CCamp : public CSiegeObject
|
||||
{
|
||||
public:
|
||||
|
||||
virtual ~CCamp();
|
||||
|
||||
// CSkillMonster 의 기능
|
||||
void NormalBehavior(unsigned long dwTick);
|
||||
void AttackBehavior(unsigned long dwTick);
|
||||
|
||||
void SearchPlayer(void);
|
||||
bool Attack(AtType attackType, unsigned char cDefenderNum, CAggresiveCreature** ppDefenders, unsigned char* cDefenserJudges, unsigned short* wDefenserMPHeal);
|
||||
|
||||
bool Dead(CAggresiveCreature* pOffencer);
|
||||
|
||||
// 길드 요새 관련 함수
|
||||
virtual bool Build(unsigned char cUpgradeStep = 0); // 길드 요새 구축 완료
|
||||
bool Cancel(); // 길드 요새 구축 취소 완료
|
||||
bool Upgrade(unsigned char cUpgradeStep); // 길드 요새 업그레이드 완료
|
||||
bool Repair(unsigned short wRepairHP); // 길드 요새 수리 완료
|
||||
virtual bool Destroy(unsigned long dwOffencerGID = 0); // 길드 요새 파괴 완료 (자체 파괴, 파괴됨)
|
||||
bool Update(unsigned char cState, unsigned long dwValue1, unsigned long dwValue2, unsigned long dwNoValue, unsigned char cSubCmd); // 길드 요새 정보 업데이트
|
||||
bool ChangeType(unsigned short wChangeType); // 길드 요새 타입 변형 완료
|
||||
|
||||
void SetRight(CampRight campRight);
|
||||
bool CheckRight(unsigned char cRightType, unsigned long dwCID, unsigned long dwGID);
|
||||
|
||||
// 길드 요새 파괴시 길드 마스터에게 돈을 돌려준다. (로그인해있을때만)
|
||||
// (로그아웃한 경우는 중계에서 알아서 처리해준다)
|
||||
void AddGoldToMaster(unsigned long dwGold);
|
||||
|
||||
// 스타터킷 아이템으로 전환 (bFullMaterial 이 true 이면 자재의 90%를 돌려준다.)
|
||||
bool ToStarterKit(bool bFullMaterial = false);
|
||||
|
||||
|
||||
// 패킷 전송 함수
|
||||
void SendAttackedMessage(); // To DBAgentServer
|
||||
|
||||
|
||||
// Get / Set 함수
|
||||
const CampRight& GetCampRight() const { return m_CampRight; }
|
||||
unsigned long GetRepairGold() const;
|
||||
|
||||
bool UpdateMaterialNum(unsigned char cMaterial);
|
||||
|
||||
protected:
|
||||
|
||||
CCamp(MonsterCreateInfo& MonsterCreate, unsigned long dwCampID, unsigned long dwGID,
|
||||
unsigned long dwHP, unsigned short wObjectType, unsigned char cState, unsigned char cSubState,
|
||||
unsigned char cUpgradeStep, unsigned char cMaterial, unsigned char cSiegeCount,
|
||||
const CampRight& campRight, bool bFullHP);
|
||||
|
||||
unsigned long m_dwLastAttackedTick; // 마지막으로 공격 받은 시간
|
||||
|
||||
CampRight m_CampRight; // 길드 요새 관리 권한
|
||||
|
||||
unsigned long m_dwCmdSenderCID; // 길드 요새 명령 패킷을 요청한 캐릭터의 CID (업그레이드와 타입 변형에만 사용)
|
||||
|
||||
friend class CSiegeObjectMgr;
|
||||
};
|
||||
|
||||
#endif _CAMP_OBJECT_H_
|
||||
@@ -0,0 +1,366 @@
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
#include <Utility/Math/Math.h>
|
||||
|
||||
#include <Log/ItemLog.h>
|
||||
#include <Log/LogStruct.h>
|
||||
|
||||
#include <Network/Dispatch/DBAgent/DBAgentDispatch.h>
|
||||
#include <Network/Packet/PacketCommand.h>
|
||||
#include <Network/Packet/WrapPacket.h>
|
||||
|
||||
#include <Item/Item.h>
|
||||
#include <Item/ItemFactory.h>
|
||||
#include <Item/Container/ContainerConstant.h>
|
||||
|
||||
#include <Map/FieldMap/CellManager.h>
|
||||
|
||||
#include <Castle/Castle.h>
|
||||
#include <Castle/CastleConstants.h>
|
||||
#include <Castle/CastleMgr.h>
|
||||
#include <Castle/CastleBlessMgr.h>
|
||||
|
||||
#include <Community/Guild/Guild.h>
|
||||
#include <Community/Guild/GuildMgr.h>
|
||||
|
||||
#include "CampShop.h"
|
||||
|
||||
CCampShop::CCampShop(MonsterCreateInfo& MonsterCreate, unsigned long dwCampID, unsigned long dwGID,
|
||||
unsigned long dwHP, unsigned short wObjectType, unsigned char cState,
|
||||
unsigned char cSubState, unsigned char cUpgradeStep, unsigned char cMaterial,
|
||||
unsigned char cSiegeCount, const CampRight& campRight, bool bFullHP)
|
||||
: CCamp(MonsterCreate, dwCampID, dwGID, dwHP, wObjectType, cState, cSubState, cUpgradeStep, cMaterial, cSiegeCount, campRight, bFullHP),
|
||||
m_dwTempSafe(0), m_cTax(0)
|
||||
{
|
||||
m_Container.Initialize(m_dwCID, ContainerConstant::CAMPSHOP_WIDTH, ContainerConstant::CAMPSHOP_HEIGHT);
|
||||
}
|
||||
|
||||
CCampShop::~CCampShop(void)
|
||||
{
|
||||
}
|
||||
|
||||
void CCampShop::SetTax(unsigned char cTax)
|
||||
{
|
||||
m_cTax = cTax;
|
||||
|
||||
PktCampCmd pktCC;
|
||||
pktCC.m_dwCID = m_dwCID;
|
||||
pktCC.m_dwCampID = GetCampID();
|
||||
pktCC.m_cState = m_cState;
|
||||
pktCC.m_dwValue1 = m_cTax;
|
||||
pktCC.m_dwValue2 = 0;
|
||||
pktCC.m_cSubCmd = PktCampCmd::CAMP_SHOP_CHANGE_TAX;
|
||||
|
||||
char* szPacket = reinterpret_cast<char *>(&pktCC);
|
||||
if (true == PacketWrap::WrapCrypt(szPacket, sizeof(PktCampCmd), CmdCampCmd, 0, 0))
|
||||
{
|
||||
m_Container.SendAllCustomer(szPacket, sizeof(PktCampCmd), false, CmdCampCmd);
|
||||
}
|
||||
}
|
||||
|
||||
bool CCampShop::AddGold(unsigned long dwGold)
|
||||
{
|
||||
if (m_dwTempSafe <= ULONG_MAX - dwGold)
|
||||
{
|
||||
m_dwTempSafe += dwGold;
|
||||
m_Container.IncreaseUpdateCount();
|
||||
return true;
|
||||
}
|
||||
|
||||
ERRLOG2(g_Log, "CID:%10u 길드 요새 상점의 임시 금고에 돈 오버플로우가 발생했습니다. : %dGold", m_dwCID, dwGold);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CCampShop::DeductGold(unsigned long dwGold)
|
||||
{
|
||||
if (dwGold <= m_dwTempSafe)
|
||||
{
|
||||
m_dwTempSafe -= dwGold;
|
||||
m_Container.IncreaseUpdateCount();
|
||||
return true;
|
||||
}
|
||||
|
||||
ERRLOG2(g_Log, "CID:%10u 길드 요새 상점의 임시 금고에 돈 언더플로우가 발생했습니다. : %dGold", m_dwCID, dwGold);
|
||||
return false;
|
||||
}
|
||||
|
||||
void CCampShop::DBUpdate(bool bForce)
|
||||
{
|
||||
if (true == m_Container.CheckUpdateCount() || true == bForce)
|
||||
{
|
||||
const int MAX_BUFFER_SIZE = sizeof(PktCampShopInfo) + CampShopInfoDB::MAX_CONTAINER_SIZE;
|
||||
char szBuffer[MAX_BUFFER_SIZE] = { 0, };
|
||||
unsigned long dwBufferSize = CampShopInfoDB::MAX_CONTAINER_SIZE;
|
||||
unsigned short wTotalSize = sizeof(PktCampShopInfo);
|
||||
|
||||
PktCampShopInfo* lpPktCampShopInfo = reinterpret_cast<PktCampShopInfo* >(szBuffer);
|
||||
char* lpItemBuffer = reinterpret_cast<char* >(lpPktCampShopInfo + 1);
|
||||
|
||||
m_Container.SerializeOut(lpItemBuffer, dwBufferSize);
|
||||
wTotalSize += static_cast<unsigned short>(dwBufferSize);
|
||||
|
||||
unsigned long* lpItemPriceBuffer = reinterpret_cast<unsigned long*>(lpItemBuffer + dwBufferSize);
|
||||
unsigned char cItemNum = 0;
|
||||
|
||||
m_Container.StallPriceOut(lpItemPriceBuffer, cItemNum);
|
||||
wTotalSize += sizeof(unsigned long) * cItemNum;
|
||||
|
||||
lpPktCampShopInfo->m_dwCampID = m_dwOwnerID;
|
||||
lpPktCampShopInfo->m_CampShopInfo.m_dwTempSafe = m_dwTempSafe;
|
||||
lpPktCampShopInfo->m_CampShopInfo.m_cTax = m_cTax;
|
||||
lpPktCampShopInfo->m_CampShopInfo.m_dwBufferSize = dwBufferSize;
|
||||
lpPktCampShopInfo->m_CampShopInfo.m_cItemNum = cItemNum;
|
||||
|
||||
GET_SINGLE_DISPATCH(lpDBAgentDispatch, CDBAgentDispatch, CDBAgentDispatch::GetDispatchTable());
|
||||
if (NULL != lpDBAgentDispatch)
|
||||
{
|
||||
CSendStream& SendStream = lpDBAgentDispatch->GetSendStream();
|
||||
SendStream.WrapCompress(szBuffer, wTotalSize, CmdCampShopInfo, 0, PktBase::NO_SERVER_ERR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CCampShop::SerializeIn(unsigned long dwTempSafe, unsigned char cTax,
|
||||
char* lpItemBuffer, unsigned long dwBufferSize, unsigned char cItemNum)
|
||||
{
|
||||
m_dwTempSafe = dwTempSafe;
|
||||
m_cTax = cTax;
|
||||
|
||||
if (false == m_Container.SerializeIn(lpItemBuffer, dwBufferSize))
|
||||
{
|
||||
ERRLOG1(g_Log, "CID:0x%08x 길드 요새 상점의 아이템 목록을 SerializeIn 하는데 실패하였습니다.", m_dwCID);
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_Container.StallPriceIn(reinterpret_cast<unsigned long*>(lpItemBuffer + dwBufferSize), cItemNum);
|
||||
}
|
||||
|
||||
Item::CItem* CCampShop::SellToCharacter(CCharacter *lpCustomer, unsigned short wKindItem, TakeType takeType,
|
||||
Item::CItem* lpRequestItem, unsigned long &dwPrice, unsigned short wCouponID, unsigned short &usError)
|
||||
{
|
||||
Item::CItem* lpItem = m_Container.GetItem(takeType.m_srcPos);
|
||||
if (NULL == lpItem) { return NULL; }
|
||||
|
||||
unsigned long dwCustomerCID = lpCustomer->GetCID();
|
||||
unsigned long dwCurrentGold = lpCustomer->GetGold();
|
||||
unsigned long dwBuyPrice = lpItem->GetBuyPrice();
|
||||
unsigned short usPrototypeID = lpItem->GetPrototypeID();
|
||||
|
||||
dwPrice = dwBuyPrice * takeType.m_cNum;
|
||||
unsigned long dwTakeGold = dwPrice;
|
||||
|
||||
if (dwPrice > dwCurrentGold)
|
||||
{
|
||||
ERRLOG2(g_Log, "길드 요새 상점 오류 : 돈이 부족합니다. 가격:%d, 소지금:%d", dwPrice, dwCurrentGold);
|
||||
GAMELOG::LogTradeItem(*this, dwCustomerCID, dwPrice, lpItem, takeType.m_srcPos, PktTr::TRC_SELL, PktTr::FAIL_ITEM_BUY);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (false == lpCustomer->GetInventory().TestItem(takeType.m_dstPos, lpItem->GetPrototypeID(), takeType.m_cNum))
|
||||
{
|
||||
Item::CItemContainer* lpItemContainer = lpCustomer->GetItemContainer(takeType.m_dstPos.m_cPos);
|
||||
if (NULL != lpItemContainer)
|
||||
{
|
||||
lpItemContainer->DumpItemInfo();
|
||||
}
|
||||
else
|
||||
{
|
||||
ERRLOG1(g_Log, "CID:%10u 아이템 덤프를 출력할 수 없습니다.", dwCustomerCID);
|
||||
}
|
||||
|
||||
ERRLOG4(g_Log, "CID:%10u 아이템 종류:%d를 (%2d:%2d)에 아이템 넣기 실패.",
|
||||
dwCustomerCID, lpItem->GetPrototypeID(), takeType.m_dstPos.m_cPos, takeType.m_dstPos.m_cIndex);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool bStackable = lpItem->IsSet(Item::DetailData::STACKABLE);
|
||||
unsigned char cNumOrDurability = lpItem->GetNumOrDurability();
|
||||
Item::ItemPos ItemPos = lpItem->GetPos();
|
||||
|
||||
// 스택 가능한 아이템인 경우, 개수제한 확인
|
||||
if (!(bStackable && (cNumOrDurability < takeType.m_cNum)))
|
||||
{
|
||||
// 스택이 불가능하거나, 전부 파는 경우에는 아이템 제거
|
||||
if (!bStackable || (bStackable && (takeType.m_cNum == lpItem->GetNumOrDurability())))
|
||||
{
|
||||
if (false == m_Container.RemoveItem(takeType.m_srcPos))
|
||||
{
|
||||
ERRLOG3(g_Log, "CID:%10u 아이템을 (%2d, %4x)위치로부터 지우는 데 실패했습니다.",
|
||||
m_dwCID, takeType.m_srcPos.m_cPos, takeType.m_srcPos.m_cIndex);
|
||||
GAMELOG::LogTradeItem(*this, dwCustomerCID, dwPrice, lpItem, takeType.m_srcPos, PktTr::TRC_SELL, PktTr::FAIL_ITEM_BUY);
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Container.SendRemoveItem(takeType, PktStRI::SC_CAMP_SELL, "");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lpItem->SetNumOrDurability(cNumOrDurability - takeType.m_cNum);
|
||||
m_Container.SendRemoveItem(takeType, PktStRI::SC_CAMP_SELL, "");
|
||||
|
||||
lpItem = Item::CItemFactory::GetInstance().CreateItem(usPrototypeID);
|
||||
if (NULL == lpItem)
|
||||
{
|
||||
ERRLOG1(g_Log, "길드 요새 상점 오류 : 아이템 생성 실패. ProtoTypeID : %d", usPrototypeID);
|
||||
GAMELOG::LogTradeItem(*this, dwCustomerCID, dwPrice, lpItem, takeType.m_srcPos, PktTr::TRC_SELL, PktTr::FAIL_ITEM_BUY);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lpItem->SetNumOrDurability(takeType.m_cNum);
|
||||
}
|
||||
/*
|
||||
// CASTLE_TODO : 성이 길드 소유가 아니므로 성의 축복 보너스 기능은 막아둔다.
|
||||
// edith 세금 부분 추가 (주석처리 뺐음)
|
||||
// 길드 요새가 성의 축복 영역에 들어있다면, 축복 보너스와 세금 처리를 한다.
|
||||
Castle::CCastle* lpCastle = Castle::CCastleMgr::GetInstance().GetCastleInBlessArea( GetPosition() );
|
||||
if (NULL != lpCastle && 0 != lpCastle->GetGID())
|
||||
{
|
||||
Guild::CGuild* lpGuild = Guild::CGuildMgr::GetInstance().GetGuild( GetGID() );
|
||||
if (NULL != lpGuild && false == lpGuild->IsEnemyGuild(lpCastle->GetGID()))
|
||||
{
|
||||
unsigned char cBlessBonus = Castle::CCastleBlessMgr::GetInstance().GetBonusPercent(
|
||||
lpCastle->GetTotalGainTaxCount(), lpCastle->GetUpgradeStep());
|
||||
|
||||
// 성의 축복 보너스 만큼 더해준다.
|
||||
unsigned long dwBlessBonusTax = static_cast<unsigned long>(dwPrice * (cBlessBonus / 100.0f));
|
||||
dwTakeGold += dwBlessBonusTax;
|
||||
|
||||
// 성에 길드 요새 Gold 세금을 낸다.
|
||||
unsigned long dwCastleTax = static_cast<unsigned long>(dwPrice * (lpCastle->GetTax(Castle::CAMP_GOLD_TAX) / 100.0f));
|
||||
dwCastleTax = std::min(dwCastleTax, dwTakeGold);
|
||||
|
||||
if (dwCastleTax > 0)
|
||||
{
|
||||
lpCastle->AddTempTaxMoney(Castle::CAMP_GOLD_TAX, dwCastleTax);
|
||||
dwTakeGold -= dwCastleTax;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
AddGold(dwTakeGold);
|
||||
|
||||
DETLOG4(g_Log, "길드 요새 상점 : %d 타입 아이템 판매로 %u 만큼의 돈을 얻었습니다."
|
||||
" 아이템의 개별 가격은 %u이고 판매 개수는 %d 입니다",
|
||||
usPrototypeID, dwPrice, dwBuyPrice, takeType.m_cNum);
|
||||
}
|
||||
else
|
||||
{
|
||||
ERRLOG4(g_Log, "길드 요새 상점 오류 : (%2d, %4x)의 아이템 개수 : %d개 팔려는 아이템 개수 : %d개",
|
||||
takeType.m_srcPos.m_cPos, takeType.m_srcPos.m_cIndex, cNumOrDurability, takeType.m_cNum);
|
||||
GAMELOG::LogTradeItem(*this, dwCustomerCID, dwPrice, lpItem, takeType.m_srcPos, PktTr::TRC_SELL, PktTr::FAIL_ITEM_BUY);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GAMELOG::LogTradeItem(*this, dwCustomerCID, dwPrice, lpItem, takeType.m_srcPos, PktTr::TRC_SELL, PktTr::NO_SERVER_ERR);
|
||||
return lpItem;
|
||||
}
|
||||
|
||||
bool CCampShop::Destroy(unsigned long dwOffencerGID)
|
||||
{
|
||||
CCamp::Destroy(dwOffencerGID);
|
||||
|
||||
// 입장객을 퇴장시킨다.
|
||||
GetContainer().Close();
|
||||
|
||||
CCell* lpCell = CCellManager::GetInstance().GetCell(0,
|
||||
static_cast<unsigned long>(GetCurrentPos().m_fPointX),
|
||||
static_cast<unsigned long>(GetCurrentPos().m_fPointY),
|
||||
static_cast<unsigned long>(GetCurrentPos().m_fPointZ));
|
||||
|
||||
if (NULL == lpCell)
|
||||
{
|
||||
ERRLOG4(g_Log, "CampID:0x%08x 아이템을 드랍할 길드 요새 상점의 위치가 이상합니다. X:%.1f, Y:%.1f, Z:%.1f",
|
||||
GetCampID(), GetCurrentPos().m_fPointX, GetCurrentPos().m_fPointY, GetCurrentPos().m_fPointZ);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 임시 금고 드랍
|
||||
if (0 != m_dwTempSafe)
|
||||
{
|
||||
CCell::ItemInfo itemInfo;
|
||||
const Position Pos(GetCurrentPos().m_fPointX + Math::Random::ComplexRandom(40) - 20,
|
||||
GetCurrentPos().m_fPointY,
|
||||
GetCurrentPos().m_fPointZ + Math::Random::ComplexRandom(40) - 20);
|
||||
|
||||
lpCell->SetItem(Pos, NULL, m_dwTempSafe, dwOffencerGID,
|
||||
(0 == dwOffencerGID) ? CCell::NONE : CCell::GUILD, itemInfo);
|
||||
}
|
||||
|
||||
GetContainer().DropItem(lpCell, GetCurrentPos(), dwOffencerGID);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned long CCampShop::RepairItem(Item::CEquipment* lpEquipment, unsigned long& dwCurrentGold)
|
||||
{
|
||||
if (NULL != lpEquipment)
|
||||
{
|
||||
// 길드 요새 상정의 세율 적용 (수리)
|
||||
unsigned long dwTax = static_cast<unsigned long>(lpEquipment->GetRepairPrice() * (m_cTax / 100.0f));
|
||||
const unsigned long dwRepairGold = lpEquipment->GetRepairPrice() + dwTax;
|
||||
|
||||
if (dwRepairGold <= dwCurrentGold)
|
||||
{
|
||||
dwCurrentGold -= dwRepairGold;
|
||||
/*
|
||||
// CASTLE_TODO : 성이 길드 소유가 아니므로 성의 축복 보너스 기능은 막아둔다.
|
||||
// edith 세금 부분 추가 (주석처리 뺐음)
|
||||
// 길드 요새가 성의 축복 영역에 들어있다면, 축복 보너스와 세금 처리를 한다.
|
||||
Castle::CCastle* lpCastle = Castle::CCastleMgr::GetInstance().GetCastleInBlessArea( GetPosition() );
|
||||
if (NULL != lpCastle && 0 != lpCastle->GetGID())
|
||||
{
|
||||
Guild::CGuild* lpGuild = Guild::CGuildMgr::GetInstance().GetGuild( GetGID() );
|
||||
if (NULL != lpGuild && false == lpGuild->IsEnemyGuild(lpCastle->GetGID()))
|
||||
{
|
||||
unsigned char cBlessBonus = Castle::CCastleBlessMgr::GetInstance().GetBonusPercent(
|
||||
lpCastle->GetTotalGainTaxCount(), lpCastle->GetUpgradeStep());
|
||||
|
||||
// 성의 축복 보너스 만큼 더해준다.
|
||||
unsigned long dwBlessBonusTax = static_cast<unsigned long>(dwRepairGold * (cBlessBonus / 100.0f));
|
||||
dwTax += dwBlessBonusTax;
|
||||
|
||||
// 성에 길드 요새 Gold 세금을 낸다.
|
||||
unsigned long dwCastleTax = static_cast<unsigned long>(dwRepairGold * (lpCastle->GetTax(Castle::CAMP_GOLD_TAX) / 100.0f));
|
||||
dwCastleTax = std::min(dwCastleTax, dwTax);
|
||||
|
||||
if (dwCastleTax > 0)
|
||||
{
|
||||
lpCastle->AddTempTaxMoney(Castle::CAMP_GOLD_TAX, dwCastleTax);
|
||||
dwTax -= dwCastleTax;
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
*/
|
||||
m_dwTempSafe += dwTax;
|
||||
lpEquipment->SetNumOrDurability(lpEquipment->GetMaxNumOrDurability());
|
||||
return dwRepairGold;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool CCampShop::ItemDump(char* pBuffer, int* nBufferSize_InOut) const
|
||||
{
|
||||
using namespace GAMELOG;
|
||||
|
||||
sItemDump* lpItemDump = reinterpret_cast<sItemDump*>(pBuffer);
|
||||
char* lpItems = reinterpret_cast<char*>(&lpItemDump[1]);
|
||||
|
||||
std::fill_n(lpItemDump->m_usDataSize, int(sItemDump::MAX_DUMP), 0);
|
||||
|
||||
unsigned long dwSize = 0;
|
||||
unsigned short usTotalSize = sizeof(sItemDump);
|
||||
|
||||
dwSize = *nBufferSize_InOut;
|
||||
m_Container.SerializeOut(lpItems, dwSize);
|
||||
usTotalSize += static_cast<unsigned short>(dwSize);
|
||||
|
||||
*nBufferSize_InOut = usTotalSize;
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Creature/Siege/Camp.h>
|
||||
#include <Item/Container/StallContainer.h>
|
||||
|
||||
namespace Item
|
||||
{
|
||||
class CEquipment;
|
||||
}
|
||||
|
||||
class CCampShop : public CCamp
|
||||
{
|
||||
public:
|
||||
|
||||
virtual ~CCampShop(void);
|
||||
|
||||
Item::CCampShopContainer& GetContainer(void) { return m_Container; }
|
||||
unsigned long GetTempSafe(void) { return m_dwTempSafe; }
|
||||
unsigned char GetTax(void) { return m_cTax; }
|
||||
|
||||
void SetTax(unsigned char cTax);
|
||||
bool AddGold(unsigned long dwGold);
|
||||
bool DeductGold(unsigned long dwGold);
|
||||
|
||||
void DBUpdate(bool bForce);
|
||||
bool SerializeIn(unsigned long dwTempSafe, unsigned char cTax,
|
||||
char* lpItemBuffer, unsigned long dwBufferSize, unsigned char cItemNum);
|
||||
|
||||
Item::CItem* SellToCharacter(CCharacter *lpCustomer, unsigned short wKindItem, TakeType takeType,
|
||||
Item::CItem* lpRequestItem, unsigned long &dwPrice, unsigned short wCouponID, unsigned short &usError);
|
||||
|
||||
bool Destroy(unsigned long dwOffencerGID = 0);
|
||||
|
||||
virtual unsigned long RepairItem(Item::CEquipment* lpEquipment, unsigned long& dwCurrentGold);
|
||||
virtual bool ItemDump(char* pBuffer, int* nBufferSize_InOut) const;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
CCampShop(MonsterCreateInfo& MonsterCreate, unsigned long dwCampID, unsigned long dwGID,
|
||||
unsigned long dwHP, unsigned short wObjectType, unsigned char cState, unsigned char cSubState,
|
||||
unsigned char cUpgradeStep, unsigned char cMaterial, unsigned char cSiegeCount,
|
||||
const CampRight& campRight, bool bFullHP);
|
||||
|
||||
Item::CCampShopContainer m_Container; // 판매 물품용 컨테이너
|
||||
unsigned long m_dwTempSafe; // 임시 금고
|
||||
|
||||
unsigned char m_cTax; // 세율
|
||||
|
||||
friend class CSiegeObjectMgr;
|
||||
};
|
||||
@@ -0,0 +1,859 @@
|
||||
#include "stdafx.h"
|
||||
#include "CastleArms.h"
|
||||
|
||||
#include <Skill/SkillTable.h>
|
||||
#include <Skill/SkillMgr.h>
|
||||
|
||||
#include <Utility/Math/Math.h>
|
||||
|
||||
#include <Item/ItemFactory.h>
|
||||
|
||||
#include <Map/FieldMap/CellManager.h>
|
||||
#include <Map/DuelMap/DuelCellManager.h>
|
||||
|
||||
#include <Network/Packet/WrapPacket.h>
|
||||
#include <Network/Packet/PacketCommand.h>
|
||||
#include <Network/Packet/PacketStruct/ServerInfo.h>
|
||||
|
||||
#include <Network/Dispatch/GameClient/GameClientDispatch.h>
|
||||
#include <Network/Dispatch/GameClient/SendCharItem.h>
|
||||
#include <Network/Dispatch/GameClient/SendCharCastle.h>
|
||||
#include <Network/Dispatch/GameClient/SendCharAttack.h>
|
||||
#include <Network/Dispatch/DBAgent/DBAgentDispatch.h>
|
||||
#include <Network/Dispatch/DBAgent/DBAgentRequest.h>
|
||||
|
||||
#include <Network/ClientSocket/ClientConstants.h>
|
||||
|
||||
|
||||
CCastleArms::CCastleArms(MonsterCreateInfo& MonsterCreate, const CastleObjectInfo& CastleObject)
|
||||
: CSiegeObject(MonsterCreate, CastleObject)
|
||||
{
|
||||
}
|
||||
|
||||
CCastleArms::~CCastleArms()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool CCastleArms::AttackCID(CCharacter* lpRideChar, AtType attackType, AtNode& attackNode, unsigned short& wError)
|
||||
{
|
||||
PERFORMANCE_CHECK(FunctionTimingCheck);
|
||||
|
||||
if (Siege::CASTLE_ARMS_NPC == m_wObjectType)
|
||||
{
|
||||
wError = PktAtAck::SERVER_ERROR;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (NULL == lpRideChar || m_CreatureStatus.m_nNowHP == 0)
|
||||
{
|
||||
wError = PktAtAck::FAIL_ALREADY_DEAD;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (0 == (attackType.m_wType & AtType::SKILL_BIT))
|
||||
{
|
||||
wError = PktAtAck::FAIL_NOT_SIEGE_ATTACK;
|
||||
return false;
|
||||
}
|
||||
|
||||
const Skill::ProtoType* pThisSkill = CSkillMgr::GetInstance().GetSkillProtoType(attackType.m_wType);
|
||||
if (NULL == pThisSkill)
|
||||
{
|
||||
ERRLOG2(g_Log, "CID:0x%08x 존재하지 않는 스킬 아이디입니다. Skill ID:0x%04x", m_dwCID, attackType.m_wType);
|
||||
return false;
|
||||
}
|
||||
|
||||
const unsigned short wLockCount = GetSkillLockCount(attackType.m_wType);
|
||||
if (wLockCount < 0 || wLockCount >= CSkillMgr::MAX_SKILL_LOCKCOUNT)
|
||||
{
|
||||
ERRLOG3(g_Log, "CID:0x%08x 쓰려는 스킬의 락카운트가 이상합니다. SkillType : 0x%04x, LockCount : %d",
|
||||
m_dwCID, attackType.m_wType, wLockCount);
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned char cDefenderNum = attackNode.m_wDefenserNum > AtNode::MAX_DEFENDER_NUM ?
|
||||
AtNode::MAX_DEFENDER_NUM : attackNode.m_wDefenserNum; // 최대 방어자 수 제한
|
||||
|
||||
CAggresiveCreature* lpAggresiveCreature[AtNode::MAX_DEFENDER_NUM] = {0, };
|
||||
unsigned short wDefenserMPHeal[AtNode::MAX_DEFENDER_NUM] = {0, };
|
||||
char cTargetType = Skill::Target::ENEMY;
|
||||
|
||||
if (0 == cDefenderNum)
|
||||
{
|
||||
if (0 != attackType.m_cMissileAttack)
|
||||
{
|
||||
return MissileAttack(attackType, 0, pThisSkill[attackType.m_cSkillLockCount].m_fEffectExtent,
|
||||
Math::Const::PI * 2, cTargetType);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 캐스팅에 실패한 경우
|
||||
return Attack(attackType, cDefenderNum, lpAggresiveCreature, attackNode.m_cDefenserJudge, wDefenserMPHeal);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (0 == pThisSkill[wLockCount].m_fMaxRange && 0 == pThisSkill[attackType.m_cSkillLockCount].m_fEffectExtent)
|
||||
{
|
||||
if (m_dwCID != attackNode.m_dwDefenser[0])
|
||||
{
|
||||
ERRLOG2(g_Log, "CID:0x%08x 자기자신에게만 쓸 수 있는 스킬입니다. SkillID:0x%04x",
|
||||
m_dwCID, attackType.m_wType);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 공성병기는 몬스터를 공격할수 없다.
|
||||
Creature::CreatureType eCreatureType = Creature::GetCreatureType(attackNode.m_dwDefenser[0]);
|
||||
if (Creature::CT_MONSTER == eCreatureType || Creature::CT_STRUCT == eCreatureType)
|
||||
{
|
||||
wError = PktAtAck::FAIL_TO_MONSTER;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 스킬 거리 체크
|
||||
CAggresiveCreature* lpTargetCreature = NULL;
|
||||
|
||||
// Target Creature 얻어오기
|
||||
if (0 != GetMapIndex())
|
||||
{
|
||||
lpTargetCreature = CCreatureManager::GetInstance().GetAggresiveCreature(attackNode.m_dwDefenser[0]);
|
||||
if (lpTargetCreature && lpTargetCreature->GetMapIndex() != GetMapIndex()) lpTargetCreature = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
lpTargetCreature = CCreatureManager::GetInstance().GetAggresiveCreature(attackNode.m_dwDefenser[0]);
|
||||
}
|
||||
|
||||
// Target Creature 처리하기
|
||||
if (NULL != lpTargetCreature)
|
||||
{
|
||||
float fSquareTargetDistance = (m_CurrentPos.m_fPointX - lpTargetCreature->GetCurrentPos().m_fPointX) *
|
||||
(m_CurrentPos.m_fPointX - lpTargetCreature->GetCurrentPos().m_fPointX) +
|
||||
(m_CurrentPos.m_fPointZ - lpTargetCreature->GetCurrentPos().m_fPointZ) *
|
||||
(m_CurrentPos.m_fPointZ - lpTargetCreature->GetCurrentPos().m_fPointZ);
|
||||
|
||||
float fSquareEffectDistance = (pThisSkill[wLockCount].m_fMaxRange + Skill::ERROR_OF_DISTANCE) *
|
||||
(pThisSkill[wLockCount].m_fMaxRange + Skill::ERROR_OF_DISTANCE);
|
||||
|
||||
if (fSquareTargetDistance > fSquareEffectDistance)
|
||||
{
|
||||
wError = PktAtAck::FAIL_TOO_FAR;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (pThisSkill[attackType.m_cSkillLockCount].m_eTargetType == Skill::Target::FRIEND ||
|
||||
pThisSkill[attackType.m_cSkillLockCount].m_eTargetType == Skill::Target::DEAD_FRIEND ||
|
||||
pThisSkill[attackType.m_cSkillLockCount].m_eTargetType == Skill::Target::FRIEND_EXCEPT_SELF ||
|
||||
pThisSkill[attackType.m_cSkillLockCount].m_eTargetType == Skill::Target::FRIEND_OBJECT ||
|
||||
pThisSkill[attackType.m_cSkillLockCount].m_eTargetType == Skill::Target::PARTY ||
|
||||
pThisSkill[attackType.m_cSkillLockCount].m_eTargetType == Skill::Target::SUMMON)
|
||||
{
|
||||
//cTargetType = Skill::Target::FRIEND;
|
||||
wError = PktAtAck::FAIL_FRIENDLY_ATTACK;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 클라이언트가 넘겨준 타겟들을 체크한다. (범위 마법에 걸리는 타겟은 따로 체크)
|
||||
for (unsigned char cDefender = 0; cDefender < cDefenderNum; ++cDefender)
|
||||
{
|
||||
// Target Creature 얻기
|
||||
CAggresiveCreature* lpCreature = NULL;
|
||||
|
||||
Creature::CreatureType eCreatureType = Creature::GetCreatureType(attackNode.m_dwDefenser[cDefender]);
|
||||
if (Creature::CT_MONSTER == eCreatureType || Creature::CT_STRUCT == eCreatureType)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
lpCreature = CCreatureManager::GetInstance().GetAggresiveCreature(attackNode.m_dwDefenser[cDefender]);
|
||||
if (lpCreature && lpCreature->GetMapIndex() != GetMapIndex())
|
||||
{
|
||||
lpCreature = NULL;
|
||||
}
|
||||
|
||||
if (NULL != lpCreature)
|
||||
{
|
||||
// 긍정적인 공격(-_-)
|
||||
if (Skill::Target::FRIEND == cTargetType)
|
||||
{
|
||||
wError = PktAtAck::FAIL_FRIENDLY_ATTACK;
|
||||
return false;
|
||||
}
|
||||
// 부정적인 공격(진짜 공격)
|
||||
else
|
||||
{
|
||||
// 자기를 중심으로 하는 범위형 스킬의 경우 타겟을 자신으로 세팅합니다.
|
||||
// (이 경우 this는 MultiAttack() 함수가 타켓에서 제외시켜 줍니다.)
|
||||
if (EnemyCheck::EC_ENEMY == IsEnemy(lpCreature) || lpCreature == this)
|
||||
{
|
||||
lpAggresiveCreature[cDefender] = lpCreature;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (0 == cDefenderNum || NULL == lpAggresiveCreature[0])
|
||||
{
|
||||
return Attack(attackType, cDefenderNum, lpAggresiveCreature, attackNode.m_cDefenserJudge, wDefenserMPHeal);
|
||||
}
|
||||
|
||||
// 범위 마법 체크
|
||||
if (0 != pThisSkill[attackType.m_cSkillLockCount].m_fEffectExtent)
|
||||
{
|
||||
if (Skill::Target::PARTY == pThisSkill[attackType.m_cSkillLockCount].m_eTargetType)
|
||||
{
|
||||
wError = PktAtAck::FAIL_FRIENDLY_ATTACK;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CAggresiveCreature::MultiAttack(attackType, cDefenderNum, lpAggresiveCreature, attackNode.m_cDefenserJudge,
|
||||
lpAggresiveCreature[0]->GetCurrentPos(), 0, pThisSkill[attackType.m_cSkillLockCount].m_fEffectExtent,
|
||||
Math::Const::PI * 2, cTargetType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Attack(attackType, cDefenderNum, lpAggresiveCreature, attackNode.m_cDefenserJudge, wDefenserMPHeal);
|
||||
}
|
||||
|
||||
bool CCastleArms::Attack(AtType attackType, unsigned char cDefenderNum, CAggresiveCreature** ppDefenders, unsigned char* cDefenserJudges, unsigned short* wDefenserMPHeal)
|
||||
{
|
||||
if (Siege::CASTLE_ARMS_NPC == m_wObjectType)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_CreatureStatus.m_nNowHP == 0)
|
||||
{
|
||||
ERRLOG1(g_Log, "CID:0x%08x 죽은 공성 오브젝트가 공격하려고 하였습니다.", m_dwCID);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cDefenderNum > AtNode::MAX_DEFENDER_NUM)
|
||||
{
|
||||
ERRLOG2(g_Log, "CID:0x%08x 공성 오브젝트가 공격할 때, 방어자의 숫자가 최대 방어자 숫자를 넘었습니다. 방어자수 : %d",
|
||||
m_dwCID, cDefenderNum);
|
||||
cDefenderNum = AtNode::MAX_DEFENDER_NUM;
|
||||
}
|
||||
|
||||
if (0 == (attackType.m_wType & AtType::SKILL_BIT) && 0 == cDefenderNum)
|
||||
{
|
||||
ERRLOG0(g_Log, "스킬이 아닌 일반 공격은, 반드시 타겟이 있을 경우에만 서버로 보내야 합니다.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (0 != (attackType.m_wType & AtType::SKILL_BIT))
|
||||
{
|
||||
const Skill::ProtoType* pSkillProtoType = CSkillMgr::GetInstance().GetSkillProtoType(attackType.m_wType);
|
||||
if (NULL == pSkillProtoType)
|
||||
{
|
||||
ERRLOG2(g_Log, "CID:0x%08x 존재하지 않는 스킬 아이디입니다. Skill ID:0x%04x", m_dwCID, attackType.m_wType);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ( IsRidable() )
|
||||
{
|
||||
CCharacter* lpRider = CCreatureManager::GetInstance().GetCharacter(m_dwRiderCID);
|
||||
if (!lpRider)
|
||||
{
|
||||
ERRLOG2(g_Log, "CID:0x%08x 공성 오브젝트에 타고있는 캐릭터가 없습니다. RiderCID : 0x%08x", m_dwCID, m_dwRiderCID);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 공격시 무적 상태가 풀린다.
|
||||
lpRider->GetSpellMgr().GetAffectedInfo().RemoveEnchantBySpellType(Skill::SpellID::Invincible);
|
||||
}
|
||||
|
||||
unsigned char cOffencerJudge = 0;
|
||||
unsigned short wOffencerMPHeal = 0;
|
||||
unsigned short wError = PktAtAck::NO_SERVER_ERR;
|
||||
|
||||
const int MAX_BUFFER = sizeof(PktAtAck) + AtNode::MAX_DEFENDER_NUM * sizeof(DefenserNode);
|
||||
char szBuffer[MAX_BUFFER];
|
||||
|
||||
PktAtAck* lpPktAtAck = reinterpret_cast<PktAtAck*>(szBuffer);
|
||||
DefenserNode* lpDefenserNode = reinterpret_cast<DefenserNode*>(lpPktAtAck + 1);
|
||||
|
||||
m_cConsumeMPCount = std::min(cDefenderNum, unsigned char(AtNode::MAX_MONSTER_DEFENDER_NUM));
|
||||
|
||||
unsigned char cDefender = 0;
|
||||
unsigned char cIndex = 0;
|
||||
|
||||
for (; cIndex < cDefenderNum; ++cIndex)
|
||||
{
|
||||
// MP 소모 타이밍까지의 카운트 (범위 마법은 한 번만 MP 소모)
|
||||
--m_cConsumeMPCount;
|
||||
|
||||
if (NULL == ppDefenders[cIndex])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (0 == ppDefenders[cIndex]->GetStatus().m_nNowHP)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// 최대 방어자 수 제한 (몬스터는 캐릭터와는 별도 처리)
|
||||
Creature::CreatureType eCreatureType = Creature::GetCreatureType(ppDefenders[cIndex]->GetCID());
|
||||
if (Creature::CT_MONSTER == eCreatureType || Creature::CT_STRUCT == eCreatureType)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO : 공격 방향을 설정해줍시다.
|
||||
cDefenserJudges[cDefender] = ClientConstants::Judge_Front;
|
||||
wDefenserMPHeal[cDefender] = 0;
|
||||
|
||||
const unsigned short nPrevHP = ppDefenders[cIndex]->GetStatus().m_nNowHP;
|
||||
const unsigned short nPrevMP = ppDefenders[cIndex]->GetStatus().m_nNowMP;
|
||||
|
||||
const unsigned short wPrevAttackerHP = m_CreatureStatus.m_nNowHP;
|
||||
|
||||
// 대미지 반영
|
||||
lpDefenserNode[cDefender].m_wDamage = ppDefenders[cIndex]->ApplyDamage(attackType, this, cOffencerJudge,
|
||||
cDefenserJudges[cDefender], wOffencerMPHeal, wDefenserMPHeal[cDefender], wError);
|
||||
|
||||
const unsigned short nNowHP = ppDefenders[cIndex]->GetStatus().m_nNowHP;
|
||||
const unsigned short nNowMP = ppDefenders[cIndex]->GetStatus().m_nNowMP;
|
||||
|
||||
// 스킬에 의한 자살 방지
|
||||
if (0 == m_CreatureStatus.m_nNowHP)
|
||||
{
|
||||
m_CreatureStatus.m_nNowHP = wPrevAttackerHP;
|
||||
wError = PktAtAck::FAIL_SUICIDE;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Creature::CT_PC == Creature::GetCreatureType(ppDefenders[cIndex]->GetCID()))
|
||||
{
|
||||
CCharacter* lpDefendCharacter = (CCharacter *)ppDefenders[cIndex];
|
||||
|
||||
CMonster* lpSummonee = lpDefendCharacter->GetSummonee();
|
||||
if (NULL != lpSummonee)
|
||||
{
|
||||
lpSummonee->GuardMe(this, lpDefenserNode[cDefender].m_wDamage);
|
||||
}
|
||||
|
||||
lpDefendCharacter->CalculateEquipDurability((ClientConstants::Judge_Guard == cDefenserJudges[cDefender]) ?
|
||||
AtType::GUARD : AtType::DEFENCE);
|
||||
|
||||
CGameClientDispatch* lpDispatch = lpDefendCharacter->GetDispatcher();
|
||||
if (NULL != lpDispatch)
|
||||
{
|
||||
GameClientSendPacket::SendCharAttacked(lpDispatch->GetSendStream(), this, lpDefendCharacter,
|
||||
attackType, m_MotionInfo.m_fDirection, lpDefenserNode[cDefender].m_wDamage,
|
||||
cDefenserJudges[cDefender], wDefenserMPHeal[cDefender], PktBase::NO_SERVER_ERR);
|
||||
}
|
||||
}
|
||||
|
||||
// 공격 패킷 만들기
|
||||
lpDefenserNode[cDefender].m_dwCharID = ppDefenders[cIndex]->GetCID();
|
||||
lpDefenserNode[cDefender].m_sCurrHP = nNowHP;
|
||||
lpDefenserNode[cDefender].m_sCurrMP = nNowMP;
|
||||
lpDefenserNode[cDefender].m_wMaxHP = ppDefenders[cIndex]->GetStatus().m_StatusInfo.m_nMaxHP;
|
||||
lpDefenserNode[cDefender].m_wMaxMP = ppDefenders[cIndex]->GetStatus().m_StatusInfo.m_nMaxMP;
|
||||
lpDefenserNode[cDefender].m_wMPHeal = wDefenserMPHeal[cDefender];
|
||||
|
||||
lpDefenserNode[cDefender].m_cJudge = cDefenserJudges[cDefender];
|
||||
}
|
||||
|
||||
++cDefender;
|
||||
}
|
||||
|
||||
if (0 != (attackType.m_wType & AtType::SKILL_BIT))
|
||||
{
|
||||
if (0 == cDefender)
|
||||
{
|
||||
Skill::CFunctions::ConsumeMP(attackType, this, 0);
|
||||
}
|
||||
}
|
||||
|
||||
lpPktAtAck->m_dwCharID = m_dwCID;
|
||||
lpPktAtAck->m_AtType = attackType;
|
||||
|
||||
lpPktAtAck->m_wHP = m_CreatureStatus.m_nNowHP;
|
||||
lpPktAtAck->m_wMP = m_CreatureStatus.m_nNowMP;
|
||||
lpPktAtAck->m_wMPHeal = wOffencerMPHeal;
|
||||
|
||||
lpPktAtAck->m_cJudge = cOffencerJudge;
|
||||
lpPktAtAck->m_cDefenserNum = cDefender;
|
||||
|
||||
if ( IsRidable() )
|
||||
{
|
||||
CCharacter* lpRider = CCreatureManager::GetInstance().GetCharacter(m_dwRiderCID);
|
||||
if (lpRider && lpRider->GetDispatcher())
|
||||
{
|
||||
CSendStream& SendStream = (lpRider->GetDispatcher())->GetSendStream();
|
||||
if (true == SendStream.WrapCompress(
|
||||
szBuffer, sizeof(PktAtAck) + cDefender * sizeof(DefenserNode), CmdCharAttack, 0, wError) &&
|
||||
PktBase::NO_SERVER_ERR == wError)
|
||||
{
|
||||
CCell* lpCell = GetCellPos().m_lpCell;
|
||||
if (lpCell)
|
||||
{
|
||||
lpCell->SendAttackInfo(m_dwCID, attackType, cDefender, lpDefenserNode);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CCell* lpCell = GetCellPos().m_lpCell;
|
||||
if (lpCell)
|
||||
{
|
||||
lpCell->SendAttackInfo(m_dwCID, attackType, cDefender, lpDefenserNode);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool CCastleArms::MissileAttack(AtType attackType, float fDir, float nRange, float fAngle, char cTargetType)
|
||||
{
|
||||
if (Siege::LONG_RANGE_CASTLE_ARMS != m_wObjectType)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CCell* lpCell = NULL;
|
||||
|
||||
// 듀얼 상태라면 듀얼 셀로 처리
|
||||
if(CServerSetup::GetInstance().GetDuelModeCheck() && NULL != GetDuelOpponent())
|
||||
{
|
||||
lpCell = CDuelCellManager::GetInstance().GetCell(GetCID());
|
||||
}
|
||||
else
|
||||
{
|
||||
lpCell = CCellManager::GetInstance().GetCell(m_CellPos.m_wMapIndex,
|
||||
static_cast<unsigned long>(attackType.m_DstPos.fPointX),
|
||||
static_cast<unsigned long>(attackType.m_DstPos.fPointY),
|
||||
static_cast<unsigned long>(attackType.m_DstPos.fPointZ));
|
||||
}
|
||||
|
||||
if (NULL == lpCell)
|
||||
{
|
||||
ERRLOG0(g_Log, "CID:0x%08x 공격 목표 지점의 셀이 존재하지 않습니다.");
|
||||
return false;
|
||||
}
|
||||
|
||||
CAggresiveCreature* ppDefenders[AtNode::MAX_DEFENDER_NUM] = {0, };
|
||||
unsigned char cDefenserJudges[AtNode::MAX_DEFENDER_NUM] = {0, };
|
||||
unsigned short wDefenserMPHeal[AtNode::MAX_DEFENDER_NUM] = {0, };
|
||||
int nDefenderNum = 0;
|
||||
|
||||
for (int nDirection = 0; nDirection < CCell::CONNECT_NUM && nDefenderNum < AtNode::MAX_DEFENDER_NUM; ++nDirection)
|
||||
{
|
||||
CCell* lpConnectCell = lpCell->GetConnectCell(nDirection);
|
||||
if (NULL == lpConnectCell)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
CAggresiveCreature* lpTempTarget = lpConnectCell->GetFirstAggresiveCreature();
|
||||
|
||||
// 타겟이 없거나, 방어자 수가 최대가 되면, 루프를 빠져나갑니다.
|
||||
while (NULL != lpTempTarget && nDefenderNum < AtNode::MAX_DEFENDER_NUM)
|
||||
{
|
||||
// 공격에 대한 예외상황
|
||||
bool bException = false;
|
||||
|
||||
// 병기에 탑승한 캐릭터는 공격하지 않는다. 대신 병기를 공격한다.
|
||||
if (Creature::CT_PC == Creature::GetCreatureType(lpTempTarget->GetCID()))
|
||||
{
|
||||
CCharacter* lpRideChar = reinterpret_cast<CCharacter*>(lpTempTarget);
|
||||
if (true == lpRideChar->IsRideArms())
|
||||
{
|
||||
bException = true;
|
||||
}
|
||||
}
|
||||
|
||||
EnemyCheck::EnemyType eTargetType = IsEnemy(lpTempTarget);
|
||||
if ((EnemyCheck::EC_NEUTRAL == eTargetType) ||
|
||||
(Skill::Target::FRIEND == cTargetType && EnemyCheck::EC_ENEMY == eTargetType) ||
|
||||
(Skill::Target::ENEMY == cTargetType && EnemyCheck::EC_FRIEND == eTargetType))
|
||||
{
|
||||
bException = true;
|
||||
}
|
||||
|
||||
// 겹치는 게 있으면 처리하지 않는다.
|
||||
for (int nIndex = 0; nIndex < nDefenderNum; nIndex++)
|
||||
{
|
||||
if (ppDefenders[nIndex] == lpTempTarget)
|
||||
{
|
||||
bException = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (false == bException)
|
||||
{
|
||||
const float fDX = lpTempTarget->GetCurrentPos().m_fPointX - attackType.m_DstPos.fPointX;
|
||||
const float fDZ = lpTempTarget->GetCurrentPos().m_fPointZ - attackType.m_DstPos.fPointZ;
|
||||
const float fDistance = (fDX * fDX) + (fDZ * fDZ);
|
||||
|
||||
const float fSquareAttackRange = nRange * nRange;
|
||||
|
||||
if (fDistance <= fSquareAttackRange)
|
||||
{
|
||||
const float fTempfDir = CalcDir2D(attackType.m_DstPos.fPointX, attackType.m_DstPos.fPointZ,
|
||||
lpTempTarget->GetCurrentPos().m_fPointX, lpTempTarget->GetCurrentPos().m_fPointZ);
|
||||
const float fDifference = (fTempfDir >= fDir) ? (fTempfDir-fDir) : (fDir-fTempfDir);
|
||||
|
||||
if (fDifference <= fAngle && 0 < lpTempTarget->GetStatus().m_nNowHP)
|
||||
{
|
||||
ppDefenders[nDefenderNum] = lpTempTarget;
|
||||
cDefenserJudges[nDefenderNum] = ClientConstants::Judge_Front;
|
||||
wDefenserMPHeal[nDefenderNum] = 0;
|
||||
++nDefenderNum;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lpTempTarget = lpConnectCell->GetNextAggresiveCreature();
|
||||
}
|
||||
}
|
||||
|
||||
if (AtNode::MAX_DEFENDER_NUM < nDefenderNum)
|
||||
{
|
||||
SERLOG0(g_Log, "스택 오버런 : 방어자수가 최대치를 넘어셨습니다.");
|
||||
}
|
||||
|
||||
return Attack(attackType, nDefenderNum, ppDefenders, cDefenserJudges, wDefenserMPHeal);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool CCastleArms::Dead(CAggresiveCreature* pOffencer)
|
||||
{
|
||||
if (Siege::CASTLE_ARMS_NPC == m_wObjectType)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (NULL == pOffencer) return false;
|
||||
if (STATE_ID_DIE == m_nCurrentState) return false;
|
||||
|
||||
//m_wObjectType = Siege::CASTLE_ARMS_NPC;
|
||||
m_CreatureStatus.m_nNowHP = 0;
|
||||
m_dwLastBehaviorTick = m_dwLastTime = CPulse::GetInstance().GetLastTick();
|
||||
m_lCurrentFrame = FPS;
|
||||
m_bAttacking = false;
|
||||
m_bCasting = false;
|
||||
|
||||
// 타고 있던 캐릭터는 죽는다.
|
||||
if (0 != m_dwRiderCID)
|
||||
{
|
||||
CCharacter* lpRider = CCreatureManager::GetInstance().GetCharacter(m_dwRiderCID);
|
||||
if (lpRider)
|
||||
{
|
||||
//lpRider->GetOff();
|
||||
lpRider->Kill(pOffencer);
|
||||
}
|
||||
|
||||
//m_dwRiderCID = 0;
|
||||
m_dwOwnerID = 0;
|
||||
}
|
||||
|
||||
// 중계 서버로 패킷 전송
|
||||
GET_SINGLE_DISPATCH(lpDBAgentDispatch, CDBAgentDispatch, CDBAgentDispatch::GetDispatchTable());
|
||||
if (lpDBAgentDispatch)
|
||||
{
|
||||
return GameClientSendPacket::SendCharCastleCmdToDBAgent(lpDBAgentDispatch->GetSendStream(), pOffencer->GetCID(),
|
||||
GetCastleID(), m_dwCID, PktCastleCmd::DESTROY, 0,
|
||||
PktCastleCmd::CASTLE_DESTROY_ARMS, PktBase::NO_SERVER_ERR);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool CCastleArms::Upgrade(unsigned char cUpgradeStep)
|
||||
{
|
||||
m_cState = Siege::COMPLETE;
|
||||
m_cUpgradeStep = cUpgradeStep;
|
||||
|
||||
UpdateObjectInfo(Siege::UPGRADE_HP);
|
||||
|
||||
// 수성 병기가 있는 반경 5셀 이내에 전송
|
||||
PktCastleCmd pktCC;
|
||||
pktCC.m_dwCastleID = GetCastleID();
|
||||
pktCC.m_dwCastleObjectID = m_dwCID;
|
||||
pktCC.m_cState = m_cState;
|
||||
pktCC.m_dwValue1 = m_cUpgradeStep; // 업그레이드 단계
|
||||
pktCC.m_dwValue2 = 0;
|
||||
pktCC.m_cSubCmd = PktCastleCmd::CASTLE_UPGRADE_ARMS_COMPLETE;
|
||||
|
||||
char* szPacket = reinterpret_cast<char *>(&pktCC);
|
||||
if (PacketWrap::WrapCrypt(szPacket, sizeof(PktCastleCmd), CmdCastleCmd, 0, 0))
|
||||
{
|
||||
// Vincent - 브로드 캐스트 테스트 코드
|
||||
//SendToRadiusCell(szPacket, sizeof(PktCastleCmd), CmdCastleCmd);
|
||||
SendToRange(Siege::BROADCAST_RADIUS, szPacket, sizeof(PktCastleCmd), CmdCastleCmd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CCastleArms::Repair(unsigned short wRepairHP)
|
||||
{
|
||||
m_cState = Siege::COMPLETE;
|
||||
UpdateObjectInfo(Siege::REPAIR_HP, wRepairHP);
|
||||
|
||||
// 수성 병기가 있는 반경 5셀 이내에 전송
|
||||
PktCastleCmd pktCC;
|
||||
pktCC.m_dwCastleID = GetCastleID();
|
||||
pktCC.m_dwCastleObjectID = m_dwCID;
|
||||
pktCC.m_cState = m_cState;
|
||||
pktCC.m_dwValue1 = wRepairHP;
|
||||
pktCC.m_dwValue2 = m_CreatureStatus.m_nNowHP; // 현재 HP
|
||||
pktCC.m_cSubCmd = PktCastleCmd::CASTLE_REPAIR_ARMS_COMPLETE;
|
||||
|
||||
char* szPacket = reinterpret_cast<char *>(&pktCC);
|
||||
if (PacketWrap::WrapCrypt(szPacket, sizeof(PktCastleCmd), CmdCastleCmd, 0, 0))
|
||||
{
|
||||
// Vincent - 브로드 캐스트 테스트 코드
|
||||
//SendToRadiusCell(szPacket, sizeof(PktCastleCmd), CmdCastleCmd);
|
||||
SendToRange(Siege::BROADCAST_RADIUS, szPacket, sizeof(PktCastleCmd), CmdCastleCmd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CCastleArms::Destroy(unsigned char cOffencerNation, bool bTakeGold)
|
||||
{
|
||||
if (!IsCastleArms() || Siege::CASTLE_ARMS_NPC == m_wObjectType)
|
||||
{
|
||||
m_dwOwnerID = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 생산 비용의 절반을 돌려준다.
|
||||
if (true == bTakeGold)
|
||||
{
|
||||
CCharacter* lpOwner = CCreatureManager::GetInstance().GetCharacter(m_dwOwnerID);
|
||||
if (0 != lpOwner)
|
||||
{
|
||||
lpOwner->AddGold(m_MonsterInfo.m_dwDevelopGold / 2, true);
|
||||
}
|
||||
}
|
||||
|
||||
m_wObjectType = Siege::CASTLE_ARMS_NPC;
|
||||
m_cState = Siege::COMPLETE;
|
||||
m_cUpgradeStep = 0;
|
||||
m_dwOwnerID = 0;
|
||||
|
||||
UpdateObjectInfo();
|
||||
|
||||
m_CreatureStatus.m_nNowHP = 0;
|
||||
|
||||
// 수성 병기가 있는 반경 5셀 이내에 전송
|
||||
PktCastleCmd pktCC;
|
||||
pktCC.m_dwCID = 0;
|
||||
pktCC.m_dwCastleID = GetCastleID();
|
||||
pktCC.m_dwCastleObjectID = m_dwCID;
|
||||
pktCC.m_cState = m_cState;
|
||||
pktCC.m_dwValue1 = m_wObjectType; // 병기 관리 NPC Type ID
|
||||
pktCC.m_dwValue2 = 0;
|
||||
pktCC.m_cSubCmd = PktCastleCmd::CASTLE_DESTROY_ARMS;
|
||||
|
||||
char* szPacket = reinterpret_cast<char *>(&pktCC);
|
||||
if (PacketWrap::WrapCrypt(szPacket, sizeof(PktCastleCmd), CmdCastleCmd, 0, 0))
|
||||
{
|
||||
// Vincent - 브로드 캐스트 테스트 코드
|
||||
//SendToRadiusCell(szPacket, sizeof(PktCastleCmd), CmdCastleCmd);
|
||||
SendToRange(Siege::BROADCAST_RADIUS, szPacket, sizeof(PktCastleCmd), CmdCastleCmd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CCastleArms::Update(unsigned char cState, unsigned long dwValue1, unsigned long dwValue2, unsigned long dwOnwerID, unsigned char cSubCmd)
|
||||
{
|
||||
if (!IsCastleArms())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_cState = cState;
|
||||
|
||||
if (cSubCmd == PktCastleCmd::CASTLE_CREATE_ARMS)
|
||||
{
|
||||
dwValue2 = (dwValue2 & 0x0000FFFF);
|
||||
m_wObjectType = static_cast<unsigned short>(dwValue2);
|
||||
m_dwOwnerID = dwOnwerID;
|
||||
|
||||
// 개인 금고에서 dwValue1 만큼의 돈을 깍는다.
|
||||
CCharacter* lpOwner = CCreatureManager::GetInstance().GetCharacter(m_dwOwnerID);
|
||||
if (0 != lpOwner)
|
||||
{
|
||||
lpOwner->DeductGold(dwValue1, true);
|
||||
}
|
||||
|
||||
UpdateObjectInfo(Siege::FULL_HP);
|
||||
}
|
||||
else if (cSubCmd == PktCastleCmd::CASTLE_REPAIR_ARMS)
|
||||
{
|
||||
// 개인 금고에서 dwValue1 만큼의 돈을 깍는다.
|
||||
CCharacter* lpOwner = CCreatureManager::GetInstance().GetCharacter(m_dwOwnerID);
|
||||
if (0 != lpOwner)
|
||||
{
|
||||
lpOwner->DeductGold(dwValue1, true);
|
||||
}
|
||||
|
||||
UpdateObjectInfo();
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateObjectInfo();
|
||||
}
|
||||
|
||||
// 수성 병기가 있는 반경 5셀 이내에 전송
|
||||
PktCastleCmd pktCC;
|
||||
pktCC.m_dwCID = m_dwOwnerID;
|
||||
pktCC.m_dwCastleID = GetCastleID();
|
||||
pktCC.m_dwCastleObjectID = m_dwCID;
|
||||
pktCC.m_cState = m_cState;
|
||||
pktCC.m_dwValue1 = dwValue1;
|
||||
pktCC.m_dwValue2 = dwValue2;
|
||||
pktCC.m_cSubCmd = cSubCmd;
|
||||
|
||||
char* szPacket = reinterpret_cast<char *>(&pktCC);
|
||||
if (PacketWrap::WrapCrypt(szPacket, sizeof(PktCastleCmd), CmdCastleCmd, 0, 0))
|
||||
{
|
||||
// Vincent - 브로드 캐스트 테스트 코드
|
||||
//SendToRadiusCell(szPacket, sizeof(PktCastleCmd), CmdCastleCmd);
|
||||
SendToRange(Siege::BROADCAST_RADIUS, szPacket, sizeof(PktCastleCmd), CmdCastleCmd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CCastleArms::ChangeType(unsigned short wType)
|
||||
{
|
||||
m_wObjectType = wType;
|
||||
m_cState = Siege::COMPLETE;
|
||||
m_cUpgradeStep = 0;
|
||||
|
||||
UpdateObjectInfo();
|
||||
|
||||
// 수성 병기가 있는 반경 5셀 이내에 전송
|
||||
PktCastleCmd pktCC;
|
||||
pktCC.m_dwCastleID = GetCastleID();
|
||||
pktCC.m_dwCastleObjectID = m_dwCID;
|
||||
pktCC.m_cState = m_cState;
|
||||
pktCC.m_dwValue1 = wType; // 병기 타입
|
||||
pktCC.m_dwValue2 = 0;
|
||||
pktCC.m_cSubCmd = PktCastleCmd::CASTLE_CREATE_ARMS_COMPLETE;
|
||||
|
||||
char* szPacket = reinterpret_cast<char *>(&pktCC);
|
||||
if (PacketWrap::WrapCrypt(szPacket, sizeof(PktCastleCmd), CmdCastleCmd, 0, 0))
|
||||
{
|
||||
// Vincent - 브로드 캐스트 테스트 코드
|
||||
//SendToRadiusCell(szPacket, sizeof(PktCastleCmd), CmdCastleCmd);
|
||||
SendToRange(Siege::BROADCAST_RADIUS, szPacket, sizeof(PktCastleCmd), CmdCastleCmd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CCastleArms::Ride(unsigned long dwCID)
|
||||
{
|
||||
if (0 == m_dwRiderCID)
|
||||
{
|
||||
CCharacter* lpRider = CCreatureManager::GetInstance().GetCharacter(dwCID);
|
||||
if (lpRider && dwCID == m_dwOwnerID)
|
||||
{
|
||||
m_dwRiderCID = dwCID;
|
||||
lpRider->Ride(m_dwCID);
|
||||
lpRider->SkillClear();
|
||||
|
||||
// 중계 서버에 보내줘야 사용하고 있음을 체크할 수 있다.
|
||||
GET_SINGLE_DISPATCH(lpDBAgentDispatch, CDBAgentDispatch, CDBAgentDispatch::GetDispatchTable());
|
||||
if (NULL == lpDBAgentDispatch)
|
||||
{
|
||||
ERRLOG0(g_Log, "에이전트 얻기 실패.");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
GameClientSendPacket::SendCharCastleCmdToDBAgent(lpDBAgentDispatch->GetSendStream(),
|
||||
dwCID, m_dwCampOrCastleID, m_dwCID, 0, 0, PktCastleCmd::CASTLE_RIDE_ARMS, PktBase::NO_SERVER_ERR);
|
||||
}
|
||||
|
||||
// Ride 함수 자체에서 패킷을 보내준다.
|
||||
PktCastleCmd pktCC;
|
||||
pktCC.m_dwCastleID = GetCastleID();
|
||||
pktCC.m_dwCastleObjectID = m_dwCID;
|
||||
pktCC.m_cState = m_cState;
|
||||
pktCC.m_dwValue1 = dwCID; // 탑승자 CID
|
||||
pktCC.m_dwValue2 = 0;
|
||||
pktCC.m_cSubCmd = PktCastleCmd::CASTLE_RIDE_ARMS;
|
||||
|
||||
char* szPacket = reinterpret_cast<char *>(&pktCC);
|
||||
if (PacketWrap::WrapCrypt(szPacket, sizeof(PktCastleCmd), CmdCastleCmd, 0, 0))
|
||||
{
|
||||
SendToRange(Siege::BROADCAST_RADIUS, szPacket, sizeof(PktCastleCmd), CmdCastleCmd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CCastleArms::GetOff(unsigned long dwCID)
|
||||
{
|
||||
if (Siege::NOT_RIDER != IsRider(dwCID))
|
||||
{
|
||||
CCharacter* lpRider = CCreatureManager::GetInstance().GetCharacter(dwCID);
|
||||
if (lpRider)
|
||||
{
|
||||
m_dwRiderCID = 0;
|
||||
lpRider->GetOff();
|
||||
|
||||
// 중계 서버에 보내줘야 사용하고 있지 않음을 체크할 수 있다.
|
||||
GET_SINGLE_DISPATCH(lpDBAgentDispatch, CDBAgentDispatch, CDBAgentDispatch::GetDispatchTable());
|
||||
if (NULL == lpDBAgentDispatch)
|
||||
{
|
||||
ERRLOG0(g_Log, "에이전트 얻기 실패.");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
GameClientSendPacket::SendCharCastleCmdToDBAgent(lpDBAgentDispatch->GetSendStream(),
|
||||
dwCID, m_dwCampOrCastleID, m_dwCID, 0, 0, PktCastleCmd::CASTLE_GETOFF_ARMS, PktBase::NO_SERVER_ERR);
|
||||
}
|
||||
|
||||
// GetOff 함수 자체에서 패킷을 보내준다.
|
||||
PktCastleCmd pktCC;
|
||||
pktCC.m_dwCastleID = GetCastleID();
|
||||
pktCC.m_dwCastleObjectID = m_dwCID;
|
||||
pktCC.m_cState = m_cState;
|
||||
pktCC.m_dwValue1 = dwCID; // 내린 사람 CID
|
||||
pktCC.m_dwValue2 = 0;
|
||||
pktCC.m_cSubCmd = PktCastleCmd::CASTLE_GETOFF_ARMS;
|
||||
|
||||
char* szPacket = reinterpret_cast<char *>(&pktCC);
|
||||
if (PacketWrap::WrapCrypt(szPacket, sizeof(PktCastleCmd), CmdCastleCmd, 0, 0))
|
||||
{
|
||||
SendToRange(Siege::BROADCAST_RADIUS, szPacket, sizeof(PktCastleCmd), CmdCastleCmd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
#ifndef _BASE_CASTLE_ARMS_OBJECT_H_
|
||||
#define _BASE_CASTLE_ARMS_OBJECT_H_
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Creature/Siege/SiegeObject.h>
|
||||
#include <Creature/Siege/SiegeConstants.h>
|
||||
|
||||
using namespace Siege;
|
||||
|
||||
|
||||
class CCastleArms : public CSiegeObject
|
||||
{
|
||||
public:
|
||||
virtual ~CCastleArms();
|
||||
|
||||
// CSkillMonster 의 기능
|
||||
virtual bool AttackCID(CCharacter* lpRideChar, AtType attackType, AtNode& attackNode, unsigned short& wError);
|
||||
virtual bool Attack(AtType attackType, unsigned char cDefenderNum, CAggresiveCreature** ppDefenders, unsigned char* cDefenserJudges, unsigned short* wDefenserMPHeal);
|
||||
virtual bool MissileAttack(AtType attackType, float fDir, float nRange, float fAngle, char cTargetType);
|
||||
|
||||
virtual bool Dead(CAggresiveCreature* pOffencer);
|
||||
|
||||
// 수성 병기 관련 함수
|
||||
bool Upgrade(unsigned char cUpgradeStep);
|
||||
bool Repair(unsigned short wRepairHP);
|
||||
bool Destroy(unsigned char cOffencerNation = 0, bool bTakeGold = false );
|
||||
bool Update(unsigned char cState, unsigned long dwValue1, unsigned long dwValue2, unsigned long dwOwnerID, unsigned char cSubCmd);
|
||||
|
||||
bool ChangeType(unsigned short wType);
|
||||
|
||||
// Rider 관련 정보
|
||||
virtual bool Ride(unsigned long dwCID); // 병기 탑승
|
||||
virtual bool GetOff(unsigned long dwCID); // 병기 내림
|
||||
|
||||
protected:
|
||||
CCastleArms(MonsterCreateInfo& MonsterCreate, const CastleObjectInfo& CastleObject);
|
||||
|
||||
friend class CSiegeObjectMgr;
|
||||
};
|
||||
|
||||
#endif _BASE_CASTLE_ARMS_OBJECT_H_
|
||||
@@ -0,0 +1,368 @@
|
||||
#include "stdafx.h"
|
||||
#include "CastleEmblem.h"
|
||||
|
||||
#include <Castle/Castle.h>
|
||||
#include <Castle/CastleMgr.h>
|
||||
|
||||
#include <Skill/SkillTable.h>
|
||||
#include <Skill/SkillMgr.h>
|
||||
|
||||
#include <Utility/Math/Math.h>
|
||||
|
||||
#include <Item/ItemFactory.h>
|
||||
|
||||
#include <Map/FieldMap/CellManager.h>
|
||||
#include <Map/DuelMap/DuelCellManager.h>
|
||||
|
||||
#include <Network/Packet/WrapPacket.h>
|
||||
#include <Network/Packet/PacketCommand.h>
|
||||
#include <Network/Packet/PacketStruct/ServerInfo.h>
|
||||
|
||||
#include <Network/Dispatch/GameClient/GameClientDispatch.h>
|
||||
#include <Network/Dispatch/GameClient/SendCharItem.h>
|
||||
#include <Network/Dispatch/GameClient/SendCharCastle.h>
|
||||
#include <Network/Dispatch/GameClient/SendCharAttack.h>
|
||||
#include <Network/Dispatch/DBAgent/DBAgentDispatch.h>
|
||||
#include <Network/Dispatch/DBAgent/DBAgentRequest.h>
|
||||
|
||||
#include <Network/ClientSocket/ClientConstants.h>
|
||||
|
||||
#include <GameTime/GameTimeConstants.h>
|
||||
#include <GameTime/GameTimeMgr.h>
|
||||
|
||||
CCastleEmblem::CCastleEmblem(MonsterCreateInfo& MonsterCreate, const CastleObjectInfo& CastleObject)
|
||||
: CSiegeObject(MonsterCreate, CastleObject), m_cEnemyNation(Creature::STATELESS), m_dwLastAttackedTick( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
CCastleEmblem::~CCastleEmblem()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void CCastleEmblem::NormalBehavior(unsigned long dwTick)
|
||||
{
|
||||
if (!CGameTimeMgr::GetInstance().IsSiegeWarTime())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 선공 몹 처리
|
||||
if (NULL == m_lpTarget && true == m_MonsterInfo.m_bFirstAttack)
|
||||
{
|
||||
SearchPlayer();
|
||||
}
|
||||
}
|
||||
|
||||
void CCastleEmblem::AttackBehavior(unsigned long dwTick)
|
||||
{
|
||||
PERFORMANCE_CHECK(FunctionTimingCheck)
|
||||
|
||||
if (!CGameTimeMgr::GetInstance().IsSiegeWarTime())
|
||||
{
|
||||
CancelTarget();
|
||||
return;
|
||||
}
|
||||
|
||||
// 상징물이 소환 완료 상태가 아닐 때는 아무런 다른 행동을 해서는 안된다.
|
||||
if (m_cState != Siege::COMPLETE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 마법 캐스팅 중일때는.. 아무런 다른 행동을 해서는 안된다.
|
||||
if (true == m_bCasting)
|
||||
{
|
||||
CastingAttackAction();
|
||||
return;
|
||||
}
|
||||
|
||||
m_lpTarget = m_Threat.GetTarget();
|
||||
if (NULL == m_lpTarget ||
|
||||
(m_lpTarget && true == m_lpTarget->GetEnchantInfo().GetFlag(Skill::SpellID::Hide)))
|
||||
{
|
||||
CancelTarget();
|
||||
return;
|
||||
}
|
||||
|
||||
const float fDY = fabs(m_lpTarget->GetCurrentPos().m_fPointY - GetCurrentPos().m_fPointY);
|
||||
const float fDX = m_lpTarget->GetCurrentPos().m_fPointX - GetCurrentPos().m_fPointX;
|
||||
const float fDZ = m_lpTarget->GetCurrentPos().m_fPointZ - GetCurrentPos().m_fPointZ;
|
||||
const float fDistance = sqrtf((fDX * fDX) + (fDZ * fDZ));
|
||||
|
||||
if (fDY > Siege::EMBLEM_ATTACK_HEIGHT_ERROR)
|
||||
{
|
||||
CancelTarget();
|
||||
return;
|
||||
}
|
||||
|
||||
if (((fDistance > m_wSearchRange) && false == m_bLongRangeAttacked) || (0 == m_lpTarget->GetStatus().m_nNowHP))
|
||||
{
|
||||
CancelTarget();
|
||||
return;
|
||||
}
|
||||
|
||||
const float fAttackRange = m_MonsterInfo.m_wAttackRange / 100.0f;
|
||||
|
||||
if (fDistance > fAttackRange && 0 >= m_lCurrentFrame)
|
||||
{
|
||||
// 공격 범위 밖이다.
|
||||
if (true == SkillAttack()) // 스킬 공격을 사용하는가 체크
|
||||
{
|
||||
SkillAttackAction();
|
||||
}
|
||||
|
||||
if (false == m_bAttacking)
|
||||
{
|
||||
m_lCurrentFrame = m_MotionInfo.m_dwFrame;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 공격 범위 안이다.
|
||||
if (false == m_bAttacking)
|
||||
{
|
||||
if (true == SkillAttack()) // 스킬 공격을 사용하는가 체크
|
||||
{
|
||||
SkillAttackAction();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CCastleEmblem::SearchPlayer(void)
|
||||
{
|
||||
// TODO : 해상도 조절을 통해 float 계산을 없애보자.
|
||||
if (NULL == m_CellPos.m_lpCell)
|
||||
{
|
||||
ERRLOG1(g_Log, "CID:0X%08 공성 오브젝트가 셀 범위 밖에 있습니다.", m_dwCID);
|
||||
return;
|
||||
}
|
||||
|
||||
CCell* pCell = NULL;
|
||||
CCharacter* pTempTarget = NULL;
|
||||
CCharacter* pCurrentTarget = NULL;
|
||||
|
||||
// const float fSquareSearchRange = (float)(m_wSearchRange * m_wSearchRange);
|
||||
const float fSquareSearchRange = (float)(32 * 32);
|
||||
|
||||
for (int nCellCount = 0; nCellCount < CCell::CONNECT_NUM; ++nCellCount)
|
||||
{
|
||||
pCell = m_CellPos.m_lpCell->GetConnectCell(nCellCount);
|
||||
if (NULL == pCell || false == pCell->IsCharacter())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
pTempTarget = pCell->GetFirstCharacter();
|
||||
|
||||
while (NULL != pTempTarget)
|
||||
{
|
||||
const float fDistY = fabs(pTempTarget->GetCurrentPos().m_fPointY - GetCurrentPos().m_fPointY);
|
||||
|
||||
if (fDistY <= Siege::EMBLEM_ATTACK_HEIGHT_ERROR &&
|
||||
pTempTarget->GetStatus().m_nNowHP > 0 &&
|
||||
EnemyCheck::EC_ENEMY == IsEnemy(pTempTarget))
|
||||
{
|
||||
if (false == pTempTarget->GetEnchantInfo().GetFlag(Skill::SpellID::Stealth) &&
|
||||
false == pTempTarget->GetEnchantInfo().GetFlag(Skill::SpellID::Invincible) &&
|
||||
false == pTempTarget->GetEnchantInfo().GetFlag(Skill::SpellID::Hide))
|
||||
{
|
||||
const float fDX = pTempTarget->GetCurrentPos().m_fPointX - GetCurrentPos().m_fPointX;
|
||||
const float fDZ = pTempTarget->GetCurrentPos().m_fPointZ - GetCurrentPos().m_fPointZ;
|
||||
|
||||
const float fDistance = (fDX * fDX) + (fDZ * fDZ);
|
||||
|
||||
if (fDistance < fSquareSearchRange)
|
||||
{
|
||||
pCurrentTarget = pTempTarget;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pTempTarget = pCell->GetNextCharacter();
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL != pCurrentTarget)
|
||||
{
|
||||
m_Threat.AddToThreatList(pCurrentTarget, 1);
|
||||
m_nCurrentState = CFSM::GetInstance().StateTransition(m_nCurrentState, INPUT_ID_SEEN_PLAYER);
|
||||
}
|
||||
}
|
||||
|
||||
bool CCastleEmblem::Attack(AtType attackType, unsigned char cDefenderNum, CAggresiveCreature** ppDefenders, unsigned char* cDefenserJudges, unsigned short* wDefenserMPHeal)
|
||||
{
|
||||
return (m_cState == Siege::COMPLETE) ? CSkillMonster::Attack(attackType, cDefenderNum, ppDefenders, cDefenserJudges, wDefenserMPHeal) : false;
|
||||
}
|
||||
|
||||
bool CCastleEmblem::Dead(CAggresiveCreature* pOffencer)
|
||||
{
|
||||
if (NULL == pOffencer) return false;
|
||||
if (STATE_ID_DIE == m_nCurrentState) return false;
|
||||
|
||||
m_CreatureStatus.m_nNowHP = 0;
|
||||
m_dwLastBehaviorTick = m_dwLastTime = CPulse::GetInstance().GetLastTick();
|
||||
m_lCurrentFrame = FPS;
|
||||
m_bAttacking = false;
|
||||
m_bCasting = false;
|
||||
|
||||
m_nCurrentState = CFSM::GetInstance().StateTransition(m_nCurrentState, INPUT_ID_ZERO_HP);
|
||||
|
||||
// 중계 서버로 패킷 전송
|
||||
GET_SINGLE_DISPATCH(lpDBAgentDispatch, CDBAgentDispatch, CDBAgentDispatch::GetDispatchTable());
|
||||
if (lpDBAgentDispatch)
|
||||
{
|
||||
m_cEnemyNation = reinterpret_cast<CCharacter*>(pOffencer)->GetNation();
|
||||
return GameClientSendPacket::SendCharCastleCmdToDBAgent(lpDBAgentDispatch->GetSendStream(), pOffencer->GetCID(),
|
||||
GetCastleID(), m_dwCID, m_cEnemyNation, 0,
|
||||
PktCastleCmd::CASTLE_UPDATE_EMBLEM, PktBase::NO_SERVER_ERR);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool CCastleEmblem::Upgrade(unsigned char cUpgradeStep)
|
||||
{
|
||||
// 성 오브젝트의 업그레이드 효과를 없애준다.
|
||||
Castle::CCastle* lpCastle = Castle::CCastleMgr::GetInstance().GetCastle(GetCastleID());
|
||||
if (lpCastle)
|
||||
{
|
||||
lpCastle->DegradeByEmblem();
|
||||
}
|
||||
|
||||
// 업그레이드 처리
|
||||
m_cState = Siege::COMPLETE;
|
||||
m_cUpgradeStep = cUpgradeStep;
|
||||
|
||||
UpdateObjectInfo(Siege::UPGRADE_HP);
|
||||
|
||||
// 업그레이트 타입에 따른 처리를 해야한다.
|
||||
if (lpCastle)
|
||||
{
|
||||
lpCastle->UpgradeByEmblem();
|
||||
}
|
||||
|
||||
// 모든 캐릭터에게 전송한다.!!
|
||||
// 성 상징물 업그레이드 단계는 성의 정보에 필요하므로 모든 캐릭터에게 전송
|
||||
PktCastleCmd pktCC;
|
||||
pktCC.m_dwCastleID = GetCastleID();
|
||||
pktCC.m_dwCastleObjectID = m_dwCID;
|
||||
pktCC.m_cState = m_cState;
|
||||
pktCC.m_dwValue1 = m_cUpgradeStep; // 업그레이드 단계
|
||||
pktCC.m_dwValue2 = 0;
|
||||
pktCC.m_cSubCmd = PktCastleCmd::CASTLE_UPGRADE_EMBLEM_COMPLETE;
|
||||
|
||||
char* szPacket = reinterpret_cast<char *>(&pktCC);
|
||||
CCreatureManager::GetInstance().SendAllCharacter(szPacket, sizeof(PktCastleCmd), CmdCastleCmd);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// 상징물 업데이트 (소환중, 소환완료, 업그레이드중)
|
||||
bool CCastleEmblem::Update(unsigned char cState, unsigned long dwValue1, unsigned long dwValue2, unsigned long dwNoValue, unsigned char cSubCmd)
|
||||
{
|
||||
if ( !IsEmblem() ) return false;
|
||||
|
||||
m_cState = cState;
|
||||
|
||||
PktCastleCmd pktCC;
|
||||
|
||||
if (PktCastleCmd::CASTLE_UPGRADE_EMBLEM == cSubCmd)
|
||||
{
|
||||
m_cUpgradeType = static_cast<unsigned char>(dwValue1);
|
||||
|
||||
UpdateObjectInfo();
|
||||
}
|
||||
else if (PktCastleCmd::CASTLE_UPDATE_EMBLEM == cSubCmd)
|
||||
{
|
||||
// 업그레이드 효과 없애주기
|
||||
Castle::CCastle* lpCastle = Castle::CCastleMgr::GetInstance().GetCastle(GetCastleID());
|
||||
if (lpCastle)
|
||||
{
|
||||
lpCastle->DegradeByEmblem();
|
||||
}
|
||||
|
||||
switch (dwValue1)
|
||||
{
|
||||
case Siege::MINE:
|
||||
{
|
||||
m_cSubState = Siege::MINE;
|
||||
std::swap(m_cNation, m_cEnemyNation);
|
||||
m_cEnemyNation = Creature::STATELESS;
|
||||
dwValue1 = m_cNation;
|
||||
}
|
||||
break;
|
||||
|
||||
case Siege::ENEMY:
|
||||
{
|
||||
m_cSubState = Siege::ENEMY;
|
||||
std::swap(m_cNation, m_cEnemyNation);
|
||||
dwValue1 = m_cNation;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
m_cUpgradeType = Siege::NO_JEWEL;
|
||||
m_cUpgradeStep = 0;
|
||||
|
||||
UpdateObjectInfo(Siege::FULL_HP);
|
||||
|
||||
// 30초간 무적
|
||||
Skill::CAddSpell<CInvincibleSpell>(
|
||||
CSpell::Spell_Info(Skill::CProcessTable::ProcessInfo::m_NullProtoType, this,
|
||||
Skill::SpellType::MAGICAL_SPELL, Skill::SpellID::Invincible, 1, 30))(this);
|
||||
|
||||
}
|
||||
else if (PktCastleCmd::CASTLE_SUMMON_EMBLEM_COMPLETE == cSubCmd)
|
||||
{
|
||||
m_cSubState = Siege::MINE;
|
||||
m_cEnemyNation = Creature::STATELESS;
|
||||
|
||||
UpdateObjectInfo(Siege::FULL_HP);
|
||||
}
|
||||
|
||||
// 메세지 처리 때문에 존의 모든 인원에게 보낸다.
|
||||
pktCC.m_dwCastleID = GetCastleID();
|
||||
pktCC.m_dwCastleObjectID = m_dwCID;
|
||||
pktCC.m_cState = m_cState;
|
||||
pktCC.m_dwValue1 = dwValue1;
|
||||
pktCC.m_dwValue2 = 0;
|
||||
pktCC.m_cSubCmd = cSubCmd;
|
||||
|
||||
char* szPacket = reinterpret_cast<char *>(&pktCC);
|
||||
if (PacketWrap::WrapCrypt(szPacket, sizeof(PktCastleCmd), CmdCastleCmd, 0, 0))
|
||||
{
|
||||
CCreatureManager::GetInstance().SendAllCharacter(szPacket, sizeof(PktCastleCmd), CmdCastleCmd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CCastleEmblem::SendAttackedMessage()
|
||||
{
|
||||
unsigned long dwNowTime = timeGetTime();
|
||||
if ( dwNowTime - m_dwLastAttackedTick >= Siege::EMBLEM_ATTACKED_INTERVAL )
|
||||
{
|
||||
m_dwLastAttackedTick = dwNowTime;
|
||||
|
||||
// 메세지 처리 때문에 존의 모든 인원에게 보낸다.
|
||||
PktCastleCmd pktCC;
|
||||
pktCC.m_dwCastleID = GetCastleID();
|
||||
pktCC.m_dwCastleObjectID = m_dwCID;
|
||||
pktCC.m_cState = m_cState;
|
||||
pktCC.m_dwValue1 = 0;
|
||||
pktCC.m_dwValue2 = 0;
|
||||
pktCC.m_cSubCmd = PktCastleCmd::CASTLE_EMBLEM_ATTACKED;
|
||||
|
||||
char* szPacket = reinterpret_cast<char *>(&pktCC);
|
||||
if (PacketWrap::WrapCrypt(szPacket, sizeof(PktCastleCmd), CmdCastleCmd, 0, 0))
|
||||
{
|
||||
CCreatureManager::GetInstance().SendAllCharacter(szPacket, sizeof(PktCastleCmd), CmdCastleCmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
#ifndef _CASTLE_EMBLEM_OBJECT_H_
|
||||
#define _CASTLE_EMBLEM_OBJECT_H_
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Creature/Siege/SiegeObject.h>
|
||||
#include <Creature/Siege/SiegeConstants.h>
|
||||
|
||||
using namespace Siege;
|
||||
|
||||
|
||||
class CCastleEmblem : public CSiegeObject
|
||||
{
|
||||
public:
|
||||
virtual ~CCastleEmblem();
|
||||
|
||||
// CSkillMonster 의 기능
|
||||
void NormalBehavior(unsigned long dwTick);
|
||||
void AttackBehavior(unsigned long dwTick);
|
||||
void SearchPlayer(void);
|
||||
|
||||
bool Attack(AtType attackType, unsigned char cDefenderNum, CAggresiveCreature** ppDefenders, unsigned char* cDefenserJudges, unsigned short* wDefenserMPHeal);
|
||||
bool Dead(CAggresiveCreature* pOffencer);
|
||||
|
||||
// 성 상징물 관련 함수
|
||||
bool Upgrade(unsigned char cUpgradeStep);
|
||||
bool Update(unsigned char cState, unsigned long dwValue1, unsigned long dwValue2, unsigned long dwNoValue, unsigned char cSubCmd); // 상징물 업데이트 (소환중, 소환완료, 업그레이드중)
|
||||
|
||||
// Get / Set 함수
|
||||
unsigned char GetEnemyNation() const { return m_cEnemyNation; }
|
||||
|
||||
// Send 함수
|
||||
void SendAttackedMessage();
|
||||
|
||||
private:
|
||||
CCastleEmblem(MonsterCreateInfo& MonsterCreate, const CastleObjectInfo& CastleObject);
|
||||
|
||||
unsigned char m_cEnemyNation; // 상징물을 부슨 적의 국적
|
||||
unsigned long m_dwLastAttackedTick; // 마지막으로 공격 받은 시간
|
||||
|
||||
friend class CSiegeObjectMgr;
|
||||
};
|
||||
|
||||
#endif _CASTLE_EMBLEM_OBJECT_H_
|
||||
@@ -0,0 +1,432 @@
|
||||
#include "stdafx.h"
|
||||
#include "CastleGate.h"
|
||||
|
||||
#include <Skill/SkillTable.h>
|
||||
#include <Skill/SkillMgr.h>
|
||||
|
||||
#include <Utility/Math/Math.h>
|
||||
|
||||
#include <Item/ItemFactory.h>
|
||||
|
||||
#include <Map/FieldMap/CellManager.h>
|
||||
#include <Map/DuelMap/DuelCellManager.h>
|
||||
|
||||
#include <Network/Packet/WrapPacket.h>
|
||||
#include <Network/Packet/PacketCommand.h>
|
||||
#include <Network/Packet/PacketStruct/ServerInfo.h>
|
||||
|
||||
#include <Network/Dispatch/GameClient/GameClientDispatch.h>
|
||||
#include <Network/Dispatch/GameClient/SendCharItem.h>
|
||||
#include <Network/Dispatch/GameClient/SendCharCastle.h>
|
||||
#include <Network/Dispatch/GameClient/SendCharAttack.h>
|
||||
#include <Network/Dispatch/DBAgent/DBAgentDispatch.h>
|
||||
#include <Network/Dispatch/DBAgent/DBAgentRequest.h>
|
||||
|
||||
#include <Network/ClientSocket/ClientConstants.h>
|
||||
|
||||
|
||||
CCastleGate::CCastleGate(MonsterCreateInfo& MonsterCreate, const CastleObjectInfo& CastleObject)
|
||||
: CSiegeObject(MonsterCreate, CastleObject)
|
||||
{
|
||||
}
|
||||
|
||||
CCastleGate::~CCastleGate()
|
||||
{
|
||||
}
|
||||
|
||||
bool CCastleGate::Dead(CAggresiveCreature* pOffencer)
|
||||
{
|
||||
if (NULL == pOffencer) return false;
|
||||
if (STATE_ID_DIE == m_nCurrentState) return false;
|
||||
|
||||
m_CreatureStatus.m_nNowHP = 0;
|
||||
m_dwLastBehaviorTick = m_dwLastTime = CPulse::GetInstance().GetLastTick();
|
||||
m_lCurrentFrame = FPS;
|
||||
m_bAttacking = false;
|
||||
m_bCasting = false;
|
||||
|
||||
m_nCurrentState = CFSM::GetInstance().StateTransition(m_nCurrentState, INPUT_ID_ZERO_HP);
|
||||
|
||||
// 중계 서버로 패킷 전송
|
||||
GET_SINGLE_DISPATCH(lpDBAgentDispatch, CDBAgentDispatch, CDBAgentDispatch::GetDispatchTable());
|
||||
if (lpDBAgentDispatch)
|
||||
{
|
||||
return GameClientSendPacket::SendCharCastleCmdToDBAgent(lpDBAgentDispatch->GetSendStream(), pOffencer->GetCID(),
|
||||
GetCastleID(), m_dwCID, 0, 0, PktCastleCmd::CASTLE_DESTROY_GATE,
|
||||
PktBase::NO_SERVER_ERR);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void CCastleGate::AddProtectGate(CCharacter* lpProtectChar)
|
||||
{
|
||||
if (lpProtectChar && lpProtectChar->GetStatus().m_nNowHP > 0)
|
||||
{
|
||||
ProtectCIDList::iterator itr = std::find(m_ProtectCharList.begin(), m_ProtectCharList.end(), lpProtectChar->GetCID());
|
||||
if (itr == m_ProtectCharList.end())
|
||||
{
|
||||
m_ProtectCharList.push_back(lpProtectChar->GetCID());
|
||||
lpProtectChar->SetProtectGateCID(m_dwCID);
|
||||
++m_CreatureStatus.m_StatusInfo.m_wBlock;
|
||||
|
||||
SendProtectGateInfo();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CCastleGate::DeleteProtectGate(CCharacter* lpProtectChar)
|
||||
{
|
||||
if (lpProtectChar)
|
||||
{
|
||||
ProtectCIDList::iterator itr = std::find(m_ProtectCharList.begin(), m_ProtectCharList.end(), lpProtectChar->GetCID());
|
||||
if (itr != m_ProtectCharList.end())
|
||||
{
|
||||
m_ProtectCharList.erase(itr);
|
||||
lpProtectChar->SetProtectGateCID(0);
|
||||
if (0 < m_CreatureStatus.m_StatusInfo.m_wBlock)
|
||||
{
|
||||
--m_CreatureStatus.m_StatusInfo.m_wBlock;
|
||||
}
|
||||
|
||||
SendProtectGateInfo();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CCastleGate::DivideDamage(CAggresiveCreature* pOffencer, unsigned short wDamage)
|
||||
{
|
||||
if (NULL == pOffencer)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int nNum = static_cast<int>(m_ProtectCharList.size());
|
||||
wDamage = static_cast<unsigned short>(wDamage * 100 / 1.33f);
|
||||
unsigned short wCharDamage = (nNum == 0) ? 0 : wDamage / nNum;
|
||||
|
||||
ProtectCIDList::iterator itr = m_ProtectCharList.begin();
|
||||
while (itr != m_ProtectCharList.end())
|
||||
{
|
||||
CCharacter* lpCharacter = CCreatureManager::GetInstance().GetCharacter((*itr));
|
||||
if (lpCharacter)
|
||||
{
|
||||
unsigned short wNowHP = lpCharacter->GetStatus().m_nNowHP;
|
||||
const unsigned short wThreatAmount = (wNowHP < wCharDamage) ? wNowHP : wCharDamage;
|
||||
lpCharacter->GetThreat().AddToThreatList(pOffencer, wThreatAmount);
|
||||
lpCharacter->GetStatus().m_nNowHP = (wNowHP > wCharDamage) ? wNowHP - wCharDamage : 0;
|
||||
|
||||
if (0 == lpCharacter->GetStatus().m_nNowHP)
|
||||
{
|
||||
lpCharacter->Dead(pOffencer);
|
||||
lpCharacter->GetThreat().ClearAll();
|
||||
}
|
||||
|
||||
AtType attackType;
|
||||
attackType.m_wType = AtType::RIGHT_MELEE;
|
||||
|
||||
CGameClientDispatch* pCharacterDispatcher = lpCharacter->GetDispatcher();
|
||||
if (NULL != pCharacterDispatcher)
|
||||
{
|
||||
GameClientSendPacket::SendCharAttacked(pCharacterDispatcher->GetSendStream(), pOffencer, lpCharacter,
|
||||
attackType, 0, wCharDamage, ClientConstants::Judge_Front, 0, PktBase::NO_SERVER_ERR);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CCastleGate::SendProtectGateInfo()
|
||||
{
|
||||
int nNum = static_cast<int>(m_ProtectCharList.size());
|
||||
// 블럭률 계산식 : INT((99 * 블럭수치 / 2) / (블럭수치 / 2 + 50) * 100) / 100
|
||||
int nBlockRate = static_cast<int>((99 * m_CreatureStatus.m_StatusInfo.m_wBlock / 2) / (m_CreatureStatus.m_StatusInfo.m_wBlock / 2 + 50) * 100) / 100;
|
||||
|
||||
if (0 == nNum) return;
|
||||
|
||||
ProtectCIDList::iterator itr = m_ProtectCharList.begin();
|
||||
while (itr != m_ProtectCharList.end())
|
||||
{
|
||||
CCharacter* lpCharacter = CCreatureManager::GetInstance().GetCharacter((*itr));
|
||||
if (lpCharacter)
|
||||
{
|
||||
CGameClientDispatch* pCharacterDispatcher = lpCharacter->GetDispatcher();
|
||||
if (NULL != pCharacterDispatcher)
|
||||
{
|
||||
GameClientSendPacket::SendCharCastleCmd(pCharacterDispatcher->GetSendStream(), GetCastleID(), m_dwCID,
|
||||
nBlockRate, m_CreatureStatus.m_nNowHP,
|
||||
PktCastleCmd::CASTLE_GATE_PROTECT_INFO, PktBase::NO_SERVER_ERR);
|
||||
}
|
||||
}
|
||||
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
|
||||
void CCastleGate::Open()
|
||||
{
|
||||
if ( !IsGate() ) return;
|
||||
|
||||
m_cSubState = Siege::OPENED;
|
||||
|
||||
// 성문이 있는 반경 5셀 이내에 전송
|
||||
PktCastleCmd pktCC;
|
||||
pktCC.m_dwCastleID = GetCastleID();
|
||||
pktCC.m_dwCastleObjectID = m_dwCID;
|
||||
pktCC.m_cState = m_cState;
|
||||
pktCC.m_dwValue1 = m_cSubState;
|
||||
pktCC.m_dwValue2 = 0;
|
||||
pktCC.m_cSubCmd = PktCastleCmd::CASTLE_GATE_OPEN;
|
||||
|
||||
char* szPacket = reinterpret_cast<char *>(&pktCC);
|
||||
if (PacketWrap::WrapCrypt(szPacket, sizeof(PktCastleCmd), CmdCastleCmd, 0, 0))
|
||||
{
|
||||
// Vincent - 브로드 캐스트 테스트 코드
|
||||
//SendToRadiusCell(szPacket, sizeof(PktCastleCmd), CmdCastleCmd);
|
||||
SendToRange(Siege::BROADCAST_RADIUS, szPacket, sizeof(PktCastleCmd), CmdCastleCmd);
|
||||
}
|
||||
}
|
||||
|
||||
void CCastleGate::Close()
|
||||
{
|
||||
if ( !IsGate() ) return;
|
||||
|
||||
m_cSubState = Siege::CLOSED;
|
||||
|
||||
// 성문이 있는 반경 5셀 이내에 전송
|
||||
PktCastleCmd pktCC;
|
||||
pktCC.m_dwCastleID = GetCastleID();
|
||||
pktCC.m_dwCastleObjectID = m_dwCID;
|
||||
pktCC.m_cState = m_cState;
|
||||
pktCC.m_dwValue1 = m_cSubState;
|
||||
pktCC.m_dwValue2 = 0;
|
||||
pktCC.m_cSubCmd = PktCastleCmd::CASTLE_GATE_CLOSE;
|
||||
|
||||
char* szPacket = reinterpret_cast<char *>(&pktCC);
|
||||
if (PacketWrap::WrapCrypt(szPacket, sizeof(PktCastleCmd), CmdCastleCmd, 0, 0))
|
||||
{
|
||||
// Vincent - 브로드 캐스트 테스트 코드
|
||||
//SendToRadiusCell(szPacket, sizeof(PktCastleCmd), CmdCastleCmd);
|
||||
SendToRange(Siege::BROADCAST_RADIUS, szPacket, sizeof(PktCastleCmd), CmdCastleCmd);
|
||||
}
|
||||
}
|
||||
|
||||
void CCastleGate::ForceOpen()
|
||||
{
|
||||
if ( !IsGate() ) return;
|
||||
if ( Siege::COMPLETE == m_cState && Siege::OPENED == m_cSubState )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_cState = Siege::COMPLETE;
|
||||
m_cSubState = Siege::OPENED;
|
||||
m_nCurrentState = STATE_ID_NORMAL;
|
||||
|
||||
UpdateObjectInfo(Siege::FULL_HP, 0);
|
||||
|
||||
// 성문이 있는 반경 5셀 이내에 전송
|
||||
PktCastleCmd pktCC;
|
||||
pktCC.m_dwCastleID = GetCastleID();
|
||||
pktCC.m_dwCastleObjectID = m_dwCID;
|
||||
pktCC.m_cState = m_cState;
|
||||
pktCC.m_dwValue1 = m_cSubState;
|
||||
pktCC.m_dwValue2 = 0;
|
||||
pktCC.m_cSubCmd = PktCastleCmd::CASTLE_GATE_OPEN;
|
||||
|
||||
char* szPacket = reinterpret_cast<char *>(&pktCC);
|
||||
if (PacketWrap::WrapCrypt(szPacket, sizeof(PktCastleCmd), CmdCastleCmd, 0, 0))
|
||||
{
|
||||
// Vincent - 브로드 캐스트 테스트 코드
|
||||
//SendToRadiusCell(szPacket, sizeof(PktCastleCmd), CmdCastleCmd);
|
||||
SendToRange(Siege::BROADCAST_RADIUS, szPacket, sizeof(PktCastleCmd), CmdCastleCmd);
|
||||
}
|
||||
}
|
||||
|
||||
void CCastleGate::ForceClose()
|
||||
{
|
||||
if ( !IsGate() ) return;
|
||||
if ( Siege::COMPLETE == m_cState && Siege::CLOSED == m_cSubState )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_cState = Siege::COMPLETE;
|
||||
m_cSubState = Siege::CLOSED;
|
||||
m_nCurrentState = STATE_ID_NORMAL;
|
||||
|
||||
UpdateObjectInfo(Siege::FULL_HP, 0);
|
||||
|
||||
// 성문이 있는 반경 5셀 이내에 전송
|
||||
PktCastleCmd pktCC;
|
||||
pktCC.m_dwCastleID = GetCastleID();
|
||||
pktCC.m_dwCastleObjectID = m_dwCID;
|
||||
pktCC.m_cState = m_cState;
|
||||
pktCC.m_dwValue1 = m_cSubState;
|
||||
pktCC.m_dwValue2 = 0;
|
||||
pktCC.m_cSubCmd = PktCastleCmd::CASTLE_GATE_CLOSE;
|
||||
|
||||
char* szPacket = reinterpret_cast<char *>(&pktCC);
|
||||
if (PacketWrap::WrapCrypt(szPacket, sizeof(PktCastleCmd), CmdCastleCmd, 0, 0))
|
||||
{
|
||||
// Vincent - 브로드 캐스트 테스트 코드
|
||||
//SendToRadiusCell(szPacket, sizeof(PktCastleCmd), CmdCastleCmd);
|
||||
SendToRange(Siege::BROADCAST_RADIUS, szPacket, sizeof(PktCastleCmd), CmdCastleCmd);
|
||||
}
|
||||
}
|
||||
|
||||
bool CCastleGate::Upgrade(unsigned char cUpgradeStep)
|
||||
{
|
||||
m_cState = Siege::COMPLETE;
|
||||
m_cUpgradeStep = cUpgradeStep;
|
||||
|
||||
UpdateObjectInfo(Siege::UPGRADE_HP);
|
||||
|
||||
// 성문이 있는 반경 5셀 이내에 전송
|
||||
PktCastleCmd pktCC;
|
||||
pktCC.m_dwCastleID = GetCastleID();
|
||||
pktCC.m_dwCastleObjectID = m_dwCID;
|
||||
pktCC.m_cState = m_cState;
|
||||
pktCC.m_dwValue1 = m_cUpgradeStep; // 업그레이드 단계
|
||||
pktCC.m_dwValue2 = 0;
|
||||
pktCC.m_cSubCmd = PktCastleCmd::CASTLE_UPGRADE_GATE_COMPLETE;
|
||||
|
||||
char* szPacket = reinterpret_cast<char *>(&pktCC);
|
||||
if (PacketWrap::WrapCrypt(szPacket, sizeof(PktCastleCmd), CmdCastleCmd, 0, 0))
|
||||
{
|
||||
// Vincent - 브로드 캐스트 테스트 코드
|
||||
//SendToRadiusCell(szPacket, sizeof(PktCastleCmd), CmdCastleCmd);
|
||||
SendToRange(Siege::BROADCAST_RADIUS, szPacket, sizeof(PktCastleCmd), CmdCastleCmd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CCastleGate::Repair(unsigned short wRepairHP)
|
||||
{
|
||||
m_cState = Siege::COMPLETE;
|
||||
|
||||
UpdateObjectInfo(Siege::REPAIR_HP, wRepairHP);
|
||||
|
||||
// 성문이 있는 반경 5셀 이내에 전송
|
||||
PktCastleCmd pktCC;
|
||||
pktCC.m_dwCastleID = GetCastleID();
|
||||
pktCC.m_dwCastleObjectID = m_dwCID;
|
||||
pktCC.m_cState = m_cState;
|
||||
pktCC.m_dwValue1 = m_CreatureStatus.m_nNowHP; // 현재 HP
|
||||
pktCC.m_dwValue2 = 0;
|
||||
pktCC.m_cSubCmd = PktCastleCmd::CASTLE_REPAIR_GATE_COMPLETE;
|
||||
|
||||
char* szPacket = reinterpret_cast<char *>(&pktCC);
|
||||
if (PacketWrap::WrapCrypt(szPacket, sizeof(PktCastleCmd), CmdCastleCmd, 0, 0))
|
||||
{
|
||||
// Vincent - 브로드 캐스트 테스트 코드
|
||||
//SendToRadiusCell(szPacket, sizeof(PktCastleCmd), CmdCastleCmd);
|
||||
SendToRange(Siege::BROADCAST_RADIUS, szPacket, sizeof(PktCastleCmd), CmdCastleCmd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CCastleGate::Restore()
|
||||
{
|
||||
m_cState = Siege::COMPLETE;
|
||||
m_cUpgradeStep = 0;
|
||||
m_nCurrentState = STATE_ID_NORMAL;
|
||||
|
||||
UpdateObjectInfo();
|
||||
|
||||
// 성문이 있는 반경 5셀 이내에 전송
|
||||
PktCastleCmd pktCC;
|
||||
pktCC.m_dwCastleID = GetCastleID();
|
||||
pktCC.m_dwCastleObjectID = m_dwCID;
|
||||
pktCC.m_cState = m_cState;
|
||||
pktCC.m_dwValue1 = m_CreatureStatus.m_nNowHP; // 현재 HP
|
||||
pktCC.m_dwValue2 = 0;
|
||||
pktCC.m_cSubCmd = PktCastleCmd::CASTLE_RESTORE_GATE_COMPLETE;
|
||||
|
||||
char* szPacket = reinterpret_cast<char *>(&pktCC);
|
||||
if (PacketWrap::WrapCrypt(szPacket, sizeof(PktCastleCmd), CmdCastleCmd, 0, 0))
|
||||
{
|
||||
// Vincent - 브로드 캐스트 테스트 코드
|
||||
//SendToRadiusCell(szPacket, sizeof(PktCastleCmd), CmdCastleCmd);
|
||||
SendToRange(Siege::BROADCAST_RADIUS, szPacket, sizeof(PktCastleCmd), CmdCastleCmd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CCastleGate::Destroy(unsigned char cOffencerNation, bool bTakeGold)
|
||||
{
|
||||
m_cState = Siege::DESTROYED;
|
||||
m_cSubState = Siege::OPENED;
|
||||
m_cUpgradeStep = 0;
|
||||
|
||||
m_CreatureStatus.m_nNowHP = 0;
|
||||
|
||||
UpdateObjectInfo();
|
||||
|
||||
// 메세지 처리 때문에 존의 모든 인원에게 보낸다.
|
||||
PktCastleCmd pktCC;
|
||||
pktCC.m_dwCastleID = GetCastleID();
|
||||
pktCC.m_dwCastleObjectID = m_dwCID;
|
||||
pktCC.m_cState = m_cState;
|
||||
pktCC.m_dwValue1 = 0;
|
||||
pktCC.m_dwValue2 = 0;
|
||||
pktCC.m_cSubCmd = PktCastleCmd::CASTLE_DESTROY_GATE;
|
||||
|
||||
char* szPacket = reinterpret_cast<char *>(&pktCC);
|
||||
if (PacketWrap::WrapCrypt(szPacket, sizeof(PktCastleCmd), CmdCastleCmd, 0, 0))
|
||||
{
|
||||
CCreatureManager::GetInstance().SendAllCharacter(szPacket, sizeof(PktCastleCmd), CmdCastleCmd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CCastleGate::Update(unsigned char cState, unsigned long dwValue1, unsigned long dwValue2, unsigned long dwNoValue, unsigned char cSubCmd)
|
||||
{
|
||||
m_cState = cState;
|
||||
|
||||
if (PktCastleCmd::CASTLE_RESTORE_GATE == cSubCmd)
|
||||
{
|
||||
UpdateObjectInfo(Siege::FULL_HP);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateObjectInfo();
|
||||
}
|
||||
|
||||
// 성문이 있는 반경 5셀 이내에 전송
|
||||
PktCastleCmd pktCC;
|
||||
pktCC.m_dwCastleID = GetCastleID();
|
||||
pktCC.m_dwCastleObjectID = m_dwCID;
|
||||
pktCC.m_cState = m_cState;
|
||||
pktCC.m_dwValue1 = dwValue1;
|
||||
pktCC.m_dwValue2 = 0;
|
||||
pktCC.m_cSubCmd = cSubCmd;
|
||||
|
||||
char* szPacket = reinterpret_cast<char *>(&pktCC);
|
||||
if (PacketWrap::WrapCrypt(szPacket, sizeof(PktCastleCmd), CmdCastleCmd, 0, 0))
|
||||
{
|
||||
// Vincent - 브로드 캐스트 테스트 코드
|
||||
//SendToRadiusCell(szPacket, sizeof(PktCastleCmd), CmdCastleCmd);
|
||||
SendToRange(Siege::BROADCAST_RADIUS, szPacket, sizeof(PktCastleCmd), CmdCastleCmd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
unsigned long CCastleGate::GetRepairGold() const
|
||||
{
|
||||
// int nDiffHP = m_CreatureStatus.m_StatusInfo.m_nMaxHP - m_CreatureStatus.m_nNowHP;
|
||||
// int nShare = nDiffHP / Siege::CASTLE_ARMS_REPAIR_HP_UNIT;
|
||||
// int nLeftOver = nDiffHP % Siege::CASTLE_ARMS_REPAIR_HP_UNIT;
|
||||
// if (nLeftOver > 0) ++nShare;
|
||||
//
|
||||
// return nShare * Siege::CASTLE_ARMS_REPAIR_GOLD_PER_UNIT;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
#ifndef _CASTLE_GATE_OBJECT_H_
|
||||
#define _CASTLE_GATE_OBJECT_H_
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <Creature/Siege/SiegeObject.h>
|
||||
#include <Creature/Siege/SiegeConstants.h>
|
||||
|
||||
using namespace Siege;
|
||||
|
||||
|
||||
class CCastleGate : public CSiegeObject
|
||||
{
|
||||
public:
|
||||
typedef std::list<unsigned long> ProtectCIDList;
|
||||
|
||||
virtual ~CCastleGate();
|
||||
|
||||
// CSkillMonster 의 기능
|
||||
bool Dead(CAggresiveCreature* pOffencer);
|
||||
|
||||
// 성문 관련 함수
|
||||
void AddProtectGate(CCharacter* lpProtectChar);
|
||||
void DeleteProtectGate(CCharacter* lpProtectChar);
|
||||
void DivideDamage(CAggresiveCreature* pOffencer, unsigned short wDamage);
|
||||
void SendProtectGateInfo();
|
||||
|
||||
void Open();
|
||||
void Close();
|
||||
void ForceOpen();
|
||||
void ForceClose();
|
||||
|
||||
bool Upgrade(unsigned char cUpgradeStep);
|
||||
bool Repair(unsigned short wRepairHP);
|
||||
bool Restore();
|
||||
bool Destroy(unsigned char cOffencerNation = 0, bool bTakeGold = false );
|
||||
bool Update(unsigned char cState, unsigned long dwValue1, unsigned long dwValue2, unsigned long dwNoValue, unsigned char cSubCmd);
|
||||
|
||||
// Get / Set 함수
|
||||
unsigned long GetRepairGold() const;
|
||||
|
||||
private:
|
||||
CCastleGate(MonsterCreateInfo& MonsterCreate, const CastleObjectInfo& CastleObject);
|
||||
|
||||
ProtectCIDList m_ProtectCharList; // 성문 막기중인 캐릭터 CID 리스트
|
||||
|
||||
friend class CSiegeObjectMgr;
|
||||
};
|
||||
|
||||
#endif _CASTLE_GATE_OBJECT_H_
|
||||
@@ -0,0 +1,204 @@
|
||||
#include "stdafx.h"
|
||||
#include "CastleGuard.h"
|
||||
|
||||
#include <Castle/CastleMgr.h>
|
||||
|
||||
#include <Skill/SkillTable.h>
|
||||
#include <Skill/SkillMgr.h>
|
||||
|
||||
#include <Utility/Math/Math.h>
|
||||
|
||||
#include <Item/ItemFactory.h>
|
||||
|
||||
#include <Map/FieldMap/CellManager.h>
|
||||
#include <Map/DuelMap/DuelCellManager.h>
|
||||
|
||||
#include <Network/Packet/WrapPacket.h>
|
||||
#include <Network/Packet/PacketCommand.h>
|
||||
#include <Network/Packet/PacketStruct/ServerInfo.h>
|
||||
|
||||
#include <Network/Dispatch/GameClient/GameClientDispatch.h>
|
||||
#include <Network/Dispatch/GameClient/SendCharItem.h>
|
||||
#include <Network/Dispatch/GameClient/SendCharCastle.h>
|
||||
#include <Network/Dispatch/GameClient/SendCharAttack.h>
|
||||
#include <Network/Dispatch/DBAgent/DBAgentDispatch.h>
|
||||
#include <Network/Dispatch/DBAgent/DBAgentRequest.h>
|
||||
|
||||
#include <Network/ClientSocket/ClientConstants.h>
|
||||
|
||||
#include <GameTime/GameTimeConstants.h>
|
||||
#include <GameTime/GameTimeMgr.h>
|
||||
|
||||
CCastleGuard::CCastleGuard(MonsterCreateInfo& MonsterCreate, const CastleObjectInfo& CastleObject)
|
||||
: CCastleArms(MonsterCreate, CastleObject)
|
||||
{
|
||||
}
|
||||
|
||||
CCastleGuard::~CCastleGuard()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void CCastleGuard::NormalBehavior(unsigned long dwTick)
|
||||
{
|
||||
if (!CGameTimeMgr::GetInstance().IsSiegeWarTime())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 선공 몹 처리
|
||||
if (NULL == m_lpTarget && true == m_MonsterInfo.m_bFirstAttack)
|
||||
{
|
||||
SearchPlayer();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CCastleGuard::AttackBehavior(unsigned long dwTick)
|
||||
{
|
||||
PERFORMANCE_CHECK(FunctionTimingCheck)
|
||||
|
||||
if (!CGameTimeMgr::GetInstance().IsSiegeWarTime())
|
||||
{
|
||||
CancelTarget();
|
||||
return;
|
||||
}
|
||||
|
||||
// 마법 캐스팅 중일때는.. 아무런 다른 행동을 해서는 안된다.
|
||||
if (true == m_bCasting)
|
||||
{
|
||||
CastingAttackAction();
|
||||
return;
|
||||
}
|
||||
|
||||
m_lpTarget = m_Threat.GetTarget();
|
||||
if (NULL == m_lpTarget ||
|
||||
(m_lpTarget && true == m_lpTarget->GetEnchantInfo().GetFlag(Skill::SpellID::Hide)))
|
||||
{
|
||||
CancelTarget();
|
||||
return;
|
||||
}
|
||||
|
||||
const float fDY = fabs(m_lpTarget->GetCurrentPos().m_fPointY - GetCurrentPos().m_fPointY);
|
||||
const float fDX = m_lpTarget->GetCurrentPos().m_fPointX - GetCurrentPos().m_fPointX;
|
||||
const float fDZ = m_lpTarget->GetCurrentPos().m_fPointZ - GetCurrentPos().m_fPointZ;
|
||||
const float fDistance = sqrtf((fDX * fDX) + (fDZ * fDZ));
|
||||
|
||||
if (((fDistance > m_wSearchRange) && false == m_bLongRangeAttacked) || (0 == m_lpTarget->GetStatus().m_nNowHP))
|
||||
{
|
||||
CancelTarget();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const float fAttackRange = m_MonsterInfo.m_wAttackRange / 100.0f;
|
||||
|
||||
if (fDistance > fAttackRange && 0 >= m_lCurrentFrame)
|
||||
{
|
||||
// 공격 범위 밖이다.
|
||||
if (true == SkillAttack()) // 스킬 공격을 사용하는가 체크
|
||||
{
|
||||
SkillAttackAction();
|
||||
}
|
||||
|
||||
if (false == m_bAttacking)
|
||||
{
|
||||
m_lCurrentFrame = m_MotionInfo.m_dwFrame;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 공격 범위 안이다.
|
||||
if (false == m_bAttacking)
|
||||
{
|
||||
if (true == SkillAttack()) // 스킬 공격을 사용하는가 체크
|
||||
{
|
||||
SkillAttackAction();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CCastleGuard::SearchPlayer(void)
|
||||
{
|
||||
// TODO : 해상도 조절을 통해 float 계산을 없애보자.
|
||||
if (NULL == m_CellPos.m_lpCell)
|
||||
{
|
||||
ERRLOG1(g_Log, "CID:0X%08 공성 오브젝트가 셀 범위 밖에 있습니다.", m_dwCID);
|
||||
return;
|
||||
}
|
||||
|
||||
CCell* pCell = NULL;
|
||||
CSiegeObject* pTempTarget = NULL;
|
||||
CSiegeObject* pCurrentTarget = NULL;
|
||||
|
||||
// const float fSquareSearchRange = (float)(m_wSearchRange * m_wSearchRange);
|
||||
const float fSquareSearchRange = (float)(45 * 45);
|
||||
|
||||
for (int nCellCount = 0; nCellCount < CCell::CONNECT_NUM; ++nCellCount)
|
||||
{
|
||||
pCell = m_CellPos.m_lpCell->GetConnectCell(nCellCount);
|
||||
if (NULL == pCell || false == pCell->IsSiegeObject())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
pTempTarget = pCell->GetFirstAirShip();
|
||||
|
||||
while (NULL != pTempTarget)
|
||||
{
|
||||
if (pTempTarget->GetStatus().m_nNowHP > 0 && EnemyCheck::EC_ENEMY == IsEnemy(pTempTarget))
|
||||
{
|
||||
if (false == pTempTarget->GetEnchantInfo().GetFlag(Skill::SpellID::Stealth) &&
|
||||
false == pTempTarget->GetEnchantInfo().GetFlag(Skill::SpellID::Invincible) &&
|
||||
false == pTempTarget->GetEnchantInfo().GetFlag(Skill::SpellID::Hide))
|
||||
{
|
||||
const float fDX = pTempTarget->GetCurrentPos().m_fPointX - GetCurrentPos().m_fPointX;
|
||||
const float fDZ = pTempTarget->GetCurrentPos().m_fPointZ - GetCurrentPos().m_fPointZ;
|
||||
|
||||
const float fDistance = (fDX * fDX) + (fDZ * fDZ);
|
||||
|
||||
if (fDistance < fSquareSearchRange)
|
||||
{
|
||||
pCurrentTarget = pTempTarget;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pTempTarget = pCell->GetNextAirShip();
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL != pCurrentTarget)
|
||||
{
|
||||
m_Threat.AddToThreatList(pCurrentTarget, 1);
|
||||
m_nCurrentState = CFSM::GetInstance().StateTransition(m_nCurrentState, INPUT_ID_SEEN_PLAYER);
|
||||
}
|
||||
}
|
||||
|
||||
bool CCastleGuard::Dead(CAggresiveCreature* pOffencer)
|
||||
{
|
||||
if (NULL == pOffencer) return false;
|
||||
if (STATE_ID_DIE == m_nCurrentState) return false;
|
||||
|
||||
m_wObjectType = Siege::CASTLE_ARMS_NPC;
|
||||
m_CreatureStatus.m_nNowHP = 0;
|
||||
m_dwLastBehaviorTick = m_dwLastTime = CPulse::GetInstance().GetLastTick();
|
||||
m_lCurrentFrame = FPS;
|
||||
m_bAttacking = false;
|
||||
m_bCasting = false;
|
||||
|
||||
m_nCurrentState = CFSM::GetInstance().StateTransition(m_nCurrentState, INPUT_ID_ZERO_HP);
|
||||
|
||||
// 중계 서버로 패킷 전송
|
||||
GET_SINGLE_DISPATCH(lpDBAgentDispatch, CDBAgentDispatch, CDBAgentDispatch::GetDispatchTable());
|
||||
if (lpDBAgentDispatch)
|
||||
{
|
||||
return GameClientSendPacket::SendCharCastleCmdToDBAgent(lpDBAgentDispatch->GetSendStream(), pOffencer->GetCID(),
|
||||
GetCastleID(), m_dwCID, PktCastleCmd::DESTROY, 0,
|
||||
PktCastleCmd::CASTLE_DESTROY_ARMS, PktBase::NO_SERVER_ERR);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
#ifndef _CASTLE_GUARD_OBJECT_H_
|
||||
#define _CASTLE_GUARD_OBJECT_H_
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Creature/Siege/CastleArms.h>
|
||||
|
||||
using namespace Siege;
|
||||
|
||||
|
||||
class CCastleGuard : public CCastleArms
|
||||
{
|
||||
public:
|
||||
virtual ~CCastleGuard();
|
||||
|
||||
// CSkillMonster 의 기능
|
||||
void NormalBehavior(unsigned long dwTick);
|
||||
void AttackBehavior(unsigned long dwTick);
|
||||
void SearchPlayer(void);
|
||||
|
||||
bool Dead(CAggresiveCreature* pOffencer);
|
||||
|
||||
// 가드는 자동 공격이므로 아래 함수의 구현이 없다.
|
||||
bool AttackCID(CCharacter* lpRideChar, AtType attackType, AtNode& attackNode, unsigned short& wError) { return false; }
|
||||
bool Attack(AtType attackType, unsigned char cDefenderNum, CAggresiveCreature** ppDefenders,
|
||||
unsigned char* cDefenserJudges, unsigned short* wDefenserMPHeal) { return false; }
|
||||
bool MissileAttack(AtType attackType, float fDir, float nRange, float fAngle, char cTargetType) { return false; }
|
||||
|
||||
// Rider 관련 정보
|
||||
bool Ride(unsigned long dwCID) { return false; } // 병기 탑승
|
||||
bool GetOff(unsigned long dwCID) { return false; } // 병기 내림 (중계 서버로 패킷 전송)
|
||||
|
||||
private:
|
||||
CCastleGuard(MonsterCreateInfo& MonsterCreate, const CastleObjectInfo& CastleObject);
|
||||
|
||||
friend class CSiegeObjectMgr;
|
||||
};
|
||||
|
||||
#endif _CASTLE_GUARD_OBJECT_H_
|
||||
@@ -0,0 +1,637 @@
|
||||
#include "stdafx.h"
|
||||
#include "MiningCamp.h"
|
||||
|
||||
#include <Network/Stream/SendStream.h>
|
||||
#include <Network/Packet/WrapPacket.h>
|
||||
#include <Network/Packet/PacketCommand.h>
|
||||
#include <Network/Packet/PacketStruct/CastlePacket.h>
|
||||
|
||||
#include <Network/Dispatch/GameClient/SendCharCastle.h>
|
||||
#include <Network/Dispatch/DBAgent/DBAgentDispatch.h>
|
||||
|
||||
#include <Community/Guild/Guild.h>
|
||||
#include <Community/Guild/GuildMgr.h>
|
||||
|
||||
#include <Item/ItemStructure.h>
|
||||
#include <Item/ItemFactory.h>
|
||||
|
||||
#include <Map/FieldMap/CellManager.h>
|
||||
#include <Map/FieldMap/MineralVeinMgr.h>
|
||||
|
||||
#include <Castle/Castle.h>
|
||||
#include <Castle/CastleMgr.h>
|
||||
#include <Castle/CastleBlessMgr.h>
|
||||
|
||||
|
||||
#include <Utility/Math/Math.h>
|
||||
|
||||
|
||||
CMiningCamp::CMiningCamp(MonsterCreateInfo& MonsterCreate, unsigned long dwCampID, unsigned long dwGID,
|
||||
unsigned long dwHP, unsigned short wObjectType, unsigned char cState,
|
||||
unsigned char cSubState, unsigned char cUpgradeStep, unsigned char cMaterial,
|
||||
unsigned char cSiegeCount, const CampRight& campRight, bool bFullHP)
|
||||
: CCamp(MonsterCreate, dwCampID, dwGID, dwHP, wObjectType, cState, cSubState, cUpgradeStep, cMaterial, cSiegeCount, campRight, bFullHP)
|
||||
{
|
||||
}
|
||||
|
||||
CMiningCamp::~CMiningCamp()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool CMiningCamp::Destroy(unsigned long dwOffencerGID)
|
||||
{
|
||||
CCamp::Destroy(dwOffencerGID);
|
||||
|
||||
CCell* lpCell = CCellManager::GetInstance().GetCell(0,
|
||||
static_cast<unsigned long>(GetCurrentPos().m_fPointX),
|
||||
static_cast<unsigned long>(GetCurrentPos().m_fPointY),
|
||||
static_cast<unsigned long>(GetCurrentPos().m_fPointZ));
|
||||
|
||||
if (NULL == lpCell)
|
||||
{
|
||||
ERRLOG4(g_Log, "CampID:0x%08x 아이템을 드랍할 채굴기의 위치가 이상합니다. X:%.1f, Y:%.1f, Z:%.1f",
|
||||
GetCampID(), GetCurrentPos().m_fPointX, GetCurrentPos().m_fPointY, GetCurrentPos().m_fPointZ);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 임시 광물 드랍
|
||||
MineralInfoMap::iterator itr = m_TemporaryMineralMap.begin();
|
||||
MineralInfoMap::iterator end = m_TemporaryMineralMap.end();
|
||||
|
||||
while (itr != end)
|
||||
{
|
||||
unsigned short wMineralID = itr->first;
|
||||
unsigned short wAmount = itr->second;
|
||||
|
||||
while (wAmount > 0)
|
||||
{
|
||||
Item::CItem* lpItem = Item::CItemFactory::GetInstance().CreateItem( wMineralID );
|
||||
if (NULL == lpItem)
|
||||
{
|
||||
ERRLOG2(g_Log, "CampID:0x%08x 채굴기 드랍 광물 아이템 생성에 실패하였습니다. ItemID:%d", GetCampID(), wMineralID);
|
||||
break;
|
||||
}
|
||||
|
||||
unsigned char cItemNum = lpItem->GetMaxNumOrDurability();
|
||||
if (wAmount < cItemNum)
|
||||
{
|
||||
cItemNum = static_cast<unsigned char>(wAmount);
|
||||
lpItem->SetNumOrDurability(cItemNum);
|
||||
wAmount = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
lpItem->SetNumOrDurability(cItemNum);
|
||||
wAmount -= cItemNum;
|
||||
}
|
||||
|
||||
CCell::ItemInfo itemInfo;
|
||||
const Position Pos(GetCurrentPos().m_fPointX + Math::Random::ComplexRandom(40) - 20,
|
||||
GetCurrentPos().m_fPointY,
|
||||
GetCurrentPos().m_fPointZ + Math::Random::ComplexRandom(40) - 20);
|
||||
|
||||
lpCell->SetItem(Pos, lpItem, 0, dwOffencerGID,
|
||||
(0 == dwOffencerGID) ? CCell::NONE : CCell::GUILD, itemInfo);
|
||||
}
|
||||
|
||||
++itr;
|
||||
}
|
||||
|
||||
// 누적 광물 드랍
|
||||
itr = m_AccumulatedMineralMap.begin();
|
||||
end = m_AccumulatedMineralMap.end();
|
||||
|
||||
while (itr != end)
|
||||
{
|
||||
unsigned short wMineralID = itr->first;
|
||||
unsigned short wAmount = itr->second;
|
||||
|
||||
while (wAmount > 0)
|
||||
{
|
||||
Item::CItem* lpItem = Item::CItemFactory::GetInstance().CreateItem( wMineralID );
|
||||
if (NULL == lpItem)
|
||||
{
|
||||
ERRLOG2(g_Log, "CampID:0x%08x 채굴기 드랍 광물 아이템 생성에 실패하였습니다. ItemID:%d", GetCampID(), wMineralID);
|
||||
break;
|
||||
}
|
||||
|
||||
unsigned char cItemNum = lpItem->GetMaxNumOrDurability();
|
||||
if (wAmount < cItemNum)
|
||||
{
|
||||
cItemNum = static_cast<unsigned char>(wAmount);
|
||||
lpItem->SetNumOrDurability(cItemNum);
|
||||
wAmount = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
lpItem->SetNumOrDurability( cItemNum );
|
||||
wAmount -= cItemNum;
|
||||
}
|
||||
|
||||
CCell::ItemInfo itemInfo;
|
||||
const Position Pos(GetCurrentPos().m_fPointX + Math::Random::ComplexRandom(40) - 20,
|
||||
GetCurrentPos().m_fPointY,
|
||||
GetCurrentPos().m_fPointZ + Math::Random::ComplexRandom(40) - 20);
|
||||
|
||||
lpCell->SetItem(Pos, lpItem, 0, dwOffencerGID,
|
||||
(0 == dwOffencerGID) ? CCell::NONE : CCell::GUILD, itemInfo);
|
||||
}
|
||||
|
||||
++itr;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMiningCamp::OnOff(unsigned char cSubState)
|
||||
{
|
||||
m_cSubState = cSubState;
|
||||
|
||||
if (Siege::MINING_OFF == m_cSubState)
|
||||
{
|
||||
m_cSiegeCount = 0;
|
||||
|
||||
// 임시 광물 날리기
|
||||
m_TemporaryMineralMap.clear();
|
||||
}
|
||||
else if (Siege::MINING_ON == m_cSubState)
|
||||
{
|
||||
m_cSiegeCount = 0;
|
||||
}
|
||||
|
||||
// 해당 진지가 있는 반경 5셀 이내에 전송
|
||||
PktCampCmd pktCC;
|
||||
pktCC.m_dwCID = m_dwCID;
|
||||
pktCC.m_dwCampID = GetCampID();
|
||||
pktCC.m_cState = m_cState;
|
||||
pktCC.m_dwValue1 = m_cSubState;
|
||||
pktCC.m_dwValue2 = Siege::MINING_CAMP_GAIN_COUNT - m_cSiegeCount;
|
||||
pktCC.m_cSubCmd = PktCampCmd::MINING_CAMP_ON_OFF;
|
||||
|
||||
char* szPacket = reinterpret_cast<char *>(&pktCC);
|
||||
if (PacketWrap::WrapCrypt(szPacket, sizeof(PktCampCmd), CmdCampCmd, 0, 0))
|
||||
{
|
||||
// Vincent - 브로드 캐스트 테스트 코드
|
||||
//SendToRadiusCell(szPacket, sizeof(PktCampCmd), CmdCampCmd);
|
||||
SendToRange(Siege::BROADCAST_RADIUS, szPacket, sizeof(PktCampCmd), CmdCampCmd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMiningCamp::GainMineral(unsigned short wMineralID, unsigned short wAmount)
|
||||
{
|
||||
unsigned short wError = PktCampCmd::NO_SERVER_ERR;
|
||||
MineralInfoMap::iterator itr = m_AccumulatedMineralMap.find(wMineralID);
|
||||
|
||||
if ( itr != m_AccumulatedMineralMap.end() )
|
||||
{
|
||||
if ( itr->second >= wAmount )
|
||||
{
|
||||
Guild::CGuild* lpGuild = Guild::CGuildMgr::GetInstance().GetGuild( m_dwGID );
|
||||
if ( lpGuild )
|
||||
{
|
||||
CCharacter* lpMaster = CCreatureManager::GetInstance().GetCharacter( lpGuild->GetMaster().m_dwCID );
|
||||
if ( lpMaster )
|
||||
{
|
||||
unsigned short tempAmount = wAmount;
|
||||
|
||||
while (tempAmount != 0)
|
||||
{
|
||||
Item::CItem* lpItem = Item::CItemFactory::GetInstance().CreateItem(wMineralID);
|
||||
if (NULL == lpItem)
|
||||
{
|
||||
ERRLOG2(g_Log, "CampID:0x%08x 아이템 스크립트에 존재하지 않는 광물을 생성하려 하였습니다. ItemID:%d", GetCampID(), wMineralID);
|
||||
wError = PktCampCmd::SERVER_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
if (true == lpItem->IsSet(Item::DetailData::STACKABLE))
|
||||
{
|
||||
if (lpItem->GetMaxNumOrDurability() > tempAmount)
|
||||
{
|
||||
lpItem->SetNumOrDurability( static_cast<unsigned char>(tempAmount) );
|
||||
tempAmount = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
lpItem->SetNumOrDurability( lpItem->GetMaxNumOrDurability() );
|
||||
tempAmount -= lpItem->GetMaxNumOrDurability();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
--tempAmount;
|
||||
}
|
||||
|
||||
if (false == lpMaster->GiveItem(lpItem))
|
||||
{
|
||||
ERRLOG1(g_Log, "CID:0x%08x 누적 광물 아이템을 받는데 실패하였습니다.", lpGuild->GetMaster().m_dwCID);
|
||||
DELETE_ITEM(lpItem);
|
||||
wError = PktCampCmd::SERVER_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
// GievItem 으로 스택된 경우
|
||||
if (NULL != lpItem)
|
||||
{
|
||||
if (lpItem->IsSet(Item::DetailData::STACKABLE) && 0 == lpItem->GetNumOrDurability())
|
||||
{
|
||||
DELETE_ITEM(lpItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (wError == PktCampCmd::NO_SERVER_ERR)
|
||||
{
|
||||
itr->second -= wAmount;
|
||||
wAmount = itr->second;
|
||||
|
||||
if (0 == itr->second)
|
||||
{
|
||||
m_AccumulatedMineralMap.erase( itr );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ERRLOG1(g_Log, "CID : 0x%08x 길드 마스터가 존재하지 않습니다.", lpGuild->GetMaster().m_dwCID);
|
||||
wError = PktCampCmd::SERVER_ERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ERRLOG1(g_Log, "GID:0x%08x 해당 길드가 존재하지 않습니다.", m_dwGID);
|
||||
wError = PktCampCmd::SERVER_ERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ERRLOG4(g_Log, "지금 누적된 광물수보다 많은 양의 광물을 획득하려 합니다. CampID:0x%08x, MineralID:%d, CurrentAmount:%d, GainAmount:%d",
|
||||
GetCampID(), wMineralID, itr->second, wAmount);
|
||||
wError = PktCampCmd::SERVER_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
// 해당 요새가 있는 반경 5셀 이내에 전송
|
||||
PktCampCmd pktCC;
|
||||
pktCC.m_dwCID = m_dwCID;
|
||||
pktCC.m_dwCampID = GetCampID();
|
||||
pktCC.m_cState = m_cState;
|
||||
pktCC.m_dwValue1 = wMineralID;
|
||||
pktCC.m_dwValue2 = wAmount; // 최종 남아 있는 갯수를 보내준다.
|
||||
pktCC.m_cSubCmd = PktCampCmd::MINING_CAMP_GAIN_MINERAL;
|
||||
|
||||
if (wError == PktCampCmd::SERVER_ERROR)
|
||||
{
|
||||
pktCC.m_dwValue1 = 0;
|
||||
pktCC.m_dwValue2 = 0;
|
||||
}
|
||||
|
||||
char* szPacket = reinterpret_cast<char *>(&pktCC);
|
||||
if (PacketWrap::WrapCrypt(szPacket, sizeof(PktCampCmd), CmdCampCmd, 0, wError))
|
||||
{
|
||||
// Vincent - 브로드 캐스트 테스트 코드
|
||||
//SendToRadiusCell(szPacket, sizeof(PktCampCmd), CmdCampCmd);
|
||||
SendToRange(Siege::BROADCAST_RADIUS, szPacket, sizeof(PktCampCmd), CmdCampCmd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMiningCamp::AddMineral(unsigned char cFlag, const CampMineralInfo& campMineralInfo)
|
||||
{
|
||||
if (campMineralInfo.m_wAmount > 0)
|
||||
{
|
||||
switch (cFlag)
|
||||
{
|
||||
case Siege::ACCUMULATED_MINERAL:
|
||||
{
|
||||
m_AccumulatedMineralMap.insert( std::make_pair(campMineralInfo.m_wMineralID, campMineralInfo.m_wAmount) ).second;
|
||||
}
|
||||
break;
|
||||
|
||||
case Siege::TEMPORARY_MINERAL:
|
||||
{
|
||||
m_TemporaryMineralMap.insert( std::make_pair(campMineralInfo.m_wMineralID, campMineralInfo.m_wAmount) ).second;
|
||||
}
|
||||
break;
|
||||
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMiningCamp::AddMineral(unsigned char cFlag, unsigned short wMineralID, unsigned short wAmount)
|
||||
{
|
||||
switch (cFlag)
|
||||
{
|
||||
case Siege::ACCUMULATED_MINERAL:
|
||||
{
|
||||
MineralInfoMap::iterator pos = m_AccumulatedMineralMap.find( wMineralID );
|
||||
if ( pos != m_AccumulatedMineralMap.end() )
|
||||
{
|
||||
pos->second += wAmount;
|
||||
if ( pos->second > Siege::MAX_MINERAL_NUM )
|
||||
{
|
||||
pos->second = Siege::MAX_MINERAL_NUM;
|
||||
}
|
||||
}
|
||||
else if (wAmount > 0)
|
||||
{
|
||||
m_AccumulatedMineralMap.insert( std::make_pair(wMineralID, wAmount) ).second;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Siege::TEMPORARY_MINERAL:
|
||||
{
|
||||
MineralInfoMap::iterator pos = m_TemporaryMineralMap.find( wMineralID );
|
||||
if ( pos != m_TemporaryMineralMap.end() )
|
||||
{
|
||||
pos->second += wAmount;
|
||||
if ( pos->second > Siege::MAX_MINERAL_NUM )
|
||||
{
|
||||
pos->second = Siege::MAX_MINERAL_NUM;
|
||||
}
|
||||
}
|
||||
else if (wAmount > 0)
|
||||
{
|
||||
m_TemporaryMineralMap.insert( std::make_pair(wMineralID, wAmount) ).second;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default: return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMiningCamp::SendMineralInfo(CSendStream& SendStream, unsigned char cMineralType)
|
||||
{
|
||||
unsigned short wSize = 0;
|
||||
char szBuffer[1024];
|
||||
PktMiningCampMineralInfo* lpPktMineralInfo = reinterpret_cast<PktMiningCampMineralInfo*>(szBuffer);
|
||||
CampMineralInfo* lpCampMineralInfo = reinterpret_cast<CampMineralInfo*>(lpPktMineralInfo + 1);
|
||||
|
||||
lpPktMineralInfo->m_dwCampID = GetCampID();
|
||||
lpPktMineralInfo->m_dwRemainTime = Siege::MINING_CAMP_GAIN_COUNT;
|
||||
lpPktMineralInfo->m_cState = m_cSubState;
|
||||
lpPktMineralInfo->m_cMineralType = cMineralType;
|
||||
|
||||
if ( Siege::MINING_ON == m_cSubState && 0 != m_cSiegeCount )
|
||||
{
|
||||
lpPktMineralInfo->m_dwRemainTime = static_cast<unsigned long>( Siege::MINING_CAMP_GAIN_COUNT - m_cSiegeCount );
|
||||
}
|
||||
|
||||
switch ( cMineralType )
|
||||
{
|
||||
case Siege::ACCUMULATED_MINERAL:
|
||||
{
|
||||
lpPktMineralInfo->m_cNum = static_cast<unsigned char>( m_AccumulatedMineralMap.size() );
|
||||
|
||||
MineralInfoMap::iterator itr = m_AccumulatedMineralMap.begin();
|
||||
MineralInfoMap::iterator end = m_AccumulatedMineralMap.end();
|
||||
|
||||
while (itr != end)
|
||||
{
|
||||
lpCampMineralInfo->m_wMineralID = itr->first;
|
||||
lpCampMineralInfo->m_wAmount = itr->second;
|
||||
|
||||
++itr;
|
||||
++lpCampMineralInfo;
|
||||
|
||||
wSize += sizeof(CampMineralInfo);
|
||||
}
|
||||
|
||||
lpPktMineralInfo->m_wSize = wSize;
|
||||
}
|
||||
break;
|
||||
|
||||
case Siege::TEMPORARY_MINERAL:
|
||||
{
|
||||
lpPktMineralInfo->m_cNum = static_cast<unsigned char>( m_TemporaryMineralMap.size() );
|
||||
|
||||
MineralInfoMap::iterator itr = m_TemporaryMineralMap.begin();
|
||||
MineralInfoMap::iterator end = m_TemporaryMineralMap.end();
|
||||
|
||||
while (itr != end)
|
||||
{
|
||||
lpCampMineralInfo->m_wMineralID = itr->first;
|
||||
lpCampMineralInfo->m_wAmount = itr->second;
|
||||
|
||||
++itr;
|
||||
++lpCampMineralInfo;
|
||||
|
||||
wSize += sizeof(CampMineralInfo);
|
||||
}
|
||||
|
||||
lpPktMineralInfo->m_wSize = wSize;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return SendStream.WrapCompress(szBuffer, static_cast<unsigned short>(sizeof(PktMiningCampMineralInfo) + wSize), CmdMiningCampMineralInfo, 0, 0);
|
||||
}
|
||||
|
||||
unsigned short CMiningCamp::GetMineralNum(unsigned char cFlag, unsigned short wMineralID) const
|
||||
{
|
||||
switch (cFlag)
|
||||
{
|
||||
case Siege::ACCUMULATED_MINERAL:
|
||||
{
|
||||
MineralInfoMap::const_iterator itr = m_AccumulatedMineralMap.find(wMineralID);
|
||||
if (itr != m_AccumulatedMineralMap.end())
|
||||
{
|
||||
return itr->second;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Siege::TEMPORARY_MINERAL:
|
||||
{
|
||||
MineralInfoMap::const_iterator itr = m_TemporaryMineralMap.find(wMineralID);
|
||||
if (itr != m_TemporaryMineralMap.end())
|
||||
{
|
||||
return itr->second;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned short CMiningCamp::GetMineralTypeNum(unsigned char cFlag) const
|
||||
{
|
||||
switch (cFlag)
|
||||
{
|
||||
case Siege::ACCUMULATED_MINERAL:
|
||||
{
|
||||
return static_cast<unsigned short>( m_AccumulatedMineralMap.size() );
|
||||
}
|
||||
break;
|
||||
|
||||
case Siege::TEMPORARY_MINERAL:
|
||||
{
|
||||
return static_cast<unsigned short>( m_TemporaryMineralMap.size() );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void CMiningCamp::ProcessMining(unsigned long dwProcessType)
|
||||
{
|
||||
// 1. 가동중이던 채굴기의 임시 광물에 새로 추가해준다.
|
||||
if ( PktProcessMining::TEMPORARY_PROCESS == dwProcessType )
|
||||
{
|
||||
MineralVeinInfo* lpVeinInfo = CMineralVeinMgr::GetInstance().GetMineralVein(GetCurrentPos().m_fPointX, GetCurrentPos().m_fPointZ);
|
||||
if ( lpVeinInfo && 0 < lpVeinInfo->m_dwNowFertility )
|
||||
{
|
||||
int nMiningCampNum = CMineralVeinMgr::GetInstance().GetMiningCampNum( lpVeinInfo->m_dwVeinColor );
|
||||
if (0 < nMiningCampNum)
|
||||
{
|
||||
MineralInfoList::const_iterator itr = lpVeinInfo->m_lstMineralInfo.begin();
|
||||
MineralInfoList::const_iterator end = lpVeinInfo->m_lstMineralInfo.end();
|
||||
|
||||
unsigned long dwMaxFertility = lpVeinInfo->m_dwMaxFertility;
|
||||
unsigned long dwNowFertility = lpVeinInfo->m_dwNowFertility;
|
||||
float fRate = (float)dwNowFertility / (float)dwMaxFertility;
|
||||
bool bCampMineralChange = false, bCastleMineralChange = false;
|
||||
Castle::CCastle* lpBlessCastle = NULL ;
|
||||
|
||||
while (itr != end)
|
||||
{
|
||||
// 지력에 의해 -_- 나오는 광석의 양이 한정되어있다.
|
||||
// 이값에 의해 나오는 광석은 0이 될수도 있따. 즉 이럴경우 광석이 안나올 확율이 높은 확율로 있다.
|
||||
|
||||
const MineralInfo& tempInfo = (*itr);
|
||||
unsigned short wAmount = static_cast<unsigned short>(
|
||||
Math::Random::ComplexRandom(tempInfo.m_cMax + 1, tempInfo.m_cMin) * fRate / nMiningCampNum );
|
||||
|
||||
if (wAmount > 0)
|
||||
{
|
||||
/*
|
||||
// CASTLE_TODO : 성이 길드 소유가 아니므로 성의 축복 보너스 기능은 막아둔다.
|
||||
// edith 세금 부분 추가 (주석처리 뺐음)
|
||||
// 길드 요새가 성의 축복 영역에 들어있다면, 축복 보너스와 세금 처리를 한다.
|
||||
lpBlessCastle = Castle::CCastleMgr::GetInstance().GetCastleInBlessArea( GetPosition() );
|
||||
if (NULL != lpBlessCastle && 0 != lpBlessCastle->GetGID())
|
||||
{
|
||||
Guild::CGuild* lpGuild = Guild::CGuildMgr::GetInstance().GetGuild( GetGID() );
|
||||
if (NULL != lpGuild && false == lpGuild->IsEnemyGuild(lpBlessCastle->GetGID()))
|
||||
{
|
||||
unsigned char cBlessBonus = Castle::CCastleBlessMgr::GetInstance().GetBonusPercent(
|
||||
lpBlessCastle->GetTotalGainTaxCount(), lpBlessCastle->GetUpgradeStep());
|
||||
|
||||
// 성의 축복 보너스 만큼 더해준다.
|
||||
unsigned short wBlessBonusAmount = static_cast<unsigned short>(wAmount * (cBlessBonus / 100.0f));
|
||||
wBlessBonusAmount = std::max(wBlessBonusAmount, static_cast<unsigned short>(1));
|
||||
|
||||
// 성에 길드 요새 광물 세금을 낸다.
|
||||
unsigned short wCastleTaxAmount = static_cast<unsigned short>(wAmount * (lpBlessCastle->GetTax(Castle::CAMP_MINERAL_TAX) / 100.0f));
|
||||
wCastleTaxAmount = std::max(wCastleTaxAmount, static_cast<unsigned short>(1));
|
||||
|
||||
wAmount += wBlessBonusAmount;
|
||||
wCastleTaxAmount = std::min(wCastleTaxAmount, wAmount);
|
||||
wAmount -= wCastleTaxAmount;
|
||||
|
||||
bCastleMineralChange = true;
|
||||
lpBlessCastle->AddMineral(Siege::TEMPORARY_MINERAL, tempInfo.m_dwMineralID, wCastleTaxAmount);
|
||||
}
|
||||
}
|
||||
//
|
||||
*/
|
||||
if (wAmount > 0)
|
||||
{
|
||||
bCampMineralChange = true;
|
||||
AddMineral(Siege::TEMPORARY_MINERAL, tempInfo.m_dwMineralID, wAmount);
|
||||
}
|
||||
}
|
||||
|
||||
++itr;
|
||||
}
|
||||
|
||||
// 중계 서버로 패킷 전송
|
||||
GET_SINGLE_DISPATCH(lpDBAgentDispatch, CDBAgentDispatch, CDBAgentDispatch::GetDispatchTable());
|
||||
if (0 == lpDBAgentDispatch)
|
||||
{
|
||||
ERRLOG0(g_Log, "에이전트 얻기 실패.");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bCampMineralChange)
|
||||
{
|
||||
// 임시 광물에 추가 될 경우에 DB 중계 서버로 임시 광물 정보 보내기
|
||||
SendMineralInfo(lpDBAgentDispatch->GetSendStream(), Siege::TEMPORARY_MINERAL);
|
||||
}
|
||||
|
||||
if (bCastleMineralChange && NULL != lpBlessCastle)
|
||||
{
|
||||
// 임시 광물 세금이 추가 될 경우에 DB 중계 서버로 임시 광물 세금 정보 보내기
|
||||
lpBlessCastle->SendMineralInfo(lpDBAgentDispatch->GetSendStream(), Siege::TEMPORARY_MINERAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 2. 7일이 지난 채굴기의 임시 광물을 누적 광물로 옮겨준다. (임시 광물 삭제)
|
||||
if ( PktProcessMining::ACCUMULATED_PROCESS == dwProcessType )
|
||||
{
|
||||
++m_cSiegeCount ;
|
||||
|
||||
if ( m_cSiegeCount >= Siege::MINING_CAMP_GAIN_COUNT )
|
||||
{
|
||||
MineralInfoMap::iterator itr = m_TemporaryMineralMap.begin();
|
||||
MineralInfoMap::iterator end = m_TemporaryMineralMap.end();
|
||||
|
||||
while (itr != end)
|
||||
{
|
||||
AddMineral(Siege::ACCUMULATED_MINERAL, itr->first, itr->second);
|
||||
++itr;
|
||||
}
|
||||
|
||||
m_cSiegeCount = 0;
|
||||
m_TemporaryMineralMap.clear();
|
||||
|
||||
// 중계 서버로 패킷 전송
|
||||
GET_SINGLE_DISPATCH(lpDBAgentDispatch, CDBAgentDispatch, CDBAgentDispatch::GetDispatchTable());
|
||||
if (0 == lpDBAgentDispatch)
|
||||
{
|
||||
ERRLOG0(g_Log, "에이전트 얻기 실패.");
|
||||
}
|
||||
else
|
||||
{
|
||||
// 중계 서버로 채굴 완료 메세지 전송
|
||||
GameClientSendPacket::SendCharCampMessageToDBAgent(lpDBAgentDispatch->GetSendStream(), GetCampID(),
|
||||
PktCampMessage::MSGCMD_MINING_END, PktBase::NO_SERVER_ERR);
|
||||
|
||||
// DB 중계 서버로 임시 광물 및 누적 광물 리스트 보내기
|
||||
SendMineralInfo(lpDBAgentDispatch->GetSendStream(), Siege::TEMPORARY_MINERAL);
|
||||
SendMineralInfo(lpDBAgentDispatch->GetSendStream(), Siege::ACCUMULATED_MINERAL);
|
||||
}
|
||||
|
||||
/*
|
||||
// 길드 마스터에게 누적 광물 정보 보내기
|
||||
Guild::CGuild* lpGuild = Guild::CGuildMgr::GetInstance().GetGuild( m_dwGID );
|
||||
if ( lpGuild )
|
||||
{
|
||||
CCharacter* lpMaster = CCreatureManager::GetInstance().GetCharacter( lpGuild->GetMaster().m_dwCID );
|
||||
if ( lpMaster && lpMaster->GetDispatcher() )
|
||||
{
|
||||
SendMineralInfo(lpMaster->GetDispatcher()->GetSendStream(), Siege::ACCUMULATED_MINERAL);
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
#ifndef _MINING_CAMP_H_
|
||||
#define _MINING_CAMP_H_
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <Creature/Siege/Camp.h>
|
||||
#include <Network/Packet/PacketStruct/CastlePacket.h>
|
||||
|
||||
using namespace Siege;
|
||||
|
||||
class CSendStream;
|
||||
|
||||
class CMiningCamp : public CCamp
|
||||
{
|
||||
public:
|
||||
virtual ~CMiningCamp();
|
||||
|
||||
typedef std::map<unsigned short, unsigned short> MineralInfoMap; // <wMineralID, wAmount>
|
||||
|
||||
void ProcessMining(unsigned long dwProcessType);
|
||||
|
||||
bool Destroy(unsigned long dwOffencerGID = 0); // 채굴기 파괴 완료시 처리
|
||||
|
||||
bool OnOff(unsigned char cSubState);
|
||||
bool GainMineral(unsigned short wMineralID, unsigned short wAmount);
|
||||
|
||||
bool AddMineral(unsigned char cFlag, const CampMineralInfo& campMineralInfo);
|
||||
bool AddMineral(unsigned char cFlag, unsigned short wMineralID, unsigned short wAmount);
|
||||
|
||||
unsigned short GetMineralNum(unsigned char cFlag, unsigned short wMineralID) const;
|
||||
unsigned short GetMineralTypeNum(unsigned char cFlag) const;
|
||||
|
||||
// 광물 정보 전송
|
||||
bool SendMineralInfo(CSendStream& SendStream, unsigned char cMineralType=Siege::ACCUMULATED_MINERAL);
|
||||
|
||||
protected:
|
||||
|
||||
CMiningCamp(MonsterCreateInfo& MonsterCreate, unsigned long dwCampID, unsigned long dwGID,
|
||||
unsigned long dwHP, unsigned short wObjectType, unsigned char cState, unsigned char cSubState,
|
||||
unsigned char cUpgradeStep, unsigned char cMaterial, unsigned char cSiegeCount,
|
||||
const CampRight& campRight, bool bFullHP);
|
||||
|
||||
|
||||
MineralInfoMap m_AccumulatedMineralMap;
|
||||
MineralInfoMap m_TemporaryMineralMap;
|
||||
|
||||
friend class CSiegeObjectMgr;
|
||||
};
|
||||
|
||||
#endif // _MINING_CAMP_H_
|
||||
@@ -0,0 +1,297 @@
|
||||
#include "stdafx.h"
|
||||
#include "SerializeSiegeObjectData.h"
|
||||
#include <Creature/Siege/SiegeObject.h>
|
||||
|
||||
|
||||
BroadCastSiege::CSerializeSiegeObjectData::CSerializeSiegeObjectData() :
|
||||
m_wBroadCastDataLen(0), m_wDeltaBroadCastDataLen(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
BroadCastSiege::CSerializeSiegeObjectData::~CSerializeSiegeObjectData()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
BroadCastSiege::CSerializeSiegeObjectData::Initialize( const CSiegeObject& siegeObject )
|
||||
{
|
||||
// Data 얻어오기
|
||||
sOwnerShipInfo ownerShipInfo;
|
||||
ownerShipInfo.m_dwCampOrCastleID = siegeObject.GetCampID();
|
||||
ownerShipInfo.m_dwOwnerCID = siegeObject.GetOwnerID();
|
||||
ownerShipInfo.m_dwGID = siegeObject.GetGID();
|
||||
ownerShipInfo.m_cNation = siegeObject.GetNation();
|
||||
|
||||
sStateInfo stateInfo;
|
||||
stateInfo.m_wObjectType = siegeObject.GetObjectType();
|
||||
stateInfo.m_cState = siegeObject.GetState();
|
||||
stateInfo.m_cSubState = siegeObject.GetSubState();
|
||||
stateInfo.m_cUpgradeStep = siegeObject.GetUpgradeStep();
|
||||
stateInfo.m_cUpgradeType = siegeObject.GetUpgradeType();
|
||||
|
||||
sHPInfo hpInfo;
|
||||
hpInfo.m_dwNowHP = siegeObject.GetNowHP();
|
||||
hpInfo.m_dwMaxHP = siegeObject.GetMaxHP();
|
||||
|
||||
sPosInfo posInfo;
|
||||
const Position& pos = siegeObject.GetPosition();
|
||||
const MotionInfo& motionInfo = siegeObject.GetMotionInfo();
|
||||
posInfo.m_fDefaultDir = siegeObject.GetDefaultDir();
|
||||
posInfo.m_NetworkPos = CNetworkPos( pos.m_fPointX, pos.m_fPointY, pos.m_fPointZ, motionInfo.m_fDirection,
|
||||
(0 == motionInfo.m_dwFrame) ? 0.0f : motionInfo.m_fVelocity / motionInfo.m_dwFrame );
|
||||
|
||||
sMaterialInfo materialInfo;
|
||||
materialInfo.m_cMaterial = siegeObject.GetMaterialNum();
|
||||
|
||||
sRiderInfo riderInfo;
|
||||
std::fill_n(&riderInfo.m_dwRiderID[0], int(Siege::AIRSHIP_RIDER_NUM), 0);
|
||||
siegeObject.GetRiders( riderInfo.m_dwRiderID );
|
||||
|
||||
// 얻어온 Data 로 초기화
|
||||
m_LastSiegeObjectData.SetOwnerShipInfo( ownerShipInfo );
|
||||
m_LastSiegeObjectData.SetStateInfo( stateInfo );
|
||||
m_LastSiegeObjectData.SetHPInfo( hpInfo );
|
||||
m_LastSiegeObjectData.SetPosInfo( posInfo );
|
||||
m_LastSiegeObjectData.SetMaterialInfo( materialInfo );
|
||||
m_LastSiegeObjectData.SetRiderInfo( riderInfo );
|
||||
|
||||
// BroadCast 버퍼 셋팅
|
||||
PrepareData( siegeObject );
|
||||
}
|
||||
|
||||
|
||||
// ==================================================================================
|
||||
// Data 를 셋팅
|
||||
void
|
||||
BroadCastSiege::CSerializeSiegeObjectData::PrepareData( const CSiegeObject& siegeObject )
|
||||
{
|
||||
PrepareBroadCastData( siegeObject );
|
||||
PrepareDeltaData( siegeObject );
|
||||
}
|
||||
|
||||
void
|
||||
BroadCastSiege::CSerializeSiegeObjectData::PrepareBroadCastData( const CSiegeObject& siegeObject )
|
||||
{
|
||||
assert( CSiegeObjectData::EstimateBufferSize(0xFFFFFFFF) < MAX_SIEGEOBJECT_DATA_SIZE && "MAX_SIEGEOBJECT_DATA_SIZE 를 늘려주세요!" );
|
||||
|
||||
m_wBroadCastDataLen = 0;
|
||||
char* szDataPos = m_aryBroadCastData;
|
||||
|
||||
// UpdateDataFlag 복사 (모든 Data 를 보낸다.)
|
||||
unsigned long dwUpdateFlag = 0xFFFFFFFF;
|
||||
COPY_AND_ADVANCE_DST( szDataPos, &dwUpdateFlag, sizeof(unsigned long) );
|
||||
|
||||
// 소유권 정보 복사
|
||||
sOwnerShipInfo ownerShipInfo;
|
||||
ownerShipInfo.m_dwCampOrCastleID = siegeObject.GetCampID();
|
||||
ownerShipInfo.m_dwOwnerCID = siegeObject.GetOwnerID();
|
||||
ownerShipInfo.m_dwGID = siegeObject.GetGID();
|
||||
ownerShipInfo.m_cNation = siegeObject.GetNation();
|
||||
COPY_AND_ADVANCE_DST( szDataPos, &ownerShipInfo, sizeof(sOwnerShipInfo) );
|
||||
|
||||
// 상태 정보 복사
|
||||
sStateInfo stateInfo;
|
||||
stateInfo.m_wObjectType = siegeObject.GetObjectType();
|
||||
stateInfo.m_cState = siegeObject.GetState();
|
||||
stateInfo.m_cSubState = siegeObject.GetSubState();
|
||||
stateInfo.m_cUpgradeStep = siegeObject.GetUpgradeStep();
|
||||
stateInfo.m_cUpgradeType = siegeObject.GetUpgradeType();
|
||||
COPY_AND_ADVANCE_DST( szDataPos, &stateInfo, sizeof(sStateInfo) );
|
||||
|
||||
// HP 정보 복사
|
||||
sHPInfo hpInfo;
|
||||
hpInfo.m_dwNowHP = siegeObject.GetNowHP();
|
||||
hpInfo.m_dwMaxHP = siegeObject.GetMaxHP();
|
||||
COPY_AND_ADVANCE_DST( szDataPos, &hpInfo, sizeof(sHPInfo) );
|
||||
|
||||
// 위치 정보 복사
|
||||
sPosInfo posInfo;
|
||||
const Position& pos = siegeObject.GetPosition();
|
||||
const MotionInfo& motionInfo = siegeObject.GetMotionInfo();
|
||||
|
||||
/*float fY = pos.m_fPointY;
|
||||
if ( siegeObject.IsSiegeArms() && Siege::AIRSHIP != siegeObject.GetObjectType() )
|
||||
{
|
||||
fY = 0.0f;
|
||||
}*/
|
||||
|
||||
posInfo.m_fDefaultDir = siegeObject.GetDefaultDir();
|
||||
posInfo.m_NetworkPos = CNetworkPos( pos.m_fPointX, pos.m_fPointY, pos.m_fPointZ, motionInfo.m_fDirection,
|
||||
(0 == motionInfo.m_dwFrame) ? 0.0f : motionInfo.m_fVelocity / motionInfo.m_dwFrame );
|
||||
COPY_AND_ADVANCE_DST( szDataPos, &posInfo, sizeof(sPosInfo) );
|
||||
|
||||
// 자재 정보 복사
|
||||
sMaterialInfo materialInfo;
|
||||
materialInfo.m_cMaterial = siegeObject.GetMaterialNum();
|
||||
COPY_AND_ADVANCE_DST( szDataPos, &materialInfo, sizeof(sMaterialInfo) );
|
||||
|
||||
// 탑승자 정보 복사
|
||||
sRiderInfo riderInfo;
|
||||
std::fill_n(&riderInfo.m_dwRiderID[0], int(Siege::AIRSHIP_RIDER_NUM), 0);
|
||||
siegeObject.GetRiders( riderInfo.m_dwRiderID );
|
||||
COPY_AND_ADVANCE_DST( szDataPos, &riderInfo, sizeof(sRiderInfo) );
|
||||
|
||||
// 데이터 길이를 구한다.
|
||||
m_wBroadCastDataLen = static_cast<unsigned short>( szDataPos - m_aryBroadCastData );
|
||||
}
|
||||
|
||||
void
|
||||
BroadCastSiege::CSerializeSiegeObjectData::PrepareDeltaData( const CSiegeObject& siegeObject )
|
||||
{
|
||||
assert( CSiegeObjectData::EstimateBufferSize(0xFFFFFFFF) < MAX_SIEGEOBJECT_DATA_SIZE && "MAX_SIEGEOBJECT_DATA_SIZE 를 늘려주세요!" );
|
||||
|
||||
// 데이터를 비교해서 Delta를 구한다.
|
||||
m_wDeltaBroadCastDataLen = 0;
|
||||
char* szDataPos = m_aryDeltaBroadCastData;
|
||||
|
||||
// UpdateFlag 는 복사할 위치를 기억해두고, 최종적으로 기록한다.
|
||||
unsigned long dwDeltaUpdateFlag = 0;
|
||||
char* szUpdateFlagCopyPos = szDataPos;
|
||||
szDataPos += sizeof(unsigned long);
|
||||
|
||||
// 소유권 정보 비교 및 복사
|
||||
if ( m_LastSiegeObjectData.GetCampID() != siegeObject.GetCampID() ||
|
||||
m_LastSiegeObjectData.GetOwnerCID() != siegeObject.GetOwnerID() ||
|
||||
m_LastSiegeObjectData.GetGID() != siegeObject.GetGID() ||
|
||||
m_LastSiegeObjectData.GetNation() != siegeObject.GetNation() )
|
||||
{
|
||||
sOwnerShipInfo ownerShipInfo;
|
||||
ownerShipInfo.m_dwCampOrCastleID = siegeObject.GetCampID();
|
||||
ownerShipInfo.m_dwOwnerCID = siegeObject.GetOwnerID();
|
||||
ownerShipInfo.m_dwGID = siegeObject.GetGID();
|
||||
ownerShipInfo.m_cNation = siegeObject.GetNation();
|
||||
|
||||
COPY_AND_ADVANCE_DST( szDataPos, &ownerShipInfo, sizeof(sOwnerShipInfo) );
|
||||
dwDeltaUpdateFlag |= DELTA_OWNERSHIP;
|
||||
|
||||
m_LastSiegeObjectData.SetOwnerShipInfo( ownerShipInfo );
|
||||
}
|
||||
|
||||
// 상태 정보 비교 및 복사
|
||||
if ( m_LastSiegeObjectData.GetObjectType() != siegeObject.GetObjectType() ||
|
||||
m_LastSiegeObjectData.GetState() != siegeObject.GetState() ||
|
||||
m_LastSiegeObjectData.GetSubState() != siegeObject.GetSubState() ||
|
||||
m_LastSiegeObjectData.GetUpgradeStep() != siegeObject.GetUpgradeStep() ||
|
||||
m_LastSiegeObjectData.GetUpgradeType() != siegeObject.GetUpgradeType() )
|
||||
{
|
||||
sStateInfo stateInfo;
|
||||
stateInfo.m_wObjectType = siegeObject.GetObjectType();
|
||||
stateInfo.m_cState = siegeObject.GetState();
|
||||
stateInfo.m_cSubState = siegeObject.GetSubState();
|
||||
stateInfo.m_cUpgradeStep = siegeObject.GetUpgradeStep();
|
||||
stateInfo.m_cUpgradeType = siegeObject.GetUpgradeType();
|
||||
|
||||
COPY_AND_ADVANCE_DST( szDataPos, &stateInfo, sizeof(sStateInfo) );
|
||||
dwDeltaUpdateFlag |= DELTA_STATE;
|
||||
|
||||
m_LastSiegeObjectData.SetStateInfo( stateInfo );
|
||||
}
|
||||
|
||||
// HP 정보 비교 및 복사
|
||||
if ( m_LastSiegeObjectData.GetNowHP() != siegeObject.GetNowHP() ||
|
||||
m_LastSiegeObjectData.GetMaxHP() != siegeObject.GetMaxHP() )
|
||||
{
|
||||
sHPInfo hpInfo;
|
||||
hpInfo.m_dwNowHP = siegeObject.GetNowHP();
|
||||
hpInfo.m_dwMaxHP = siegeObject.GetMaxHP();
|
||||
|
||||
COPY_AND_ADVANCE_DST( szDataPos, &hpInfo, sizeof(sHPInfo) );
|
||||
dwDeltaUpdateFlag |= DELTA_HP;
|
||||
|
||||
m_LastSiegeObjectData.SetHPInfo( hpInfo );
|
||||
}
|
||||
|
||||
// 위치 정보 비교 및 복사
|
||||
const MotionInfo& motionInfo = siegeObject.GetMotionInfo();
|
||||
CNetworkPos netPos = CNetworkPos( siegeObject.GetCurrentPos().m_fPointX, siegeObject.GetCurrentPos().m_fPointY,
|
||||
siegeObject.GetCurrentPos().m_fPointZ, motionInfo.m_fDirection,
|
||||
(0 == motionInfo.m_dwFrame) ? 0.0f : motionInfo.m_fVelocity / motionInfo.m_dwFrame );
|
||||
|
||||
// Code by By Minbobo
|
||||
if( (netPos!=m_LastSiegeObjectData.GetNetworkPos()) ||
|
||||
(m_LastSiegeObjectData.GetDefaultDir()!=siegeObject.GetDefaultDir()) )
|
||||
{
|
||||
sPosInfo posInfo;
|
||||
const Position& pos = siegeObject.GetPosition();
|
||||
float fY = pos.m_fPointY;
|
||||
|
||||
if ( siegeObject.IsSiegeArms() && Siege::AIRSHIP != siegeObject.GetObjectType() )
|
||||
{
|
||||
fY = 0.0f;
|
||||
}
|
||||
|
||||
posInfo.m_fDefaultDir = siegeObject.GetDefaultDir();
|
||||
posInfo.m_NetworkPos = CNetworkPos( pos.m_fPointX, fY, pos.m_fPointZ, motionInfo.m_fDirection,
|
||||
(0 == motionInfo.m_dwFrame) ? 0.0f : motionInfo.m_fVelocity / motionInfo.m_dwFrame );
|
||||
|
||||
COPY_AND_ADVANCE_DST( szDataPos, &posInfo, sizeof(sPosInfo) );
|
||||
dwDeltaUpdateFlag |= DELTA_POS;
|
||||
|
||||
posInfo.m_NetworkPos = netPos;
|
||||
m_LastSiegeObjectData.SetPosInfo( posInfo );
|
||||
}
|
||||
|
||||
/*if ( (m_LastSiegeObjectData.GetDefaultDir() - siegeObject.GetDefaultDir()) > FLOAT_EPSILON ||
|
||||
(m_LastSiegeObjectData.GetNetworkPos().GetXPos() - netPos.GetXPos()) > FLOAT_EPSILON ||
|
||||
(m_LastSiegeObjectData.GetNetworkPos().GetYPos() - netPos.GetYPos()) > FLOAT_EPSILON ||
|
||||
(m_LastSiegeObjectData.GetNetworkPos().GetZPos() - netPos.GetZPos()) > FLOAT_EPSILON )
|
||||
{
|
||||
sPosInfo posInfo;
|
||||
const Position& pos = siegeObject.GetPosition();
|
||||
float fY = pos.m_fPointY;
|
||||
if ( siegeObject.IsSiegeArms() && Siege::AIRSHIP != siegeObject.GetObjectType() )
|
||||
{
|
||||
fY = 0.0f;
|
||||
}
|
||||
posInfo.m_fDefaultDir = siegeObject.GetDefaultDir();
|
||||
posInfo.m_NetworkPos = CNetworkPos( pos.m_fPointX, fY, pos.m_fPointZ, motionInfo.m_fDirection,
|
||||
(0 == motionInfo.m_dwFrame) ? 0.0f : motionInfo.m_fVelocity / motionInfo.m_dwFrame );
|
||||
|
||||
COPY_AND_ADVANCE_DST( szDataPos, &posInfo, sizeof(sPosInfo) );
|
||||
dwDeltaUpdateFlag |= DELTA_POS;
|
||||
|
||||
posInfo.m_NetworkPos = netPos;
|
||||
m_LastSiegeObjectData.SetPosInfo( posInfo );
|
||||
}*/
|
||||
|
||||
// 자재 정보 비교 및 복사
|
||||
if ( m_LastSiegeObjectData.GetMaterialNum() != siegeObject.GetMaterialNum() )
|
||||
{
|
||||
sMaterialInfo materialInfo;
|
||||
materialInfo.m_cMaterial = siegeObject.GetMaterialNum();
|
||||
|
||||
COPY_AND_ADVANCE_DST( szDataPos, &materialInfo, sizeof(sMaterialInfo) );
|
||||
dwDeltaUpdateFlag |= DELTA_MATERIAL;
|
||||
|
||||
m_LastSiegeObjectData.SetMaterialInfo( materialInfo );
|
||||
}
|
||||
|
||||
// 탑승자 정보 비교 및 복사
|
||||
unsigned long dwRiders[ Siege::AIRSHIP_RIDER_NUM ];
|
||||
std::fill_n(dwRiders, int(Siege::AIRSHIP_RIDER_NUM), 0);
|
||||
siegeObject.GetRiders( dwRiders );
|
||||
if ( !m_LastSiegeObjectData.IsSameRiders( dwRiders ) )
|
||||
{
|
||||
sRiderInfo riderInfo;
|
||||
std::fill_n(&riderInfo.m_dwRiderID[0], int(Siege::AIRSHIP_RIDER_NUM), 0);
|
||||
siegeObject.GetRiders( riderInfo.m_dwRiderID );
|
||||
|
||||
COPY_AND_ADVANCE_DST( szDataPos, &riderInfo, sizeof(sRiderInfo) );
|
||||
dwDeltaUpdateFlag |= DELTA_RIDER;
|
||||
|
||||
m_LastSiegeObjectData.SetRiders( riderInfo.m_dwRiderID );
|
||||
}
|
||||
|
||||
// 복사 완료 및 데이터 길이 계산.
|
||||
memcpy( szUpdateFlagCopyPos, &dwDeltaUpdateFlag, sizeof(unsigned long) );
|
||||
m_wDeltaBroadCastDataLen = static_cast<unsigned short>( szDataPos - m_aryDeltaBroadCastData);
|
||||
|
||||
// 변경된것이 없다면,
|
||||
if ( 0 == dwDeltaUpdateFlag )
|
||||
{
|
||||
m_wDeltaBroadCastDataLen = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
#ifndef __SERIALIZE_SIEGEOBJECT_DATA_H__
|
||||
#define __SERIALIZE_SIEGEOBJECT_DATA_H__
|
||||
|
||||
#include "BroadCastSiegeObjectData.h"
|
||||
|
||||
// 전방 참조
|
||||
class CSiegeObject;
|
||||
|
||||
namespace BroadCastSiege
|
||||
{
|
||||
class CSerializeSiegeObjectData
|
||||
{
|
||||
public:
|
||||
CSerializeSiegeObjectData();
|
||||
~CSerializeSiegeObjectData();
|
||||
|
||||
// ==================================================================================
|
||||
// 초기화
|
||||
void Initialize( const CSiegeObject& siegeObject );
|
||||
|
||||
// ==================================================================================
|
||||
// Data 를 셋팅
|
||||
void PrepareData( const CSiegeObject& siegeObject );
|
||||
|
||||
void PrepareBroadCastData( const CSiegeObject& siegeObject );
|
||||
void PrepareDeltaData( const CSiegeObject& siegeObject );
|
||||
void ClearDeltaData() { m_wDeltaBroadCastDataLen = 0; }
|
||||
|
||||
// ==================================================================================
|
||||
// Get 함수
|
||||
const CSiegeObjectData& GetSiegeObjectData() { return m_LastSiegeObjectData; }
|
||||
|
||||
const char* GetBroadCastData() { return m_aryBroadCastData; }
|
||||
unsigned short GetBroadCastDataLen() { return m_wBroadCastDataLen; }
|
||||
|
||||
const char* GetDeltaData() { return m_aryDeltaBroadCastData; }
|
||||
unsigned short GetDeltaDataLen() { return m_wDeltaBroadCastDataLen; }
|
||||
|
||||
private:
|
||||
CSiegeObjectData m_LastSiegeObjectData;
|
||||
|
||||
unsigned short m_wBroadCastDataLen;
|
||||
unsigned short m_wDeltaBroadCastDataLen;
|
||||
|
||||
char m_aryBroadCastData[ MAX_SIEGEOBJECT_DATA_SIZE ];
|
||||
char m_aryDeltaBroadCastData[ MAX_SIEGEOBJECT_DATA_SIZE ];
|
||||
};
|
||||
}
|
||||
|
||||
#endif __SERIALIZE_SIEGEOBJECT_DATA_H__
|
||||
@@ -0,0 +1,879 @@
|
||||
#include "stdafx.h"
|
||||
#include "SiegeArms.h"
|
||||
|
||||
#include <Skill/SkillTable.h>
|
||||
#include <Skill/SkillMgr.h>
|
||||
|
||||
#include <Utility/Math/Math.h>
|
||||
|
||||
#include <Item/Item.h>
|
||||
#include <Item/ItemFactory.h>
|
||||
|
||||
#include <Map/FieldMap/CellManager.h>
|
||||
#include <Map/Duelmap/DuelCellManager.h>
|
||||
|
||||
#include <Network/Packet/WrapPacket.h>
|
||||
#include <Network/Packet/PacketCommand.h>
|
||||
#include <Network/Packet/PacketStruct/ServerInfo.h>
|
||||
|
||||
#include <Network/Dispatch/GameClient/GameClientDispatch.h>
|
||||
#include <Network/Dispatch/GameClient/SendCharItem.h>
|
||||
#include <Network/Dispatch/GameClient/SendCharCastle.h>
|
||||
#include <Network/Dispatch/GameClient/SendCharAttack.h>
|
||||
#include <Network/Dispatch/DBAgent/DBAgentDispatch.h>
|
||||
#include <Network/Dispatch/DBAgent/DBAgentRequest.h>
|
||||
|
||||
#include <Network/ClientSocket/ClientConstants.h>
|
||||
|
||||
|
||||
|
||||
|
||||
CSiegeArms::CSiegeArms(MonsterCreateInfo& MonsterCreate, unsigned long dwOwnerID, unsigned char cNation,
|
||||
unsigned long dwHP, unsigned short wObjectType, unsigned char cState,
|
||||
unsigned char cUpgradeStep)
|
||||
: CSiegeObject(MonsterCreate, dwOwnerID, cNation, dwHP, wObjectType, cState, cUpgradeStep)
|
||||
{
|
||||
}
|
||||
|
||||
CSiegeArms::~CSiegeArms()
|
||||
{
|
||||
}
|
||||
|
||||
bool CSiegeArms::AttackCID(CCharacter* lpRideChar, AtType attackType, AtNode& attackNode, unsigned short& wError)
|
||||
{
|
||||
PERFORMANCE_CHECK(FunctionTimingCheck);
|
||||
|
||||
if (NULL == lpRideChar || m_CreatureStatus.m_nNowHP == 0)
|
||||
{
|
||||
wError = PktAtAck::FAIL_ALREADY_DEAD;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (0 == (attackType.m_wType & AtType::SKILL_BIT))
|
||||
{
|
||||
wError = PktAtAck::FAIL_NOT_SIEGE_ATTACK;
|
||||
return false;
|
||||
}
|
||||
|
||||
const Skill::ProtoType* pThisSkill = CSkillMgr::GetInstance().GetSkillProtoType(attackType.m_wType);
|
||||
if (NULL == pThisSkill)
|
||||
{
|
||||
ERRLOG2(g_Log, "CID:0x%08x 존재하지 않는 스킬 아이디입니다. Skill ID:0x%04x", m_dwCID, attackType.m_wType);
|
||||
return false;
|
||||
}
|
||||
|
||||
const unsigned short wLockCount = GetSkillLockCount(attackType.m_wType);
|
||||
if (wLockCount < 0 || wLockCount >= CSkillMgr::MAX_SKILL_LOCKCOUNT)
|
||||
{
|
||||
ERRLOG3(g_Log, "CID:0x%08x 쓰려는 스킬의 락카운트가 이상합니다. SkillType : 0x%04x, LockCount : %d",
|
||||
m_dwCID, attackType.m_wType, wLockCount);
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned char cDefenderNum = attackNode.m_wDefenserNum > AtNode::MAX_DEFENDER_NUM ?
|
||||
AtNode::MAX_DEFENDER_NUM : attackNode.m_wDefenserNum; // 최대 방어자 수 제한
|
||||
|
||||
CAggresiveCreature* lpAggresiveCreature[AtNode::MAX_DEFENDER_NUM] = {0, };
|
||||
unsigned short wDefenserMPHeal[AtNode::MAX_DEFENDER_NUM] = {0, };
|
||||
char cTargetType = Skill::Target::ENEMY;
|
||||
|
||||
if (0 == cDefenderNum)
|
||||
{
|
||||
if (0 != attackType.m_cMissileAttack)
|
||||
{
|
||||
return MissileAttack(attackType, 0, pThisSkill[attackType.m_cSkillLockCount].m_fEffectExtent,
|
||||
Math::Const::PI * 2, cTargetType);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 캐스팅에 실패한 경우
|
||||
return Attack(attackType, cDefenderNum, lpAggresiveCreature, attackNode.m_cDefenserJudge, wDefenserMPHeal);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (0 == pThisSkill[wLockCount].m_fMaxRange && 0 == pThisSkill[attackType.m_cSkillLockCount].m_fEffectExtent)
|
||||
{
|
||||
if (m_dwCID != attackNode.m_dwDefenser[0])
|
||||
{
|
||||
ERRLOG2(g_Log, "CID:0x%08x 자기자신에게만 쓸 수 있는 스킬입니다. SkillID:0x%04x",
|
||||
m_dwCID, attackType.m_wType);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 공성병기는 몬스터를 공격할수 없다.
|
||||
Creature::CreatureType eCreatureType = Creature::GetCreatureType(attackNode.m_dwDefenser[0]);
|
||||
if (Creature::CT_MONSTER == eCreatureType || Creature::CT_STRUCT == eCreatureType)
|
||||
{
|
||||
wError = PktAtAck::FAIL_TO_MONSTER;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 스킬 거리 체크
|
||||
CAggresiveCreature* lpTargetCreature = NULL;
|
||||
|
||||
// Target Creature 얻어오기
|
||||
if (0 != GetMapIndex())
|
||||
{
|
||||
lpTargetCreature = CCreatureManager::GetInstance().GetAggresiveCreature(attackNode.m_dwDefenser[0]);
|
||||
if (lpTargetCreature && lpTargetCreature->GetMapIndex() != GetMapIndex()) lpTargetCreature = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
lpTargetCreature = CCreatureManager::GetInstance().GetAggresiveCreature(attackNode.m_dwDefenser[0]);
|
||||
}
|
||||
|
||||
// Target Creature 처리하기
|
||||
if (NULL != lpTargetCreature)
|
||||
{
|
||||
float fSquareTargetDistance = (m_CurrentPos.m_fPointX - lpTargetCreature->GetCurrentPos().m_fPointX) *
|
||||
(m_CurrentPos.m_fPointX - lpTargetCreature->GetCurrentPos().m_fPointX) +
|
||||
(m_CurrentPos.m_fPointZ - lpTargetCreature->GetCurrentPos().m_fPointZ) *
|
||||
(m_CurrentPos.m_fPointZ - lpTargetCreature->GetCurrentPos().m_fPointZ);
|
||||
|
||||
float fSquareEffectDistance = (pThisSkill[wLockCount].m_fMaxRange + Skill::ERROR_OF_DISTANCE) *
|
||||
(pThisSkill[wLockCount].m_fMaxRange + Skill::ERROR_OF_DISTANCE);
|
||||
|
||||
if (fSquareTargetDistance > fSquareEffectDistance)
|
||||
{
|
||||
wError = PktAtAck::FAIL_TOO_FAR;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (pThisSkill[attackType.m_cSkillLockCount].m_eTargetType == Skill::Target::FRIEND ||
|
||||
pThisSkill[attackType.m_cSkillLockCount].m_eTargetType == Skill::Target::DEAD_FRIEND ||
|
||||
pThisSkill[attackType.m_cSkillLockCount].m_eTargetType == Skill::Target::FRIEND_EXCEPT_SELF ||
|
||||
pThisSkill[attackType.m_cSkillLockCount].m_eTargetType == Skill::Target::FRIEND_OBJECT ||
|
||||
pThisSkill[attackType.m_cSkillLockCount].m_eTargetType == Skill::Target::PARTY ||
|
||||
pThisSkill[attackType.m_cSkillLockCount].m_eTargetType == Skill::Target::SUMMON)
|
||||
{
|
||||
//cTargetType = Skill::Target::FRIEND;
|
||||
wError = PktAtAck::FAIL_FRIENDLY_ATTACK;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 클라이언트가 넘겨준 타겟들을 체크한다. (범위 마법에 걸리는 타겟은 따로 체크)
|
||||
for (unsigned char cDefender = 0; cDefender < cDefenderNum; ++cDefender)
|
||||
{
|
||||
// Target Creature 얻기
|
||||
CAggresiveCreature* lpCreature = NULL;
|
||||
|
||||
Creature::CreatureType eCreatureType = Creature::GetCreatureType(attackNode.m_dwDefenser[cDefender]);
|
||||
if (Creature::CT_MONSTER == eCreatureType || Creature::CT_STRUCT == eCreatureType)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
lpCreature = CCreatureManager::GetInstance().GetAggresiveCreature(attackNode.m_dwDefenser[cDefender]);
|
||||
if (lpCreature && lpCreature->GetMapIndex() != GetMapIndex())
|
||||
{
|
||||
lpCreature = NULL;
|
||||
}
|
||||
|
||||
if (NULL != lpCreature)
|
||||
{
|
||||
// 긍정적인 공격(-_-)
|
||||
if (Skill::Target::FRIEND == cTargetType)
|
||||
{
|
||||
wError = PktAtAck::FAIL_FRIENDLY_ATTACK;
|
||||
return false;
|
||||
}
|
||||
// 부정적인 공격(진짜 공격)
|
||||
else
|
||||
{
|
||||
// 자기를 중심으로 하는 범위형 스킬의 경우 타겟을 자신으로 세팅합니다.
|
||||
// (이 경우 this는 MultiAttack() 함수가 타켓에서 제외시켜 줍니다.)
|
||||
if (EnemyCheck::EC_ENEMY == IsEnemy(lpCreature) || lpCreature == this)
|
||||
{
|
||||
lpAggresiveCreature[cDefender] = lpCreature;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (0 == cDefenderNum || NULL == lpAggresiveCreature[0])
|
||||
{
|
||||
return Attack(attackType, cDefenderNum, lpAggresiveCreature, attackNode.m_cDefenserJudge, wDefenserMPHeal);
|
||||
}
|
||||
|
||||
// 범위 마법 체크
|
||||
if (0 != pThisSkill[attackType.m_cSkillLockCount].m_fEffectExtent)
|
||||
{
|
||||
if (Skill::Target::PARTY == pThisSkill[attackType.m_cSkillLockCount].m_eTargetType)
|
||||
{
|
||||
wError = PktAtAck::FAIL_FRIENDLY_ATTACK;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CAggresiveCreature::MultiAttack(attackType, cDefenderNum, lpAggresiveCreature, attackNode.m_cDefenserJudge,
|
||||
lpAggresiveCreature[0]->GetCurrentPos(), 0, pThisSkill[attackType.m_cSkillLockCount].m_fEffectExtent,
|
||||
Math::Const::PI * 2, cTargetType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Attack(attackType, cDefenderNum, lpAggresiveCreature, attackNode.m_cDefenserJudge, wDefenserMPHeal);
|
||||
}
|
||||
|
||||
bool CSiegeArms::Attack(AtType attackType, unsigned char cDefenderNum, CAggresiveCreature** ppDefenders, unsigned char* cDefenserJudges, unsigned short* wDefenserMPHeal)
|
||||
{
|
||||
if (m_CreatureStatus.m_nNowHP == 0)
|
||||
{
|
||||
ERRLOG1(g_Log, "CID:0x%08x 죽은 공성 오브젝트가 공격하려고 하였습니다.", m_dwCID);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cDefenderNum > AtNode::MAX_DEFENDER_NUM)
|
||||
{
|
||||
ERRLOG2(g_Log, "CID:0x%08x 공성 오브젝트가 공격할 때, 방어자의 숫자가 최대 방어자 숫자를 넘었습니다. 방어자수 : %d",
|
||||
m_dwCID, cDefenderNum);
|
||||
cDefenderNum = AtNode::MAX_DEFENDER_NUM;
|
||||
}
|
||||
|
||||
if (0 == (attackType.m_wType & AtType::SKILL_BIT) && 0 == cDefenderNum)
|
||||
{
|
||||
ERRLOG0(g_Log, "스킬이 아닌 일반 공격은, 반드시 타겟이 있을 경우에만 서버로 보내야 합니다.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (0 != (attackType.m_wType & AtType::SKILL_BIT))
|
||||
{
|
||||
const Skill::ProtoType* pSkillProtoType = CSkillMgr::GetInstance().GetSkillProtoType(attackType.m_wType);
|
||||
if (NULL == pSkillProtoType)
|
||||
{
|
||||
ERRLOG2(g_Log, "CID:0x%08x 존재하지 않는 스킬 아이디입니다. Skill ID:0x%04x", m_dwCID, attackType.m_wType);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ( IsRidable() )
|
||||
{
|
||||
CCharacter* lpRider = CCreatureManager::GetInstance().GetCharacter(m_dwRiderCID);
|
||||
if (!lpRider)
|
||||
{
|
||||
ERRLOG2(g_Log, "CID:0x%08x 공성 오브젝트에 타고있는 캐릭터가 없습니다. RiderCID : 0x%08x", m_dwCID, m_dwRiderCID);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 공격시 무적 상태가 풀린다.
|
||||
lpRider->GetSpellMgr().GetAffectedInfo().RemoveEnchantBySpellType(Skill::SpellID::Invincible);
|
||||
}
|
||||
|
||||
unsigned char cOffencerJudge = 0;
|
||||
unsigned short wOffencerMPHeal = 0;
|
||||
unsigned short wError = PktAtAck::NO_SERVER_ERR;
|
||||
|
||||
const int MAX_BUFFER = sizeof(PktAtAck) + AtNode::MAX_DEFENDER_NUM * sizeof(DefenserNode);
|
||||
char szBuffer[MAX_BUFFER];
|
||||
|
||||
PktAtAck* lpPktAtAck = reinterpret_cast<PktAtAck*>(szBuffer);
|
||||
DefenserNode* lpDefenserNode = reinterpret_cast<DefenserNode*>(lpPktAtAck + 1);
|
||||
|
||||
m_cConsumeMPCount = std::min(cDefenderNum, unsigned char(AtNode::MAX_MONSTER_DEFENDER_NUM));
|
||||
|
||||
unsigned char cDefender = 0;
|
||||
unsigned char cIndex = 0;
|
||||
|
||||
for (; cIndex < cDefenderNum; ++cIndex)
|
||||
{
|
||||
// MP 소모 타이밍까지의 카운트 (범위 마법은 한 번만 MP 소모)
|
||||
--m_cConsumeMPCount;
|
||||
|
||||
if (NULL == ppDefenders[cIndex])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (0 == ppDefenders[cIndex]->GetStatus().m_nNowHP)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// 최대 방어자 수 제한 (몬스터는 캐릭터와는 별도 처리)
|
||||
Creature::CreatureType eCreatureType = Creature::GetCreatureType(ppDefenders[cIndex]->GetCID());
|
||||
if (Creature::CT_MONSTER == eCreatureType || Creature::CT_STRUCT == eCreatureType)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO : 공격 방향을 설정해줍시다.
|
||||
cDefenserJudges[cDefender] = ClientConstants::Judge_Front;
|
||||
wDefenserMPHeal[cDefender] = 0;
|
||||
|
||||
const unsigned short nPrevHP = ppDefenders[cIndex]->GetStatus().m_nNowHP;
|
||||
const unsigned short nPrevMP = ppDefenders[cIndex]->GetStatus().m_nNowMP;
|
||||
|
||||
const unsigned short wPrevAttackerHP = m_CreatureStatus.m_nNowHP;
|
||||
|
||||
// 대미지 반영
|
||||
lpDefenserNode[cDefender].m_wDamage = ppDefenders[cIndex]->ApplyDamage(attackType, this, cOffencerJudge,
|
||||
cDefenserJudges[cDefender], wOffencerMPHeal, wDefenserMPHeal[cDefender], wError);
|
||||
|
||||
const unsigned short nNowHP = ppDefenders[cIndex]->GetStatus().m_nNowHP;
|
||||
const unsigned short nNowMP = ppDefenders[cIndex]->GetStatus().m_nNowMP;
|
||||
|
||||
// 스킬에 의한 자살 방지
|
||||
if (0 == m_CreatureStatus.m_nNowHP)
|
||||
{
|
||||
m_CreatureStatus.m_nNowHP = wPrevAttackerHP;
|
||||
wError = PktAtAck::FAIL_SUICIDE;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Creature::CT_PC == Creature::GetCreatureType(ppDefenders[cIndex]->GetCID()))
|
||||
{
|
||||
CCharacter* lpDefendCharacter = (CCharacter *)ppDefenders[cIndex];
|
||||
|
||||
CMonster* lpSummonee = lpDefendCharacter->GetSummonee();
|
||||
if (NULL != lpSummonee)
|
||||
{
|
||||
lpSummonee->GuardMe(this, lpDefenserNode[cDefender].m_wDamage);
|
||||
}
|
||||
|
||||
lpDefendCharacter->CalculateEquipDurability((ClientConstants::Judge_Guard == cDefenserJudges[cDefender]) ?
|
||||
AtType::GUARD : AtType::DEFENCE);
|
||||
|
||||
CGameClientDispatch* lpDispatch = lpDefendCharacter->GetDispatcher();
|
||||
if (NULL != lpDispatch)
|
||||
{
|
||||
GameClientSendPacket::SendCharAttacked(lpDispatch->GetSendStream(), this, lpDefendCharacter,
|
||||
attackType, m_MotionInfo.m_fDirection, lpDefenserNode[cDefender].m_wDamage,
|
||||
cDefenserJudges[cDefender], wDefenserMPHeal[cDefender], PktBase::NO_SERVER_ERR);
|
||||
}
|
||||
}
|
||||
|
||||
// 공격 패킷 만들기
|
||||
lpDefenserNode[cDefender].m_dwCharID = ppDefenders[cIndex]->GetCID();
|
||||
lpDefenserNode[cDefender].m_sCurrHP = nNowHP;
|
||||
lpDefenserNode[cDefender].m_sCurrMP = nNowMP;
|
||||
lpDefenserNode[cDefender].m_wMaxHP = ppDefenders[cIndex]->GetStatus().m_StatusInfo.m_nMaxHP;
|
||||
lpDefenserNode[cDefender].m_wMaxMP = ppDefenders[cIndex]->GetStatus().m_StatusInfo.m_nMaxMP;
|
||||
lpDefenserNode[cDefender].m_wMPHeal = wDefenserMPHeal[cDefender];
|
||||
|
||||
lpDefenserNode[cDefender].m_cJudge = cDefenserJudges[cDefender];
|
||||
}
|
||||
|
||||
++cDefender;
|
||||
}
|
||||
|
||||
if (0 != (attackType.m_wType & AtType::SKILL_BIT))
|
||||
{
|
||||
if (0 == cDefender)
|
||||
{
|
||||
Skill::CFunctions::ConsumeMP(attackType, this, 0);
|
||||
}
|
||||
}
|
||||
|
||||
lpPktAtAck->m_dwCharID = m_dwCID;
|
||||
lpPktAtAck->m_AtType = attackType;
|
||||
|
||||
lpPktAtAck->m_wHP = m_CreatureStatus.m_nNowHP;
|
||||
lpPktAtAck->m_wMP = m_CreatureStatus.m_nNowMP;
|
||||
lpPktAtAck->m_wMPHeal = wOffencerMPHeal;
|
||||
|
||||
lpPktAtAck->m_cJudge = cOffencerJudge;
|
||||
lpPktAtAck->m_cDefenserNum = cDefender;
|
||||
|
||||
if ( IsRidable() )
|
||||
{
|
||||
CCharacter* lpRider = CCreatureManager::GetInstance().GetCharacter(m_dwRiderCID);
|
||||
if (lpRider && lpRider->GetDispatcher())
|
||||
{
|
||||
CSendStream& SendStream = (lpRider->GetDispatcher())->GetSendStream();
|
||||
if (true == SendStream.WrapCompress(
|
||||
szBuffer, sizeof(PktAtAck) + cDefender * sizeof(DefenserNode), CmdCharAttack, 0, wError) &&
|
||||
PktBase::NO_SERVER_ERR == wError)
|
||||
{
|
||||
CCell* lpCell = GetCellPos().m_lpCell;
|
||||
if (lpCell)
|
||||
{
|
||||
lpCell->SendAttackInfo(m_dwCID, attackType, cDefender, lpDefenserNode);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CCell* lpCell = GetCellPos().m_lpCell;
|
||||
if (lpCell)
|
||||
{
|
||||
lpCell->SendAttackInfo(m_dwCID, attackType, cDefender, lpDefenserNode);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool CSiegeArms::MissileAttack(AtType attackType, float fDir, float nRange, float fAngle, char cTargetType)
|
||||
{
|
||||
if (Siege::LONG_RANGE_SIEGE_ARMS != m_wObjectType)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CCell* lpCell = NULL;
|
||||
|
||||
// 듀얼 상태라면 듀얼 셀로 처리
|
||||
if(CServerSetup::GetInstance().GetDuelModeCheck() && NULL != GetDuelOpponent())
|
||||
{
|
||||
lpCell = CDuelCellManager::GetInstance().GetCell(GetCID());
|
||||
}
|
||||
else
|
||||
{
|
||||
lpCell = CCellManager::GetInstance().GetCell(m_CellPos.m_wMapIndex,
|
||||
static_cast<unsigned long>(attackType.m_DstPos.fPointX),
|
||||
static_cast<unsigned long>(attackType.m_DstPos.fPointY),
|
||||
static_cast<unsigned long>(attackType.m_DstPos.fPointZ));
|
||||
}
|
||||
|
||||
if (NULL == lpCell)
|
||||
{
|
||||
ERRLOG0(g_Log, "CID:0x%08x 공격 목표 지점의 셀이 존재하지 않습니다.");
|
||||
return false;
|
||||
}
|
||||
|
||||
CAggresiveCreature* ppDefenders[AtNode::MAX_DEFENDER_NUM] = {0, };
|
||||
unsigned char cDefenserJudges[AtNode::MAX_DEFENDER_NUM] = {0, };
|
||||
unsigned short wDefenserMPHeal[AtNode::MAX_DEFENDER_NUM] = {0, };
|
||||
int nDefenderNum = 0;
|
||||
|
||||
for (int nDirection = 0; nDirection < CCell::CONNECT_NUM && nDefenderNum < AtNode::MAX_DEFENDER_NUM; ++nDirection)
|
||||
{
|
||||
CCell* lpConnectCell = lpCell->GetConnectCell(nDirection);
|
||||
if (NULL == lpConnectCell)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
CAggresiveCreature* lpTempTarget = lpConnectCell->GetFirstAggresiveCreature();
|
||||
|
||||
// 타겟이 없거나, 방어자 수가 최대가 되면, 루프를 빠져나갑니다.
|
||||
while (NULL != lpTempTarget && nDefenderNum < AtNode::MAX_DEFENDER_NUM)
|
||||
{
|
||||
// 공격에 대한 예외상황
|
||||
bool bException = false;
|
||||
|
||||
// 병기에 탑승한 캐릭터는 공격하지 않는다. 대신 병기를 공격한다.
|
||||
if (Creature::CT_PC == Creature::GetCreatureType(lpTempTarget->GetCID()))
|
||||
{
|
||||
CCharacter* lpRideChar = reinterpret_cast<CCharacter*>(lpTempTarget);
|
||||
if (true == lpRideChar->IsRideArms())
|
||||
{
|
||||
bException = true;
|
||||
}
|
||||
}
|
||||
|
||||
EnemyCheck::EnemyType eTargetType = IsEnemy(lpTempTarget);
|
||||
if ((EnemyCheck::EC_NEUTRAL == eTargetType) ||
|
||||
(Skill::Target::FRIEND == cTargetType && EnemyCheck::EC_ENEMY == eTargetType) ||
|
||||
(Skill::Target::ENEMY == cTargetType && EnemyCheck::EC_FRIEND == eTargetType))
|
||||
{
|
||||
bException = true;
|
||||
}
|
||||
|
||||
// 겹치는 게 있으면 처리하지 않는다.
|
||||
for (int nIndex = 0; nIndex < nDefenderNum; nIndex++)
|
||||
{
|
||||
if (ppDefenders[nIndex] == lpTempTarget)
|
||||
{
|
||||
bException = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (false == bException)
|
||||
{
|
||||
const float fDX = lpTempTarget->GetCurrentPos().m_fPointX - attackType.m_DstPos.fPointX;
|
||||
const float fDZ = lpTempTarget->GetCurrentPos().m_fPointZ - attackType.m_DstPos.fPointZ;
|
||||
const float fDistance = (fDX * fDX) + (fDZ * fDZ);
|
||||
|
||||
const float fSquareAttackRange = nRange * nRange;
|
||||
|
||||
if (fDistance <= fSquareAttackRange)
|
||||
{
|
||||
const float fTempfDir = CalcDir2D(attackType.m_DstPos.fPointX, attackType.m_DstPos.fPointZ,
|
||||
lpTempTarget->GetCurrentPos().m_fPointX, lpTempTarget->GetCurrentPos().m_fPointZ);
|
||||
const float fDifference = (fTempfDir >= fDir) ? (fTempfDir-fDir) : (fDir-fTempfDir);
|
||||
|
||||
if (fDifference <= fAngle && 0 < lpTempTarget->GetStatus().m_nNowHP)
|
||||
{
|
||||
ppDefenders[nDefenderNum] = lpTempTarget;
|
||||
cDefenserJudges[nDefenderNum] = ClientConstants::Judge_Front;
|
||||
wDefenserMPHeal[nDefenderNum] = 0;
|
||||
++nDefenderNum;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lpTempTarget = lpConnectCell->GetNextAggresiveCreature();
|
||||
}
|
||||
}
|
||||
|
||||
if (AtNode::MAX_DEFENDER_NUM < nDefenderNum)
|
||||
{
|
||||
SERLOG0(g_Log, "스택 오버런 : 방어자수가 최대치를 넘어셨습니다.");
|
||||
}
|
||||
|
||||
return Attack(attackType, nDefenderNum, ppDefenders, cDefenserJudges, wDefenserMPHeal);
|
||||
}
|
||||
|
||||
|
||||
bool CSiegeArms::Dead(CAggresiveCreature* pOffencer)
|
||||
{
|
||||
if (NULL == pOffencer) return false;
|
||||
if (STATE_ID_DIE == m_nCurrentState) return false;
|
||||
|
||||
m_CreatureStatus.m_nNowHP = 0;
|
||||
m_dwLastBehaviorTick = m_dwLastTime = CPulse::GetInstance().GetLastTick();
|
||||
m_lCurrentFrame = FPS;
|
||||
m_bAttacking = false;
|
||||
m_bCasting = false;
|
||||
|
||||
// 타고 있던 캐릭터는 죽는다.
|
||||
if (0 != m_dwRiderCID)
|
||||
{
|
||||
CCharacter* lpRider = CCreatureManager::GetInstance().GetCharacter(m_dwRiderCID);
|
||||
if (lpRider)
|
||||
{
|
||||
lpRider->GetOff();
|
||||
lpRider->Kill(pOffencer);
|
||||
}
|
||||
|
||||
m_dwRiderCID = 0;
|
||||
}
|
||||
|
||||
// 크리쳐 매니져에서 삭제 (해당 셀에서도 삭제한다.)
|
||||
CCreatureManager::GetInstance().DeleteCreature(m_dwCID);
|
||||
|
||||
// 중계 서버로 패킷 전송
|
||||
GET_SINGLE_DISPATCH(lpDBAgentDispatch, CDBAgentDispatch, CDBAgentDispatch::GetDispatchTable());
|
||||
if (lpDBAgentDispatch)
|
||||
{
|
||||
return GameClientSendPacket::SendCharSiegeArmsCmdToDBAgent(lpDBAgentDispatch->GetSendStream(), 0, m_dwCID,
|
||||
0, PktSiegeArmsCmd::SIEGE_DESTROY_ARMS,
|
||||
PktSiegeArmsCmd::NO_SERVER_ERR);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool CSiegeArms::ToStarterKit(bool bMaterial)
|
||||
{
|
||||
unsigned short wItemProtoTypeID;
|
||||
|
||||
switch (m_wObjectType)
|
||||
{
|
||||
case Siege::SHORT_RANGE_SIEGE_ARMS: wItemProtoTypeID = Item::EtcItemID::SHORT_RANGE_ARMS_KIT_ID; break;
|
||||
case Siege::LONG_RANGE_SIEGE_ARMS: wItemProtoTypeID = Item::EtcItemID::LONG_RANGE_ARMS_KIT_ID; break;
|
||||
case Siege::AIRSHIP: wItemProtoTypeID = Item::EtcItemID::AIRSHIP_KIT_ID; break;
|
||||
}
|
||||
|
||||
// 스타트킷 아이템 생성
|
||||
Item::CItem* lpItem = Item::CItemFactory::GetInstance().CreateItem(wItemProtoTypeID);
|
||||
|
||||
if (NULL == lpItem)
|
||||
{
|
||||
ERRLOG0(g_Log, "길드 요새 생성 스타트킷 아이템 생성에 실패했습니다.");
|
||||
return false;
|
||||
}
|
||||
|
||||
CCharacter* lpCharacter = CCreatureManager::GetInstance().GetCharacter( m_dwOwnerID );
|
||||
|
||||
if (NULL != lpCharacter)
|
||||
{
|
||||
if (false == lpCharacter->GiveItem(lpItem))
|
||||
{
|
||||
ERRLOG0(g_Log, "길드 요새 생성 스타트킷을 돌려주는데 실패하였습니다.");
|
||||
|
||||
DELETE_ITEM(lpItem);
|
||||
return false;
|
||||
}
|
||||
|
||||
// GievItem 으로 스택된 경우
|
||||
if (lpItem->IsSet(Item::DetailData::STACKABLE) && 0 == lpItem->GetNumOrDurability())
|
||||
{
|
||||
DELETE_ITEM(lpItem);
|
||||
}
|
||||
|
||||
if(bMaterial)
|
||||
{
|
||||
GiveBackSiegeMaterial();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 우선 임시로 주석 처리.
|
||||
|
||||
if(bMaterial)
|
||||
{
|
||||
GiveBackSiegeMaterial();
|
||||
}
|
||||
|
||||
// 바닥에 아이템 떨어뜨리기
|
||||
CCell::ItemInfo itemInfo;
|
||||
GetCellPos().m_lpCell->SetItem(GetCurrentPos(), lpItem, 0, 0, CCell::NONE, itemInfo);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSiegeArms::GiveBackSiegeMaterial()
|
||||
{
|
||||
// 업그레이드에 따른 갯수 설정
|
||||
unsigned char cNum = 0;
|
||||
|
||||
const CMonsterMgr::MonsterProtoType* lpProtoType = CMonsterMgr::GetInstance().GetMonsterProtoType(m_wObjectType);
|
||||
|
||||
if (lpProtoType)
|
||||
{
|
||||
cNum = Siege::SIEGE_ARMS_UPGRADE_MATERIAL_NUM / 2;
|
||||
}
|
||||
|
||||
if (cNum > 0)
|
||||
{
|
||||
// 자재 아이템 돌려주기
|
||||
Item::CItem* lpMaterial = Item::CItemFactory::GetInstance().CreateItem(Item::EtcItemID::SIEGE_MATERIAL_ID);
|
||||
|
||||
if (NULL == lpMaterial)
|
||||
{
|
||||
ERRLOG0(g_Log, "공성 병기 제작용 자재 아이템 생성에 실패했습니다.");
|
||||
return false;
|
||||
}
|
||||
|
||||
lpMaterial->SetNumOrDurability(cNum);
|
||||
|
||||
CCharacter* lpCharacter = CCreatureManager::GetInstance().GetCharacter(m_dwOwnerID);
|
||||
|
||||
if (NULL != lpCharacter)
|
||||
{
|
||||
if (false == lpCharacter->GiveItem(lpMaterial))
|
||||
{
|
||||
ERRLOG0(g_Log, "공성 병기 제작용 자재를 돌려주는데 실패하였습니다.");
|
||||
|
||||
DELETE_ITEM(lpMaterial);
|
||||
return false;
|
||||
}
|
||||
|
||||
// GievItem 으로 스택된 경우
|
||||
if (lpMaterial->IsSet(Item::DetailData::STACKABLE) && 0 == lpMaterial->GetNumOrDurability())
|
||||
{
|
||||
DELETE_ITEM(lpMaterial);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CCell::ItemInfo itemInfo;
|
||||
GetCellPos().m_lpCell->SetItem(GetCurrentPos(), lpMaterial, 0, 0, CCell::NONE, itemInfo);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned short CSiegeArms::GetRepairMaterialNum()
|
||||
{
|
||||
unsigned long dwHp = m_CreatureStatus.m_StatusInfo.m_nMaxHP - m_CreatureStatus.m_nNowHP;
|
||||
unsigned long dwPerHp = m_CreatureStatus.m_StatusInfo.m_nMaxHP/Siege::SIEGE_ARMS_REPAIR_HP_PER_MATERIAL;
|
||||
unsigned short wNum = static_cast<unsigned short>(dwHp / dwPerHp);
|
||||
|
||||
if((dwHp%dwPerHp)!=0)
|
||||
{
|
||||
wNum++;
|
||||
}
|
||||
|
||||
return wNum;
|
||||
}
|
||||
|
||||
bool CSiegeArms::Build(unsigned char cUpgradeStep)
|
||||
{
|
||||
m_cState = Siege::COMPLETE;
|
||||
m_cUpgradeStep = cUpgradeStep;
|
||||
|
||||
UpdateObjectInfo();
|
||||
|
||||
// 공성 병기가 있는 반경 5셀 이내에 전송
|
||||
PktSiegeArmsCmd pktSAC;
|
||||
pktSAC.m_dwCID = GetOwnerID();
|
||||
pktSAC.m_dwArmsID = m_dwCID;
|
||||
pktSAC.m_cState = m_cState;
|
||||
pktSAC.m_dwValue = m_cUpgradeStep;
|
||||
pktSAC.m_cSubCmd = PktSiegeArmsCmd::SIEGE_CREATE_ARMS_COMPLETE;
|
||||
|
||||
char* szPacket = reinterpret_cast<char *>(&pktSAC);
|
||||
if (PacketWrap::WrapCrypt(szPacket, sizeof(PktSiegeArmsCmd), CmdSiegeArmsCmd, 0, 0))
|
||||
{
|
||||
// Vincent - 브로드 캐스트 테스트 코드
|
||||
//SendToRadiusCell(szPacket, sizeof(PktSiegeArmsCmd), CmdSiegeArmsCmd);
|
||||
SendToRange(Siege::BROADCAST_RADIUS, szPacket, sizeof(PktSiegeArmsCmd), CmdSiegeArmsCmd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSiegeArms::Repair(unsigned short wRepairHP)
|
||||
{
|
||||
m_cState = Siege::COMPLETE;
|
||||
UpdateObjectInfo(Siege::REPAIR_HP, wRepairHP);
|
||||
|
||||
// 공성 병기가 있는 반경 5셀 이내에 전송
|
||||
PktSiegeArmsCmd pktSAC;
|
||||
pktSAC.m_dwCID = GetOwnerID();
|
||||
pktSAC.m_dwArmsID = m_dwCID;
|
||||
pktSAC.m_cState = m_cState;
|
||||
pktSAC.m_dwValue = m_CreatureStatus.m_nNowHP;
|
||||
pktSAC.m_cSubCmd = PktSiegeArmsCmd::SIEGE_REPAIR_ARMS_COMPLETE;
|
||||
|
||||
char* szPacket = reinterpret_cast<char *>(&pktSAC);
|
||||
if (PacketWrap::WrapCrypt(szPacket, sizeof(PktSiegeArmsCmd), CmdSiegeArmsCmd, 0, 0))
|
||||
{
|
||||
// Vincent - 브로드 캐스트 테스트 코드
|
||||
//SendToRadiusCell(szPacket, sizeof(PktSiegeArmsCmd), CmdSiegeArmsCmd);
|
||||
SendToRange(Siege::BROADCAST_RADIUS, szPacket, sizeof(PktSiegeArmsCmd), CmdSiegeArmsCmd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSiegeArms::Destroy(unsigned char cOffencerNation, bool bTakeGold)
|
||||
{
|
||||
m_cState = Siege::DESTROYED;
|
||||
m_cUpgradeStep = 0;
|
||||
m_CreatureStatus.m_nNowHP = 0;
|
||||
|
||||
// 공성 병기가 있는 반경 5셀 이내에 전송
|
||||
PktSiegeArmsCmd pktSAC;
|
||||
pktSAC.m_dwCID = GetOwnerID();
|
||||
pktSAC.m_dwArmsID = m_dwCID;
|
||||
pktSAC.m_cState = m_cState;
|
||||
pktSAC.m_dwValue = m_cUpgradeStep;
|
||||
pktSAC.m_cSubCmd = PktSiegeArmsCmd::SIEGE_DESTROY_ARMS;
|
||||
|
||||
// CreatureManager 에서 삭제
|
||||
CCreatureManager::GetInstance().DeleteCreature(m_dwCID);
|
||||
|
||||
char* szPacket = reinterpret_cast<char *>(&pktSAC);
|
||||
if (PacketWrap::WrapCrypt(szPacket, sizeof(PktSiegeArmsCmd), CmdSiegeArmsCmd, 0, 0))
|
||||
{
|
||||
// Vincent - 브로드 캐스트 테스트 코드
|
||||
//SendToRadiusCell(szPacket, sizeof(PktSiegeArmsCmd), CmdSiegeArmsCmd);
|
||||
SendToRange(Siege::BROADCAST_RADIUS, szPacket, sizeof(PktSiegeArmsCmd), CmdSiegeArmsCmd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSiegeArms::Update(unsigned char cState, unsigned long dwValue1, unsigned long dwValue2, unsigned long dwNoValue, unsigned char cSubCmd)
|
||||
{
|
||||
m_cState = cState;
|
||||
|
||||
UpdateObjectInfo();
|
||||
|
||||
// 공성 병기가 있는 반경 5셀 이내에 전송
|
||||
PktSiegeArmsCmd pktSAC;
|
||||
pktSAC.m_dwCID = GetOwnerID();
|
||||
pktSAC.m_dwArmsID = m_dwCID;
|
||||
pktSAC.m_cState = m_cState;
|
||||
pktSAC.m_dwValue = dwValue1;
|
||||
pktSAC.m_cSubCmd = cSubCmd;
|
||||
|
||||
char* szPacket = reinterpret_cast<char *>(&pktSAC);
|
||||
if (PacketWrap::WrapCrypt(szPacket, sizeof(PktSiegeArmsCmd), CmdSiegeArmsCmd, 0, 0))
|
||||
{
|
||||
// Vincent - 브로드 캐스트 테스트 코드
|
||||
//SendToRadiusCell(szPacket, sizeof(PktSiegeArmsCmd), CmdSiegeArmsCmd);
|
||||
SendToRange(Siege::BROADCAST_RADIUS, szPacket, sizeof(PktSiegeArmsCmd), CmdSiegeArmsCmd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CSiegeArms::Ride(unsigned long dwCID)
|
||||
{
|
||||
if (0 == m_dwRiderCID)
|
||||
{
|
||||
CCharacter* lpRider = CCreatureManager::GetInstance().GetCharacter(dwCID);
|
||||
if (lpRider && dwCID == m_dwOwnerID)
|
||||
{
|
||||
m_dwRiderCID = dwCID;
|
||||
lpRider->Ride(m_dwCID);
|
||||
lpRider->SkillClear();
|
||||
|
||||
// 부하가 크면 게임서버에로 시간 체크 루틴을 옮겨오도록 수정하자!!
|
||||
// 중계 서버로 패킷 전송 (시간 체크때문에...)
|
||||
GET_SINGLE_DISPATCH(lpDBAgentDispatch, CDBAgentDispatch, CDBAgentDispatch::GetDispatchTable());
|
||||
if (lpDBAgentDispatch)
|
||||
{
|
||||
GameClientSendPacket::SendCharSiegeArmsCmdToDBAgent(lpDBAgentDispatch->GetSendStream(), dwCID, m_dwCID,
|
||||
0, PktSiegeArmsCmd::SIEGE_RIDE_ARMS, PktBase::NO_SERVER_ERR);
|
||||
}
|
||||
|
||||
// Ride 함수 자체에서 클라이언트에게 패킷을 보내준다.
|
||||
PktSiegeArmsCmd pktSAC;
|
||||
pktSAC.m_dwCID = GetOwnerID();
|
||||
pktSAC.m_dwArmsID = m_dwCID;
|
||||
pktSAC.m_cState = m_cState;
|
||||
pktSAC.m_dwValue = dwCID;
|
||||
pktSAC.m_cSubCmd = PktSiegeArmsCmd::SIEGE_RIDE_ARMS;
|
||||
|
||||
char* szPacket = reinterpret_cast<char *>(&pktSAC);
|
||||
if (PacketWrap::WrapCrypt(szPacket, sizeof(PktSiegeArmsCmd), CmdSiegeArmsCmd, 0, 0))
|
||||
{
|
||||
SendToRange(Siege::BROADCAST_RADIUS, szPacket, sizeof(PktSiegeArmsCmd), CmdSiegeArmsCmd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CSiegeArms::GetOff(unsigned long dwCID)
|
||||
{
|
||||
if (Siege::NOT_RIDER != IsRider(dwCID))
|
||||
{
|
||||
CCharacter* lpRider = CCreatureManager::GetInstance().GetCharacter(dwCID);
|
||||
if (lpRider)
|
||||
{
|
||||
m_dwRiderCID = 0;
|
||||
lpRider->GetOff();
|
||||
|
||||
GET_SINGLE_DISPATCH(lpDBAgentDispatch,
|
||||
CDBAgentDispatch, CDBAgentDispatch::GetDispatchTable());
|
||||
|
||||
// 공성병기에서 내렸다는 정보를 DBAgent 서버에 알려준다.
|
||||
if (0 != lpDBAgentDispatch)
|
||||
{
|
||||
CSendStream& AgentSendStream = lpDBAgentDispatch->GetSendStream();
|
||||
GameClientSendPacket::SendCharSiegeArmsCmdToDBAgent(AgentSendStream, dwCID, m_dwCID,
|
||||
0, PktSiegeArmsCmd::SIEGE_GETOFF_ARMS, PktBase::NO_SERVER_ERR);
|
||||
}
|
||||
|
||||
// GetOff 함수 자체에서 클라이언트에게 패킷을 보내준다.
|
||||
PktSiegeArmsCmd pktSAC;
|
||||
pktSAC.m_dwCID = GetOwnerID();
|
||||
pktSAC.m_dwArmsID = m_dwCID;
|
||||
pktSAC.m_cState = m_cState;
|
||||
pktSAC.m_dwValue = dwCID;
|
||||
pktSAC.m_cSubCmd = PktSiegeArmsCmd::SIEGE_GETOFF_ARMS;
|
||||
|
||||
char* szPacket = reinterpret_cast<char *>(&pktSAC);
|
||||
if (PacketWrap::WrapCrypt(szPacket, sizeof(PktSiegeArmsCmd), CmdSiegeArmsCmd, 0, 0))
|
||||
{
|
||||
SendToRange(Siege::BROADCAST_RADIUS, szPacket, sizeof(PktSiegeArmsCmd), CmdSiegeArmsCmd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
#ifndef _BASE_SIEGE_ARMS_OBJECT_H_
|
||||
#define _BASE_SIEGE_ARMS_OBJECT_H_
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Creature/Siege/SiegeObject.h>
|
||||
#include <Creature/Siege/SiegeConstants.h>
|
||||
|
||||
using namespace Siege;
|
||||
|
||||
|
||||
class CSiegeArms : public CSiegeObject
|
||||
{
|
||||
public:
|
||||
virtual ~CSiegeArms();
|
||||
|
||||
// CSkillMonster 의 기능
|
||||
virtual bool AttackCID(CCharacter* lpRideChar, AtType attackType, AtNode& attackNode, unsigned short& wError);
|
||||
virtual bool Attack(AtType attackType, unsigned char cDefenderNum, CAggresiveCreature** ppDefenders, unsigned char* cDefenserJudges, unsigned short* wDefenserMPHeal);
|
||||
virtual bool MissileAttack(AtType attackType, float fDir, float nRange, float fAngle, char cTargetType);
|
||||
|
||||
virtual bool Dead(CAggresiveCreature* pOffencer);
|
||||
|
||||
// 공성 병기 관련 함수
|
||||
bool Build(unsigned char cUpgradeStep = 0);
|
||||
bool Repair(unsigned short wRepairHP);
|
||||
bool Destroy(unsigned char cOffencerNation = 0, bool bTakeGold = false );
|
||||
bool Update(unsigned char cState, unsigned long dwValue1, unsigned long dwValue2, unsigned long dwNoValue, unsigned char cSubCmd);
|
||||
|
||||
// 스타터킷 아이템으로 전환 (bMaterial 이 true 이면 자재의 50% 를 돌려준다.)
|
||||
|
||||
bool ToStarterKit(bool bMaterial = false);
|
||||
|
||||
bool GiveBackSiegeMaterial(); // 공성 병기 자재 돌려주기
|
||||
unsigned short GetRepairMaterialNum(); // 수리시 필요한 자재수
|
||||
|
||||
// Rider 관련 정보
|
||||
virtual bool Ride(unsigned long dwCID); // 병기 탑승
|
||||
virtual bool GetOff(unsigned long dwCID); // 병기 내림 (중계 서버로 패킷 전송 : 사용안할시 파괴를 위해)
|
||||
|
||||
protected:
|
||||
CSiegeArms(MonsterCreateInfo& MonsterCreate, unsigned long dwOwnerID, unsigned char cNation,
|
||||
unsigned long dwHP, unsigned short wObjectType, unsigned char cState, unsigned char cUpgradeStep);
|
||||
|
||||
friend class CSiegeObjectMgr;
|
||||
};
|
||||
|
||||
#endif _BASE_SIEGE_ARMS_OBJECT_H_
|
||||
@@ -0,0 +1,313 @@
|
||||
#ifndef _SIEGE_CONSTANTS_H_
|
||||
#define _SIEGE_CONSTANTS_H_
|
||||
|
||||
namespace Siege
|
||||
{
|
||||
enum SiegeObjectType
|
||||
{
|
||||
// 몬스터 Kind ID 를 사용한다.
|
||||
EMBLEM = 5000, // 성 상징물 ( DESTORYING, CHANGING, DEVELOPING, CANCELING, RESTORING, DESTROYED 1개만 존재 )
|
||||
GATE = 5324, // 성문 ( DESTORYING, CHANGING, DEVELOPING, CANCELING, RESTORING, DESTROYED 1개만 존재 )
|
||||
BACKDOOR = 5378, // 뒷문 ( Only COMPLETE 상태만 존재 )
|
||||
CAMP = 5379, // 길드 요새 (캠프) ( DEVELOPING, CANCELING, RESTORING, DESTROYED 1개만 존재 )
|
||||
CASTLE_ARMS_NPC = 5433, // 병기 관리 NPC ( Only COMPLETE 상태만 존재 )
|
||||
GUARD = 5434, // 가드 ( DESTORYING, CHANGING, DEVELOPING, CANCELING, RESTORING, DESTROYED 1개만 존재 )
|
||||
SHORT_RANGE_CASTLE_ARMS = 5488, // 근거리 수성 병기 ( DESTORYING, CHANGING, DEVELOPING, CANCELING, RESTORING, DESTROYED 1개만 존재 )
|
||||
LONG_RANGE_CASTLE_ARMS = 5542, // 원거리 수성 병기 ( DESTORYING, CHANGING, DEVELOPING, CANCELING, RESTORING, DESTROYED 1개만 존재 )
|
||||
SHORT_RANGE_SIEGE_ARMS = 5596, // 근거릭 공성 병기 ( CHANGING, CANCELING, RESTORING, DESTROYED 1개만 존재 )
|
||||
LONG_RANGE_SIEGE_ARMS = 5650, // 원거리 공성 병기 ( CHANGING, CANCELING, RESTORING, DESTROYED 1개만 존재 )
|
||||
AIRSHIP = 5704, // 비공정 ( CHANGING, CANCELING, RESTORING, DESTROYED 1개만 존재 )
|
||||
MINING_CAMP = 5758, // 채굴기 (캠프) ( DEVELOPING, CANCELING, RESTORING, DESTROYED 1개만 존재 )
|
||||
CAMP_SHOP = 5812, // 상점타입요새 (캠프) ( DEVELOPING, CANCELING, RESTORING, DESTROYED 1개만 존재 )
|
||||
KARTERANT_WEAPON = 5866, // 카르테란트 월드 웨폰 (캠프) ( DEVELOPING, CANCELING, RESTORING, DESTROYED 1개만 존재 )
|
||||
MERKADIA_WEAPON = 5920, // 메르카디아 월드 웨폰 (캠프) ( DEVELOPING, CANCELING, RESTORING, DESTROYED 1개만 존재 )
|
||||
|
||||
DEFAULT_TYPE = 0 // 디폴트 전달인자용
|
||||
};
|
||||
|
||||
enum State
|
||||
{
|
||||
// KID => SiegeObjectType
|
||||
// + (State * UPGRADE_KIND_NUM)
|
||||
// + UpgradeStep
|
||||
|
||||
// KID (성 상징물) => SiegeObjectType
|
||||
// + (State * JEWEL_TYPE_NUM * UPGRADE_KIND_NUM)
|
||||
// + (JewelType * UPGRADE_KIND_NUM)
|
||||
// + UpgradeStep
|
||||
|
||||
COMPLETE = 0, // 성 상징물 소환 완료, 길드 요새 구축 완료, 가드, 경비병, 근거리, 원거리, 비공정 개발 완료
|
||||
UPGRADING = 1, // 성 상징물, 길드 요새, 성문, 가드, 근거리/원거리 수성병기 업그레이드 중인 상태
|
||||
REPARING = 2, // 길드 요새, 성문, 근거리/원거리, 비공정 수리 상태
|
||||
DESTROYING = 3, // 길드 요새, 근거리/원거리, 비공정 파괴해서 스타트 킷으로 돌리는 상태
|
||||
CHANGING = 4, // 길드 요새 변형중
|
||||
DEVELOPING = 5, // 성 상징물 소환중, 길드 요새 구축중, 가드, 경비병, 근거리, 원거리, 비공정 개발중
|
||||
CANCELING = 6, // 길드 요새, 근거리/원거리, 비공정 개발을 취소중인 상태 (스타트킷 아이템으로 돌아간다.)
|
||||
RESTORING = 7, // 성문 복구 상태
|
||||
DESTROYED = 8, // 성문 파괴 상태
|
||||
|
||||
// SubState
|
||||
NONE = 0,
|
||||
|
||||
MINE = 1, // 아군 성 상징물
|
||||
ENEMY = 2, // 적군 성 상징물
|
||||
|
||||
OPENED = 1, // 성문 열린 상태
|
||||
CLOSED = 2, // 성문 닫힌 상태
|
||||
|
||||
MINING_OFF = 0, // 채굴기 정지 상태
|
||||
MINING_ON = 1, // 채굴기 가동 상태
|
||||
MINING_READY = 2, // 채굴기 가동 준비 상태
|
||||
|
||||
WEAPON_EMPTY = 0, // 월드웨폰 무기 비장전 상태
|
||||
WEAPON_CHARGE = 1, // 무기 장전중
|
||||
WEAPON_READY = 2, // 무기 장전된 상태
|
||||
WEAPON_FIRE = 3, // 무기 발사중
|
||||
};
|
||||
|
||||
enum JewelType
|
||||
{
|
||||
// 보석 순서가 바뀌면 안됨!!
|
||||
// 아이템 스크립트의 순서대로이다.
|
||||
NO_JEWEL = 0, // 보석 없음
|
||||
RUBY = 1, // 루비
|
||||
EMERALD = 2, // 에메랄드
|
||||
SAPPHIRE = 3, // 사파이어
|
||||
DIAMOND = 4, // 다이아몬드
|
||||
BLACKMOON = 5, // 블랙문
|
||||
|
||||
JEWEL_PROTOTYPE_ID = 1900,
|
||||
JEWEL_KIND = 5,
|
||||
|
||||
JEWEL_TYPE_NUM = 6, // 상징물 업그레이트 보석 타입 종류수 (없음 포함)
|
||||
};
|
||||
|
||||
|
||||
enum CampConst
|
||||
{
|
||||
CAMP_BUILDING_RADIUS = 315, // 캠프 구축 반경 (m)
|
||||
|
||||
CAMP_REPAIR_GOLD_PER_HP = 10, // HP 단위당 10 골드
|
||||
|
||||
CAMP_UPGRADE_MATERIAL_NUM = 30, // 길드 요새 한단계 업그레이드시 필요한 자재수
|
||||
MINING_CAMP_UPGRADE_MATERIAL_NUM = 50, // 채굴기 한단계 업그레이드시 필요한 자재수
|
||||
CAMP_SHOP_UPGRADE_MATERIAL_NUM = 40, // 길드 요새 상점 한단계 업그레이드시 필요한 자재수
|
||||
WEAPON_CHARGE_MATERIAL_NUM = 50, // 월드 웨폰 무기 장전에 필요한 자재수
|
||||
CAMP_REPAIR_HP_PER_MATERIAL = 5000, // 자재 하나당 수리되는 HP
|
||||
|
||||
FAME_FOR_CAMP_BUILDING_TEST = 0,//1000, // 길드 요새 구축시 길드의 필요 명성치 (테섭용)
|
||||
FAME_FOR_CAMP_BUILDING = 0,//2000, // 길드 요새 구축시 길드의 필요 명성치 (정섭용)
|
||||
FAME_FOR_WEAPON_BUILDING_TEST = 1000, // 월드 웨폰 구축시 길드의 필요 명성치 (테섭용)
|
||||
FAME_FOR_WEAPON_BUILDING = 2000, // 월드 웨폰 구축시 길드의 필요 명성치 (정섭용)
|
||||
FAME_FOR_SELF_DESTROY_CAMP = -50, // 길드 요새 파괴시 깍이는 명성치 (자신이 파괴)
|
||||
FAME_FOR_DESTROYED_CAMP = -100, // 길드 요새 파괴시 깍이는 명성치 (다른 사람이 파괴)
|
||||
|
||||
GOLD_FOR_SELF_DESTROY_CAMP = 500000, // 길드 요새 파괴시 돌려주는 돈 (자신이 파괴)
|
||||
GOLD_FOR_CANCEL_CAMP = 1000000, // 길드 요새 구축 해제시 돌려주는 돈
|
||||
|
||||
CAMP_ATTACK_RANGE = 45, // 요새 공격 범위 (반경 45m)
|
||||
|
||||
// 시간 업데이트 타입
|
||||
TYPE_REMAIN_TIME = 0, // 시간 변수 업데이트
|
||||
TYPE_LAST_USE_TIME = 1, // 마지막 사용 시간 업데이트
|
||||
|
||||
// 채굴 아이템 타입 종류
|
||||
ACCUMULATED_MINERAL = 1, // 누적된 광물 아이템
|
||||
TEMPORARY_MINERAL = 2, // 임시 보관된 광물 아이템
|
||||
|
||||
MAX_MINERAL_NUM = 1000, // 광물 최고 스택 갯수
|
||||
|
||||
// 상점 타입 관련
|
||||
MAX_TAX = 100, // 최대 세율
|
||||
|
||||
// 월드 웨폰 관련
|
||||
WEAPON_FIRE_WARNING_COUNT = 10, // 월드 웨폰 발사 경고 표시 횟수 (10번 : 10초)
|
||||
WEAPON_REBUILD_SIEGE_TIME_COUNT = 3, // 공성 시간이 3번 지나야 다시 지을수 있음 (부서진 국가일 경우)
|
||||
WEAPON_DAMAGE_RANGE = 256, // 월드 웨폰 데미지 반경 (256m)
|
||||
WEAPON_DAMAGE = 10000 // 월드 웨폰 절대 데미지
|
||||
};
|
||||
|
||||
enum EmblemConst
|
||||
{
|
||||
MAX_EMBLEM_UPGRADE = 3, // 성 상징물 업그레이드 최대치
|
||||
// TODO : 상위 보석 2종류가 추가되면 Const::MAX_UPGRADE_NUM 를 사용한다.
|
||||
|
||||
EMBLEM_ATTACK_HEIGHT_ERROR = 5, // 높이차가 최소 5m 안에 있는 적만 공격이 가능
|
||||
};
|
||||
|
||||
enum GateConst
|
||||
{
|
||||
GATE_REPAIR_MIN_PER_HP = 1, // HP 1당 1분의 수리 시간
|
||||
};
|
||||
|
||||
enum CastleArmsConst
|
||||
{
|
||||
CASTLE_ARMS_REPAIR_TIME = 1, // 수성 병기 수리 시간 (1분)
|
||||
CASTLE_ARMS_REPAIR_GOLD_PER_UNIT = 10000, // 수리 비용 단위당 10000 골드 ( 단위는 10%당 )
|
||||
|
||||
FAME_FOR_DESTROY_CASTLE_ARMS = -500, // 수성 병기를 NPC 로 변형할때 깍이는 명성치
|
||||
};
|
||||
|
||||
enum SiegeArmsConst
|
||||
{
|
||||
SIEGE_ARMS_REPAIR_TIME = 1, // 공성 병기 수리 시간 (1분).
|
||||
|
||||
SIEGE_ARMS_UPGRADE_MATERIAL_NUM = 10, // 공성 병기 한단계 업그레이드시 필요한 자재수
|
||||
SIEGE_ARMS_REPAIR_HP_PER_MATERIAL = 10, // 자재 하나당 10% 의 HP 수리
|
||||
|
||||
AIRSHIP_RIDER_NUM = 10, // 수송선 최대 탑승 인원
|
||||
AIRSHIP_PASSENGER_NUM = 9, // 수송선 승객 최대 인원
|
||||
};
|
||||
|
||||
enum Const
|
||||
{
|
||||
INSIDE = 0, // 뒷문 사용( 안으로 )
|
||||
OUTSIDE = 1, // 뒷문 사용( 밖으로 )
|
||||
|
||||
MAX_UPGRADE_NUM = 5, // 공성 오브젝트 업그레이드 최대치
|
||||
UPGRADE_KIND_NUM = 6, // 업그레이트 종류 수 (0 ~ 5)
|
||||
|
||||
VIRTUAL_CID_START_NUM = 1000, // 길드 요새, 공성 병기의 가상 CID 인덱스 시작 번호
|
||||
|
||||
BROADCAST_CELL_SIZE = 5, // 브로드캐스트 반경 (5셀)
|
||||
BROADCAST_RADIUS = 150, // 브로드캐스트 반경 (150m)
|
||||
BROADCAST_SQUARED_RADIUS = 22500, // 브로드캐스트 반경 제곱값 (150 x 150)
|
||||
|
||||
MAX_HP_UPDATE_COUNT = 5, // 5 번에 한번은 DB 중계서버로 HP 정보 갱신
|
||||
|
||||
MAX_REPAIR_GOLD = 99999999, // 수리를 할수 없는 객체를 수리할때 드는 디폴트 비용 (에러나게 하기위해)
|
||||
|
||||
MAX_SIEGE_OBJECT = 5,
|
||||
|
||||
CREATE_LEVEL_LIMIT = 80
|
||||
};
|
||||
|
||||
enum RiderValue
|
||||
{
|
||||
NOT_RIDER = 0, // 탑승하지 않았음
|
||||
RIDER_FOR_OWNER = 1, // 주인으로 탑승한 상태
|
||||
RIDER_FOR_PASSENGER = 2 // 승객으로 탑승한 상태
|
||||
};
|
||||
|
||||
enum TimeValue
|
||||
{
|
||||
/*
|
||||
// Test : 길드 요새 테스트용 시간
|
||||
DEFAULT_TIME_VALUE = 1, // 1 분
|
||||
DEFAULT_REPAIR_TIME = 30, // 30 초
|
||||
|
||||
CAMP_ENCAMPING_TIME = 1, // 1 분
|
||||
CAMP_CANCELING_TIME = 1, // 1 분
|
||||
CAMP_REPAIR_TIME = 30, // 30 초
|
||||
CAMP_TO_STARTKIT_TIME = 1, // 1 분
|
||||
CAMP_CHANGING_TIME = 1, // 1 분
|
||||
CAMP_LEAST_USE_TIME = 7, // 7 일
|
||||
CAMP_ENCAMPING_INTERVAL = 10, // 10 분 간격으로 구축중 메세지 보냄
|
||||
CAMP_ATTACKED_INTERVAL = 60000, // 60000 ms (1분)
|
||||
MINING_CAMP_GAIN_COUNT = 1, // 1 회
|
||||
CAMP_SHOP_TRANSFER_COUNT = 1, // 1 회
|
||||
WEAPON_CHARGE_TIME = 1, // 1 분
|
||||
*/
|
||||
|
||||
DEFAULT_TIME_VALUE = 10, // 10 분
|
||||
DEFAULT_REPAIR_TIME = 30, // 30 초
|
||||
|
||||
CAMP_ENCAMPING_TIME = 30, // 30 분
|
||||
CAMP_CANCELING_TIME = 20, // 20 분
|
||||
CAMP_REPAIR_TIME = 30, // 30 초
|
||||
CAMP_TO_STARTKIT_TIME = 10, // 10 분
|
||||
CAMP_CHANGING_TIME = 10, // 10 분
|
||||
CAMP_LEAST_USE_TIME = 7, // 7 일
|
||||
CAMP_ENCAMPING_INTERVAL = 10, // 10 분 간격으로 구축중 메세지 보냄
|
||||
CAMP_ATTACKED_INTERVAL = 60000, // 60000 ms (1분)
|
||||
MINING_CAMP_GAIN_COUNT = 1, // 1 회
|
||||
CAMP_SHOP_TRANSFER_COUNT = 1, // 1 회
|
||||
WEAPON_CHARGE_TIME = 10, // 10 분
|
||||
|
||||
EMBLEM_SUMMON_TIME = 1, // 1 분
|
||||
EMBLEM_ATTACKED_INTERVAL = 60000, // 60000 ms (1분)
|
||||
|
||||
SIEGE_ARMS_BUILDING_TIME = 3, // 3 분
|
||||
SIEGE_ARMS_TO_STARTKIT_TIME = 3, // 1 분
|
||||
SIEGE_ARMS_LEAST_USE_TIME = 10, // 10 분
|
||||
|
||||
CASTLE_ARMS_LEAST_USE_TIME = 10, // 10 분
|
||||
};
|
||||
|
||||
enum eReturn
|
||||
{
|
||||
RET_OK = 0,
|
||||
RET_DESTROY_CAMP = 1, // 길드 요새 객체 삭제
|
||||
RET_DESTROY_SIEGE_ARMS = 2, // 공성 병기 객체 삭제
|
||||
RET_CHANGE_TYPE = 3, // 길드 요새 타입 변형
|
||||
};
|
||||
|
||||
enum eUpdateHPType
|
||||
{
|
||||
NOW_HP = 0, // 현재 HP 그대로
|
||||
UPGRADE_HP = 1, // 업그레이드된 HP 로
|
||||
REPAIR_HP = 2, // 수리된 HP 로
|
||||
FULL_HP = 3, // Full HP 로
|
||||
};
|
||||
|
||||
|
||||
static int GetKID(unsigned short wObjectType, unsigned char cState, unsigned char cUpgradeType, unsigned char cUpgradeStep)
|
||||
{
|
||||
int nKID = 0;
|
||||
|
||||
if (Siege::EMBLEM == wObjectType)
|
||||
{
|
||||
nKID = wObjectType
|
||||
+ (cState * Siege::JEWEL_TYPE_NUM * Siege::UPGRADE_KIND_NUM)
|
||||
+ (cUpgradeType * Siege::UPGRADE_KIND_NUM)
|
||||
+ cUpgradeStep;
|
||||
}
|
||||
else
|
||||
{
|
||||
nKID = wObjectType
|
||||
+ (cState * Siege::UPGRADE_KIND_NUM)
|
||||
+ cUpgradeStep;
|
||||
}
|
||||
|
||||
return nKID;
|
||||
}
|
||||
|
||||
static int GetUpgradeMaterialNum(unsigned short wObjectType)
|
||||
{
|
||||
int nNum = 0;
|
||||
|
||||
switch (wObjectType)
|
||||
{
|
||||
case Siege::MINING_CAMP:
|
||||
nNum = Siege::MINING_CAMP_UPGRADE_MATERIAL_NUM;
|
||||
break;
|
||||
|
||||
case Siege::CAMP_SHOP:
|
||||
nNum = Siege::CAMP_SHOP_UPGRADE_MATERIAL_NUM;
|
||||
break;
|
||||
|
||||
case Siege::CAMP:
|
||||
case Siege::KARTERANT_WEAPON:
|
||||
case Siege::MERKADIA_WEAPON:
|
||||
nNum = Siege::CAMP_UPGRADE_MATERIAL_NUM;
|
||||
break;
|
||||
}
|
||||
|
||||
return nNum;
|
||||
}
|
||||
|
||||
static int GetChangingTypeMaterialNum(unsigned short wBeforeType, unsigned short wAfterType, unsigned char cUpgradeStep)
|
||||
{
|
||||
int nBeforeNum = GetUpgradeMaterialNum(wBeforeType);
|
||||
int nAfterNum = GetUpgradeMaterialNum(wAfterType);
|
||||
|
||||
if (nBeforeNum < nAfterNum)
|
||||
{
|
||||
return ( (nAfterNum - nBeforeNum) * cUpgradeStep );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // _SIEGE_CONSTANTS_H_
|
||||
@@ -0,0 +1,946 @@
|
||||
#include "stdafx.h"
|
||||
#include "SiegeObject.h"
|
||||
|
||||
#include <Utility/Math/Math.h>
|
||||
#include <Utility/Setup/ServerSetup.h>
|
||||
|
||||
#include <Item/ItemFactory.h>
|
||||
|
||||
#include <Network/ClientSocket/ClientConstants.h>
|
||||
#include <Network/Dispatch/GameClient/GameClientDispatch.h>
|
||||
#include <Network/Dispatch/GameClient/SendCharItem.h>
|
||||
#include <Network/Dispatch/GameClient/SendCharCastle.h>
|
||||
#include <Network/Dispatch/GameClient/SendCharAttack.h>
|
||||
#include <Network/Dispatch/DBAgent/DBAgentDispatch.h>
|
||||
#include <Network/Dispatch/DBAgent/DBAgentRequest.h>
|
||||
#include <Network/Packet/WrapPacket.h>
|
||||
#include <Network/Packet/PacketCommand.h>
|
||||
#include <Network/Packet/PacketStruct/ServerInfo.h>
|
||||
|
||||
#include <Community/Guild/Guild.h>
|
||||
#include <Community/Guild/GuildMgr.h>
|
||||
|
||||
#include <Creature/Siege/SiegeObjectMgr.h>
|
||||
#include <Creature/Monster/MonsterMgr.h>
|
||||
#include <Creature/EnemyCheck.h>
|
||||
|
||||
#include <Castle/Castle.h>
|
||||
#include <Castle/CastleMgr.h>
|
||||
|
||||
#include <Map/FieldMap/CellManager.h>
|
||||
#include <Map/DuelMap/DuelCellManager.h>
|
||||
|
||||
#include <Skill/SkillTable.h>
|
||||
#include <Skill/SkillMgr.h>
|
||||
|
||||
#include <GameTime/GameTimeConstants.h>
|
||||
#include <GameTime/GameTimeMgr.h>
|
||||
|
||||
|
||||
CSiegeObject::CSiegeObject(MonsterCreateInfo& MonsterCreate, const CastleObjectInfo& CastleObject)
|
||||
: CSkillMonster(MonsterCreate), m_dwCampOrCastleID(CastleObject.m_dwCastleID), m_dwOwnerID(CastleObject.m_dwOwnerID),
|
||||
m_cNation(CastleObject.m_cNation), m_dwGID(0), m_wObjectType(CastleObject.m_wObjectType), m_cState(CastleObject.m_cState),
|
||||
m_cSubState(CastleObject.m_cSubState), m_cUpgradeStep(CastleObject.m_cUpgradeStep), m_cUpgradeType(CastleObject.m_cUpgradeType),
|
||||
m_cMaterial(0), m_cSiegeCount(0), m_fDefaultDir(CastleObject.m_fDefaultDir), m_dwRiderCID(0), m_cHPUpdateCount(0),
|
||||
m_dwBroadCastSize(0), m_dwDeltaSize(0)
|
||||
{
|
||||
InitMonster(MonsterCreate.m_Pos);
|
||||
m_MotionInfo.m_fDirection = m_fDefaultDir;
|
||||
|
||||
m_CreatureStatus.m_nNowHP = static_cast<unsigned short>(CastleObject.m_dwHP);
|
||||
|
||||
switch (m_wObjectType)
|
||||
{
|
||||
case Siege::GUARD: m_wDefaultSearchRange = 32; break;
|
||||
case Siege::EMBLEM: m_wDefaultSearchRange = 32; break;
|
||||
}
|
||||
|
||||
// 브로드캐스팅 데이터 준비
|
||||
m_SerializeSiegeObjectData.PrepareData( *this );
|
||||
m_SerializeSiegeObjectData.ClearDeltaData();
|
||||
}
|
||||
|
||||
CSiegeObject::CSiegeObject(MonsterCreateInfo& MonsterCreate, unsigned long dwCampID, unsigned long dwGID,
|
||||
unsigned long dwHP, unsigned short wObjectType, unsigned char cState,
|
||||
unsigned char cSubState, unsigned char cUpgradeStep, unsigned char cMaterial,
|
||||
unsigned char cSiegeCount, bool bFullHP)
|
||||
: CSkillMonster(MonsterCreate), m_dwCampOrCastleID(dwCampID), m_dwOwnerID(0), m_wObjectType(wObjectType),
|
||||
m_dwGID(dwGID), m_cNation(0), m_cState(cState), m_cSubState(cSubState), m_cUpgradeStep(cUpgradeStep),
|
||||
m_cUpgradeType(0), m_cMaterial(cMaterial), m_cSiegeCount(cSiegeCount), m_fDefaultDir(0), m_dwRiderCID(0),
|
||||
m_cHPUpdateCount(0), m_dwBroadCastSize(0),m_dwDeltaSize(0)
|
||||
{
|
||||
InitMonster(MonsterCreate.m_Pos);
|
||||
|
||||
if (bFullHP) m_CreatureStatus.m_nNowHP = m_CreatureStatus.m_StatusInfo.m_nMaxHP;
|
||||
else m_CreatureStatus.m_nNowHP = static_cast<unsigned short>(dwHP);
|
||||
|
||||
// 브로드캐스팅 데이터 준비
|
||||
m_SerializeSiegeObjectData.PrepareData( *this );
|
||||
m_SerializeSiegeObjectData.ClearDeltaData();
|
||||
}
|
||||
|
||||
CSiegeObject::CSiegeObject(MonsterCreateInfo& MonsterCreate, unsigned long dwOwnerID, unsigned char cNation,
|
||||
unsigned long dwHP, unsigned short wObjectType, unsigned char cState, unsigned char cUpgradeStep)
|
||||
: CSkillMonster(MonsterCreate), m_dwCampOrCastleID(0), m_dwOwnerID(dwOwnerID), m_wObjectType(wObjectType), m_cNation(cNation),
|
||||
m_dwGID(0), m_cState(cState), m_cSubState(0), m_cUpgradeStep(cUpgradeStep), m_cUpgradeType(0), m_cMaterial(0),
|
||||
m_cSiegeCount(0), m_fDefaultDir(0), m_dwRiderCID(0), m_cHPUpdateCount(0), m_dwBroadCastSize(0),m_dwDeltaSize(0)
|
||||
{
|
||||
InitMonster(MonsterCreate.m_Pos);
|
||||
|
||||
if (0 == dwHP) m_CreatureStatus.m_nNowHP = m_CreatureStatus.m_StatusInfo.m_nMaxHP;
|
||||
else m_CreatureStatus.m_nNowHP = static_cast<unsigned short>(dwHP);
|
||||
|
||||
// 브로드캐스팅 데이터 준비
|
||||
m_SerializeSiegeObjectData.PrepareData( *this );
|
||||
m_SerializeSiegeObjectData.ClearDeltaData();
|
||||
}
|
||||
|
||||
CSiegeObject::~CSiegeObject()
|
||||
{
|
||||
}
|
||||
|
||||
EnemyCheck::EnemyType CSiegeObject::IsEnemy(CCreature* lpTarget, unsigned char* cResult)
|
||||
{
|
||||
if (NULL == lpTarget)
|
||||
{
|
||||
ERRLOG1(g_Log, "CID:0x%08x 피아식별할 타겟이 없습니다.", m_dwCID);
|
||||
return EnemyCheck::EC_NEUTRAL;
|
||||
}
|
||||
|
||||
BattleInclination::CharData ownerInfo;
|
||||
BattleInclination::CharData targetInfo;
|
||||
|
||||
BattleInclination::SetCharData(*this, ownerInfo);
|
||||
BattleInclination::SetCharData(*lpTarget, targetInfo);
|
||||
|
||||
BattleInclination::RelationData relationInfo;
|
||||
BattleInclination::SetRelationData(*this, *lpTarget, relationInfo);
|
||||
|
||||
unsigned char cResultFromStruct = 0;
|
||||
unsigned long dwResult = EnemyCheck::CCheckTable::GetInstance().IsEnemyFromStruct(
|
||||
ownerInfo, targetInfo, relationInfo, cResultFromStruct);
|
||||
|
||||
return static_cast<EnemyCheck::EnemyType>(dwResult);
|
||||
}
|
||||
|
||||
unsigned char CSiegeObject::IsRider(unsigned long dwCID) const
|
||||
{
|
||||
if (m_dwRiderCID == dwCID)
|
||||
{
|
||||
return Siege::RIDER_FOR_OWNER;
|
||||
}
|
||||
|
||||
return Siege::NOT_RIDER;
|
||||
}
|
||||
|
||||
bool CSiegeObject::SkillAttack()
|
||||
{
|
||||
unsigned char cSkillLockCount = m_cUpgradeStep + 1;
|
||||
unsigned char cSkillLevel = CSkillMonster::USE_SKILL_LEVEL;
|
||||
|
||||
if (cSkillLockCount >= CSkillMgr::MAX_SKILL_LOCKCOUNT - 1)
|
||||
{
|
||||
cSkillLockCount = CSkillMgr::MAX_SKILL_LOCKCOUNT - 2;
|
||||
}
|
||||
|
||||
|
||||
enum { FIRST_PATTERN=0, SECOND_PATTERN=1, MAX_PATTERN = 2 };
|
||||
int nSelectPattern = FIRST_PATTERN;
|
||||
|
||||
CAggresiveCreature* ppAggresiveCreature[AtNode::MAX_DEFENDER_NUM] = {0, };
|
||||
|
||||
AtType attackType;
|
||||
attackType.m_cSkillLockCount = cSkillLockCount;
|
||||
attackType.m_cSkillLevel = cSkillLevel;
|
||||
|
||||
char nSkillPattern = 0;
|
||||
|
||||
while (nSelectPattern < MAX_PATTERN)
|
||||
{
|
||||
switch (nSelectPattern)
|
||||
{
|
||||
case FIRST_PATTERN:
|
||||
{
|
||||
// 조건 대상 행동
|
||||
// A B A : 스킬 사용 가능 MP 잔여량 있음 / 대상이 스킬 사용 가능 범위에 있을 때
|
||||
// : 자신에게 가장 위협적인 적에게
|
||||
// : A 스킬 사용
|
||||
|
||||
// 스킬이 없다면.. 다음 패턴으로..
|
||||
if (0 == m_MonsterInfo.m_wSkillID[A_SKILL])
|
||||
{
|
||||
++nSelectPattern;
|
||||
continue;
|
||||
}
|
||||
|
||||
nSkillPattern = A_SKILL;
|
||||
attackType.m_wType = m_MonsterInfo.m_wSkillID[A_SKILL];
|
||||
ppAggresiveCreature[0] = m_lpTarget;
|
||||
}
|
||||
break;
|
||||
|
||||
case SECOND_PATTERN:
|
||||
{
|
||||
// 조건 대상 행동
|
||||
// A B D : 스킬 사용 가능 MP 잔여량 있음 / 대상이 스킬 사용 가능 범위에 있을 때
|
||||
// : 자신에게 가장 위협적인 적에게
|
||||
// : D 스킬 사용
|
||||
|
||||
// 스킬이 없다면.. 다음 패턴으로..
|
||||
if (0 == m_MonsterInfo.m_wSkillID[D_SKILL])
|
||||
{
|
||||
++nSelectPattern;
|
||||
continue;
|
||||
}
|
||||
|
||||
nSkillPattern = D_SKILL;
|
||||
attackType.m_wType = m_MonsterInfo.m_wSkillID[D_SKILL];
|
||||
ppAggresiveCreature[0] = m_lpTarget;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
ERRLOG1(g_Log, "CID:0x%08x 없는 패턴이 넘어왔습니다.", m_dwCID);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 스킬 사용 (캐스팅 타입인 경우에는 사용할수 있는지만 체크하게 된다.)
|
||||
if (true == UseSkill(attackType, ppAggresiveCreature, nSkillPattern))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
++nSelectPattern;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CSiegeObject::UpdateObjectInfo(unsigned char cHPType, unsigned short wRepairHP)
|
||||
{
|
||||
unsigned short wPrevMaxHP = m_CreatureStatus.m_StatusInfo.m_nMaxHP;
|
||||
unsigned short wNowHP = m_CreatureStatus.m_nNowHP;
|
||||
int nKID = Siege::GetKID(m_wObjectType, m_cState, m_cUpgradeType, m_cUpgradeStep);
|
||||
|
||||
const CMonsterMgr::MonsterProtoType* lpProtoType = CMonsterMgr::GetInstance().GetMonsterProtoType(nKID);
|
||||
if (lpProtoType)
|
||||
{
|
||||
m_CreatureStatus = lpProtoType->m_CreatureStatus;
|
||||
m_MonsterInfo = lpProtoType->m_MonsterInfo;
|
||||
|
||||
m_CreatureStatus.m_StatusInfo.CalculateSubStatus();
|
||||
}
|
||||
|
||||
unsigned long dwTempHp;
|
||||
switch (cHPType)
|
||||
{
|
||||
case Siege::NOW_HP:
|
||||
m_CreatureStatus.m_nNowHP = wNowHP;
|
||||
SendHPUpdateToDBAgent();
|
||||
break;
|
||||
|
||||
case Siege::UPGRADE_HP:
|
||||
dwTempHp = wNowHP + m_CreatureStatus.m_StatusInfo.m_nMaxHP - wPrevMaxHP;
|
||||
m_CreatureStatus.m_nNowHP = static_cast<unsigned short>(
|
||||
std::min(dwTempHp, static_cast<unsigned long>(m_CreatureStatus.m_StatusInfo.m_nMaxHP)));
|
||||
SendHPUpdateToDBAgent(true);
|
||||
break;
|
||||
|
||||
case Siege::REPAIR_HP:
|
||||
dwTempHp = wNowHP + wRepairHP;
|
||||
m_CreatureStatus.m_nNowHP = static_cast<unsigned short>(
|
||||
std::min(dwTempHp, static_cast<unsigned long>(m_CreatureStatus.m_StatusInfo.m_nMaxHP)));
|
||||
SendHPUpdateToDBAgent(true);
|
||||
break;
|
||||
|
||||
case Siege::FULL_HP:
|
||||
m_CreatureStatus.m_nNowHP = m_CreatureStatus.m_StatusInfo.m_nMaxHP;
|
||||
SendHPUpdateToDBAgent(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CSiegeObject::UpgradeByEmblem(unsigned char cUpgradeType, unsigned char cUpgradeStep)
|
||||
{
|
||||
// 성 관련 오브젝트로 상징물의 업그레이드 효과를 받는 오브젝트만
|
||||
if (!IsCastleObject())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int nKID = Siege::GetKID(Siege::EMBLEM, Siege::COMPLETE, cUpgradeType, cUpgradeStep);
|
||||
|
||||
const CMonsterMgr::MonsterProtoType* lpProtoType = CMonsterMgr::GetInstance().GetMonsterProtoType(nKID);
|
||||
if (lpProtoType)
|
||||
{
|
||||
// 업그레이드 속도 향상
|
||||
m_MonsterInfo.m_cUpgradeSpeed -= static_cast<unsigned char>(m_MonsterInfo.m_cUpgradeSpeed
|
||||
* lpProtoType->m_MonsterInfo.m_fUpgradeSpeedUp);
|
||||
|
||||
// 개발 속도 향상
|
||||
m_MonsterInfo.m_cDevelopSpeed -= static_cast<unsigned char>(m_MonsterInfo.m_cDevelopSpeed
|
||||
* lpProtoType->m_MonsterInfo.m_fDevelopSpeedUp);
|
||||
|
||||
// 방어력 향상
|
||||
m_CreatureStatus.m_StatusInfo.m_wArmor += static_cast<short>(m_CreatureStatus.m_StatusInfo.m_wArmor
|
||||
* lpProtoType->m_MonsterInfo.m_fDefenseUp);
|
||||
m_CreatureStatus.m_StatusInfo.m_wMagicResist += static_cast<short>(m_CreatureStatus.m_StatusInfo.m_wMagicResist
|
||||
* lpProtoType->m_MonsterInfo.m_fDefenseUp);
|
||||
|
||||
// HP 향상
|
||||
unsigned short wAddHP = static_cast<unsigned short>(m_CreatureStatus.m_StatusInfo.m_nMaxHP
|
||||
* lpProtoType->m_MonsterInfo.m_fHPUp);
|
||||
m_CreatureStatus.m_StatusInfo.m_nMaxHP += wAddHP;
|
||||
m_CreatureStatus.m_nNowHP += wAddHP;
|
||||
|
||||
// 공격력 향상
|
||||
m_CreatureStatus.m_StatusInfo.m_lMinDamage += static_cast<long>(m_CreatureStatus.m_StatusInfo.m_lMinDamage
|
||||
* lpProtoType->m_MonsterInfo.m_fOffenseUp);
|
||||
m_CreatureStatus.m_StatusInfo.m_lMaxDamage += static_cast<long>(m_CreatureStatus.m_StatusInfo.m_lMaxDamage
|
||||
* lpProtoType->m_MonsterInfo.m_fOffenseUp);
|
||||
m_CreatureStatus.m_StatusInfo.m_wMagicPower += static_cast<short>(m_CreatureStatus.m_StatusInfo.m_wMagicPower
|
||||
* lpProtoType->m_MonsterInfo.m_fOffenseUp);
|
||||
|
||||
// 생성 비용 절감
|
||||
m_MonsterInfo.m_dwDevelopGold -= static_cast<unsigned long>(m_MonsterInfo.m_dwDevelopGold
|
||||
* lpProtoType->m_MonsterInfo.m_fDevelopGoldDown);
|
||||
|
||||
// 업그레이드 비용 절감
|
||||
m_MonsterInfo.m_dwUpgradeGold -= static_cast<unsigned long>(m_MonsterInfo.m_dwUpgradeGold
|
||||
* lpProtoType->m_MonsterInfo.m_fUpgradeGoldDown);
|
||||
}
|
||||
}
|
||||
|
||||
void CSiegeObject::DegradeByEmblem(unsigned char cUpgradeType, unsigned char cUpgradeStep)
|
||||
{
|
||||
// 성 관련 오브젝트로 상징물의 업그레이드 효과를 받는 오브젝트만
|
||||
if (!IsCastleObject())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int nKID = Siege::GetKID(Siege::EMBLEM, Siege::COMPLETE, cUpgradeType, cUpgradeStep);
|
||||
const CMonsterMgr::MonsterProtoType* lpProtoTypeEmblem = CMonsterMgr::GetInstance().GetMonsterProtoType(nKID);
|
||||
|
||||
nKID = GetKID();
|
||||
const CMonsterMgr::MonsterProtoType* lpProtoType = CMonsterMgr::GetInstance().GetMonsterProtoType(nKID);
|
||||
|
||||
if (lpProtoType && lpProtoTypeEmblem)
|
||||
{
|
||||
unsigned short wNowHP = m_CreatureStatus.m_nNowHP -
|
||||
static_cast<unsigned short>(m_CreatureStatus.m_nNowHP * lpProtoTypeEmblem->m_MonsterInfo.m_fHPUp);
|
||||
|
||||
m_CreatureStatus = lpProtoType->m_CreatureStatus;
|
||||
m_MonsterInfo = lpProtoType->m_MonsterInfo;
|
||||
|
||||
m_CreatureStatus.m_nNowHP = wNowHP;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned short CSiegeObject::GetDefaultNowHP()
|
||||
{
|
||||
// 성 관련 오브젝트로 상징물의 업그레이드 효과를 받는 오브젝트만
|
||||
if (IsCastleObject())
|
||||
{
|
||||
Castle::CCastle* lpCastle = Castle::CCastleMgr::GetInstance().GetCastle( GetCastleID() );
|
||||
CSiegeObject* lpEmblem = lpCastle->GetCastleEmblem();
|
||||
|
||||
if (lpCastle && lpEmblem)
|
||||
{
|
||||
int nKID = lpEmblem->GetKID();
|
||||
const CMonsterMgr::MonsterProtoType* lpProtoTypeEmblem = CMonsterMgr::GetInstance().GetMonsterProtoType(nKID);
|
||||
|
||||
if (lpProtoTypeEmblem)
|
||||
{
|
||||
return m_CreatureStatus.m_nNowHP - static_cast<unsigned short>(m_CreatureStatus.m_nNowHP * lpProtoTypeEmblem->m_MonsterInfo.m_fHPUp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return m_CreatureStatus.m_nNowHP;
|
||||
}
|
||||
|
||||
void CSiegeObject::MoveTo(const Position& NewPosition)
|
||||
{
|
||||
CAggresiveCreature::MoveTo(NewPosition, false);
|
||||
}
|
||||
|
||||
|
||||
unsigned long CSiegeObject::GetRepairHP()
|
||||
{
|
||||
return m_CreatureStatus.m_StatusInfo.m_nMaxHP - m_CreatureStatus.m_nNowHP;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int CSiegeObject::GetKID() const
|
||||
{
|
||||
return Siege::GetKID(m_wObjectType, m_cState, m_cUpgradeType, m_cUpgradeStep);
|
||||
}
|
||||
|
||||
void CSiegeObject::GetRiders( unsigned long* pRiders ) const
|
||||
{
|
||||
pRiders[0] = m_dwRiderCID;
|
||||
}
|
||||
|
||||
unsigned char CSiegeObject::GetRiderNum() const
|
||||
{
|
||||
return (0 == m_dwRiderCID) ? 0 : 1;
|
||||
}
|
||||
|
||||
unsigned long CSiegeObject::GetDevelopGold(unsigned short wDefaultObjectType) const
|
||||
{
|
||||
wDefaultObjectType = (wDefaultObjectType == Siege::DEFAULT_TYPE) ? m_wObjectType : wDefaultObjectType;
|
||||
int nKID = Siege::GetKID(wDefaultObjectType, Siege::DEVELOPING, m_cUpgradeType, m_cUpgradeStep);
|
||||
const CMonsterMgr::MonsterProtoType* pProtoType = CMonsterMgr::GetInstance().GetMonsterProtoType(nKID);
|
||||
|
||||
if ( pProtoType )
|
||||
{
|
||||
return pProtoType->m_MonsterInfo.m_dwDevelopGold;
|
||||
}
|
||||
|
||||
ERRLOG1(g_Log, "개발 비용 오류 ( KID : %d )", nKID);
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned char CSiegeObject::GetDevelopSpeed(unsigned short wDefaultObjectType) const
|
||||
{
|
||||
wDefaultObjectType = (wDefaultObjectType == Siege::DEFAULT_TYPE) ? m_wObjectType : wDefaultObjectType;
|
||||
int nKID = Siege::GetKID(wDefaultObjectType, Siege::DEVELOPING, m_cUpgradeType, m_cUpgradeStep);
|
||||
const CMonsterMgr::MonsterProtoType* pProtoType = CMonsterMgr::GetInstance().GetMonsterProtoType(nKID);
|
||||
|
||||
if ( pProtoType )
|
||||
{
|
||||
return pProtoType->m_MonsterInfo.m_cDevelopSpeed;
|
||||
}
|
||||
|
||||
ERRLOG1(g_Log, "개발 시간 오류 ( KID : %d )", nKID);
|
||||
return Siege::DEFAULT_TIME_VALUE;
|
||||
}
|
||||
|
||||
unsigned long CSiegeObject::GetUpgradeGold() const
|
||||
{
|
||||
int nKID = Siege::GetKID(m_wObjectType, Siege::UPGRADING, m_cUpgradeType, m_cUpgradeStep);
|
||||
if ( m_cUpgradeStep < Siege::MAX_UPGRADE_NUM )
|
||||
{
|
||||
const CMonsterMgr::MonsterProtoType* pProtoType = CMonsterMgr::GetInstance().GetMonsterProtoType(nKID);
|
||||
|
||||
if ( pProtoType )
|
||||
{
|
||||
return pProtoType->m_MonsterInfo.m_dwUpgradeGold;
|
||||
}
|
||||
}
|
||||
|
||||
ERRLOG1(g_Log, "업그레이드 비용 오류 ( KID : %d )", nKID);
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned char CSiegeObject::GetUpgradeSpeed(unsigned char cDefaultUpgradeType) const
|
||||
{
|
||||
cDefaultUpgradeType = (cDefaultUpgradeType == Siege::NO_JEWEL) ? m_cUpgradeType : cDefaultUpgradeType;
|
||||
int nKID = Siege::GetKID(m_wObjectType, Siege::UPGRADING, cDefaultUpgradeType, m_cUpgradeStep);
|
||||
|
||||
if ( m_cUpgradeStep < Siege::MAX_UPGRADE_NUM )
|
||||
{
|
||||
const CMonsterMgr::MonsterProtoType* pProtoType = CMonsterMgr::GetInstance().GetMonsterProtoType(nKID);
|
||||
|
||||
if ( pProtoType )
|
||||
{
|
||||
return pProtoType->m_MonsterInfo.m_cUpgradeSpeed;
|
||||
}
|
||||
}
|
||||
|
||||
ERRLOG1(g_Log, "업그레이드 시간 오류 ( KID : %d )", nKID);
|
||||
return Siege::DEFAULT_TIME_VALUE;
|
||||
}
|
||||
|
||||
float CSiegeObject::GetBonusRate() const
|
||||
{
|
||||
return m_MonsterInfo.m_fBonusRate;
|
||||
}
|
||||
|
||||
unsigned long CSiegeObject::GetGID() const
|
||||
{
|
||||
// 병기에 타고 있는 캐릭터가 있으면, 병기에 탑승한 캐릭터의 GetGID() 호출
|
||||
if ( IsRidable() && 0 != m_dwRiderCID )
|
||||
{
|
||||
CCharacter* lpRider = CCreatureManager::GetInstance().GetCharacter(m_dwRiderCID);
|
||||
if (lpRider)
|
||||
{
|
||||
return lpRider->GetGID();
|
||||
}
|
||||
}
|
||||
|
||||
return m_dwGID;
|
||||
}
|
||||
|
||||
unsigned char CSiegeObject::GetNation() const
|
||||
{
|
||||
// 병기에 타고 있는 캐릭터가 있으면, 병기에 탑승한 캐릭터의 GetNation() 호출
|
||||
if ( IsRidable() && 0 != m_dwRiderCID )
|
||||
{
|
||||
CCharacter* lpRider = CCreatureManager::GetInstance().GetCharacter(m_dwRiderCID);
|
||||
if (lpRider)
|
||||
{
|
||||
return lpRider->GetNation();
|
||||
}
|
||||
}
|
||||
|
||||
if ( IsCastleObject() || IsSiegeArms() )
|
||||
{
|
||||
return m_cNation;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 해당 Guild 의 GetNation() 호출
|
||||
CGuild* lpGuild = CGuildMgr::GetInstance().GetGuild(m_dwGID);
|
||||
if (NULL != lpGuild)
|
||||
{
|
||||
return lpGuild->GetNation();
|
||||
}
|
||||
}
|
||||
|
||||
// 성주가 없는 공성 병기에 대해서 무국적을 리턴한다.
|
||||
return Creature::STATELESS;
|
||||
}
|
||||
|
||||
bool CSiegeObject::IsPeaceMode()
|
||||
{
|
||||
// 병기에 타고 있는 캐릭터가 있으면, 병기에 탑승한 캐릭터의 GetNation() 호출
|
||||
if ( IsRidable() && 0 != m_dwRiderCID )
|
||||
{
|
||||
CCharacter* lpRider = CCreatureManager::GetInstance().GetCharacter(m_dwRiderCID);
|
||||
if (lpRider)
|
||||
{
|
||||
return lpRider->IsPeaceMode();
|
||||
}
|
||||
}
|
||||
|
||||
if ( IsCastleObject() || IsSiegeArms() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 해당 Guild 의 GetNation() 호출
|
||||
CGuild* lpGuild = CGuildMgr::GetInstance().GetGuild(m_dwGID);
|
||||
if (NULL != lpGuild)
|
||||
{
|
||||
return lpGuild->IsPeaceMode();
|
||||
}
|
||||
}
|
||||
|
||||
// 성주가 없는 공성 병기에 대해서 전쟁모드
|
||||
return false;
|
||||
}
|
||||
|
||||
CAggresiveCreature* CSiegeObject::GetDuelOpponent(void) const
|
||||
{
|
||||
// 병기에 타고 있는 캐릭터가 있으면, 병기에 탑승한 캐릭터의 GetNation() 호출
|
||||
if ( IsRidable() && 0 != m_dwRiderCID )
|
||||
{
|
||||
CCharacter* lpRider = CCreatureManager::GetInstance().GetCharacter(m_dwRiderCID);
|
||||
if (lpRider)
|
||||
{
|
||||
return lpRider->GetDuelOpponent();
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool CSiegeObject::IsWorldWeapon() const
|
||||
{
|
||||
if (Siege::KARTERANT_WEAPON == m_wObjectType || Siege::MERKADIA_WEAPON == m_wObjectType)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
bool CSiegeObject::SerializeOut(char* szBuffer_In, unsigned short& wDataLen)
|
||||
{
|
||||
PktSiegeBroadCast* lpBroadCast = reinterpret_cast<PktSiegeBroadCast*>(szBuffer_In);
|
||||
|
||||
lpBroadCast->m_dwCID = m_dwCID;
|
||||
lpBroadCast->m_dwOwnerID = m_dwOwnerID; // 성, 길드 요새, 소유캐릭터 ID
|
||||
lpBroadCast->m_dwGID = m_dwGID; // 길드 ID
|
||||
|
||||
if (IsEmblem() && m_dwEnemyGID)
|
||||
{
|
||||
lpBroadCast->m_dwGID = m_dwEnemyGID; // 길드 ID
|
||||
}
|
||||
|
||||
lpBroadCast->m_wObjectType = m_wObjectType;
|
||||
lpBroadCast->m_dwNowHP = m_CreatureStatus.m_nNowHP;
|
||||
lpBroadCast->m_dwMaxHP = m_CreatureStatus.m_StatusInfo.m_nMaxHP;
|
||||
lpBroadCast->m_cState = m_cState;
|
||||
lpBroadCast->m_cSubState = m_cSubState;
|
||||
lpBroadCast->m_cUpgradeStep = m_cUpgradeStep;
|
||||
lpBroadCast->m_cUpgradeType = m_cUpgradeType;
|
||||
lpBroadCast->m_fDefaultDir = m_fDefaultDir;
|
||||
std::fill_n(&lpBroadCast->m_dwRiderID[0], int(Siege::AIRSHIP_RIDER_NUM), 0);
|
||||
GetRiders( lpBroadCast->m_dwRiderID );
|
||||
|
||||
float fY = GetCurrentPos().m_fPointY;
|
||||
const MotionInfo& motionInfo = GetMotionInfo();
|
||||
|
||||
if (IsSiegeArms())
|
||||
{
|
||||
if (Siege::AIRSHIP != m_wObjectType)
|
||||
{
|
||||
fY = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
lpBroadCast->m_NetworkPos.Initialize(GetCurrentPos().m_fPointX, fY, GetCurrentPos().m_fPointZ, motionInfo.m_fDirection,
|
||||
(0 == motionInfo.m_dwFrame) ? 0.0f : motionInfo.m_fVelocity / motionInfo.m_dwFrame);
|
||||
|
||||
wDataLen = sizeof(PktSiegeBroadCast);
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
void CSiegeObject::SendToRadiusCell(const char* szPacket, unsigned long dwPacketSize, unsigned char cCMD_In)
|
||||
{
|
||||
// 반경 5셀에 패킷 전송
|
||||
CCell* lpCenterCell = GetCellPos().m_lpCell;
|
||||
if (lpCenterCell)
|
||||
{
|
||||
int nCellWidth = Siege::BROADCAST_CELL_SIZE * 2 - 1;
|
||||
int nCellHeight = Siege::BROADCAST_CELL_SIZE * 2 - 1;
|
||||
int i, j;
|
||||
|
||||
CCell* lpStartCell = NULL;
|
||||
for (i=1; i<Siege::BROADCAST_CELL_SIZE; ++i)
|
||||
{
|
||||
lpStartCell = lpCenterCell->GetConnectCell(CCell::LEFT);
|
||||
if (NULL == lpStartCell)
|
||||
{
|
||||
nCellWidth = nCellWidth - (Siege::BROADCAST_CELL_SIZE - i);
|
||||
break;
|
||||
}
|
||||
|
||||
lpCenterCell = lpStartCell;
|
||||
}
|
||||
|
||||
for (i=1; i<Siege::BROADCAST_CELL_SIZE; ++i)
|
||||
{
|
||||
lpStartCell = lpCenterCell->GetConnectCell(CCell::UP);
|
||||
if (NULL == lpStartCell)
|
||||
{
|
||||
nCellHeight = nCellHeight - (Siege::BROADCAST_CELL_SIZE - i);
|
||||
break;
|
||||
}
|
||||
|
||||
lpCenterCell = lpStartCell;
|
||||
}
|
||||
|
||||
lpStartCell = lpCenterCell;
|
||||
|
||||
for (i=0; i<nCellHeight; ++i)
|
||||
{
|
||||
CCell* lpTempCell = lpStartCell;
|
||||
for (j=0; j<nCellWidth; ++j)
|
||||
{
|
||||
if (lpTempCell)
|
||||
{
|
||||
lpTempCell->SendAllCharacter(szPacket, dwPacketSize, cCMD_In);
|
||||
lpTempCell = lpTempCell->GetConnectCell(CCell::RIGHT);
|
||||
}
|
||||
else break;
|
||||
}
|
||||
|
||||
lpStartCell = lpStartCell->GetConnectCell(CCell::DOWN);
|
||||
if (NULL == lpStartCell) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
void CSiegeObject::RangeTest()
|
||||
{
|
||||
// 브로드캐스트 반경을 벗어난 캐릭터들을 제거한다. (제거하라고 알려준다.)
|
||||
PktNewSiegeBroadCast pktNSBC;
|
||||
ZeroMemory(&pktNSBC, sizeof(PktNewSiegeBroadCast));
|
||||
pktNSBC.m_dwCID = GetCID();
|
||||
pktNSBC.m_cType = BroadCastSiege::BROADCAST_DELETE_DATA;
|
||||
|
||||
bool bDeletePacketCrypt = true;
|
||||
char* szPacket = reinterpret_cast<char *>(&pktNSBC);
|
||||
if (!PacketWrap::WrapCrypt(szPacket, sizeof(PktNewSiegeBroadCast), CmdNewSiegeBroadCast, 0, 0))
|
||||
{
|
||||
ERRLOG0(g_Log, "Siege Broadcast delete data packet crypt fail..");
|
||||
bDeletePacketCrypt = false;
|
||||
}
|
||||
|
||||
BroadCastSet::iterator itr = m_BroadCastSet.begin();
|
||||
while (itr != m_BroadCastSet.end())
|
||||
{
|
||||
CCharacter* lpCharacter = CCreatureManager::GetInstance().GetCharacter( (*itr) );
|
||||
if (lpCharacter)
|
||||
{
|
||||
if (lpCharacter->GetCurrentPos().GetSquaredDistance( GetCurrentPos() ) > Siege::BROADCAST_SQUARED_RADIUS)
|
||||
{
|
||||
itr = m_BroadCastSet.erase(itr);
|
||||
|
||||
CGameClientDispatch* lpDispatch = lpCharacter->GetDispatcher();
|
||||
if (NULL != lpDispatch && bDeletePacketCrypt)
|
||||
{
|
||||
lpDispatch->GetSendStream().PutBuffer(szPacket, sizeof(PktNewSiegeBroadCast), CmdNewSiegeBroadCast);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
itr = m_BroadCastSet.erase(itr);
|
||||
}
|
||||
}
|
||||
|
||||
// BroadCast Data 와 Delta Data 를 압축해둔다.
|
||||
char szSrcBuffer[ BroadCastSiege::MAX_SIEGEBROADCAST_BUFFER_SIZE ] ;
|
||||
char szDeltaSrcBuffer[ BroadCastSiege::MAX_SIEGEBROADCAST_BUFFER_SIZE ] ;
|
||||
m_dwBroadCastSize = BroadCastSiege::MAX_SIEGEBROADCAST_BUFFER_SIZE;
|
||||
m_dwDeltaSize = 0;
|
||||
|
||||
PktNewSiegeBroadCast* lpPktNewSiegeBC = reinterpret_cast<PktNewSiegeBroadCast*>( szSrcBuffer );
|
||||
char* lpDataPos = reinterpret_cast<char*>( lpPktNewSiegeBC + 1 );
|
||||
lpPktNewSiegeBC->m_dwCID = GetCID();
|
||||
lpPktNewSiegeBC->m_cType = BroadCastSiege::BROADCAST_ALL_DATA;
|
||||
memcpy( lpDataPos, m_SerializeSiegeObjectData.GetBroadCastData(), m_SerializeSiegeObjectData.GetBroadCastDataLen() );
|
||||
PacketWrap::WrapCompress( m_szBroadCastBuffer, m_dwBroadCastSize, szSrcBuffer,
|
||||
static_cast<unsigned short>( sizeof(PktNewSiegeBroadCast) + m_SerializeSiegeObjectData.GetBroadCastDataLen() ),
|
||||
CmdNewSiegeBroadCast, 0, 0 );
|
||||
|
||||
if ( m_SerializeSiegeObjectData.GetDeltaDataLen() > 0 )
|
||||
{
|
||||
m_dwDeltaSize = BroadCastSiege::MAX_SIEGEBROADCAST_BUFFER_SIZE;
|
||||
|
||||
lpPktNewSiegeBC = reinterpret_cast<PktNewSiegeBroadCast*>( szDeltaSrcBuffer ) ;
|
||||
lpDataPos = reinterpret_cast<char*>( lpPktNewSiegeBC + 1 );
|
||||
lpPktNewSiegeBC->m_dwCID = GetCID();
|
||||
lpPktNewSiegeBC->m_cType = BroadCastSiege::BROADCAST_DELTA_DATA;
|
||||
memcpy( lpDataPos, m_SerializeSiegeObjectData.GetDeltaData(), m_SerializeSiegeObjectData.GetDeltaDataLen() );
|
||||
PacketWrap::WrapCompress( m_szDeltaBuffer, m_dwDeltaSize, szDeltaSrcBuffer,
|
||||
static_cast<unsigned short>( sizeof(PktNewSiegeBroadCast) + m_SerializeSiegeObjectData.GetDeltaDataLen() ),
|
||||
CmdNewSiegeBroadCast, 0, 0 );
|
||||
}
|
||||
|
||||
// 범위내에 있는 캐릭터노드들을 검사한다.
|
||||
CCharSphereTree::GetInstance().RangeTest( GetCurrentPos(), Siege::BROADCAST_RADIUS, this );
|
||||
}
|
||||
|
||||
void CSiegeObject::RangeTestCallBack( const Position& centerPos, float fDistance, CCharSphereNode* pNode )
|
||||
{
|
||||
if ( pNode )
|
||||
{
|
||||
BroadCastSet::iterator itr = m_BroadCastSet.find(pNode->GetCID());
|
||||
if (itr != m_BroadCastSet.end())
|
||||
{
|
||||
CCharacter* lpCharacter = pNode->GetCharacter();
|
||||
if (NULL != lpCharacter)
|
||||
{
|
||||
// 기존에 있던 캐릭터이다. Delta 정보만 보내준다.
|
||||
if (m_SerializeSiegeObjectData.GetDeltaDataLen() > 0)
|
||||
{
|
||||
CGameClientDispatch* lpDispatch = lpCharacter->GetDispatcher();
|
||||
if (NULL != lpDispatch)
|
||||
{
|
||||
lpDispatch->GetSendStream().PutBuffer(m_szDeltaBuffer, m_dwDeltaSize, CmdNewSiegeBroadCast);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 새로 추가된 캐릭터이다. BroadCast 로 모든 정보를 보낸다.
|
||||
CCharacter* lpCharacter = pNode->GetCharacter();
|
||||
if (NULL != lpCharacter)
|
||||
{
|
||||
CGameClientDispatch* lpDispatch = lpCharacter->GetDispatcher();
|
||||
if (NULL != lpDispatch)
|
||||
{
|
||||
lpDispatch->GetSendStream().PutBuffer(m_szBroadCastBuffer, m_dwBroadCastSize, CmdNewSiegeBroadCast);
|
||||
}
|
||||
|
||||
m_BroadCastSet.insert( pNode->GetCID() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSiegeObject::SendToRange( float fRadius, const char* szPacket, unsigned long dwPacketSize, unsigned char cCMD_In )
|
||||
{
|
||||
CCharSphereTree::GetInstance().SendToRange( GetCurrentPos(), fRadius, szPacket, dwPacketSize, cCMD_In );
|
||||
}
|
||||
|
||||
void CSiegeObject::SendHPUpdateToDBAgent(bool bForce)
|
||||
{
|
||||
++m_cHPUpdateCount;
|
||||
|
||||
// 중계 서버로 패킷 전송
|
||||
GET_SINGLE_DISPATCH(lpDBAgentDispatch, CDBAgentDispatch, CDBAgentDispatch::GetDispatchTable());
|
||||
if (lpDBAgentDispatch)
|
||||
{
|
||||
switch (m_wObjectType)
|
||||
{
|
||||
case Siege::CAMP: // 길드 요새
|
||||
case Siege::CAMP_SHOP: // 길드 요새 상점
|
||||
case Siege::MINING_CAMP: // 채굴기
|
||||
case Siege::KARTERANT_WEAPON: // 월드 웨폰
|
||||
case Siege::MERKADIA_WEAPON: // 월드 웨폰
|
||||
{
|
||||
if (bForce || m_cHPUpdateCount >= MAX_HP_UPDATE_COUNT)
|
||||
{
|
||||
GameClientSendPacket::SendCharCampCmdToDBAgent(lpDBAgentDispatch->GetSendStream(), 0, GetCampID(),
|
||||
m_CreatureStatus.m_nNowHP, 0, PktCampCmd::CAMP_UPDATE_HP,
|
||||
PktBase::NO_SERVER_ERR);
|
||||
m_cHPUpdateCount = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Siege::EMBLEM: // 성 상징물
|
||||
case Siege::GATE: // 성문
|
||||
case Siege::GUARD: // 가드
|
||||
case Siege::SHORT_RANGE_CASTLE_ARMS: // 근거리 수성 병기
|
||||
case Siege::LONG_RANGE_CASTLE_ARMS: // 원거리 수성 병기
|
||||
{
|
||||
if (bForce || m_cHPUpdateCount >= MAX_HP_UPDATE_COUNT)
|
||||
{
|
||||
GameClientSendPacket::SendCharCastleCmdToDBAgent(lpDBAgentDispatch->GetSendStream(), 0, GetCastleID(), m_dwCID,
|
||||
GetDefaultNowHP(), 0, PktCastleCmd::CASTLE_UPDATE_HP,
|
||||
PktBase::NO_SERVER_ERR);
|
||||
m_cHPUpdateCount = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Siege::SHORT_RANGE_SIEGE_ARMS: // 근거리 공성 병기
|
||||
case Siege::LONG_RANGE_SIEGE_ARMS: // 원거리 공성 병기
|
||||
case Siege::AIRSHIP: // 수송선
|
||||
{
|
||||
if (bForce || m_cHPUpdateCount >= MAX_HP_UPDATE_COUNT)
|
||||
{
|
||||
GameClientSendPacket::SendCharSiegeArmsCmdToDBAgent(lpDBAgentDispatch->GetSendStream(), m_dwOwnerID, m_dwCID,
|
||||
m_CreatureStatus.m_nNowHP, PktSiegeArmsCmd::SIEGE_UPDATE_HP,
|
||||
PktBase::NO_SERVER_ERR);
|
||||
m_cHPUpdateCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CSiegeObject::IsCamp() const
|
||||
{
|
||||
switch ( m_wObjectType )
|
||||
{
|
||||
case Siege::CAMP:
|
||||
case Siege::CAMP_SHOP:
|
||||
case Siege::MINING_CAMP:
|
||||
case Siege::KARTERANT_WEAPON:
|
||||
case Siege::MERKADIA_WEAPON:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CSiegeObject::IsCastleObject() const
|
||||
{
|
||||
switch ( m_wObjectType )
|
||||
{
|
||||
case Siege::EMBLEM :
|
||||
case Siege::GATE :
|
||||
case Siege::BACKDOOR :
|
||||
case Siege::CASTLE_ARMS_NPC :
|
||||
case Siege::GUARD :
|
||||
case Siege::SHORT_RANGE_CASTLE_ARMS :
|
||||
case Siege::LONG_RANGE_CASTLE_ARMS :
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CSiegeObject::IsCastleArms() const
|
||||
{
|
||||
switch ( m_wObjectType )
|
||||
{
|
||||
case Siege::GUARD :
|
||||
case Siege::SHORT_RANGE_CASTLE_ARMS :
|
||||
case Siege::LONG_RANGE_CASTLE_ARMS :
|
||||
case Siege::CASTLE_ARMS_NPC :
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CSiegeObject::IsSiegeArms() const
|
||||
{
|
||||
switch ( m_wObjectType )
|
||||
{
|
||||
case Siege::SHORT_RANGE_SIEGE_ARMS :
|
||||
case Siege::LONG_RANGE_SIEGE_ARMS :
|
||||
case Siege::AIRSHIP :
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool CSiegeObject::IsRidable() const
|
||||
{
|
||||
switch ( m_wObjectType )
|
||||
{
|
||||
case Siege::SHORT_RANGE_CASTLE_ARMS :
|
||||
case Siege::LONG_RANGE_CASTLE_ARMS :
|
||||
case Siege::SHORT_RANGE_SIEGE_ARMS :
|
||||
case Siege::LONG_RANGE_SIEGE_ARMS :
|
||||
case Siege::AIRSHIP :
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CSiegeObject::SetMaterialNum(unsigned char cMaterial)
|
||||
{
|
||||
m_cMaterial = cMaterial;
|
||||
}
|
||||
|
||||
void CSiegeObject::SetNation(unsigned char cNation)
|
||||
{
|
||||
m_cNation = cNation;
|
||||
|
||||
if (IsEmblem() && Creature::STATELESS == cNation)
|
||||
{
|
||||
m_cState = Siege::COMPLETE;
|
||||
m_cSubState = Siege::NONE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
#ifndef _SIEGE_OBJECT_H_
|
||||
#define _SIEGE_OBJECT_H_
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <Creature/Monster/PatternMonster.h>
|
||||
#include <Creature/Siege/SiegeConstants.h>
|
||||
#include <Creature/Character/SphereTree/CharSphereTree.h>
|
||||
#include <Creature/Siege/SerializeSiegeObjectData.h>
|
||||
#include <Network/Packet/PacketStruct/CastlePacket.h>
|
||||
|
||||
using namespace Siege;
|
||||
|
||||
// 전방 참조
|
||||
class CCharacter;
|
||||
|
||||
namespace BroadCastSiege
|
||||
{
|
||||
class CSerializeSiegeObjectData;
|
||||
}
|
||||
|
||||
class CSiegeObject : public CSkillMonster, public ICharSphereTreeCallBack
|
||||
{
|
||||
public:
|
||||
|
||||
typedef std::set<unsigned long> BroadCastSet;
|
||||
|
||||
virtual ~CSiegeObject();
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// CSkillMonster 로부터 상속받은 함수
|
||||
|
||||
// 적아군 식별
|
||||
virtual EnemyCheck::EnemyType IsEnemy(CCreature* lpTarget, unsigned char* cResult = NULL);
|
||||
|
||||
// 자체 공격 능력 구현 함수
|
||||
virtual void NormalBehavior(unsigned long dwTick) { }
|
||||
virtual void AttackBehavior(unsigned long dwTick) { }
|
||||
virtual void SearchPlayer(void) { }
|
||||
bool SkillAttack(void);
|
||||
|
||||
virtual bool Dead(CAggresiveCreature* pOffencer) { return false; }
|
||||
virtual void MoveTo(const Position& NewPosition);
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// 캐릭터가 조종해서 공격할 경우 Attack Packet 처리 함수
|
||||
|
||||
virtual bool AttackCID(CCharacter* lpRideChar, AtType attackType, AtNode& attackNode, unsigned short& wError) { return false; }
|
||||
virtual bool Attack(AtType attackType, unsigned char cDefenderNum, CAggresiveCreature** ppDefenders,
|
||||
unsigned char* cDefenserJudges, unsigned short* wDefenserMPHeal) { return false; }
|
||||
virtual bool MissileAttack(AtType attackType, float fDir, float nRange, float fAngle, char cTargetType) { return false; }
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// SiegeObject 처리 함수
|
||||
|
||||
virtual bool Build(unsigned char cUpgradeStep = 0) { return false; } // 구축 완료시 처리
|
||||
virtual bool Cancel() { return false; } // 구축 취소 완료
|
||||
virtual bool Upgrade(unsigned char cUpgradeStep) { return false; } // 업그레이드 완료시 처리
|
||||
virtual bool Repair(unsigned short wRepairHP) { return false; } // 수리 완료시 처리
|
||||
virtual bool Restore() { return false; } // 복구 완료시 처리
|
||||
virtual bool Destroy(unsigned char cOffencerNation, bool bTakeGold) { return false; } // 파괴 완료시 처리 (자체 파괴, 파괴됨)
|
||||
virtual bool Destroy(unsigned long dwOffencerGID) { return false; } // 길드 요새 파괴 완료시 처리 (자체 파괴, 파괴됨)
|
||||
virtual bool Update(unsigned char cState, unsigned long dwValue1, unsigned long dwValue2, unsigned long dwOwnerID, unsigned char cSubCmd) { return false; } // 정보 업데이트
|
||||
virtual bool ChangeType(unsigned short wChangeType) { return false; } // 변형 완료시 처리
|
||||
|
||||
// 스타터킷 아이템으로 전환 (bFullMaterial 이 true 이면 자재의 90%를 돌려준다.)
|
||||
virtual bool ToStarterKit(bool bFullMaterial=false) { return false; }
|
||||
|
||||
virtual unsigned long GetRepairGold() const { return Siege::MAX_REPAIR_GOLD; }
|
||||
unsigned long GetRepairHP();
|
||||
|
||||
// Rider 관련 정보
|
||||
virtual unsigned char IsRider(unsigned long dwCID) const; // 해당 캐릭터가 병기에 탑승해 있는가?
|
||||
virtual bool Ride(unsigned long dwCID) { return false; } // 병기 탑승
|
||||
virtual bool GetOff(unsigned long dwCID) { return false; } // 병기 내림
|
||||
virtual void AllGetOff() { GetOff(m_dwRiderCID); } // 병기에서 모두 내림
|
||||
|
||||
// 성 오브젝트 관련된 함수 (상징물 업그레이드에 따른 효과)
|
||||
void UpgradeByEmblem(unsigned char cUpgradeType, unsigned char cUpgradeStep);
|
||||
void DegradeByEmblem(unsigned char cUpgradeType, unsigned char cUpgradeStep);
|
||||
unsigned short GetDefaultNowHP(); // 상징물의 업그레이드 효과가 없는 현재 HP 얻기
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
// 반경 5셀에 패킷을 전송하는 함수
|
||||
void SendHPUpdateToDBAgent(bool bForce=false);
|
||||
|
||||
// 이전 브로드캐스트 함수
|
||||
// void SendToRadiusCell(const char* szPacket, unsigned long dwPacketSize, unsigned char cCMD_In);
|
||||
// bool SerializeOut(char* szBuffer_In, unsigned short& wDataLen);
|
||||
|
||||
void RangeTest();
|
||||
virtual void RangeTestCallBack( const Position& centerPos, float fDistance, CCharSphereNode* pNode );
|
||||
void SendToRange( float fRadius, const char* szPacket, unsigned long dwPacketSize, unsigned char cCMD_In );
|
||||
|
||||
BroadCastSiege::CSerializeSiegeObjectData& GetSerializeData(void) { return m_SerializeSiegeObjectData; }
|
||||
|
||||
|
||||
|
||||
// Get / Set 함수
|
||||
bool IsEmblem() const { return (Siege::EMBLEM == m_wObjectType); }
|
||||
bool IsCamp() const;
|
||||
bool IsGate() const { return (Siege::GATE == m_wObjectType); }
|
||||
bool IsGuard() const { return (Siege::GUARD == m_wObjectType); }
|
||||
bool IsCastleObject() const;
|
||||
bool IsCastleArms() const;
|
||||
bool IsSiegeArms() const;
|
||||
bool IsRidable() const; // 탈수 있는 오브젝트인가?
|
||||
bool IsCastleNPC() const { return (m_wObjectType == Siege::BACKDOOR || m_wObjectType == Siege::CASTLE_ARMS_NPC); }
|
||||
bool IsMaxHP() const { return (m_CreatureStatus.m_nNowHP == m_CreatureStatus.m_StatusInfo.m_nMaxHP); }
|
||||
bool IsPeaceMode();
|
||||
bool IsRideArms(void) const { return false; }
|
||||
bool IsWorldWeapon() const;
|
||||
|
||||
unsigned short GetObjectType() const { return m_wObjectType; }
|
||||
|
||||
unsigned long GetCID() const { return m_dwCID; }
|
||||
unsigned long GetNowHP() const { return m_CreatureStatus.m_nNowHP; }
|
||||
unsigned long GetMaxHP() const { return m_CreatureStatus.m_StatusInfo.m_nMaxHP; }
|
||||
unsigned char GetState() const { return m_cState; }
|
||||
unsigned char GetSubState() const { return m_cSubState; }
|
||||
unsigned char GetUpgradeStep() const { return m_cUpgradeStep; }
|
||||
unsigned char GetUpgradeType() const { return m_cUpgradeType; }
|
||||
const Position& GetPosition() const { return m_CurrentPos; }
|
||||
unsigned char GetMaterialNum() const { return m_cMaterial; }
|
||||
unsigned char GetSiegeCount() const { return m_cSiegeCount; }
|
||||
float GetDefaultDir() const { return m_fDefaultDir; }
|
||||
unsigned long GetRiderCID() const { return m_dwRiderCID; }
|
||||
virtual void GetRiders( unsigned long* pRiders ) const;
|
||||
virtual unsigned char GetRiderNum() const;
|
||||
|
||||
unsigned long GetDevelopGold(unsigned short wDefaultObjectType=Siege::DEFAULT_TYPE) const;
|
||||
unsigned char GetDevelopSpeed(unsigned short wDefaultObjectType=Siege::DEFAULT_TYPE) const;
|
||||
unsigned long GetUpgradeGold() const;
|
||||
unsigned char GetUpgradeSpeed(unsigned char cDefaultUpgradeType=Siege::NO_JEWEL) const;
|
||||
float GetBonusRate() const;
|
||||
|
||||
int GetKID() const;
|
||||
unsigned char GetNation() const;
|
||||
unsigned long GetGID() const;
|
||||
CAggresiveCreature* GetDuelOpponent(void) const;
|
||||
|
||||
char GetConsumeMPCount(void) { return m_cConsumeMPCount; }
|
||||
|
||||
unsigned long GetCastleID() const { return m_dwCampOrCastleID; }
|
||||
unsigned long GetCampID() const { return m_dwCampOrCastleID; }
|
||||
unsigned long GetOwnerID() const { return m_dwOwnerID; }
|
||||
|
||||
void SetGID(unsigned long dwGID) { m_dwGID = dwGID; }
|
||||
void SetFullMP() { m_CreatureStatus.m_nNowMP = m_CreatureStatus.m_StatusInfo.m_nMaxMP; }
|
||||
void SetState(unsigned char cState) { m_cState = cState; }
|
||||
void SetSubState(unsigned char cSubState) { m_cSubState = cSubState; }
|
||||
void SetMaterialNum(unsigned char cMaterial);
|
||||
void SetSiegeCount(unsigned char cSiegeCount) { m_cSiegeCount = cSiegeCount; }
|
||||
void SetNation(unsigned char cNation);
|
||||
|
||||
protected:
|
||||
|
||||
CSiegeObject(MonsterCreateInfo& MonsterCreate, const CastleObjectInfo& CastleObject);
|
||||
CSiegeObject(MonsterCreateInfo& MonsterCreate, unsigned long dwCampID, unsigned long dwGID,
|
||||
unsigned long dwHP, unsigned short wObjectType, unsigned char cState, unsigned char cSubState,
|
||||
unsigned char cUpgradeStep, unsigned char cMaterial, unsigned char cSiegeCount, bool bFullHP);
|
||||
CSiegeObject(MonsterCreateInfo& MonsterCreate, unsigned long dwOwnerID, unsigned char cNation,
|
||||
unsigned long dwHP, unsigned short wObjectType, unsigned char cState, unsigned char cUpgradeStep);
|
||||
|
||||
void UpdateObjectInfo(unsigned char cHPType=Siege::NOW_HP, unsigned short wRepairHP=0); // 상태, 업그레이드 변화시에 내부값들 변경
|
||||
|
||||
unsigned long m_dwCampOrCastleID; // CastleID : 성 상징물, 성문, 뒷문, 가드, 근거리/원거리 수성병기
|
||||
// CampID : 길드 요새 상징물, 경비병
|
||||
unsigned long m_dwOwnerID; // CID : 근거리/원거리 수성병기, 근거리/원거리 공성병기, 비공정
|
||||
|
||||
unsigned long m_dwGID; // GID : 길드 요새 및 월드 웨폰의 소유 길드의 길드ID
|
||||
// 주의!! 공성전 관련 오브젝트는 GID 를 사용하지 않는다!!
|
||||
unsigned char m_cNation; // 공성전 관련 오브젝트가 사용하는 국가
|
||||
|
||||
unsigned short m_wObjectType; // 공성 관련 오브젝트 타입
|
||||
unsigned char m_cState; // 현재 오브젝트의 상태
|
||||
unsigned char m_cSubState; // 현재 오브젝트의 서브 상태 (Use EMBLEM & GATE)
|
||||
unsigned char m_cUpgradeStep; // 현재 오브젝트의 업그레이드 단계
|
||||
unsigned char m_cUpgradeType; // 성 상징물의 업그레이드 타입 (Only EMBLEM)
|
||||
unsigned char m_cMaterial; // 공성 자재 갯수
|
||||
unsigned char m_cSiegeCount; // 공성 지난 횟수
|
||||
float m_fDefaultDir; // 수성 병기의 기본 방향
|
||||
unsigned long m_dwRiderCID; // 수성 병기, 공성 병기에 탑승한 캐릭터의 CID
|
||||
|
||||
unsigned char m_cHPUpdateCount; // HP 정보 업데이트 카운트
|
||||
|
||||
// Rider 정보가 필요한 이유
|
||||
// 1. 몇명이나 타고 있는지 알수가 없다.
|
||||
// 2. 누군가가 내렸을 경우 누가 내렸는지 알수가 없다.
|
||||
//
|
||||
// * 드랍쉽에 타고 내릴때 소유주체크를 하면 안된다.
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// New BroadCast Data
|
||||
BroadCastSiege::CSerializeSiegeObjectData m_SerializeSiegeObjectData; // 공성 오브젝트 데이터 보관 및 변경된 데이터 보관
|
||||
|
||||
char m_szBroadCastBuffer[ BroadCastSiege::MAX_SIEGEBROADCAST_BUFFER_SIZE ];
|
||||
char m_szDeltaBuffer[ BroadCastSiege::MAX_SIEGEBROADCAST_BUFFER_SIZE ];
|
||||
unsigned long m_dwBroadCastSize;
|
||||
unsigned long m_dwDeltaSize;
|
||||
|
||||
BroadCastSet m_BroadCastSet;
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
friend class CSiegeObjectMgr;
|
||||
};
|
||||
|
||||
#endif // _SIEGE_OBJECT_H_
|
||||
@@ -0,0 +1,745 @@
|
||||
#include "stdafx.h"
|
||||
#include "SiegeObject.h"
|
||||
|
||||
#include <Utility/Registry/RegFunctions.h>
|
||||
#include <Utility/Math/Math.h>
|
||||
|
||||
#include <Skill/Spell/Spell.h>
|
||||
#include <Skill/SkillMgr.h>
|
||||
|
||||
#include <Network/Dispatch/DBAgent/DBAgentDispatch.h>
|
||||
#include <Network/Dispatch/DBAgent/DBAgentRequest.h>
|
||||
#include <Network/Dispatch/GameClient/SendCharCastle.h>
|
||||
|
||||
#include <Creature/CreatureManager.h>
|
||||
|
||||
#include <Map/FieldMap/CellManager.h>
|
||||
|
||||
#include <Creature/Monster/Monster.h>
|
||||
#include <Creature/Monster/PatternMonster.h>
|
||||
|
||||
#include <Castle/Castle.h>
|
||||
#include <Castle/CastleMgr.h>
|
||||
|
||||
|
||||
|
||||
void CSiegeObject::NormalBehavior(unsigned long dwTick)
|
||||
{
|
||||
if ( !IsEmblem() && !IsGuard() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (false == Castle::CCastleMgr::GetInstance().IsSiegeTime())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 선공 몹 처리
|
||||
if (NULL == m_lpTarget && true == m_MonsterInfo.m_bFirstAttack)
|
||||
{
|
||||
SearchPlayer();
|
||||
}
|
||||
}
|
||||
|
||||
void CSiegeObject::AttackBehavior(unsigned long dwTick)
|
||||
{
|
||||
PERFORMANCE_CHECK(FunctionTimingCheck)
|
||||
|
||||
if ( !IsEmblem() && !IsGuard() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (false == Castle::CCastleMgr::GetInstance().IsSiegeTime())
|
||||
{
|
||||
CancelTarget();
|
||||
return;
|
||||
}
|
||||
|
||||
// 마법 캐스팅 중일때는.. 아무런 다른 행동을 해서는 안된다.
|
||||
if (true == m_bCasting)
|
||||
{
|
||||
CastingAttackAction();
|
||||
return;
|
||||
}
|
||||
|
||||
m_lpTarget = m_Threat.GetTarget();
|
||||
if (NULL == m_lpTarget ||
|
||||
(m_lpTarget && true == m_lpTarget->GetEnchantInfo().GetFlag(Skill::SpellID::Hide)))
|
||||
{
|
||||
CancelTarget();
|
||||
return;
|
||||
}
|
||||
|
||||
const float fDY = fabs(m_lpTarget->GetCurrentPos().m_fPointY - GetCurrentPos().m_fPointY);
|
||||
const float fDX = m_lpTarget->GetCurrentPos().m_fPointX - GetCurrentPos().m_fPointX;
|
||||
const float fDZ = m_lpTarget->GetCurrentPos().m_fPointZ - GetCurrentPos().m_fPointZ;
|
||||
const float fDistance = sqrtf((fDX * fDX) + (fDZ * fDZ));
|
||||
|
||||
if (IsEmblem() && fDY > Siege::EMBLEM_ATTACK_HEIGHT_ERROR)
|
||||
{
|
||||
CancelTarget();
|
||||
return;
|
||||
}
|
||||
|
||||
if (((fDistance > m_wSearchRange) && false == m_bLongRangeAttacked) || (0 == m_lpTarget->GetStatus().m_nNowHP))
|
||||
{
|
||||
CancelTarget();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const float fAttackRange = m_MonsterInfo.m_wAttackRange / 100.0f;
|
||||
|
||||
if (fDistance > fAttackRange && 0 >= m_lCurrentFrame)
|
||||
{
|
||||
// 공격 범위 밖이다.
|
||||
if (true == SkillAttack()) // 스킬 공격을 사용하는가 체크
|
||||
{
|
||||
SkillAttackAction();
|
||||
}
|
||||
/* else
|
||||
{
|
||||
m_MotionInfo.m_wAction = MonsterInfo::Z3D_CA_WALK; // 일단 걷기로 세팅
|
||||
GetMotion(m_MotionInfo.m_wAction, m_MotionInfo); // 걷기 모션 정보를 얻어온다.
|
||||
|
||||
// 몬스터가 이동 공격을 할만한 거리인가 체크
|
||||
if (fDistance < fAttackRange + m_MotionInfo.m_fVelocity)
|
||||
{
|
||||
// 걸어가면서 공격한다.
|
||||
WalkAttackAction(fDistance - fAttackRange + 0.1f);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 달려간다
|
||||
RunAction(fDistance, m_lpTarget->GetCurrentPos().m_fPointX, m_lpTarget->GetCurrentPos().m_fPointZ);
|
||||
|
||||
// 내 활동구역을 벗어나따. 돌아가자~!
|
||||
if (true == m_MonsterInfo.m_bReturnPosition && true == IsReturn())
|
||||
{
|
||||
m_wSearchRange = OutsideSearchRange;
|
||||
CancelTarget();
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
if (false == m_bAttacking)
|
||||
{
|
||||
m_lCurrentFrame = m_MotionInfo.m_dwFrame;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 공격 범위 안이다.
|
||||
if (false == m_bAttacking)
|
||||
{
|
||||
if (true == SkillAttack()) // 스킬 공격을 사용하는가 체크
|
||||
{
|
||||
SkillAttackAction();
|
||||
}
|
||||
/* else
|
||||
{
|
||||
AttackAction();
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool CSiegeObject::SkillAttack()
|
||||
{
|
||||
unsigned char cSkillLockCount = m_cUpgradeStep + 1;
|
||||
unsigned char cSkillLevel = CSkillMonster::USE_SKILL_LEVEL;
|
||||
|
||||
// MON_TODO : 5단계 마법(LockCount : 4)은 아직 사용할수 없다.
|
||||
if (cSkillLockCount >= CSkillMgr::MAX_SKILL_LOCKCOUNT - 1)
|
||||
{
|
||||
cSkillLockCount = CSkillMgr::MAX_SKILL_LOCKCOUNT - 2;
|
||||
}
|
||||
|
||||
|
||||
enum { FIRST_PATTERN=0, SECOND_PATTERN=1, MAX_PATTERN = 2 };
|
||||
int nSelectPattern = FIRST_PATTERN;
|
||||
|
||||
CAggresiveCreature* ppAggresiveCreature[AtNode::MAX_DEFENDER_NUM] = {0, };
|
||||
|
||||
AtType attackType;
|
||||
attackType.m_cSkillLockCount = cSkillLockCount;
|
||||
attackType.m_cSkillLevel = cSkillLevel;
|
||||
|
||||
char nSkillPattern = 0;
|
||||
|
||||
while (nSelectPattern < MAX_PATTERN)
|
||||
{
|
||||
switch (nSelectPattern)
|
||||
{
|
||||
case FIRST_PATTERN:
|
||||
{
|
||||
// 조건 대상 행동
|
||||
// A B A : 스킬 사용 가능 MP 잔여량 있음 / 대상이 스킬 사용 가능 범위에 있을 때
|
||||
// : 자신에게 가장 위협적인 적에게
|
||||
// : 공격 스킬열에 해당하는 스킬 사용
|
||||
|
||||
// 스킬이 없다면.. 다음 패턴으로..
|
||||
if (0 == m_MonsterInfo.m_wSkillID[SkillPattern::ATTACK_SKILL])
|
||||
{
|
||||
++nSelectPattern;
|
||||
continue;
|
||||
}
|
||||
|
||||
nSkillPattern = SkillPattern::ATTACK_SKILL;
|
||||
attackType.m_wType = m_MonsterInfo.m_wSkillID[SkillPattern::ATTACK_SKILL];
|
||||
ppAggresiveCreature[0] = m_lpTarget;
|
||||
}
|
||||
break;
|
||||
|
||||
case SECOND_PATTERN:
|
||||
{
|
||||
// 조건 대상 행동
|
||||
// A B D : 스킬 사용 가능 MP 잔여량 있음 / 대상이 스킬 사용 가능 범위에 있을 때
|
||||
// : 자신에게 가장 위협적인 적에게
|
||||
// : 범위 스킬열에 해당하는 스킬 사용
|
||||
|
||||
// 스킬이 없다면.. 다음 패턴으로..
|
||||
if (0 == m_MonsterInfo.m_wSkillID[SkillPattern::EXTENT_SKILL])
|
||||
{
|
||||
++nSelectPattern;
|
||||
continue;
|
||||
}
|
||||
|
||||
nSkillPattern = SkillPattern::EXTENT_SKILL;
|
||||
attackType.m_wType = m_MonsterInfo.m_wSkillID[SkillPattern::EXTENT_SKILL];
|
||||
ppAggresiveCreature[0] = m_lpTarget;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
ERRLOG1(g_Log, "CID:0x%08x 없는 패턴이 넘어왔습니다.", m_dwCID);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 스킬 사용 (캐스팅 타입인 경우에는 사용할수 있는지만 체크하게 된다.)
|
||||
if (true == UseSkill(attackType, ppAggresiveCreature, nSkillPattern))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
++nSelectPattern;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CSiegeObject::UpdateObjectInfo(unsigned char cHPType, unsigned short wRepairHP)
|
||||
{
|
||||
unsigned short wPrevMaxHP = m_CreatureStatus.m_StatusInfo.m_nMaxHP;
|
||||
unsigned short wNowHP = m_CreatureStatus.m_nNowHP;
|
||||
int nKID = Siege::GetKID(m_wObjectType, m_cState, m_cUpgradeType, m_cUpgradeStep);
|
||||
|
||||
const CMonsterMgr::MonsterProtoType* lpProtoType = CMonsterMgr::GetInstance().GetMonsterProtoType(nKID);
|
||||
if (lpProtoType)
|
||||
{
|
||||
m_CreatureStatus = lpProtoType->m_CreatureStatus;
|
||||
m_MonsterInfo = lpProtoType->m_MonsterInfo;
|
||||
|
||||
m_CreatureStatus.m_StatusInfo.CalculateSubStatus();
|
||||
}
|
||||
|
||||
switch (cHPType)
|
||||
{
|
||||
case Siege::NOW_HP:
|
||||
m_CreatureStatus.m_nNowHP = wNowHP;
|
||||
break;
|
||||
|
||||
case Siege::UPGRADE_HP:
|
||||
m_CreatureStatus.m_nNowHP = wNowHP + m_CreatureStatus.m_StatusInfo.m_nMaxHP - wPrevMaxHP;
|
||||
SendHPUpdateToDBAgent();
|
||||
break;
|
||||
|
||||
case Siege::REPAIR_HP:
|
||||
m_CreatureStatus.m_nNowHP = wNowHP + wRepairHP;
|
||||
SendHPUpdateToDBAgent(true);
|
||||
break;
|
||||
|
||||
case Siege::FULL_HP:
|
||||
m_CreatureStatus.m_nNowHP = m_CreatureStatus.m_StatusInfo.m_nMaxHP;
|
||||
SendHPUpdateToDBAgent(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CSiegeObject::UpgradeByEmblem(unsigned char cUpgradeType, unsigned char cUpgradeStep)
|
||||
{
|
||||
int nKID = Siege::GetKID(Siege::EMBLEM, Siege::COMPLETE, cUpgradeType, cUpgradeStep);
|
||||
|
||||
const CMonsterMgr::MonsterProtoType* lpProtoType = CMonsterMgr::GetInstance().GetMonsterProtoType(nKID);
|
||||
if (lpProtoType)
|
||||
{
|
||||
// 업그레이드 속도 향상
|
||||
m_MonsterInfo.m_cUpgradeSpeed -= static_cast<unsigned char>(m_MonsterInfo.m_cUpgradeSpeed
|
||||
* lpProtoType->m_MonsterInfo.m_fUpgradeSpeedUp);
|
||||
|
||||
// 개발 속도 향상
|
||||
m_MonsterInfo.m_cDevelopSpeed -= static_cast<unsigned char>(m_MonsterInfo.m_cDevelopSpeed
|
||||
* lpProtoType->m_MonsterInfo.m_fDevelopSpeedUp);
|
||||
|
||||
// 방어력 향상
|
||||
m_CreatureStatus.m_StatusInfo.m_wArmor += static_cast<short>(m_CreatureStatus.m_StatusInfo.m_wArmor
|
||||
* lpProtoType->m_MonsterInfo.m_fDefenseUp);
|
||||
m_CreatureStatus.m_StatusInfo.m_wMagicResist += static_cast<short>(m_CreatureStatus.m_StatusInfo.m_wMagicResist
|
||||
* lpProtoType->m_MonsterInfo.m_fDefenseUp);
|
||||
|
||||
// HP 향상
|
||||
unsigned short wAddHP = static_cast<unsigned short>(m_CreatureStatus.m_StatusInfo.m_nMaxHP
|
||||
* lpProtoType->m_MonsterInfo.m_fHPUp);
|
||||
m_CreatureStatus.m_StatusInfo.m_nMaxHP += wAddHP;
|
||||
m_CreatureStatus.m_nNowHP += wAddHP;
|
||||
|
||||
// 공격력 향상
|
||||
m_CreatureStatus.m_StatusInfo.m_wMinDamage += static_cast<short>(m_CreatureStatus.m_StatusInfo.m_wMinDamage
|
||||
* lpProtoType->m_MonsterInfo.m_fOffenseUp);
|
||||
m_CreatureStatus.m_StatusInfo.m_wMaxDamage += static_cast<short>(m_CreatureStatus.m_StatusInfo.m_wMaxDamage
|
||||
* lpProtoType->m_MonsterInfo.m_fOffenseUp);
|
||||
m_CreatureStatus.m_StatusInfo.m_wMagicPower += static_cast<short>(m_CreatureStatus.m_StatusInfo.m_wMagicPower
|
||||
* lpProtoType->m_MonsterInfo.m_fOffenseUp);
|
||||
|
||||
// 생성 비용 절감
|
||||
m_MonsterInfo.m_dwDevelopGold -= static_cast<unsigned long>(m_MonsterInfo.m_dwDevelopGold
|
||||
* lpProtoType->m_MonsterInfo.m_fDevelopGoldDown);
|
||||
|
||||
// 업그레이드 비용 절감
|
||||
m_MonsterInfo.m_dwUpgradeGold -= static_cast<unsigned long>(m_MonsterInfo.m_dwUpgradeGold
|
||||
* lpProtoType->m_MonsterInfo.m_fUpgradeGoldDown);
|
||||
}
|
||||
}
|
||||
|
||||
void CSiegeObject::DegradeByEmblem(unsigned char cUpgradeType, unsigned char cUpgradeStep)
|
||||
{
|
||||
int nKID = Siege::GetKID(Siege::EMBLEM, Siege::COMPLETE, cUpgradeType, cUpgradeStep);
|
||||
const CMonsterMgr::MonsterProtoType* lpProtoTypeEmblem = CMonsterMgr::GetInstance().GetMonsterProtoType(nKID);
|
||||
|
||||
nKID = GetKID();
|
||||
const CMonsterMgr::MonsterProtoType* lpProtoType = CMonsterMgr::GetInstance().GetMonsterProtoType(nKID);
|
||||
|
||||
if (lpProtoType && lpProtoTypeEmblem)
|
||||
{
|
||||
unsigned short wNowHP = m_CreatureStatus.m_nNowHP -
|
||||
static_cast<unsigned short>(m_CreatureStatus.m_nNowHP * lpProtoTypeEmblem->m_MonsterInfo.m_fHPUp);
|
||||
|
||||
m_CreatureStatus = lpProtoType->m_CreatureStatus;
|
||||
m_MonsterInfo = lpProtoType->m_MonsterInfo;
|
||||
|
||||
m_CreatureStatus.m_nNowHP = wNowHP;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned short CSiegeObject::GetDefaultNowHP()
|
||||
{
|
||||
Castle::CCastle* lpCastle = Castle::CCastleMgr::GetInstance().GetCastle( GetCastleID() );
|
||||
CSiegeObject* lpEmblem = lpCastle->GetCastleEmblem();
|
||||
|
||||
if (lpCastle && lpEmblem)
|
||||
{
|
||||
int nKID = lpEmblem->GetKID();
|
||||
const CMonsterMgr::MonsterProtoType* lpProtoTypeEmblem = CMonsterMgr::GetInstance().GetMonsterProtoType(nKID);
|
||||
|
||||
if (lpProtoTypeEmblem)
|
||||
{
|
||||
return m_CreatureStatus.m_nNowHP - static_cast<unsigned short>(m_CreatureStatus.m_nNowHP * lpProtoTypeEmblem->m_MonsterInfo.m_fHPUp);
|
||||
}
|
||||
}
|
||||
|
||||
return m_CreatureStatus.m_nNowHP;
|
||||
}
|
||||
|
||||
void CSiegeObject::SetACTByObjectType()
|
||||
{
|
||||
switch (m_wObjectType)
|
||||
{
|
||||
case Siege::EMBLEM: m_cAttackableCreatureType = Creature::ACT_EMBLEM; break;
|
||||
case Siege::GATE: m_cAttackableCreatureType = Creature::ACT_GATE; break;
|
||||
case Siege::BACKDOOR: m_cAttackableCreatureType = Creature::ACT_NONE; break;
|
||||
case Siege::CAMP: m_cAttackableCreatureType = Creature::ACT_CAMP; break;
|
||||
case Siege::CASTLE_ARMS_NPC: m_cAttackableCreatureType = Creature::ACT_NONE; break;
|
||||
case Siege::GUARD: m_cAttackableCreatureType = Creature::ACT_GUARD; break;
|
||||
case Siege::SHORT_RANGE_CASTLE_ARMS: m_cAttackableCreatureType = Creature::ACT_SHORT_RANGE_CASTLE_ARMS; break;
|
||||
case Siege::LONG_RANGE_CASTLE_ARMS: m_cAttackableCreatureType = Creature::ACT_LONG_RANGE_CASTLE_ARMS; break;
|
||||
case Siege::SHORT_RANGE_SIEGE_ARMS: m_cAttackableCreatureType = Creature::ACT_SHORT_RANGE_SIEGE_ARMS; break;
|
||||
case Siege::LONG_RANGE_SIEGE_ARMS: m_cAttackableCreatureType = Creature::ACT_LONG_RANGE_SIEGE_ARMS; break;
|
||||
case Siege::AIRSHIP: m_cAttackableCreatureType = Creature::ACT_AIRSHIP; break;
|
||||
}
|
||||
}
|
||||
|
||||
void CSiegeObject::SearchPlayer()
|
||||
{
|
||||
switch (m_wObjectType)
|
||||
{
|
||||
case Siege::GUARD:
|
||||
SearchAirShip();
|
||||
break;
|
||||
|
||||
case Siege::EMBLEM:
|
||||
SearchEnemyPlayer();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CSiegeObject::SearchAirShip()
|
||||
{
|
||||
// TODO : 해상도 조절을 통해 float 계산을 없애보자.
|
||||
if (NULL == m_CellPos.m_lpCell)
|
||||
{
|
||||
ERRLOG1(g_Log, "CID:0X%08 공성 오브젝트가 셀 범위 밖에 있습니다.", m_dwCID);
|
||||
return;
|
||||
}
|
||||
|
||||
CCell* pCell = NULL;
|
||||
CSiegeObject* pTempTarget = NULL;
|
||||
CSiegeObject* pCurrentTarget = NULL;
|
||||
|
||||
// const float fSquareSearchRange = (float)(m_wSearchRange * m_wSearchRange);
|
||||
const float fSquareSearchRange = (float)(45 * 45);
|
||||
|
||||
for (int nCellCount = 0; nCellCount < CCell::CONNECT_NUM; ++nCellCount)
|
||||
{
|
||||
pCell = m_CellPos.m_lpCell->GetConnectCell(nCellCount);
|
||||
if (NULL == pCell || false == pCell->IsSiegeObject())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
pTempTarget = pCell->GetFirstAirShip();
|
||||
|
||||
while (NULL != pTempTarget)
|
||||
{
|
||||
if (pTempTarget->GetStatus().m_nNowHP > 0 && CCreature::ENEMY == IsEnemy(pTempTarget))
|
||||
{
|
||||
if (false == pTempTarget->GetEnchantInfo().GetFlag(Skill::SpellID::Stealth) &&
|
||||
false == pTempTarget->GetEnchantInfo().GetFlag(Skill::SpellID::Invincible) &&
|
||||
false == pTempTarget->GetEnchantInfo().GetFlag(Skill::SpellID::Hide))
|
||||
{
|
||||
const float fDX = pTempTarget->GetCurrentPos().m_fPointX - GetCurrentPos().m_fPointX;
|
||||
const float fDZ = pTempTarget->GetCurrentPos().m_fPointZ - GetCurrentPos().m_fPointZ;
|
||||
|
||||
const float fDistance = (fDX * fDX) + (fDZ * fDZ);
|
||||
|
||||
if (fDistance < fSquareSearchRange)
|
||||
{
|
||||
pCurrentTarget = pTempTarget;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pTempTarget = pCell->GetNextAirShip();
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL != pCurrentTarget)
|
||||
{
|
||||
m_Threat.AddToThreatList(pCurrentTarget, 1);
|
||||
m_nCurrentState = CFSM::GetInstance().StateTransition(m_nCurrentState, INPUT_ID_SEEN_PLAYER);
|
||||
}
|
||||
}
|
||||
|
||||
void CSiegeObject::SearchEnemyPlayer()
|
||||
{
|
||||
// TODO : 해상도 조절을 통해 float 계산을 없애보자.
|
||||
if (NULL == m_CellPos.m_lpCell)
|
||||
{
|
||||
ERRLOG1(g_Log, "CID:0X%08 공성 오브젝트가 셀 범위 밖에 있습니다.", m_dwCID);
|
||||
return;
|
||||
}
|
||||
|
||||
CCell* pCell = NULL;
|
||||
CCharacter* pTempTarget = NULL;
|
||||
CCharacter* pCurrentTarget = NULL;
|
||||
|
||||
// const float fSquareSearchRange = (float)(m_wSearchRange * m_wSearchRange);
|
||||
const float fSquareSearchRange = (float)(32 * 32);
|
||||
|
||||
for (int nCellCount = 0; nCellCount < CCell::CONNECT_NUM; ++nCellCount)
|
||||
{
|
||||
pCell = m_CellPos.m_lpCell->GetConnectCell(nCellCount);
|
||||
if (NULL == pCell || false == pCell->IsCharacter())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
pTempTarget = pCell->GetFirstCharacter();
|
||||
|
||||
while (NULL != pTempTarget)
|
||||
{
|
||||
const float fDistY = fabs(pTempTarget->GetCurrentPos().m_fPointY - GetCurrentPos().m_fPointY);
|
||||
|
||||
if (fDistY <= Siege::EMBLEM_ATTACK_HEIGHT_ERROR &&
|
||||
pTempTarget->GetStatus().m_nNowHP > 0 &&
|
||||
CCreature::ENEMY == IsEnemy(pTempTarget))
|
||||
{
|
||||
if (false == pTempTarget->GetEnchantInfo().GetFlag(Skill::SpellID::Stealth) &&
|
||||
false == pTempTarget->GetEnchantInfo().GetFlag(Skill::SpellID::Invincible) &&
|
||||
false == pTempTarget->GetEnchantInfo().GetFlag(Skill::SpellID::Hide))
|
||||
{
|
||||
const float fDX = pTempTarget->GetCurrentPos().m_fPointX - GetCurrentPos().m_fPointX;
|
||||
const float fDZ = pTempTarget->GetCurrentPos().m_fPointZ - GetCurrentPos().m_fPointZ;
|
||||
|
||||
const float fDistance = (fDX * fDX) + (fDZ * fDZ);
|
||||
|
||||
if (fDistance < fSquareSearchRange)
|
||||
{
|
||||
pCurrentTarget = pTempTarget;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pTempTarget = pCell->GetNextCharacter();
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL != pCurrentTarget)
|
||||
{
|
||||
m_Threat.AddToThreatList(pCurrentTarget, 1);
|
||||
m_nCurrentState = CFSM::GetInstance().StateTransition(m_nCurrentState, INPUT_ID_SEEN_PLAYER);
|
||||
}
|
||||
}
|
||||
|
||||
void CSiegeObject::MoveTo(const Position& NewPosition)
|
||||
{
|
||||
CAggresiveCreature::MoveTo(NewPosition, false);
|
||||
|
||||
for (int i=1; i<Siege::AIRSHIP_LIMIT_NUM; ++i)
|
||||
{
|
||||
if (0 != m_dwRideCID[i])
|
||||
{
|
||||
CCharacter* lpRideCharacter = CCreatureManager::GetInstance().GetCharacter(m_dwRideCID[i]);
|
||||
if (lpRideCharacter)
|
||||
{
|
||||
lpRideCharacter->MoveTo(NewPosition, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool CSiegeObject::Dead(CAggresiveCreature* pOffencer)
|
||||
{
|
||||
switch (m_wObjectType)
|
||||
{
|
||||
case Siege::CAMP: return CampDead(pOffencer);
|
||||
case Siege::EMBLEM: return EmblemDead(pOffencer);
|
||||
|
||||
case Siege::GATE: return GateDead(pOffencer);
|
||||
case Siege::GUARD: return GuardDead(pOffencer);
|
||||
|
||||
case Siege::SHORT_RANGE_CASTLE_ARMS:
|
||||
case Siege::LONG_RANGE_CASTLE_ARMS:
|
||||
return CastleArmsDead(pOffencer);
|
||||
|
||||
case Siege::AIRSHIP:
|
||||
case Siege::SHORT_RANGE_SIEGE_ARMS:
|
||||
case Siege::LONG_RANGE_SIEGE_ARMS:
|
||||
return SiegeArmsDead(pOffencer);
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CSiegeObject::CampDead(CAggresiveCreature* pOffencer)
|
||||
{
|
||||
if (STATE_ID_DIE == m_nCurrentState) { return false; }
|
||||
|
||||
m_CreatureStatus.m_nNowHP = 0;
|
||||
m_dwLastBehaviorTick = m_dwLastTime = CPulse::GetInstance().GetLastTick();
|
||||
m_lCurrentFrame = FPS;
|
||||
m_bAttacking = false;
|
||||
m_bCasting = false;
|
||||
|
||||
m_nCurrentState = CFSM::GetInstance().StateTransition(m_nCurrentState, INPUT_ID_ZERO_HP);
|
||||
|
||||
// 크리쳐 매니져에서 삭제 (해당 셀에서도 삭제한다.)
|
||||
CCreatureManager::GetInstance().DeleteCreature(m_dwCID);
|
||||
|
||||
// 중계 서버로 패킷 전송
|
||||
GET_SINGLE_DISPATCH(lpDBAgentDispatch, CDBAgentDispatch, CDBAgentDispatch::GetDispatchTable());
|
||||
if (lpDBAgentDispatch)
|
||||
{
|
||||
if ( pOffencer )
|
||||
{
|
||||
return GameClientSendPacket::SendCharCampCmdToDBAgent(lpDBAgentDispatch->GetSendStream(), pOffencer->GetCID(), GetCampID(),
|
||||
pOffencer->GetGID(), 0, PktCampCmd::CAMP_DESTROY, PktBase::NO_SERVER_ERR);
|
||||
}
|
||||
else
|
||||
{
|
||||
return GameClientSendPacket::SendCharCampCmdToDBAgent(lpDBAgentDispatch->GetSendStream(), 0, GetCampID(),
|
||||
0, 0, PktCampCmd::CAMP_DESTROY, PktBase::NO_SERVER_ERR);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CSiegeObject::EmblemDead(CAggresiveCreature* pOffencer)
|
||||
{
|
||||
if (NULL == pOffencer) return false;
|
||||
if (STATE_ID_DIE == m_nCurrentState) return false;
|
||||
|
||||
m_CreatureStatus.m_nNowHP = 0;
|
||||
m_dwLastBehaviorTick = m_dwLastTime = CPulse::GetInstance().GetLastTick();
|
||||
m_lCurrentFrame = FPS;
|
||||
m_bAttacking = false;
|
||||
m_bCasting = false;
|
||||
|
||||
m_nCurrentState = CFSM::GetInstance().StateTransition(m_nCurrentState, INPUT_ID_ZERO_HP);
|
||||
|
||||
// 중계 서버로 패킷 전송
|
||||
GET_SINGLE_DISPATCH(lpDBAgentDispatch, CDBAgentDispatch, CDBAgentDispatch::GetDispatchTable());
|
||||
if (lpDBAgentDispatch)
|
||||
{
|
||||
m_dwEnemyGID = reinterpret_cast<CCharacter*>(pOffencer)->GetGID();
|
||||
return GameClientSendPacket::SendCharCastleCmdToDBAgent(lpDBAgentDispatch->GetSendStream(), GetCastleID(), m_dwCID,
|
||||
m_dwEnemyGID, 0, PktCastleCmd::CASTLE_UPDATE_EMBLEM, PktBase::NO_SERVER_ERR);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CSiegeObject::GateDead(CAggresiveCreature* pOffencer)
|
||||
{
|
||||
if (NULL == pOffencer) return false;
|
||||
if (STATE_ID_DIE == m_nCurrentState) return false;
|
||||
|
||||
m_CreatureStatus.m_nNowHP = 0;
|
||||
m_dwLastBehaviorTick = m_dwLastTime = CPulse::GetInstance().GetLastTick();
|
||||
m_lCurrentFrame = FPS;
|
||||
m_bAttacking = false;
|
||||
m_bCasting = false;
|
||||
|
||||
m_nCurrentState = CFSM::GetInstance().StateTransition(m_nCurrentState, INPUT_ID_ZERO_HP);
|
||||
|
||||
// 중계 서버로 패킷 전송
|
||||
GET_SINGLE_DISPATCH(lpDBAgentDispatch, CDBAgentDispatch, CDBAgentDispatch::GetDispatchTable());
|
||||
if (lpDBAgentDispatch)
|
||||
{
|
||||
return GameClientSendPacket::SendCharCastleCmdToDBAgent(lpDBAgentDispatch->GetSendStream(), GetCastleID(), m_dwCID,
|
||||
0, 0, PktCastleCmd::CASTLE_DESTROY_GATE, PktBase::NO_SERVER_ERR);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CSiegeObject::GuardDead(CAggresiveCreature* pOffencer)
|
||||
{
|
||||
if (NULL == pOffencer) return false;
|
||||
if (STATE_ID_DIE == m_nCurrentState) return false;
|
||||
|
||||
m_wObjectType = Siege::CASTLE_ARMS_NPC;
|
||||
m_CreatureStatus.m_nNowHP = 0;
|
||||
m_dwLastBehaviorTick = m_dwLastTime = CPulse::GetInstance().GetLastTick();
|
||||
m_lCurrentFrame = FPS;
|
||||
m_bAttacking = false;
|
||||
m_bCasting = false;
|
||||
|
||||
SetACTByObjectType();
|
||||
|
||||
m_nCurrentState = CFSM::GetInstance().StateTransition(m_nCurrentState, INPUT_ID_ZERO_HP);
|
||||
|
||||
// 중계 서버로 패킷 전송
|
||||
GET_SINGLE_DISPATCH(lpDBAgentDispatch, CDBAgentDispatch, CDBAgentDispatch::GetDispatchTable());
|
||||
if (lpDBAgentDispatch)
|
||||
{
|
||||
return GameClientSendPacket::SendCharCastleCmdToDBAgent(lpDBAgentDispatch->GetSendStream(), GetCastleID(), m_dwCID,
|
||||
PktCastleCmd::DESTROY, 0, PktCastleCmd::CASTLE_DESTROY_ARMS,
|
||||
PktBase::NO_SERVER_ERR);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CSiegeObject::CastleArmsDead(CAggresiveCreature* pOffencer)
|
||||
{
|
||||
if (NULL == pOffencer) return false;
|
||||
if (STATE_ID_DIE == m_nCurrentState) return false;
|
||||
if ( !IsCastleArms() || IsGuard() ) return false;
|
||||
|
||||
m_wObjectType = Siege::CASTLE_ARMS_NPC;
|
||||
m_CreatureStatus.m_nNowHP = 0;
|
||||
m_dwLastBehaviorTick = m_dwLastTime = CPulse::GetInstance().GetLastTick();
|
||||
m_lCurrentFrame = FPS;
|
||||
m_bAttacking = false;
|
||||
m_bCasting = false;
|
||||
|
||||
SetACTByObjectType();
|
||||
|
||||
// 타고 있던 캐릭터는 죽는다.
|
||||
for (int i=0; i<Siege::AIRSHIP_LIMIT_NUM; ++i)
|
||||
{
|
||||
CCharacter* lpRideChar = CCreatureManager::GetInstance().GetCharacter(m_dwRideCID[i]);
|
||||
if (lpRideChar)
|
||||
{
|
||||
m_dwRideCID[i] = 0;
|
||||
lpRideChar->GetOff();
|
||||
lpRideChar->Kill(pOffencer);
|
||||
}
|
||||
}
|
||||
|
||||
// 중계 서버로 패킷 전송
|
||||
GET_SINGLE_DISPATCH(lpDBAgentDispatch, CDBAgentDispatch, CDBAgentDispatch::GetDispatchTable());
|
||||
if (lpDBAgentDispatch)
|
||||
{
|
||||
return GameClientSendPacket::SendCharCastleCmdToDBAgent(lpDBAgentDispatch->GetSendStream(), GetCastleID(), m_dwCID,
|
||||
PktCastleCmd::DESTROY, 0, PktCastleCmd::CASTLE_DESTROY_ARMS,
|
||||
PktBase::NO_SERVER_ERR);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CSiegeObject::SiegeArmsDead(CAggresiveCreature* pOffencer)
|
||||
{
|
||||
if (NULL == pOffencer) return false;
|
||||
if (STATE_ID_DIE == m_nCurrentState) return false;
|
||||
if ( !IsSiegeArms() ) return false;
|
||||
|
||||
m_CreatureStatus.m_nNowHP = 0;
|
||||
m_dwLastBehaviorTick = m_dwLastTime = CPulse::GetInstance().GetLastTick();
|
||||
m_lCurrentFrame = FPS;
|
||||
m_bAttacking = false;
|
||||
m_bCasting = false;
|
||||
|
||||
// 타고 있던 캐릭터는 죽는다.
|
||||
for (int i=0; i<Siege::AIRSHIP_LIMIT_NUM; ++i)
|
||||
{
|
||||
CCharacter* lpRideChar = CCreatureManager::GetInstance().GetCharacter(m_dwRideCID[i]);
|
||||
if (lpRideChar)
|
||||
{
|
||||
lpRideChar->GetOff();
|
||||
lpRideChar->Kill(pOffencer);
|
||||
}
|
||||
|
||||
m_dwRideCID[i] = 0;
|
||||
}
|
||||
|
||||
// 크리쳐 매니져에서 삭제 (해당 셀에서도 삭제한다.)
|
||||
CCreatureManager::GetInstance().DeleteCreature(m_dwCID);
|
||||
|
||||
// 중계 서버로 패킷 전송
|
||||
GET_SINGLE_DISPATCH(lpDBAgentDispatch, CDBAgentDispatch, CDBAgentDispatch::GetDispatchTable());
|
||||
if (lpDBAgentDispatch)
|
||||
{
|
||||
return GameClientSendPacket::SendCharSiegeArmsCmdToDBAgent(lpDBAgentDispatch->GetSendStream(), 0, m_dwCID,
|
||||
0, PktSiegeArmsCmd::SIEGE_DESTROY_ARMS,
|
||||
PktSiegeArmsCmd::NO_SERVER_ERR);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,125 @@
|
||||
#ifndef _SIEGE_OBJECT_MANAGER_H_
|
||||
#define _SIEGE_OBJECT_MANAGER_H_
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <Creature/Siege/SiegeConstants.h>
|
||||
|
||||
#include <Network/Stream/SendStream.h>
|
||||
#include <Network/Packet/PacketStruct/CastlePacket.h>
|
||||
|
||||
|
||||
// 전방 참조
|
||||
class CSiegeObject;
|
||||
class CCamp;
|
||||
|
||||
class CSiegeObjectMgr
|
||||
{
|
||||
public:
|
||||
~CSiegeObjectMgr();
|
||||
|
||||
static CSiegeObjectMgr& GetInstance();
|
||||
|
||||
// 타입 정의
|
||||
typedef std::map<unsigned long, CSiegeObject*> SiegeObjectMap; // <CID, CSiegeObject*>
|
||||
typedef std::map<unsigned long, CCamp*> CampMap; // <CampID, CCamp*>
|
||||
|
||||
void Destroy();
|
||||
void DestroyAllCamp();
|
||||
|
||||
// DBAgent Server 접속시 DB 에서 얻어온 정보로 객체 생성함수
|
||||
CSiegeObject* CreateCastleObject(CastleObjectInfo& CastleObject);
|
||||
|
||||
// 클라이언트의 요청으로 DBAgentServer 를 거쳐서 객체를 생성하는 함수
|
||||
CSiegeObject* CreateCamp(unsigned long dwCID, unsigned long dwCampID, unsigned long dwGID, unsigned long dwHP,
|
||||
unsigned char cState, unsigned char cUpgradeStep, const CampRight& campRight,
|
||||
Position Pos, unsigned char cMaterial, bool bFullHP);
|
||||
|
||||
CSiegeObject* CreateWorldWeapon(unsigned long dwCID, unsigned long dwCampID, unsigned long dwGID, unsigned long dwHP,
|
||||
unsigned char cState, unsigned char cUpgradeStep, const CampRight& campRight,
|
||||
Position Pos, unsigned char cMaterial, bool bFullHP, unsigned short wObjectType);
|
||||
|
||||
CSiegeObject* CreateSiegeArms(unsigned long dwCID, unsigned long dwOwnerID, unsigned char cNation, unsigned long dwHP,
|
||||
unsigned short wObjectType, unsigned char cState, unsigned char cUpgradeStep,
|
||||
Position Pos);
|
||||
|
||||
|
||||
CSiegeObject* ChangeCampType(unsigned long dwCampID, unsigned short wChangeType);
|
||||
|
||||
CCamp* GetCamp(unsigned long dwCampID);
|
||||
CSiegeObject* GetSiegeObject(unsigned long dwObjectID);
|
||||
|
||||
bool DeleteSiegeObject(unsigned long dwCID);
|
||||
bool DeleteSiegeObject(CSiegeObject* lpObject);
|
||||
bool DeleteCamp(unsigned long dwCampID);
|
||||
|
||||
bool ExistBuildingOrDestroyingCamp(unsigned long dwGID);
|
||||
bool ExistCampInRadius(const Position& Pos);
|
||||
bool ExistCompleteCampInRadius(const Position& Pos, unsigned long dwGID);
|
||||
void HasCampByGID(unsigned long dwGID, bool& bHasDevelopingCamp, bool& bHasCompleteCamp);
|
||||
|
||||
bool HasSiegeArms(unsigned long dwCID); // 해당 CID 가 공성 병기 소유 여부.
|
||||
|
||||
unsigned long GetSiegeObjectCount(void);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------
|
||||
// 월드 웨폰 관련 함수
|
||||
void SetWorldWeaponInfo(unsigned char cKarRemainSiegeTime, unsigned char cMerRemainSiegeTime);
|
||||
void UpdateWorldWeaponInfo(unsigned char cNation, unsigned char cRemainSiegeTime);
|
||||
bool EnableCreateWorldWeapon(unsigned char cNation, unsigned short& wError) const;
|
||||
void DecreaseWeaponRemainSiegeTime();
|
||||
CCamp* GetWorldWeapon() const { return m_lpWorldWeapon; }
|
||||
void RequestWorldWeaponCreation() { m_bRequestWorldWeaponCreation = true; }
|
||||
void ReleaseWorldWeaponCreation() { m_bRequestWorldWeaponCreation = false; }
|
||||
// ------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------
|
||||
// Process 함수
|
||||
void ProcessAllSiegeObject();
|
||||
void ProcessCampRegenHPAndMP();
|
||||
|
||||
void ProcessMiningCamp(unsigned long dwProcessType);
|
||||
void ProcessCampShopUpdate(bool bForce);
|
||||
void ProcessWorldWeaponFire();
|
||||
// ------------------------------------------------------------------------------------------------------
|
||||
|
||||
// DBAgentServer -> GameServer 요새 정보 전송
|
||||
bool SerializeIn(char* lpBuffer, unsigned short wSize, unsigned long dwCID);
|
||||
|
||||
// Client 에게 길드 요새 정보 전송
|
||||
bool SendCampInfo(CSendStream& SendStream);
|
||||
|
||||
// 해당 성의 모든 오브젝트의 주인이 바뀌었다는것을 병기의 반경 5셀에 있는 캐릭터에게 알려준다.
|
||||
bool SendChangeMaster(unsigned long dwCastleID, unsigned char cNation);
|
||||
bool SendLoseOwnership(unsigned long dwCastleID);
|
||||
|
||||
// 모든 공성관련 오브젝트들을 반경 5셀에 있는 캐릭터들에게 알려준다.
|
||||
// Vincent - 브로드 캐스트 테스트 코드
|
||||
void PrepareBroadCast();
|
||||
void BroadCast();
|
||||
|
||||
|
||||
private:
|
||||
CSiegeObjectMgr();
|
||||
|
||||
// DBAgent Server 접속시 DB 에서 얻어온 정보로 객체 생성함수
|
||||
CSiegeObject* CreateCamp(char* lpBuffer, unsigned short wSize, unsigned long dwCID);
|
||||
CSiegeObject* CreateMiningCamp(char* lpBuffer, unsigned short wSize, unsigned long dwCID);
|
||||
CSiegeObject* CreateCampShop(char* lpBuffer, unsigned short wSize, unsigned long dwCID);
|
||||
CSiegeObject* CreateWorldWeapon(char* lpBuffer, unsigned short wSize, unsigned long dwCID, unsigned char cNation);
|
||||
|
||||
SiegeObjectMap m_SiegeObjectMap;
|
||||
CampMap m_CampMap;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------
|
||||
// 월드 웨폰 관련
|
||||
CCamp* m_lpWorldWeapon; // 월드 웨폰 (하나 뿐이므로 따로 관리)
|
||||
unsigned char m_cKarRemainSiegeTime; // 카르테란트 월드 웨폰이 부서진후 지나야할 공성 시간 횟수
|
||||
unsigned char m_cMerRemainSiegeTime; // 카르테란트 월드 웨폰이 부서진후 지나야할 공성 시간 횟수
|
||||
bool m_bRequestWorldWeaponCreation; // 월드 웨폰 생성을 DBAgentServer 에 요청한 상태인가
|
||||
// ------------------------------------------------------------------------------------------------------
|
||||
};
|
||||
|
||||
#endif // _SIEGE_OBJECT_MANAGER_H_
|
||||
@@ -0,0 +1,200 @@
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
// File Name: WorldWeapon.cpp
|
||||
//
|
||||
// Programmer: Zergra( Park Jongtae ) in GamaSoft corp.
|
||||
//
|
||||
// File Desciption: 월드 웨폰
|
||||
//
|
||||
// Date: 2004. 12. 14. (화)
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
#include "WorldWeapon.h"
|
||||
|
||||
#include <Creature/Siege/SiegeObjectMgr.h>
|
||||
|
||||
#include <Community/Guild/Guild.h>
|
||||
#include <Community/Guild/GuildMgr.h>
|
||||
|
||||
#include <Network/Stream/SendStream.h>
|
||||
#include <Network/Packet/WrapPacket.h>
|
||||
#include <Network/Packet/PacketCommand.h>
|
||||
#include <Network/Packet/PacketStruct/CastlePacket.h>
|
||||
|
||||
#include <Network/Dispatch/DBAgent/DBAgentDispatch.h>
|
||||
#include <Network/Dispatch/DBAgent/DBAgentRequest.h>
|
||||
#include <Network/Dispatch/GameClient/SendCharCastle.h>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class CWorldWeapon
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
// Constrcutor, Destructor
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
CWorldWeapon::CWorldWeapon(MonsterCreateInfo& MonsterCreate, unsigned long dwCampID, unsigned long dwGID, unsigned long dwHP,
|
||||
unsigned short wObjectType, unsigned char cState, unsigned char cSubState, unsigned char cUpgradeStep,
|
||||
unsigned char cMaterial, unsigned char cSiegeCount, const CampRight& campRight, bool bFullHP)
|
||||
: CCamp(MonsterCreate, dwCampID, dwGID, dwHP, wObjectType, cState, cSubState, cUpgradeStep, cMaterial, cSiegeCount, campRight, bFullHP),
|
||||
m_iFireX(0), m_iFireZ(0)
|
||||
{
|
||||
}
|
||||
|
||||
CWorldWeapon::~CWorldWeapon()
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
// Member Functions
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
bool CWorldWeapon::Build(unsigned char cUpgradeStep)
|
||||
{
|
||||
CCamp::Build(cUpgradeStep);
|
||||
|
||||
// 월드 웨폰 인챈트 적용
|
||||
unsigned char cNation = Creature::STATELESS;
|
||||
switch (m_wObjectType)
|
||||
{
|
||||
case Siege::KARTERANT_WEAPON: cNation = Creature::KARTERANT; break;
|
||||
case Siege::MERKADIA_WEAPON: cNation = Creature::MERKADIA; break;
|
||||
}
|
||||
|
||||
CCreatureManager::GetInstance().AddWorldWeaponEnchant(reinterpret_cast<CAggresiveCreature*>(this), cNation);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CWorldWeapon::Destroy(unsigned long dwOffencerGID)
|
||||
{
|
||||
// 월드 웨폰일 경우 파괴 정보 업데이트
|
||||
if (Siege::KARTERANT_WEAPON == m_wObjectType)
|
||||
{
|
||||
CSiegeObjectMgr::GetInstance().UpdateWorldWeaponInfo(Creature::KARTERANT, Siege::WEAPON_REBUILD_SIEGE_TIME_COUNT);
|
||||
}
|
||||
else if (Siege::MERKADIA_WEAPON == m_wObjectType)
|
||||
{
|
||||
CSiegeObjectMgr::GetInstance().UpdateWorldWeaponInfo(Creature::MERKADIA, Siege::WEAPON_REBUILD_SIEGE_TIME_COUNT);
|
||||
}
|
||||
|
||||
return CCamp::Destroy(dwOffencerGID);
|
||||
}
|
||||
|
||||
bool CWorldWeapon::UpdateWeaponState(unsigned char cWeaponState, int iX, int iZ)
|
||||
{
|
||||
m_iFireX = iX;
|
||||
m_iFireZ = iZ;
|
||||
m_cSubState = cWeaponState;
|
||||
m_iWorldWeaponCount = Siege::WEAPON_FIRE_WARNING_COUNT;
|
||||
|
||||
// 해당 진지가 있는 반경 5셀 이내에 전송
|
||||
PktCampCmd pktCC;
|
||||
pktCC.m_dwCID = m_dwCID;
|
||||
pktCC.m_dwCampID = GetCampID();
|
||||
pktCC.m_cState = m_cState;
|
||||
pktCC.m_dwValue1 = iX;
|
||||
pktCC.m_dwValue2 = iZ;
|
||||
pktCC.m_cSubCmd = 0;
|
||||
|
||||
switch (cWeaponState)
|
||||
{
|
||||
case Siege::WEAPON_CHARGE:
|
||||
{
|
||||
pktCC.m_cSubCmd = PktCampCmd::WORLDWEAPON_CHARGE;
|
||||
pktCC.m_dwValue1 = m_cMaterial;
|
||||
pktCC.m_dwValue2 = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case Siege::WEAPON_READY: pktCC.m_cSubCmd = PktCampCmd::WORLDWEAPON_CHARGE_COMPLETE; break;
|
||||
case Siege::WEAPON_FIRE: pktCC.m_cSubCmd = PktCampCmd::WORLDWEAPON_FIRE; break;
|
||||
}
|
||||
|
||||
char* szPacket = reinterpret_cast<char *>(&pktCC);
|
||||
if (PacketWrap::WrapCrypt(szPacket, sizeof(PktCampCmd), CmdCampCmd, 0, 0))
|
||||
{
|
||||
// Vincent - 브로드 캐스트 테스트 코드
|
||||
//SendToRadiusCell(szPacket, sizeof(PktCampCmd), CmdCampCmd);
|
||||
SendToRange(Siege::BROADCAST_RADIUS, szPacket, sizeof(PktCampCmd), CmdCampCmd);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CWorldWeapon::FireWarning()
|
||||
{
|
||||
// 경고 메세지를 모든 캐릭터에게 전송
|
||||
PktCampMessage pktCampMessage;
|
||||
memset(&pktCampMessage, 0, sizeof(PktCampMessage));
|
||||
|
||||
pktCampMessage.m_dwCampID = GetCampID();
|
||||
pktCampMessage.m_dwGID = GetGID();
|
||||
pktCampMessage.m_cZone = CServerSetup::GetInstance().GetServerZone();
|
||||
pktCampMessage.m_cMsgCmd = PktCampMessage::MSGCMD_WEAPON_FIRE_WARNING;
|
||||
pktCampMessage.m_cRemainTime = static_cast<unsigned char>(m_iWorldWeaponCount);
|
||||
pktCampMessage.m_cNation = GetNation();
|
||||
pktCampMessage.m_bNotify = true;
|
||||
pktCampMessage.m_nValue1 = m_iFireX;
|
||||
pktCampMessage.m_nValue2 = m_iFireZ;
|
||||
|
||||
Guild::CGuild* lpGuild = Guild::CGuildMgr::GetInstance().GetGuild(m_dwGID);
|
||||
if (NULL != lpGuild)
|
||||
{
|
||||
strcpy(pktCampMessage.m_szGuildName, lpGuild->GetName());
|
||||
}
|
||||
|
||||
char* szPacket = reinterpret_cast<char* >(&pktCampMessage);
|
||||
if (PacketWrap::WrapCrypt(szPacket, sizeof(PktCampMessage), CmdCampMessage, 0, 0))
|
||||
{
|
||||
CCreatureManager::GetInstance().SendAllCharacter(szPacket, sizeof(PktCampMessage), CmdCampMessage);
|
||||
}
|
||||
|
||||
--m_iWorldWeaponCount;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CWorldWeapon::Fire()
|
||||
{
|
||||
// 월드 웨폰일 경우 파괴 정보 업데이트
|
||||
if (Siege::KARTERANT_WEAPON == m_wObjectType)
|
||||
{
|
||||
CSiegeObjectMgr::GetInstance().UpdateWorldWeaponInfo(Creature::KARTERANT, Siege::WEAPON_REBUILD_SIEGE_TIME_COUNT);
|
||||
}
|
||||
else if (Siege::MERKADIA_WEAPON == m_wObjectType)
|
||||
{
|
||||
CSiegeObjectMgr::GetInstance().UpdateWorldWeaponInfo(Creature::MERKADIA, Siege::WEAPON_REBUILD_SIEGE_TIME_COUNT);
|
||||
}
|
||||
|
||||
// DB 중계 서버에 월드 웨폰 객체 삭제 명령 전송 (발사 완료, 시간 기록)
|
||||
// 중계 서버로 패킷 전송
|
||||
GET_SINGLE_DISPATCH(lpDBAgentDispatch, CDBAgentDispatch, CDBAgentDispatch::GetDispatchTable());
|
||||
if (NULL != lpDBAgentDispatch)
|
||||
{
|
||||
GameClientSendPacket::SendCharCampCmdToDBAgent(lpDBAgentDispatch->GetSendStream(), 0, GetCampID(),
|
||||
0, 0, PktCampCmd::WORLDWEAPON_FIRE_COMPLETE, PktBase::NO_SERVER_ERR);
|
||||
}
|
||||
|
||||
// 모든 캐릭터에게 월드 웨폰 발사 명령 전송 (이펙트 처리 및 월드 웨폰 객체 삭제를 위해)
|
||||
PktCampCmd pktCampCmd;
|
||||
pktCampCmd.m_dwCID = m_dwCID;
|
||||
pktCampCmd.m_dwCampID = GetCampID();
|
||||
pktCampCmd.m_cState = GetState();
|
||||
pktCampCmd.m_dwValue1 = m_iFireX;
|
||||
pktCampCmd.m_dwValue2 = m_iFireZ;
|
||||
pktCampCmd.m_cSubCmd = PktCampCmd::WORLDWEAPON_FIRE_COMPLETE;
|
||||
|
||||
char* szPacket = reinterpret_cast<char *>(&pktCampCmd);
|
||||
if (PacketWrap::WrapCrypt(szPacket, sizeof(PktCampCmd), CmdCampCmd, 0, 0))
|
||||
{
|
||||
CCreatureManager::GetInstance().SendAllCharacter(szPacket, sizeof(PktCampCmd), CmdCampCmd);
|
||||
}
|
||||
|
||||
// 모든 캐릭터 및 공성 오브젝트에 대해서 데미지 처리
|
||||
CCreatureManager::GetInstance().ProcessWorldWeaponDamage(m_iFireX, m_iFireZ, m_cUpgradeStep);
|
||||
|
||||
// 모든 캐릭터의 월드 웨폰 인챈트 해제
|
||||
CCreatureManager::GetInstance().ClearWorldWeaponEnchant();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
// File Name: WorldWeapon.h
|
||||
//
|
||||
// Programmer: Zergra( Park Jongtae ) in GamaSoft corp.
|
||||
//
|
||||
// File Desciption: 월드 웨폰
|
||||
//
|
||||
// Date: 2004. 12. 14. (화)
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
#ifndef _WORLD_WEAPON_OBJECT_H_
|
||||
#define _WORLD_WEAPON_OBJECT_H_
|
||||
|
||||
#pragma once
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
// Headers
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
#include <Creature/Siege/Camp.h>
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
// Classes
|
||||
//--------------------------------------------------------------------------------------------------------------------------
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class CWorldWeapon
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
class CWorldWeapon : public CCamp
|
||||
{
|
||||
public:
|
||||
virtual ~CWorldWeapon();
|
||||
|
||||
bool Build(unsigned char cUpgradeStep = 0); // 월드 웨폰 구축 완료
|
||||
bool Destroy(unsigned long dwOffencerGID = 0); // 월드 웨폰 파괴 완료 (자체 파괴, 파괴됨)
|
||||
|
||||
bool UpdateWeaponState(unsigned char cWeaponState, int iX = 0, int iZ = 0);
|
||||
bool FireWarning();
|
||||
bool Fire();
|
||||
|
||||
int GetFireCount() const { return m_iWorldWeaponCount; }
|
||||
|
||||
private:
|
||||
CWorldWeapon(MonsterCreateInfo& MonsterCreate, unsigned long dwCampID, unsigned long dwGID,
|
||||
unsigned long dwHP, unsigned short wObjectType, unsigned char cState, unsigned char cSubState,
|
||||
unsigned char cUpgradeStep, unsigned char cMaterial, unsigned char cSiegeCount,
|
||||
const CampRight& campRight, bool bFullHP);
|
||||
|
||||
int m_iFireX, m_iFireZ; // 발사 좌표
|
||||
int m_iWorldWeaponCount; // 월드 웨폰 발사 카운트
|
||||
|
||||
friend class CSiegeObjectMgr;
|
||||
};
|
||||
|
||||
#endif //_WORLD_WEAPON_OBJECT_H_
|
||||
Reference in New Issue
Block a user