Files
LGram16 dd97ddec92 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>
2025-11-29 20:17:20 +09:00

369 lines
9.7 KiB
C++

#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);
}
}
}