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:
2025-11-29 20:17:20 +09:00
parent 5d3cd64a25
commit dd97ddec92
11602 changed files with 1446576 additions and 0 deletions

View File

@@ -0,0 +1,502 @@
#include "stdafx.h"
#include <Utility/Math/Math.h>
#include <Utility/Compress/MiniLZO/MiniLZOWrapper.h>
#include <Utility/Resource/EnsureCleanup.h>
#include <Utility/CheckSum/Crc32Static.h>
#include <Utility/DelimitedFile.h>
#include <Network/XORCrypt/XORCrypt.h>
#include <Creature/Character/CharacterClass.h>
// 클라이언트에서도 쓰이므로 include를 명시한다.
#include <Log/ServerLog.h>
#include <algorithm>
#include "SkillMgr.h"
#include "GMMemory.h"
#define DECODE_HEADER(Start_In, Length_In, PageVer_In, PageNum_In) CXORCrypt::GetInstance().DecodeHeader((Start_In),(Length_In),(PageVer_In),(PageNum_In))
#define ENCODE_HEADER(Start_In, Length_In, PageVer_In, PageNum_In) CXORCrypt::GetInstance().EncodeHeader((Start_In),(Length_In),(PageVer_In),(PageNum_In))
#define COMPRESS(In, In_len, Out, Out_len) CMiniLZO::Compress((In), (In_len), (Out), (Out_len))
#define DECOMPRESS(In, In_len, Out, Out_len) CMiniLZO::Decompress((In), (In_len), (Out), (Out_len))
CSkillMgr CSkillMgr::ms_this;
const char* CSkillMgr::ms_szSkillScriptFileName = "./Script/Game/SkillScript.txt";
CSkillMgr::CSkillMgr()
: m_ProtoTypeArray(NULL), m_nSkillNum(0), m_dwCRC32(0)
{
}
CSkillMgr::~CSkillMgr()
{
ClearProtoType();
}
void CSkillMgr::ClearProtoType(void)
{
if (NULL != m_ProtoTypeArray)
{
delete [] m_ProtoTypeArray;
m_ProtoTypeArray = NULL;
}
}
bool CSkillMgr::LoadSkillsFromFile(const char* szFileName)
{
using namespace Skill;
// 임시변수들
const int SKILL_ID_LEN = 32;
const int HEADER_LINE_NUM = 1;
char szBuffer[SKILL_ID_LEN];
unsigned char chTempValue;
int nLineCount = 0;
int nSkillCount = 0;
CDelimitedFile DelimitedFile; // 객체 소멸시, 자동 Close.
ProtoTypeArray tempProtoType;
// 매크로에 로그 코드 삽입을 잊지 말 것.
// 매크로에서 \뒤에 공백이나 문자 삽입되지 않도록 주의할 것.
// ( '이스케이프 시퀀스가 잘못되었습니다' 에러 발생 )
#define READ_DATA(ColumnName, Argument) \
if (false == DelimitedFile.ReadData(ColumnName, Argument)) \
{ \
ERRLOG2(g_Log, "스킬 스크립트 읽기 실패 : %d행 %s컬럼에서 에러 발생!", nLineCount + HEADER_LINE_NUM, #ColumnName); \
return false; \
}
#define READ_STRING(ColumnName, Buffer, BufferSize) \
if (false == DelimitedFile.ReadString(ColumnName, Buffer, BufferSize)) \
{\
ERRLOG2(g_Log, "스킬 스크립트 읽기 실패 : %d행 %s컬럼에서 에러 발생!", nLineCount + HEADER_LINE_NUM, #ColumnName);\
return false;\
}
#define READ_STRING_TO_TYPE_VALUE(saveType, saveValue, szColumn, TypeArray, nMaxType)\
saveValue = static_cast<saveType>(ReadStringToTypeValue(DelimitedFile, szColumn, TypeArray, nMaxType));\
if (nMaxType == saveValue)\
{\
ERRLOG2(g_Log, "스킬 스크립트 읽기 실패 : %d행 %s컬럼에서 에러 발생!", nLineCount + HEADER_LINE_NUM, #szColumn); \
return false;\
}
if (false == DelimitedFile.Open(szFileName ? szFileName : ms_szSkillScriptFileName, HEADER_LINE_NUM))
{
ERRLOG1(g_Log, "%s 파일을 열 수 없습니다.", szFileName ? szFileName : ms_szSkillScriptFileName);
return false;
}
std::vector<ProtoTypeArray> ProtoTypeVector;
while (DelimitedFile.ReadLine())
{
++nLineCount;
READ_STRING("ID", szBuffer, SKILL_ID_LEN);
tempProtoType.m_ProtoTypes[nSkillCount].m_usSkill_ID = Math::Convert::Atos(szBuffer);
READ_STRING_TO_TYPE_VALUE(Skill::Type::SkillType, tempProtoType.m_ProtoTypes[nSkillCount].m_eSkillType,
"Type", Type::SkillTypes, Type::MAX_SKILL_TYPE);
READ_DATA("ClassSkill", chTempValue); tempProtoType.m_ProtoTypes[nSkillCount].m_bIsClassSkill = chTempValue != 0;
READ_STRING("Name[5]", tempProtoType.m_ProtoTypes[nSkillCount].m_SpriteInfo.m_szName, ProtoType::MAX_SKILL_NAME);
READ_STRING_TO_TYPE_VALUE(Skill::UseLimit::Type, tempProtoType.m_ProtoTypes[nSkillCount].m_eUseLimit,
"Limit", UseLimit::UseLimits, UseLimit::MAX_USE_LIMIT);
READ_STRING_TO_TYPE_VALUE(unsigned char, tempProtoType.m_ProtoTypes[nSkillCount].m_StatusLimitType[0],
"Stat[0]", StatusLimit::StatusLimits, StatusLimit::MAX_STATUS_LIMIT);
READ_DATA("Value[0]", tempProtoType.m_ProtoTypes[nSkillCount].m_StatusLimitValue[0]);
READ_STRING_TO_TYPE_VALUE(unsigned char, tempProtoType.m_ProtoTypes[nSkillCount].m_StatusLimitType[1],
"Stat[1]", StatusLimit::StatusLimits, StatusLimit::MAX_STATUS_LIMIT);
READ_DATA("Value[1]", tempProtoType.m_ProtoTypes[nSkillCount].m_StatusLimitValue[1]);
READ_STRING_TO_TYPE_VALUE(Skill::Target::Type, tempProtoType.m_ProtoTypes[nSkillCount].m_eTargetType,
"Target", Target::TargetTypes, Target::MAX_TARGET_TYPE);
READ_DATA("mRange", tempProtoType.m_ProtoTypes[nSkillCount].m_fMinRange);
READ_DATA("Range", tempProtoType.m_ProtoTypes[nSkillCount].m_fMaxRange);
READ_DATA("Region", tempProtoType.m_ProtoTypes[nSkillCount].m_fEffectExtent);
READ_DATA("StartMP", tempProtoType.m_ProtoTypes[nSkillCount].m_StartMP);
READ_DATA("LevelMP", tempProtoType.m_ProtoTypes[nSkillCount].m_LevelMP);
READ_DATA("LockAdd", tempProtoType.m_ProtoTypes[nSkillCount].m_LockMP);
READ_DATA("Starttick", tempProtoType.m_ProtoTypes[nSkillCount].m_StartTick);
READ_DATA("LevelTick", tempProtoType.m_ProtoTypes[nSkillCount].m_LevelTick);
READ_STRING("CastingFlag", tempProtoType.m_ProtoTypes[nSkillCount].m_szCastingFileName, ProtoType::MAX_FILE_NAME);
READ_STRING("EffectFlag", tempProtoType.m_ProtoTypes[nSkillCount].m_szEffectFileName, ProtoType::MAX_FILE_NAME);
READ_STRING("HitFlag", tempProtoType.m_ProtoTypes[nSkillCount].m_szHitFileName, ProtoType::MAX_FILE_NAME);
READ_DATA("CoolDownTime", tempProtoType.m_ProtoTypes[nSkillCount].m_dwCoolDownTime);
READ_DATA("EndCoolDown", tempProtoType.m_ProtoTypes[nSkillCount].m_cEndCoolDown);
READ_STRING("dds", tempProtoType.m_ProtoTypes[nSkillCount].m_SpriteInfo.m_szSpriteName, ProtoType::MAX_FILE_NAME);
READ_DATA("MinX", tempProtoType.m_ProtoTypes[nSkillCount].m_SpriteInfo.m_nSpriteMinX);
READ_DATA("MinY", tempProtoType.m_ProtoTypes[nSkillCount].m_SpriteInfo.m_nSpriteMinY);
READ_DATA("MaxX", tempProtoType.m_ProtoTypes[nSkillCount].m_SpriteInfo.m_nSpriteMaxX);
READ_DATA("MaxY", tempProtoType.m_ProtoTypes[nSkillCount].m_SpriteInfo.m_nSpriteMaxY);
READ_DATA("Hit", tempProtoType.m_ProtoTypes[nSkillCount].m_cStrikeNum);
READ_DATA("EndScript", tempProtoType.m_ProtoTypes[nSkillCount].m_cEndScript);
READ_DATA("Protection", chTempValue); tempProtoType.m_ProtoTypes[nSkillCount].m_bProtection = chTempValue != 0;
READ_DATA("Interrupt", chTempValue); tempProtoType.m_ProtoTypes[nSkillCount].m_bInterrupt = chTempValue != 0;
READ_DATA("Counter", chTempValue); tempProtoType.m_ProtoTypes[nSkillCount].m_bCounter = chTempValue != 0;
READ_DATA("Gauge", chTempValue); tempProtoType.m_ProtoTypes[nSkillCount].m_bGauge = chTempValue != 0;
READ_STRING("Parent", szBuffer, SKILL_ID_LEN);
tempProtoType.m_ProtoTypes[nSkillCount].m_usParentSkill = Math::Convert::Atos(szBuffer);
READ_STRING("Child", szBuffer, SKILL_ID_LEN);
tempProtoType.m_ProtoTypes[nSkillCount].m_usChildSkill = Math::Convert::Atos(szBuffer);
READ_STRING("Text", tempProtoType.m_ProtoTypes[nSkillCount].m_szSkillDescribe, ProtoType::MAX_SKILL_DESCRIBE);
if (tempProtoType.m_ProtoTypes[0].m_usSkill_ID != tempProtoType.m_ProtoTypes[nSkillCount].m_usSkill_ID)
{
ERRLOG2(g_Log, "스킬 숫자가 맞지 않습니다. 클래스 스킬을 제외하고는, 각 스킬은 반드시 같은 ID가"
" 5개가 연속해서 나와야 합니다. 현재 스킬 번호는 0x%04x, 개수는 %d입니다.",
tempProtoType.m_ProtoTypes[nSkillCount].m_usSkill_ID, nSkillCount);
return false;
}
++nSkillCount;
if (MAX_SKILL_LOCKCOUNT == nSkillCount || tempProtoType.m_ProtoTypes[0].m_bIsClassSkill)
{
ProtoTypeVector.push_back(tempProtoType);
for (int nIndex = 0; nIndex < nSkillCount; ++nIndex)
{
tempProtoType.m_ProtoTypes[nIndex].Initialize();
}
nSkillCount = 0;
}
}
std::sort(ProtoTypeVector.begin(), ProtoTypeVector.end());
for (std::vector<ProtoTypeArray>::iterator itr = ProtoTypeVector.begin();
itr != ProtoTypeVector.end() - 1; ++itr)
{
if (itr->m_ProtoTypes[0].m_usSkill_ID == (itr+1)->m_ProtoTypes[0].m_usSkill_ID)
{
ERRLOG1(g_Log, "겹치는 스킬 종류 ID가 있습니다. 종류ID:0x%04x", itr->m_ProtoTypes[0].m_usSkill_ID);
return false;
}
}
m_nSkillNum = ProtoTypeVector.size();
m_ProtoTypeArray = new ProtoTypeArray[m_nSkillNum];
if (NULL == m_ProtoTypeArray)
{
ERRLOG0(g_Log, "메모리 할당에 실패했습니다.");
return false;
}
std::copy(ProtoTypeVector.begin(), ProtoTypeVector.end(), m_ProtoTypeArray);
if (false == CheckParentChildRule())
{
ERRLOG0(g_Log, "스킬 스크립트의 잘못된 부모/자식 관계를 수정해주세요.");
return false;
}
// 스킬 체크섬을 빌드하겠소.
if(NO_ERROR != CCrc32Static::BufferCrc32(reinterpret_cast<const char*>(m_ProtoTypeArray),
sizeof(ProtoTypeArray) * m_nSkillNum, m_dwCRC32))
{
ERRLOG0(g_Log, "스킬 스크립트 체크섬 빌드에 실패했습니다.");
return false;
}
return true;
}
bool CSkillMgr::LoadSkillsFromBinary(const char* szFileNameBinary)
{
HANDLE hFile = CreateFile((0 == szFileNameBinary) ? ms_szSkillScriptFileName : szFileNameBinary,
GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) { return false; }
CEnsureCloseHandle hfile(hFile);
unsigned long dwRead = 0;
unsigned long dwFileHighSize = 0;
unsigned long dwFileSize = GetFileSize(hFile, &dwFileHighSize);
char* lpAllocated = new char[dwFileSize];
CEnsureDeleteArray<char> allocated(lpAllocated);
if (NULL == lpAllocated)
{
ERRLOG0(g_Log, "메모리가 부족합니다.");
return false;
}
if (false == ReadFile(hFile, lpAllocated, dwFileSize, &dwRead, NULL))
{
ERRLOG1(g_Log, "읽기 실패 : %d에러", GetLastError());
return false;
}
unsigned long dwHeaderSize = sizeof(unsigned long) + *reinterpret_cast<unsigned long*>(lpAllocated) + sizeof(unsigned long);
unsigned long dwDecompressedSize = *reinterpret_cast<unsigned long*>(lpAllocated + dwHeaderSize - sizeof(unsigned long));
ClearProtoType();
m_nSkillNum = dwDecompressedSize/sizeof(ProtoTypeArray);
m_ProtoTypeArray = new ProtoTypeArray[m_nSkillNum];
if (NULL == m_ProtoTypeArray)
{
ERRLOG0(g_Log, "스킬 스크립트 내용을 불러올 수 없습니다. 메모리가 부족합니다.");
return false;
}
DECOMPRESS(lpAllocated + dwHeaderSize, dwFileSize - dwHeaderSize,
reinterpret_cast<char*>(m_ProtoTypeArray), &dwDecompressedSize);
DECODE_HEADER(reinterpret_cast<char*>(m_ProtoTypeArray), dwDecompressedSize, 3, 3);
// 스킬 체크섬을 빌드하겠소.
if(NO_ERROR != CCrc32Static::BufferCrc32(reinterpret_cast<const char*>(m_ProtoTypeArray),
sizeof(ProtoTypeArray) * m_nSkillNum, m_dwCRC32))
{
ERRLOG0(g_Log, "스킬 스크립트 체크섬 빌드에 실패했습니다.");
return false;
}
return true;
}
bool CSkillMgr::SaveSkillsToBinary(const char* szFileNameBinary, const char* szTrashFile)
{
HANDLE hFile = CreateFile((0 == szFileNameBinary) ? ms_szSkillScriptFileName : szFileNameBinary,
GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) { return false; }
CEnsureCloseHandle file(hFile);
unsigned long dwSkillSize = static_cast<unsigned long>(sizeof(ProtoTypeArray) * m_nSkillNum);
unsigned long dwCompressSize = dwSkillSize;
char* lpSkill_Info = new char[dwSkillSize];
char* lpCompressedInfo = new char[dwSkillSize];
if (NULL == lpSkill_Info || NULL == lpCompressedInfo)
{
ERRLOG0(g_Log, "메모리가 부족합니다.");
return false;
}
CEnsureDeleteArray<char> skill_info(lpSkill_Info);
CEnsureDeleteArray<char> compress_info(lpCompressedInfo);
memcpy(lpSkill_Info, m_ProtoTypeArray, dwSkillSize);
ENCODE_HEADER(lpSkill_Info, dwSkillSize, 3, 3);
COMPRESS(lpSkill_Info, dwSkillSize, lpCompressedInfo, &dwCompressSize);
unsigned long dwWritten = 0;
// 쓰레기(더미) 자료
HANDLE hTrashFile = CreateFile(szTrashFile, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hTrashFile == INVALID_HANDLE_VALUE)
{
ERRLOG1(g_Log, "%s 파일을 열 수 없습니다.", szTrashFile);
return false;
}
CEnsureCloseHandle trashFile(hTrashFile);
unsigned long dwRead = 0;
unsigned long dwFileHighSize = 0;
unsigned long dwFileSize = GetFileSize(hTrashFile, &dwFileHighSize);
char* lpAllocated = new char[dwFileSize];
CEnsureDeleteArray<char> allocated(lpAllocated);
if (false == ReadFile(hTrashFile, lpAllocated, dwFileSize, &dwRead, NULL))
{
ERRLOG0(g_Log, "쓰레기 파일을 읽을 수 없습니다.");
return false;
}
WriteFile(hFile, &dwFileSize, sizeof(unsigned long), &dwWritten, 0);
WriteFile(hFile, lpAllocated, dwFileSize, &dwWritten, 0);
// 올바른 자료
WriteFile(hFile, &dwSkillSize, sizeof(unsigned long), &dwWritten, 0); // 원본 데이터 크기
WriteFile(hFile, lpCompressedInfo, dwCompressSize, &dwWritten, 0); // 압축된 데이터 크기
return true;
}
const Skill::ProtoType* CSkillMgr::GetSkillProtoType(unsigned short usSkill_ID)
{
ProtoTypeArray* lpFirst = m_ProtoTypeArray;
ProtoTypeArray* lpLast = m_ProtoTypeArray + m_nSkillNum;
ProtoTypeArray* lpMid = NULL;
size_t nCount = m_nSkillNum;
size_t nCount2 = 0;
for (; 0 < nCount; )
{
nCount2 = nCount / 2;
lpMid = lpFirst + nCount2;
if (lpMid->m_ProtoTypes[0].m_usSkill_ID < usSkill_ID)
{
lpFirst = ++lpMid, nCount -= nCount2 + 1;
}
else
{
nCount = nCount2;
}
}
return (lpFirst != lpLast && !(usSkill_ID < lpFirst->m_ProtoTypes[0].m_usSkill_ID)) ?
lpFirst->m_ProtoTypes : NULL;
}
void CSkillMgr::GetClassSkill(unsigned char cClass, unsigned short *arySkillID, unsigned char *cSkillNum)
{
*cSkillNum = 0;
for (size_t nIndex = 0; nIndex < m_nSkillNum; nIndex++)
{
Skill::ProtoType protoType = (m_ProtoTypeArray + nIndex)->m_ProtoTypes[0];
if (true == protoType.m_bIsClassSkill)
{
unsigned char cSkillClass = static_cast<unsigned char>((((protoType.m_usSkill_ID - Skill::SKILL_MASK) & 0xFF00) >> 8) & 0x00FF);
if (cClass == cSkillClass || CClass::GetPreviousJob(cClass) == cSkillClass)
{
arySkillID[*cSkillNum] = protoType.m_usSkill_ID;
(*cSkillNum)++;
}
}
}
}
unsigned char CSkillMgr::ReadStringToTypeValue(CDelimitedFile& DelimitedFile, const char* szColumn,
const CTypeName* TypeArray, const unsigned char nMaxType)
{
char szReadData[MAX_PATH];
unsigned char nCount = 0;
// 등급 구분 읽기.
if (false == DelimitedFile.ReadString(szColumn, szReadData, MAX_PATH))
{
ERRLOG0(g_Log, "등급 구분 읽기에 실패하였습니다.");
return nMaxType; // 실패시 nMaxType을 리턴.
}
for (nCount = 0; nCount < nMaxType; ++nCount)
{
if (0 == strcmp(szReadData, TypeArray[nCount].GetTypeName()))
{
break;
}
}
if (nCount == nMaxType)
{
ERRLOG0(g_Log, "읽어들인 정보가 타입 배열에 존재하지 않습니다.");
return nMaxType;
}
return TypeArray[nCount].GetTypeValue();
}
bool CSkillMgr::CheckParentChildRule(void)
{
for (ProtoTypeArray* lpPointer = m_ProtoTypeArray; lpPointer != m_ProtoTypeArray + m_nSkillNum; ++lpPointer)
{
Skill::ProtoType ProtoType = lpPointer->m_ProtoTypes[0];
const Skill::ProtoType* lpParent = GetSkillProtoType(ProtoType.m_usParentSkill);
const Skill::ProtoType* lpChild = GetSkillProtoType(ProtoType.m_usChildSkill);
if (0 != ProtoType.m_usParentSkill && NULL == lpParent)
{
ERRLOG1(g_Log, "앨터너티브 스킬 오류 : 존재하지 않는 스킬이 부모로 설정되었습니다. SkillID:0x%04x",
ProtoType.m_usSkill_ID);
return false;
}
if (0 != ProtoType.m_usChildSkill && NULL == lpChild)
{
ERRLOG1(g_Log, "앨터너티브 스킬 오류 : 존재하지 않는 스킬이 자식으로 설정되었습니다. SkillID:0x%04x",
ProtoType.m_usSkill_ID);
return false;
}
if (NULL == lpParent && NULL == lpChild) { continue; }
switch (ProtoType.m_eSkillType)
{
case Skill::Type::PASSIVE:
{
if (0 != ProtoType.m_usChildSkill)
{
ERRLOG1(g_Log, "앨터너티브 스킬 오류 : 패시브 스킬이 부모로 설정되었습니다. SkillID:0x%04x",
ProtoType.m_usSkill_ID);
return false;
}
} break;
case Skill::Type::CHANT:
{
if (0 != ProtoType.m_usParentSkill)
{
ERRLOG1(g_Log, "앨터너티브 스킬 오류 : 챈트 스킬이 자식으로 설정되었습니다. SkillID:0x%04x",
ProtoType.m_usSkill_ID);
return false;
}
if (0 != ProtoType.m_usChildSkill)
{
if (Skill::Type::CHANT == lpChild->m_eSkillType)
{
ERRLOG1(g_Log, "앨터너티브 스킬 오류 : 챈트 스킬의 자식으로 챈트 스킬이 설정되었습니다. SkillID:0x%04x",
ProtoType.m_usSkill_ID);
return false;
}
}
} break;
}
}
return true;
}
bool CSkillMgr::CheckData()
{
unsigned long dwCheckSum = 0;
// 스킬 체크섬을 빌드하겠소.
if(NO_ERROR != CCrc32Static::BufferCrc32(reinterpret_cast<const char*>(m_ProtoTypeArray),
sizeof(ProtoTypeArray) * m_nSkillNum, dwCheckSum))
{
ERRLOG0(g_Log, "스킬 스크립트 체크섬 빌드에 실패했습니다.");
return false;
}
return (m_dwCRC32 == dwCheckSum);
}

View File

@@ -0,0 +1,68 @@
#ifndef _SKILL_MGR_H_
#define _SKILL_MGR_H_
#define g_SkillMgr CSkillMgr::GetInstance()
#include <limits>
#include <Pattern/Singleton.h>
#include "SkillStructure.h"
// 전방 참조
class CDelimitedFile;
class CSkillMgr : public CSingleton<CSkillMgr>
{
public:
enum _Const
{
MAX_SKILL_LOCKCOUNT = 5, // 스킬의 최대 개수 (이 개수만큼 ProtoType이 존재한다)
MAX_SKILL_LEVEL = 6, // 스킬 레벨의 한계
MAX_SKILL_PER_STATUS = 16, // 챈트와 인챈트의 가짓수
};
~CSkillMgr();
void ClearProtoType(void);
bool LoadSkillsFromFile(const char* szFileName = 0);
bool LoadSkillsFromBinary(const char* szFileNameBinary = 0);
bool SaveSkillsToBinary(const char* szFileNameBinary = 0, const char* szTrashFile = 0);
const Skill::ProtoType* GetSkillProtoType(unsigned short usSkill_ID);
void GetClassSkill(unsigned char cClass, unsigned short *arySkillID, unsigned char *cSkillNum);
// 로드 당시의 체크섬과, 현재 데이터로 만든 체크섬을 비교한다.
// 데이터가 바뀌면 false를 리턴한다.
bool CheckData();
private:
CSkillMgr();
struct ProtoTypeArray
{
Skill::ProtoType m_ProtoTypes[MAX_SKILL_LOCKCOUNT];
inline bool operator < (ProtoTypeArray& rhs)
{ return m_ProtoTypes[0].m_usSkill_ID < rhs.m_ProtoTypes[0].m_usSkill_ID; }
};
static const char* ms_szSkillScriptFileName;
static CSkillMgr ms_this;
ProtoTypeArray* m_ProtoTypeArray;
size_t m_nSkillNum;
unsigned long m_dwCRC32;
// 문자열과 비교해서, 알맞은 타입 값을 리턴한다. 실패시 nMaxType을 리턴한다.
unsigned char ReadStringToTypeValue(CDelimitedFile& DelimitedFile, const char* szColumn,
const CTypeName* TypeArray, const unsigned char nMaxType);
bool CheckParentChildRule(void);
};
#endif

View File

@@ -0,0 +1,97 @@
#include "stdafx.h"
#include <algorithm>
#include "SkillStructure.h"
#include "GMMemory.h"
const CTypeName Skill::Type::SkillTypes[MAX_SKILL_TYPE] =
{
CTypeName(Skill::Type::NONE, "NONE"),
CTypeName(Skill::Type::PASSIVE, "PASSIVE"),
CTypeName(Skill::Type::INSTANCE, "INSTANCE"),
CTypeName(Skill::Type::CAST, "CAST"),
CTypeName(Skill::Type::CHANT, "CHANT"),
CTypeName(Skill::Type::ENCHANT, "ENCHANT"),
CTypeName(Skill::Type::ITEM, "ITEM"),
CTypeName(Skill::Type::SET, "SET"),
CTypeName(Skill::Type::ACTION, "ACTION"),
CTypeName(Skill::Type::ABILITY, "ABILITY"),
CTypeName(Skill::Type::GATHER, "GATHER")
};
const CTypeName Skill::UseLimit::UseLimits[MAX_USE_LIMIT] =
{
CTypeName(Skill::UseLimit::NONE, "NONE"),
CTypeName(Skill::UseLimit::FOR_FIGHTER, "FORFIGHTER"),
CTypeName(Skill::UseLimit::WITH_SHIELD, "WITHSHIELD"),
CTypeName(Skill::UseLimit::FOR_FIGHTER_TWOHANDED, "FORFIGHTERTWOHAND"),
CTypeName(Skill::UseLimit::FOR_ALL_ONEHAND, "FORALLONEHAND"),
CTypeName(Skill::UseLimit::WITH_DAGGER, "WITHDAGGER"),
CTypeName(Skill::UseLimit::WITH_THROWING_DAGGER, "WITHTHROWINGDAGGER"),
CTypeName(Skill::UseLimit::RANGED, "RANGED"),
CTypeName(Skill::UseLimit::LEFT_ARM, "LEFTARM"),
CTypeName(Skill::UseLimit::GUARD_ARM, "GUARDARM"),
CTypeName(Skill::UseLimit::WITH_WEAPON, "WITHWEAPON"),
CTypeName(Skill::UseLimit::ATTACK_ARM, "ATTACKARM"),
CTypeName(Skill::UseLimit::GUN_ARM, "GUNARM"),
CTypeName(Skill::UseLimit::KNIFE_ARM, "KNIFEARM"),
CTypeName(Skill::UseLimit::WITH_CLOW, "WITHCLOW")
};
const CTypeName Skill::StatusLimit::StatusLimits[MAX_STATUS_LIMIT] =
{
CTypeName(Skill::StatusLimit::NONE, "NONE"),
CTypeName(Skill::StatusLimit::STR, "STR"),
CTypeName(Skill::StatusLimit::DEX, "DEX"),
CTypeName(Skill::StatusLimit::CON, "CON"),
CTypeName(Skill::StatusLimit::INT, "INT"),
CTypeName(Skill::StatusLimit::WIS, "WIS"),
CTypeName(Skill::StatusLimit::LEVEL, "LEVEL") //--//
};
const CTypeName Skill::Target::TargetTypes[MAX_TARGET_TYPE] =
{
CTypeName(Skill::Target::NONE, "NONE"),
CTypeName(Skill::Target::MELEE, "MELEE"),
CTypeName(Skill::Target::FRIEND, "FRIEND"),
CTypeName(Skill::Target::ENEMY, "ENEMY"),
CTypeName(Skill::Target::DEAD_FRIEND, "FRDEAD"),
CTypeName(Skill::Target::DEAD_ENEMY, "ENDEAD"),
CTypeName(Skill::Target::FRIEND_OBJECT, "FROBJ"),
CTypeName(Skill::Target::ENEMY_OBJECT, "ENOBJ"),
CTypeName(Skill::Target::PARTY, "PARTY"),
CTypeName(Skill::Target::FRIEND_EXCEPT_SELF, "FREXME"),
CTypeName(Skill::Target::LINE_ENEMY, "ENLINE"),
CTypeName(Skill::Target::SUMMON, "SUMMON"),
};
Skill::ProtoType::ProtoType() { Initialize(); }
void Skill::ProtoType::Initialize()
{
m_eSkillType = Type::NONE;
m_eUseLimit = UseLimit::NONE;
m_eTargetType = Target::NONE;
m_fMinRange = m_fMaxRange = m_fEffectExtent = 0.0f;
m_bCounter = m_bInterrupt = m_bProtection = m_bGauge = m_bIsClassSkill = false;
m_cStrikeNum = m_cEndScript = m_cEndCoolDown = 0;
m_usSkill_ID = m_StartMP = m_LevelMP = m_LockMP = m_StartTick = m_LevelTick = m_usParentSkill = m_usChildSkill = 0;
m_dwCoolDownTime = 0;
m_SpriteInfo.Initialize();
std::fill_n(&m_StatusLimitType[0], int(MAX_LIMIT_NUM), 0);
std::fill_n(&m_StatusLimitValue[0], int(MAX_LIMIT_NUM), 0);
std::fill_n(&m_szEffectFileName[0], int(MAX_FILE_NAME), 0);
std::fill_n(&m_szHitFileName[0], int(MAX_FILE_NAME), 0);
std::fill_n(&m_szCastingFileName[0], int(MAX_FILE_NAME), 0);
std::fill_n(&m_szSkillDescribe[0], int(MAX_SKILL_DESCRIBE), 0);
}

View File

@@ -0,0 +1,205 @@
#ifndef _SKILL_STRUCTURE_H_
#define _SKILL_STRUCTURE_H_
#pragma once
#include <Utility/TypeArray.h>
#include <Item/ItemStructure.h>
#pragma pack(8)
namespace Skill
{
enum Const
{
SKILL_MASK = 0x8000,
ERROR_OF_DISTANCE = 10 // 거리 예상 오차 (스킬 타겟 거리 계산시 사용)
};
namespace Type
{
enum AbilityType
{
AB_ANIMAL_TALK = 0, // 동물NPC와 대화
AB_SOCIALEX = 1, // 확장 소셜모션 사용가능
AB_NOFIRSTATK = 2, // 선공몹 공격 안당함
AB_MOUNT_SPEEDUP = 3, // 탈것 이속 증가
AB_TEMPINVEN_TIMEUP = 4, // 임시인벤토리 시간증가
AB_GETUP_GOLD = 5, // 골드 획득량 증가
AB_RESPAWN_EX = 6, // 확장 리스폰 사용
AB_FOOD_UP = 7, // 음식류 능력치 증가
AB_SHOP_MEMBERSHIP = 8, // 상점 멤버십(구매가격 하락, 판매가격 상승)
AB_CHEMICAL = 9, // 잡템을 회복템으로 변경
AB_ENDUR_SHILD = 10, // 내구도 하락 감소
AB_RECOVERY_UP = 11, // HP,MP 회복도 증가
AB_GATHER_FIND = 12, // 미니맵에 게더를 보여준다
AB_MYEQUIP_UP = 13, // 자신의 장비 획득율 증가
AB_LUCK_UP = 14, // 럭찬 증가
AB_EQUIP_LEVELDOWN = 15, // 장비의 제한 레벨을 다운시킨다.
AB_HERBS = 16, // 약초 채집
AB_MINING = 17, // 채광
MAX_ABILITY_TYPE = 18
};
enum SkillType
{
NONE = 0,
PASSIVE = 1,
INSTANCE = 2,
CAST = 3,
CHANT = 4,
ENCHANT = 5,
ITEM = 6,
SET = 7,
ACTION = 8,
ABILITY = 9,
GATHER = 10,
MAX_SKILL_TYPE = 11
};
extern const CTypeName SkillTypes[MAX_SKILL_TYPE];
enum DRCType
{
MAGIC = 0,
RIGHT_WEAPON = 1,
LEFT_WEAPON = 2
};
};
namespace UseLimit
{
enum Type
{
NONE = 0,
// 인간
FOR_FIGHTER = 1, // 스탶 대거 맨손 활 석궁 사용불가
WITH_SHIELD = 2, // 방패착용 : 방패가 없으면 사용할 수 없다.
FOR_FIGHTER_TWOHANDED = 3, // 양손무기착용(스탶제외) : 양손무기 착용시에만 사용이 가능하다. 스태프일 경우에는 사용이 불가능하다.
FOR_ALL_ONEHAND = 4, // 한손무기착용 : 양손무기나 맨손으로는 사용이 불가능하다. 대거 제외
WITH_DAGGER = 5, // 대거착용 : 대거 착용시에만 사용이 가능하다.
WITH_THROWING_DAGGER = 6, // 쓰로잉대거소모 : 인벤토리에 쓰로잉 대거가 남아있을 때에만 사용이 가능하다. (손에 장착되어 있을 필요는 없다.)
RANGED = 7, // 활/석궁장착,화살소모 : 활이나 석궁이 장착되어 있고 인벤토리에 화살이 남아있을 때에만 사용이 가능하다.
// 아칸
LEFT_ARM = 8, // 왼팔장착 : 왼팔을 장착하고 있어야지만 사용이 가능하다.
GUARD_ARM = 9, // 가드암장착 : 방어용의 암을 장착하고 있어야지만 사용이 가능하다.
WITH_WEAPON = 10, // 무기장착 : 오른손이 맨손일 때에는 사용이 불가능하다.
ATTACK_ARM = 11, // 어택암장착 : 공격용의 암을 장착하고 있어야지만 사용이 가능하다.
GUN_ARM = 12, // 건암장착 탄약소모 : 장거리용의 암을 장착하고 탄약을 가지고 있어야지만 사용이 가능하다.
KNIFE_ARM = 13, // 나이프암장착 : 나이프형의 암을 장착하고 있어야지만 사용이 가능하다.
WITH_CLOW = 14, // 클로우장착 : 클로우 착용시에만 사용이 가능하다.
MAX_USE_LIMIT = 15
};
extern const CTypeName UseLimits[MAX_USE_LIMIT];
};
// 스킬 습득 제한
namespace StatusLimit
{
enum Type
{
NONE = 0, // 제한 없음
STR = 1, // STR이 일정 이상 필요
DEX = 2, // DEX가 일정 이상 필요
CON = 3, // CON이 일정 이상 필요
INT = 4, // INT가 일정 이상 필요
WIS = 5, // WIS가 일정 이상 필요
LEVEL = 6, // LEVEL이 일정 이상 필요 //--//
MAX_STATUS_LIMIT = 7 //--//
};
extern const CTypeName StatusLimits[MAX_STATUS_LIMIT];
};
namespace Target
{
enum Type
{
NONE = 0,
MELEE = 1,
FRIEND = 2,
ENEMY = 3,
DEAD_FRIEND = 4,
DEAD_ENEMY = 5,
FRIEND_OBJECT = 6,
ENEMY_OBJECT = 7,
PARTY = 8,
FRIEND_EXCEPT_SELF = 9,
LINE_ENEMY = 10,
SUMMON = 11,
MAX_TARGET_TYPE = 12
};
extern const CTypeName TargetTypes[MAX_TARGET_TYPE];
};
struct ProtoType
{
enum
{
MAX_LIMIT_NUM = 2,
MAX_FILE_NAME = 32,
MAX_SKILL_NAME = 32,
MAX_SKILL_DESCRIBE = 256
};
char m_szEffectFileName[MAX_FILE_NAME]; // 이펙트 파일명
char m_szHitFileName[MAX_FILE_NAME]; // 히트 파일명
char m_szCastingFileName[MAX_FILE_NAME]; // 캐스팅 파일명
Item::SpriteData m_SpriteInfo; // 스프라이트 정보
char m_szSkillDescribe[MAX_SKILL_DESCRIBE]; // 스킬 설명
Type::SkillType m_eSkillType; // See Namespace Type
Target::Type m_eTargetType; // See Namespace Target
UseLimit::Type m_eUseLimit; // See Namespace UseLimit
unsigned char m_StatusLimitType[MAX_LIMIT_NUM]; // 습득 제한 스탯 종류
char m_StatusLimitValue[MAX_LIMIT_NUM]; // 습득 제한 스탯 값
unsigned short m_usSkill_ID; // 스킬 아이디
unsigned short m_StartMP; // 시작 소모 MP
unsigned short m_LevelMP; // 레벨당 소모 MP
unsigned short m_LockMP; // 락카운트당 소모 MP
unsigned short m_StartTick; // 시작 틱카운트
unsigned short m_LevelTick; // 레벨당 틱카운트
unsigned short m_usParentSkill; // 부모 스킬 아이디
unsigned short m_usChildSkill; // 자식 스킬 아이디
unsigned long m_dwCoolDownTime; // 쿨다운 시간
float m_fMinRange; // 최소 사정 거리
float m_fMaxRange; // 최대 사정 거리
float m_fEffectExtent; // 효과 범위
bool m_bProtection; // 보호 스킬에 의해 막히는가?
bool m_bGauge; // 연속 사용이 가능한 스킬인가? (ex. 패스트히드)
bool m_bIsClassSkill; // 클래스 스킬인가?
bool m_bInterrupt; // 스턴을 깨는 스킬인가?
bool m_bCounter; // 카운터 당하는 스킬인가?
unsigned char m_cEndScript; // EndScript를 사용하는가?
unsigned char m_cEndCoolDown; // 스킬 효과가 없어지면 쿨다운이 돌아간다. (ex. 스텔스)
unsigned char m_cStrikeNum; // 다단 히트 횟수
unsigned char m_cPadding[1];
ProtoType();
void Initialize();
};
}
#pragma pack()
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,683 @@
#ifndef _SKILL_TABLE_H_
#define _SKILL_TABLE_H_
#pragma once
#include <Pattern/Singleton.h>
#include <Creature/AggresiveCreature.h>
#include <Utility/Math/Math.h>
#include <Utility/TypeArray.h>
#include <Skill/Spell/Spell.h>
#include <Skill/Spell/SpellUtil.h>
#include <Skill/Spell/SpellTable.h>
#include <Skill/Spell/GlobalSpellMgr.h>
#include "SkillMgr.h"
namespace Skill
{
enum PassiveType
{
ActivatePassive = 1,
DeactivatePassive = 2
};
enum MasteryType
{
NONE_MASTERY = 0,
SWORD_MASTERY = 1,
AXE_MASTERY = 2,
BLUNT_MASTERY = 3,
DAGGER_MASTERY = 4,
CRUSH_WEAPON = 5,
BLADE = 6,
CLAW_MASTERY = 7
};
typedef unsigned short (*FnProcess)(const Skill::ProtoType& ProtoType, AtType attackType,
CAggresiveCreature* lpSkillUser, CAggresiveCreature* lpVictim, unsigned char &cOffencerJudge,
unsigned char &cDefenserJudge, unsigned short& wOffencerMPHeal, unsigned short& wDefenserMPHeal, unsigned short &wError);
class CProcessTable : public CSingleton<CProcessTable>
{
public:
struct ProcessInfo
{
unsigned short m_usSkill_ID;
Skill::FnProcess m_fnProcess;
Skill::ProtoType* m_lpProtoType;
static Skill::ProtoType m_NullProtoType;
ProcessInfo() : m_usSkill_ID(0), m_fnProcess(NULL), m_lpProtoType(&m_NullProtoType) { }
ProcessInfo(unsigned short usSkill_ID, Skill::FnProcess fnProcess, Skill::ProtoType* lpProtoType)
: m_usSkill_ID(usSkill_ID), m_fnProcess(fnProcess), m_lpProtoType(lpProtoType)
{ }
inline bool operator < (const ProcessInfo& rhs) const { return (m_usSkill_ID < rhs.m_usSkill_ID); }
};
typedef std::vector<ProcessInfo> ProcessVector;
bool Initialize();
bool InsertSkill(Skill::CProcessTable::ProcessVector& processVector, unsigned short usSkill_ID, FnProcess fnProcess);
const ProcessInfo* GetProcessInfo(unsigned short usSkill_ID);
inline unsigned short UseSkill(AtType attackType, CAggresiveCreature* lpSkillUser, CAggresiveCreature* lpVictim,
unsigned char &cOffencerJudge, unsigned char &cDefenserJudge, unsigned short& wOffencerMPHeal,
unsigned short& wDefenserMPHeal, unsigned short &wError)
{
const ProcessInfo* lpProcessInfo = GetProcessInfo(attackType.m_wType);
if (NULL == lpProcessInfo)
return 0;
char cLockCount = CSkillMgr::MAX_SKILL_LOCKCOUNT;
if(lpProcessInfo->m_lpProtoType->m_eSkillType == Skill::Type::ITEM)
cLockCount = 7;
if (attackType.m_cSkillLockCount >= cLockCount ||
attackType.m_cSkillLevel > CSkillMgr::MAX_SKILL_LEVEL)
{
unsigned long dwCID = (NULL != lpSkillUser) ? lpSkillUser->GetCID() : 0;
ERRLOG3(g_Log, "CID:0x%08x 잘못된 락카운트/레벨의 스킬을 사용하려 합니다. LockCount:%d, Level:%d",
dwCID, attackType.m_cSkillLockCount, attackType.m_cSkillLevel);
}
else
{
return lpProcessInfo->m_fnProcess(lpProcessInfo->m_lpProtoType[attackType.m_cSkillLockCount], attackType,
lpSkillUser, lpVictim, cOffencerJudge, cDefenserJudge, wOffencerMPHeal, wDefenserMPHeal, wError);
}
return 0;
}
private:
CProcessTable();
~CProcessTable();
unsigned short m_usProcessInfo;
ProcessInfo* m_fnProcessTable;
static CProcessTable ms_this;
};
class CFunctions
{
public:
static short ConsumeMP(AtType attackType, CAggresiveCreature* lpSkillUser, unsigned char cOffencerJudge);
protected: // 함수 테이블을 통해서만 호출할 수 있도록 한다.
enum Const
{
VarCastMeeleEnchantLevelMultiplier = 4
};
friend class CProcessTable;
// 패시브 스킬 : 리턴값 - 일단은 0;
// 인스턴스 스킬 : 리턴값 - Victim에게 입힌 대미지
// 캐스트 스킬 : 리턴값 - Victim에게 입힌 대미지
static inline bool CheckChantOff(unsigned char cSkillLockCount, unsigned char cSkillLevel);
static inline bool SlowlySkillAttack(const Skill::ProtoType& ProtoType, AtType attackType,
CAggresiveCreature* lpSkillUser, CAggresiveCreature* lpVictim);
// ------------------------------------------------------------------------------------------------------------
// 기획 측에서 사용하는 용어/수식을 구현한 함수들
// 락카운트
static inline const unsigned short GetSkillLockCount(CAggresiveCreature* lpSkillUser, AtType attackType);
// 엘리트, 레벨갭
static inline const float LevelFactor(CAggresiveCreature* lpSkillUser, CAggresiveCreature* lpVictim);
// 성공 확률
static inline const unsigned short SuccessHitRate(CAggresiveCreature* lpSkillUser, CAggresiveCreature* lpVictim, float fFactor);
// 성공 확률
static inline const unsigned short SuccessRate(CAggresiveCreature* lpSkillUser, CAggresiveCreature* lpVictim, float fFactor);
// 인스턴스 마법 데미지
static inline const unsigned short InstanceMagicDamage(CAggresiveCreature* lpSkillUser, CAggresiveCreature* lpVictim,
AtType attackType, unsigned char cFactor);
// 인스턴스 적대 인챈트
static inline const unsigned long InstanceEnemyEnchantTick(CAggresiveCreature* lpSkillUser, CAggresiveCreature* lpVictim,
AtType attackType, float fFactor);
// 인스턴스 마법 회복
static inline const unsigned short InstanceMagicRegen(CAggresiveCreature* lpSkillUser, AtType attackType, unsigned char cFactor);
// 캐스트 마법 데미지
static inline const unsigned short CastMagicDamage(CAggresiveCreature* lpSkillUser, CAggresiveCreature* lpVictim,
AtType attackType, unsigned char cFactor);
// 그리스 인챈트
static inline const unsigned long CastEnchantTick(CAggresiveCreature* lpSkillUser, CAggresiveCreature* lpVictim,
AtType attackType, float fFactor);
// 캐스트 인챈트
static inline const unsigned short CastEnchantLevel(CAggresiveCreature* lpSkillUser, CAggresiveCreature* lpVictim,
AtType attackType, float fFactor);
// 밀리 케스트 인챈트
static inline const unsigned short CastMeelsEnchantLevel(CAggresiveCreature* lpSkillUser, CAggresiveCreature* lpVictim,
AtType attackType, float fFactor);
// 캐스트 마법 회복
static inline const unsigned short CastMagicRegen(CAggresiveCreature* lpSkillUser, AtType attackType, unsigned char cFactor);
// 챈트 공식
static inline const unsigned short ChantLevel(CAggresiveCreature* lpSkillUser, AtType attackType, unsigned char cFactor);
// 회복류 아이템의 HP, MP 절대값 리턴 함수
static inline const unsigned short PotionHPValue(unsigned char cPercent);
static inline const unsigned short PotionMPValue(unsigned char cPercent);
// ------------------------------------------------------------------------------------------------------------
// 3차 밸런스 패치 관련 함수
// 인스턴스 밀리 회복
static inline const unsigned short InstanceMeleeRegen(CAggresiveCreature* lpSkillUser, AtType attackType, unsigned char cFactor);
// 캐스트 밀리 회복
static inline const unsigned short CastMeleeRegen(CAggresiveCreature* lpSkillUser, AtType attackType, unsigned char cFactor);
// 밀리 챈트 공식
static inline const unsigned short MeleeChantLevel(CAggresiveCreature* lpSkillUser, AtType attackType, unsigned char cFactor);
// 캐스트 인챈트 스킬 레벨
static inline const unsigned short CastEnchantSkillLevel(CAggresiveCreature* lpSkillUser, CAggresiveCreature* lpVictim,
AtType attackType, float fFactor1, float fFactor2 = 1.0f, float fFactor3 = 0.0f);
// ------------------------------------------------------------------------------------------------------------
#define DECLARE_SKILL(SpellName) \
static unsigned short SpellName(const Skill::ProtoType& ProtoType, AtType attackType, CAggresiveCreature* lpSkillUser, \
CAggresiveCreature* lpVictim, unsigned char &cOffencerJudge, unsigned char &cDefenserJudge, \
unsigned short& wOffencerMPHeal, unsigned short& wDefenserMPHeal, unsigned short &wError)
#define DEFINE_SKILL(SpellName) \
unsigned short Skill::CFunctions::##SpellName(const Skill::ProtoType& ProtoType, AtType attackType, \
CAggresiveCreature* lpSkillUser, CAggresiveCreature* lpVictim, \
unsigned char &cOffencerJudge, unsigned char &cDefenserJudge, \
unsigned short& wOffencerMPHeal, unsigned short& wDefenserMPHeal, unsigned short &wError)
// 소설모션
DECLARE_SKILL(SocialMotion);
// 파이터
DECLARE_SKILL(Net);
DECLARE_SKILL(SwordMastery);
DECLARE_SKILL(AxeMastery);
DECLARE_SKILL(HardHit);
DECLARE_SKILL(BluntMastery);
DECLARE_SKILL(WillPower);
DECLARE_SKILL(Toughness);
// 로그
DECLARE_SKILL(Detection);
DECLARE_SKILL(ImprovedCritical);
DECLARE_SKILL(Evasion);
DECLARE_SKILL(NeedleSpit);
// 메이지
DECLARE_SKILL(BloodyMana);
DECLARE_SKILL(VampiricTouch);
DECLARE_SKILL(ManaShell);
DECLARE_SKILL(Grease);
DECLARE_SKILL(Serenity);
// 어콜라이트
DECLARE_SKILL(Purification);
DECLARE_SKILL(Faith);
DECLARE_SKILL(Encourage);
DECLARE_SKILL(FirstAid);
DECLARE_SKILL(HammerOfLight);
// 디펜더
DECLARE_SKILL(Charging);
DECLARE_SKILL(SharedPain);
DECLARE_SKILL(FullSwing);
// 워리어
DECLARE_SKILL(Blaze);
DECLARE_SKILL(BattleSong);
DECLARE_SKILL(ChainAction);
DECLARE_SKILL(DualWieldMastery);
DECLARE_SKILL(CounterAttack);
DECLARE_SKILL(CounterAttackMotion);
// 어쌔신
DECLARE_SKILL(BackStab);
DECLARE_SKILL(Stealth);
DECLARE_SKILL(DaggerMastery);
DECLARE_SKILL(BombSet);
DECLARE_SKILL(Explosion);
DECLARE_SKILL(StealHand);
// 아처
DECLARE_SKILL(AimedShot);
DECLARE_SKILL(DualShot);
DECLARE_SKILL(Camouflage);
DECLARE_SKILL(Accuracy);
// 소서러
DECLARE_SKILL(Recall);
DECLARE_SKILL(FireBolt);
DECLARE_SKILL(LightningArrow);
DECLARE_SKILL(FrostBolt);
DECLARE_SKILL(DeathRay);
DECLARE_SKILL(FreshToStone);
// 엔찬터
DECLARE_SKILL(Disenchant);
DECLARE_SKILL(Entangle);
DECLARE_SKILL(LowerStrength);
DECLARE_SKILL(EnchantWeapon);
DECLARE_SKILL(Shatter);
// 프리스트
DECLARE_SKILL(Resurrection);
DECLARE_SKILL(MaintenanceChant);
DECLARE_SKILL(AccelerationChant);
DECLARE_SKILL(BrightArmor);
DECLARE_SKILL(ManaFlow);
DECLARE_SKILL(ManaBurn);
// 클레릭
DECLARE_SKILL(Dazzle);
DECLARE_SKILL(CureWounds);
DECLARE_SKILL(WoundsCrafting);
DECLARE_SKILL(CureLight);
DECLARE_SKILL(WoundsMake);
DECLARE_SKILL(Regeneration);
// 컴배턴트
DECLARE_SKILL(CrusherMastery);
DECLARE_SKILL(BladeMastery);
DECLARE_SKILL(SplitLife);
DECLARE_SKILL(ExtraLife);
// 오피세이터
DECLARE_SKILL(Dispel);
DECLARE_SKILL(MagicMissile);
DECLARE_SKILL(Flexibility);
DECLARE_SKILL(ClawMastery);
DECLARE_SKILL(LifeAura);
DECLARE_SKILL(InnerSight);
// 템플러
DECLARE_SKILL(Guard);
DECLARE_SKILL(HardenSkin);
DECLARE_SKILL(FastHit);
DECLARE_SKILL(ManaConvert);
// 어태커
DECLARE_SKILL(PowerDrain);
DECLARE_SKILL(SkillArmFight);
DECLARE_SKILL(RingGeyser);
// 거너
DECLARE_SKILL(FireRing);
DECLARE_SKILL(Blast);
// 룬오프
DECLARE_SKILL(Rot);
DECLARE_SKILL(Shock);
DECLARE_SKILL(Shackle);
DECLARE_SKILL(Crevice);
DECLARE_SKILL(SummonKindling);
// 라이프오프
DECLARE_SKILL(Flash);
// 쉐도우오프
DECLARE_SKILL(WoundsBlast);
DECLARE_SKILL(DaggerFire);
DECLARE_SKILL(Envenom);
// 회복 아이템
DECLARE_SKILL(UseFood);
// DECLARE_SKILL(UseFoodPer);
DECLARE_SKILL(UseDrink);
// DECLARE_SKILL(UseDrinkPer);
DECLARE_SKILL(UseFusionFood);
// DECLARE_SKILL(UseFusionFoodPer);
// DECLARE_SKILL(UseHealPotion);
DECLARE_SKILL(UseHealPotionPer);
// DECLARE_SKILL(UseManaPotion);
DECLARE_SKILL(UseManaPotionPer);
// DECLARE_SKILL(UseRefreshPotion);
DECLARE_SKILL(UseRefreshPotionPer);
// 버프포션
// DECLARE_SKILL(DemagePotion);
DECLARE_SKILL(DemagePotionPer);
// DECLARE_SKILL(ArmorPotion);
DECLARE_SKILL(ArmorPotionPer);
// DECLARE_SKILL(HitRatePotion);
DECLARE_SKILL(HitRatePotionPer);
// DECLARE_SKILL(EvadePotion);
DECLARE_SKILL(EvadePotionPer);
// DECLARE_SKILL(MaxHPPotion);
DECLARE_SKILL(MaxHPPotionPer);
// DECLARE_SKILL(MaxMPPotion);
DECLARE_SKILL(MaxMPPotionPer);
// DECLARE_SKILL(HPRegenPotion);
// DECLARE_SKILL(HPRegenPotionPer);
// DECLARE_SKILL(MPRegenPotion);
// DECLARE_SKILL(MPRegenPotionPer);
// DECLARE_SKILL(CriticalPotion);
DECLARE_SKILL(CriticalPotionPer);
// DECLARE_SKILL(BlockPotion);
DECLARE_SKILL(BlockPotionPer);
// DECLARE_SKILL(SpeedPotion);
DECLARE_SKILL(SpeedPotionPer);
// DECLARE_SKILL(DeCoolDownPotion);
DECLARE_SKILL(DeCoolDownPotionPer);
// DECLARE_SKILL(MagicPowerPotion);
DECLARE_SKILL(MagicPowerPotionPer);
// DECLARE_SKILL(MagicResistPotion);
DECLARE_SKILL(MagicResistPotionPer);
DECLARE_SKILL(ConcentrationPotionPer);
DECLARE_SKILL(FireCracker);
DECLARE_SKILL(ChinaFireCracker);
DECLARE_SKILL(Drunk);
DECLARE_SKILL(LuckyExpOrb);
DECLARE_SKILL(MichaelBless);
DECLARE_SKILL(ExpOrb);
DECLARE_SKILL(LuckyOrb);
DECLARE_SKILL(AntidotePotion);
DECLARE_SKILL(AntiFreeze);
DECLARE_SKILL(AntiFire);
DECLARE_SKILL(Gather);
// 공성 오브젝트 스킬
DECLARE_SKILL(SRSAAttack);
DECLARE_SKILL(LRSAAttack);
DECLARE_SKILL(SRCAAttack);
DECLARE_SKILL(LRCAAttack);
DECLARE_SKILL(GuardAttack);
DECLARE_SKILL(EmblemAttack);
DECLARE_SKILL(CampAttack);
DECLARE_SKILL(EmblemNewAttack);
};
// 스텔스 시킬인가?
static inline bool IsStealthSkill(unsigned short wSkillID);
};
inline const float Skill::CFunctions::LevelFactor(CAggresiveCreature* lpSkillUser, CAggresiveCreature* lpVictim)
{
return lpSkillUser->CalculateLevelGapAffect(lpVictim);
}
inline const unsigned short Skill::CFunctions::SuccessHitRate(CAggresiveCreature* lpSkillUser, CAggresiveCreature* lpVictim, float fFactor)
{
return static_cast<unsigned short>((lpSkillUser->GetStatus().m_StatusInfo.m_wHitRate * fFactor /
(lpSkillUser->GetStatus().m_StatusInfo.m_wHitRate * fFactor + lpVictim->GetStatus().m_StatusInfo.m_wEvade)) * 100);
}
inline const unsigned short Skill::CFunctions::SuccessRate(CAggresiveCreature* lpSkillUser, CAggresiveCreature* lpVictim, float fFactor)
{
return static_cast<unsigned short>((lpSkillUser->GetStatus().m_StatusInfo.m_wMagicPower * fFactor /
(lpSkillUser->GetStatus().m_StatusInfo.m_wMagicPower * fFactor + lpVictim->GetStatus().m_StatusInfo.m_fMagicResistRate)) * 100);
}
inline const unsigned short Skill::CFunctions::InstanceMagicDamage(CAggresiveCreature* lpSkillUser, CAggresiveCreature* lpVictim,
AtType attackType, unsigned char cFactor)
{
long lDamage = static_cast<long>((attackType.m_cSkillLevel + attackType.m_cSkillLockCount * 6) * cFactor *
(75 + Math::Random::ComplexRandom(75) + lpSkillUser->GetStatus().m_StatusInfo.m_wMagicPower) / 100.0f *
(100 - lpVictim->GetStatus().m_StatusInfo.m_fMagicResistRate) / 100.0f * LevelFactor(lpSkillUser, lpVictim));
return static_cast<unsigned short>(min(lDamage, USHRT_MAX));
}
inline const unsigned long Skill::CFunctions::InstanceEnemyEnchantTick(CAggresiveCreature* lpSkillUser, CAggresiveCreature* lpVictim,
AtType attackType, float fFactor)
{
return static_cast<unsigned long>((attackType.m_cSkillLevel + attackType.m_cSkillLockCount * 6) *
fFactor * LevelFactor(lpSkillUser, lpVictim));
}
inline const unsigned short Skill::CFunctions::InstanceMagicRegen(CAggresiveCreature* lpSkillUser, AtType attackType, unsigned char cFactor)
{
return static_cast<unsigned short>((attackType.m_cSkillLevel + attackType.m_cSkillLockCount * 6) *
cFactor * (50 + Math::Random::ComplexRandom(50) + lpSkillUser->GetStatus().m_StatusInfo.m_wMagicPower) / 100.0f);
}
inline const unsigned short Skill::CFunctions::CastMagicDamage(CAggresiveCreature* lpSkillUser, CAggresiveCreature* lpVictim,
AtType attackType, unsigned char cFactor)
{
const unsigned short wLockCount = GetSkillLockCount(lpSkillUser, attackType);
long lDamage = static_cast<long>(((wLockCount + 1) * attackType.m_cSkillLevel + 1 + attackType.m_cSkillLockCount * wLockCount * 5) *
cFactor * (75 + Math::Random::ComplexRandom(75) + lpSkillUser->GetStatus().m_StatusInfo.m_wMagicPower) / 100.0f *
(100 - lpVictim->GetStatus().m_StatusInfo.m_fMagicResistRate) / 100.0f * LevelFactor(lpSkillUser, lpVictim));
return static_cast<unsigned short>(min(lDamage, USHRT_MAX));
}
inline const unsigned long Skill::CFunctions::CastEnchantTick(CAggresiveCreature* lpSkillUser, CAggresiveCreature* lpVictim,
AtType attackType, float fFactor)
{
return static_cast<unsigned long>((GetSkillLockCount(lpSkillUser, attackType) + attackType.m_cSkillLevel + attackType.m_cSkillLockCount * 2) *
fFactor * LevelFactor(lpSkillUser, lpVictim));
}
inline const unsigned short Skill::CFunctions::CastEnchantLevel(CAggresiveCreature* lpSkillUser, CAggresiveCreature* lpVictim,
AtType attackType, float fFactor)
{
unsigned short wFirstCase = static_cast<unsigned short>(((GetSkillLockCount(lpSkillUser, attackType) + 1) *
attackType.m_cSkillLevel + attackType.m_cSkillLockCount * GetSkillLockCount(lpSkillUser, attackType)) * fFactor *
(100 + lpSkillUser->GetStatus().m_StatusInfo.m_wMagicPower) / 100.0f);
unsigned short wSecondCase = static_cast<unsigned short>(lpVictim->GetStatus().m_nLevel * 3 * fFactor);
return min(wFirstCase, wSecondCase);
}
inline const unsigned short Skill::CFunctions::CastMeelsEnchantLevel(CAggresiveCreature* lpSkillUser, CAggresiveCreature* lpVictim,
AtType attackType, float fFactor)
{
unsigned short wFirstCase = static_cast<unsigned short>(((GetSkillLockCount(lpSkillUser, attackType) + 1) *
attackType.m_cSkillLevel + attackType.m_cSkillLockCount *
GetSkillLockCount(lpSkillUser, attackType)) * fFactor *
(VarCastMeeleEnchantLevelMultiplier + GetSkillLockCount(lpSkillUser, attackType)));
unsigned short wSecondCase = static_cast<unsigned short>(lpVictim->GetStatus().m_nLevel * 3 * fFactor);
return min(wFirstCase, wSecondCase);
}
inline const unsigned short Skill::CFunctions::CastMagicRegen(CAggresiveCreature* lpSkillUser, AtType attackType, unsigned char cFactor)
{
return static_cast<unsigned short>(((GetSkillLockCount(lpSkillUser, attackType) + 1) *
attackType.m_cSkillLevel + 1 + attackType.m_cSkillLockCount * GetSkillLockCount(lpSkillUser, attackType) * 5) * cFactor *
(50 + Math::Random::ComplexRandom(50) + lpSkillUser->GetStatus().m_StatusInfo.m_wMagicPower) / 100.0f);
}
inline const unsigned short Skill::CFunctions::PotionHPValue(unsigned char cPercent)
{
switch (cPercent)
{
case 10: return 1000;
case 20: return 3000;
case 30: return 5000;
case 40: return 6000;
case 50: return 7000;
case 60: return 8000;
case 80: return 10000;
}
return 0;
}
inline const unsigned short Skill::CFunctions::PotionMPValue(unsigned char cPercent)
{
switch (cPercent)
{
case 5: return 500;
case 10: return 1000;
case 15: return 2000;
case 20: return 3000;
case 30: return 4000;
case 45: return 6000;
case 60: return 8000;
}
return 0;
}
inline const unsigned short Skill::CFunctions::ChantLevel(CAggresiveCreature* lpSkillUser, AtType attackType, unsigned char cFactor)
{
return static_cast<unsigned short>((attackType.m_cSkillLevel + attackType.m_cSkillLockCount * 6) * cFactor *
(100 + lpSkillUser->GetStatus().m_StatusInfo.m_wMagicPower) / 100.0f);
}
inline const unsigned short Skill::CFunctions::GetSkillLockCount(CAggresiveCreature* lpSkillUser, AtType attackType)
{
unsigned short wLockCount = 0;
Creature::CreatureType eCreatureType = Creature::GetCreatureType(lpSkillUser->GetCID());
if (Creature::CT_MONSTER == eCreatureType ||
Creature::CT_SUMMON == eCreatureType ||
Creature::CT_STRUCT == eCreatureType)
{
wLockCount = attackType.m_cSkillLockCount;
}
else
{
wLockCount = lpSkillUser->GetSkillLockCount(attackType.m_wType);
}
if (wLockCount < 0 || wLockCount >= CSkillMgr::MAX_SKILL_LOCKCOUNT)
{
ERRLOG3(g_Log, "CID:0x%08x 쓰려는 스킬의 락카운트가 이상합니다. SkillType : 0x%04x, LockCount : %d",
lpSkillUser->GetCID(), attackType.m_wType, wLockCount);
return 0;
}
return wLockCount;
}
inline bool Skill::CFunctions::CheckChantOff(unsigned char cSkillLockCount, unsigned char cSkillLevel)
{
return (0 == cSkillLockCount && 0 == cSkillLevel) ? true : false;
}
inline bool Skill::CFunctions::SlowlySkillAttack(const Skill::ProtoType& ProtoType, AtType attackType,
CAggresiveCreature* lpSkillUser, CAggresiveCreature* lpVictim)
{
unsigned short wLockCount = GetSkillLockCount(lpSkillUser, attackType);
unsigned short wEnchantLevel = attackType.m_cSkillLevel + wLockCount * 6;
unsigned long dwDurationSec = static_cast<unsigned long>(
(attackType.m_cSkillLevel + wLockCount * 6) * 0.5f * LevelFactor(lpSkillUser, lpVictim));
unsigned short wResult = CAddSpell<CSlowSpell>(CSpell::Spell_Info(ProtoType, lpSkillUser,
SpellType::MAGICAL_SPELL, SpellID::Slow, wEnchantLevel, dwDurationSec))(lpVictim);
return (wResult == CSpell::ENCHANT_FAIL_BY_ENEMY_ENCHANT) ? false : true;
}
inline bool Skill::IsStealthSkill(unsigned short wSkillID)
{
switch (wSkillID)
{
case 0x8704: // 스텔스 (어쌔)
case 0x9804: // 스텔스 (쉐옵)
case 0x8805: // 캐모플라쥐 (아처)
case 0x9504: // 캐모플라쥐 (거너)
return true;
}
return false;
}
// ------------------------------------------------------------------------------------------------------------
// 3차 밸런스 패치 관련 함수
inline const unsigned short Skill::CFunctions::InstanceMeleeRegen(CAggresiveCreature* lpSkillUser, AtType attackType, unsigned char cFactor)
{
return static_cast<unsigned short>((attackType.m_cSkillLevel + attackType.m_cSkillLockCount * 6) *
cFactor * (50 + Math::Random::ComplexRandom(50) + (attackType.m_cSkillLevel + attackType.m_cSkillLockCount * 6) * 25) / 100.0f);
}
inline const unsigned short Skill::CFunctions::CastMeleeRegen(CAggresiveCreature* lpSkillUser, AtType attackType, unsigned char cFactor)
{
return static_cast<unsigned short>(((GetSkillLockCount(lpSkillUser, attackType) + 1) *
attackType.m_cSkillLevel + 1 + attackType.m_cSkillLockCount * GetSkillLockCount(lpSkillUser, attackType) * 5) * cFactor *
(50 + Math::Random::ComplexRandom(50) + GetSkillLockCount(lpSkillUser, attackType) * 100) / 100.0f);
}
inline const unsigned short Skill::CFunctions::MeleeChantLevel(CAggresiveCreature* lpSkillUser, AtType attackType, unsigned char cFactor)
{
return static_cast<unsigned short>((attackType.m_cSkillLevel + attackType.m_cSkillLockCount * 6) * cFactor *
(100 + (attackType.m_cSkillLevel + attackType.m_cSkillLockCount * 6) * 31) / 100.0f);
}
inline const unsigned short Skill::CFunctions::CastEnchantSkillLevel(CAggresiveCreature* lpSkillUser, CAggresiveCreature* lpVictim,
AtType attackType, float fFactor1, float fFactor2, float fFactor3)
{
unsigned short wFirstCase = static_cast<unsigned short>((((GetSkillLockCount(lpSkillUser, attackType) + 1) *
attackType.m_cSkillLevel + attackType.m_cSkillLockCount * GetSkillLockCount(lpSkillUser, attackType)) * fFactor1 *
(GetSkillLockCount(lpSkillUser, attackType) + 4) * fFactor2) + fFactor3);
unsigned short wSecondCase = static_cast<unsigned short>(lpVictim->GetStatus().m_nLevel * 3 * fFactor1);
return min(wFirstCase, wSecondCase);
}
#endif

View File

@@ -0,0 +1,623 @@
#include "stdafx.h"
#include <Skill/SkillMgr.h>
#include <Creature/AggresiveCreature.h>
#include "Spell.h"
#include "Affected.h"
#include "SpellKind.h"
bool CAffectedSpell::Add(CSpell* pSpell, unsigned short& wError)
{
if (true == RemoveOverlappedSpell(pSpell))
{
switch (pSpell->GetSkillType())
{
case Skill::Type::CHANT:
{
if (m_cChantNum < MAX_CHANT)
{
m_pChant[m_cChantNum] = pSpell;
++m_cChantNum;
return true;
}
} break;
case Skill::Type::ENCHANT:
{
if (Skill::SpellTarget::ENEMY_TARGET_ENCHANT == pSpell->GetSpellTarget())
{
RemoveEnchantBySpellType(Skill::SpellID::Stealth);
}
if (Skill::SpellID::Stealth == pSpell->GetSpellID() &&
true == IsSpellThisTargetType(Skill::SpellTarget::ENEMY_TARGET_ENCHANT))
{
ERRLOG1(g_Log, "CID:0x%08x 적대 스킬이 풀리지 않은 상태에서 스텔스를 걸려고 합니다.", m_pOwner->GetCID());
wError = CSpell::ENCHANT_FAIL_BY_ENEMY_ENCHANT;
return false;
}
if (m_cEnchantNum < MAX_ENCHANT)
{
/*
// edith 2008.10.16 오브 삭제시 로그 남김.
if(pSpell->GetSpellID() == Skill::SpellID::ExpOrb)
{
unsigned long time = pSpell->GetDurationSec();
if(m_pOwner)
SERLOG4(g_SkillLog, "UID:%d/CID:0x%08x CAffectedSpell::Add 경험치의 오브 생성 : Type:%d : %d Tick남음", m_pOwner->GetUID(), m_pOwner->GetCID(), pSpell->GetSpellType(), time);
else
SERLOG4(g_SkillLog, "UID:%d/CID:0x%08x CAffectedSpell::Add 경험치의 오브 생성 : Type:%d : %d Tick남음", 0, 0, pSpell->GetSpellType(), time);
}
else if(pSpell->GetSpellID() == Skill::SpellID::LuckyOrb)
{
unsigned long time = pSpell->GetDurationSec();
if(m_pOwner)
SERLOG4(g_SkillLog, "UID:%d/CID:0x%08x CAffectedSpell::Add 행운의 오브 생성 : Type:%d : %d Tick남음", m_pOwner->GetUID(), m_pOwner->GetCID(), pSpell->GetSpellType(), time);
else
SERLOG4(g_SkillLog, "UID:%d/CID:0x%08x CAffectedSpell::Add 행운의 오브 생성 : Type:%d : %d Tick남음", 0, 0, pSpell->GetSpellType(), time);
}
*/
m_pEnchant[m_cEnchantNum] = pSpell;
++m_cEnchantNum;
return true;
}
} break;
}
}
wError = CSpell::ENCHNAT_FAIL_ALREADY_AFFECTED;
return false;
}
bool CAffectedSpell::Remove(CSpell* pSpell)
{
CSpell** ppBegin = NULL;
CSpell** ppPastEnd = NULL;
switch (pSpell->GetSkillType())
{
case Skill::Type::CHANT:
{
for (ppBegin = m_pChant, ppPastEnd = m_pChant + m_cChantNum;
ppBegin != ppPastEnd; ++ppBegin)
{
if (pSpell == *ppBegin)
{
std::copy(ppBegin + 1, ppPastEnd, ppBegin);
--m_cChantNum;
m_pChant[m_cChantNum] = 0;
return true;
}
}
} break;
case Skill::Type::ENCHANT:
{
for (ppBegin = m_pEnchant, ppPastEnd = m_pEnchant + m_cEnchantNum;
ppBegin != ppPastEnd; ++ppBegin)
{
if (pSpell == *ppBegin)
{
// edith 2008.10.16 오브 삭제시 로그 남김.
if(pSpell->GetSpellType() == Skill::SpellType::PAYBUFF_SPELL)
{
unsigned long time = pSpell->GetDurationSec();
if(m_pOwner)
SERLOG4(g_SkillLog, "UID:%d/CID:0x%08x CAffectedSpell::Remove : Type:%d : %d Tick남음", m_pOwner->GetUID(), m_pOwner->GetCID(), pSpell->GetSpellType(), time);
else
SERLOG4(g_SkillLog, "UID:%d/CID:0x%08x CAffectedSpell::Remove : Type:%d : %d Tick남음", 0, 0, pSpell->GetSpellType(), time);
}
/*
// edith 2008.10.16 오브 삭제시 로그 남김.
if(pSpell->GetSpellID() == Skill::SpellID::ExpOrb)
{
unsigned long time = pSpell->GetDurationSec();
if(m_pOwner)
SERLOG4(g_SkillLog, "UID:%d/CID:0x%08x CAffectedSpell::Remove 경험치의 오브 삭제 : Type:%d : %d Tick남음", m_pOwner->GetUID(), m_pOwner->GetCID(), pSpell->GetSpellType(), time);
else
SERLOG4(g_SkillLog, "UID:%d/CID:0x%08x CAffectedSpell::Remove 경험치의 오브 삭제 : Type:%d : %d Tick남음", 0, 0, pSpell->GetSpellType(), time);
}
else if(pSpell->GetSpellID() == Skill::SpellID::LuckyOrb)
{
unsigned long time = pSpell->GetDurationSec();
if(m_pOwner)
SERLOG4(g_SkillLog, "UID:%d/CID:0x%08x CAffectedSpell::Remove 행운의 오브 삭제 : Type:%d : %d Tick남음", m_pOwner->GetUID(), m_pOwner->GetCID(), pSpell->GetSpellType(), time);
else
SERLOG4(g_SkillLog, "UID:%d/CID:0x%08x CAffectedSpell::Remove 행운의 오브 삭제 : Type:%d : %d Tick남음", 0, 0, pSpell->GetSpellType(), time);
}
*/
std::copy(ppBegin + 1, ppPastEnd, ppBegin);
--m_cEnchantNum;
m_pEnchant[m_cEnchantNum] = 0;
return true;
}
}
} break;
}
return false;
}
void CAffectedSpell::ClearChant()
{
CSpell** pprBegin = m_pChant + m_cChantNum - 1;
CSpell** pprPastEnd = m_pChant - 1;
for (;pprBegin != pprPastEnd; --pprBegin)
{
(*pprBegin)->RemoveAffected(m_pOwner);
}
}
void CAffectedSpell::ClearEnchant()
{
CSpell** pprBegin = m_pEnchant + m_cEnchantNum - 1;
CSpell** pprPastEnd = m_pEnchant - 1;
for (;pprBegin != pprPastEnd; --pprBegin)
{
(*pprBegin)->RemoveAffected(m_pOwner);
}
}
void CAffectedSpell::EnableChant(unsigned long dwOperateFlag)
{
CSpell** pprBegin = m_pChant + m_cChantNum - 1;
CSpell** pprPastEnd = m_pChant - 1;
for (;pprBegin != pprPastEnd; --pprBegin)
{
(*pprBegin)->Enable(dwOperateFlag);
}
}
void CAffectedSpell::EnableEnchant(unsigned long dwOperateFlag)
{
CSpell** pprBegin = m_pEnchant + m_cEnchantNum - 1;
CSpell** pprPastEnd = m_pEnchant - 1;
for (;pprBegin != pprPastEnd; --pprBegin)
{
(*pprBegin)->Enable(dwOperateFlag);
}
}
void CAffectedSpell::DisableChant(unsigned long dwOperateFlag)
{
CSpell** pprBegin = m_pChant + m_cChantNum - 1;
CSpell** pprPastEnd = m_pChant - 1;
for (;pprBegin != pprPastEnd; --pprBegin)
{
(*pprBegin)->Disable(dwOperateFlag);
}
}
void CAffectedSpell::DisableEnchant(unsigned long dwOperateFlag)
{
CSpell** pprBegin = m_pEnchant + m_cEnchantNum - 1;
CSpell** pprPastEnd = m_pEnchant - 1;
for (;pprBegin != pprPastEnd; --pprBegin)
{
(*pprBegin)->Disable(dwOperateFlag);
}
}
CSpell* CAffectedSpell::GetEnchant(int Index)
{
if(Index < 0)
return NULL;
if(Index >= MAX_ENCHANT)
return NULL;
return m_pEnchant[Index];
}
CSpell* CAffectedSpell::GetSpell(unsigned short usSpellID)
{
CSpell** ppBegin = NULL;
CSpell** ppPastEnd = NULL;
// 챈트
ppBegin = m_pChant;
ppPastEnd = m_pChant + m_cChantNum;
for (;ppBegin != ppPastEnd; ++ppBegin)
{
if ((*ppBegin)->GetSpellID() == usSpellID && true == (*ppBegin)->IsActivate(m_pOwner))
{
return *ppBegin;
}
}
// 인챈트
ppBegin = m_pEnchant;
ppPastEnd = m_pEnchant + m_cEnchantNum;
for (;ppBegin != ppPastEnd; ++ppBegin)
{
if ((*ppBegin)->GetSpellID() == usSpellID)
{
return *ppBegin;
}
}
return NULL;
}
SPELL CAffectedSpell::GetSpellInfo(BOOL bDead)
{
SPELL spell = SPELL::SPELL();
/*
CSpell** ppBegin = NULL;
CSpell** ppPastEnd = NULL;
// 인챈트
ppBegin = m_pEnchant;
ppPastEnd = m_pEnchant + MAX_ENCHANT;
unsigned char cIndex = 0;
for (;ppBegin != ppPastEnd; ++ppBegin)
{
switch((*ppBegin)->GetSpellType())
{
case Skill::SpellType::BUFF_SPELL:
if(bDead == TRUE)
continue;
// edith 2008.06.03 석상전 버프를 저장한다.
case Skill::SpellType::STATUE_SPELL:
case Skill::SpellType::PAYBUFF_SPELL:
case Skill::SpellType::ETERNAL_SPELL:
spell.Spells[cIndex] = SPELLINSTANCE((*ppBegin)->GetDurationSec(), (*ppBegin)->GetSpellID(), (*ppBegin)->GetSpellLevel(), (*ppBegin)->GetSpellType());
++cIndex;
break;
}
if(cIndex >= SPELL::MAX_SPELL_NUM)
break;
}
*/
unsigned char cIndex = 0;
for (int i = 0; i < MAX_ENCHANT; ++i)
{
if(!m_pEnchant[i])
continue;
switch(m_pEnchant[i]->GetSpellType())
{
case Skill::SpellType::BUFF_SPELL:
if(bDead == TRUE)
break;
// edith 2008.06.03 석상전 버프를 저장한다.
case Skill::SpellType::STATUE_SPELL:
case Skill::SpellType::PAYBUFF_SPELL:
case Skill::SpellType::ETERNAL_SPELL:
spell.Spells[cIndex] = SPELLINSTANCE(m_pEnchant[i]->GetDurationSec(), m_pEnchant[i]->GetSpellID(), m_pEnchant[i]->GetSpellLevel(), m_pEnchant[i]->GetSpellType());
++cIndex;
break;
}
if(cIndex >= SPELL::MAX_SPELL_NUM)
break;
}
return spell;
}
void CAffectedSpell::ApplyPartyChant(CAggresiveCreature* pAffected)
{
unsigned short wError = CSpell::NO_ENCHANT_ERROR;
for (CSpell** ppBegin = m_pChant, **ppPastEnd = m_pChant + m_cChantNum;
ppBegin != ppPastEnd; ++ppBegin)
{
if ((*ppBegin)->IsPartySkill())
{
(*ppBegin)->AddAffected(pAffected, wError);
}
}
}
void CAffectedSpell::ApplyEnchant(CAggresiveCreature* pAffected)
{
unsigned short wError = CSpell::NO_ENCHANT_ERROR;
for (CSpell** ppBegin = m_pEnchant, **ppPastEnd = m_pEnchant + m_cEnchantNum;
ppBegin != ppPastEnd; ++ppBegin)
{
(*ppBegin)->AddAffected(pAffected, wError);
}
}
bool CAffectedSpell::RemoveOverlappedSpell(CSpell* pSpell)
{
CSkillMgr& SkillMgr = CSkillMgr::GetInstance();
unsigned short usSkill_ID = pSpell->GetSpellID();
CSpell** ppBegin = NULL;
CSpell** ppPastEnd = NULL;
if (Skill::Type::ENCHANT == pSpell->GetSkillType())
{
ppBegin = m_pEnchant;
ppPastEnd = m_pEnchant + m_cEnchantNum;
}
else
{
return true;
}
for (; ppBegin != ppPastEnd; ++ppBegin)
{
CSpell* pOverlappedSpell = (*ppBegin);
if (NULL != pOverlappedSpell)
{
if (usSkill_ID == pOverlappedSpell->GetSpellID())
{
bool bRemoveAffected = false;
// 여기서 스킬을 비교한다. 스킬레벨이 더 높은걸로 돌게 비교
if (pSpell->GetSpellLevel() > pOverlappedSpell->GetSpellLevel())
{
bRemoveAffected = true;
}
else if (pSpell->GetSpellLevel() == pOverlappedSpell->GetSpellLevel())
{
if (pSpell->GetDurationSec() >= pOverlappedSpell->GetDurationSec())
{
bRemoveAffected = true;
}
}
if (true == bRemoveAffected)
{
pOverlappedSpell->ClearAll();
}
else
{
return false;
}
}
}
}
return true;
}
void CAffectedSpell::RemoveChantByCaster(CAggresiveCreature* pCaster)
{
for (CSpell** ppBegin = m_pChant, **ppPastEnd = m_pChant + m_cChantNum;
ppBegin != ppPastEnd; ++ppBegin)
{
CSpell* lpSpell = (*ppBegin);
if (0 != lpSpell && pCaster == lpSpell->GetCaster())
{
lpSpell->RemoveAffected(m_pOwner);
}
}
}
void CAffectedSpell::RemoveEnchantByCaster(CAggresiveCreature* pCaster)
{
for (CSpell** ppBegin = m_pEnchant, **ppPastEnd = m_pEnchant + m_cEnchantNum;
ppBegin != ppPastEnd; ++ppBegin)
{
CSpell* lpSpell = (*ppBegin);
if (0 != lpSpell && pCaster == lpSpell->GetCaster())
{
lpSpell->RemoveAffected(m_pOwner);
}
}
}
void CAffectedSpell::RemoveChantBySpellType(unsigned char cSpellType)
{
for (CSpell** ppBegin = m_pChant, **ppPastEnd = m_pChant + m_cChantNum;
ppBegin != ppPastEnd; ++ppBegin)
{
CSpell* lpSpell = (*ppBegin);
if (0 != lpSpell && lpSpell->GetSpellID() == cSpellType)
{
lpSpell->RemoveAffected(m_pOwner);
}
}
}
bool CAffectedSpell::RemoveEnchantBySpellType(unsigned char cSpellType)
{
for (CSpell** ppBegin = m_pEnchant, **ppPastEnd = m_pEnchant + m_cEnchantNum;
ppBegin != ppPastEnd; ++ppBegin)
{
CSpell* lpSpell = (*ppBegin);
if (0 != lpSpell && lpSpell->GetSpellID() == cSpellType)
{
lpSpell->RemoveAffected(m_pOwner);
return true;
}
}
return false;
}
bool CAffectedSpell::IsSpellOfEnemyCharacter(void)
{
for (CSpell** ppBegin = m_pEnchant, **ppPastEnd = m_pEnchant + m_cEnchantNum;
ppBegin != ppPastEnd; ++ppBegin)
{
CAggresiveCreature* lpCaster = (*ppBegin)->GetCaster();
Creature::CreatureType eCreatureType = Creature::GetCreatureType(lpCaster->GetCID());
if (Creature::CT_MONSTER == eCreatureType ||
Creature::CT_SUMMON == eCreatureType ||
Creature::CT_STRUCT == eCreatureType)
{
continue;
}
if (EnemyCheck::EC_ENEMY == m_pOwner->IsEnemy(lpCaster))
{
return true;
}
}
return false;
}
bool CAffectedSpell::IsSpellThisTargetType(Skill::SpellTarget::Type eTargetType)
{
for (CSpell** ppBegin = m_pEnchant, **ppPastEnd = m_pEnchant + m_cEnchantNum;
ppBegin != ppPastEnd; ++ppBegin)
{
if ((*ppBegin)->GetSpellTarget() == eTargetType)
{
return true;
}
}
return false;
}
// --------------------------------------------------------------------------------------------------
// CAffectedSpell::Disenchant
//
// 인자 : 주문 종류(마법형/물리형/월드웨폰/월드웨폰제외/모두), 타겟(긍정적/부정적/모두), 파괴 기준(레벨/시간/모두), 주문 레벨, 갯수
// 리턴 : 파괴한 인챈트 갯수
// --------------------------------------------------------------------------------------------------
unsigned char CAffectedSpell::Disenchant(Skill::SpellType::Type eSpellType, Skill::SpellTarget::Type eTargetType,
Skill::Disenchant::Type eDisenchantType, unsigned short usSkillLevel, unsigned char cNum)
{
CSpell *pTargetSpell = NULL;
unsigned short usMaxLevel = 0;
unsigned long dwMaxDuration = 0;
unsigned char cResult = 0;
if (Skill::Disenchant::INFINITE_NUM == cNum)
{
cNum = m_cEnchantNum;
}
for (unsigned char nIndex = 0; nIndex < cNum; nIndex++)
{
for (CSpell** ppBegin = m_pEnchant, **ppPastEnd = m_pEnchant + m_cEnchantNum;
ppBegin != ppPastEnd; ++ppBegin)
{
if (Skill::SpellTarget::ALL_ENCHANT != eTargetType && (*ppBegin)->GetSpellTarget() != eTargetType)
{
// 긍정적? 부정적?
continue;
}
// 죽었을때 없애는 인챈트이면
if (Skill::Disenchant::DEAD == eDisenchantType)
{
// 버프스펠보다 낮은거면 다 지워라
if(Skill::SpellType::BUFF_SPELL >= (*ppBegin)->GetSpellType())
{
pTargetSpell = *ppBegin;
break;
}
}
// edith 경험치의 오브이면 해제하면 안된다.
if((*ppBegin)->GetSpellID() == Skill::SpellID::ExpOrb)
continue;
if((*ppBegin)->GetSpellID() == Skill::SpellID::LuckyOrb)
continue;
// 유료면 디스펠에서 디스펠 되면 안된다.
if(Skill::SpellType::PAYBUFF_SPELL == (*ppBegin)->GetSpellType())
continue;
if (Skill::SpellType::NONE != eSpellType && (*ppBegin)->GetSpellType() != eSpellType)
{
// 마법형? 물리형?
continue;
}
else if (Skill::SpellType::ETERNAL_SPELL != eSpellType &&
Skill::SpellType::ETERNAL_SPELL == (*ppBegin)->GetSpellType())
{
// 영구적으로 유지되야 하는 스펠이면 제외
continue;
}
// 모두 파괴
if (Skill::Disenchant::NONE == eDisenchantType)
{
pTargetSpell = *ppBegin;
break;
}
switch (eDisenchantType)
{
// 일정 레벨보다 낮은 것들 중 가장 높은 레벨의 것을 파괴
case Skill::Disenchant::LEVEL:
{
if ((*ppBegin)->GetSpellLevel() < usSkillLevel && (*ppBegin)->GetSpellLevel() > usMaxLevel)
{
pTargetSpell = *ppBegin;
usMaxLevel = (*ppBegin)->GetSpellLevel();
}
} break;
// 가장 긴 시간이 남은 것을 파괴
case Skill::Disenchant::DURATION:
{
if (CSpell::INFINITE_DURATION != (*ppBegin)->GetDurationSec() && (*ppBegin)->GetDurationSec() > dwMaxDuration)
{
pTargetSpell = *ppBegin;
dwMaxDuration = (*ppBegin)->GetDurationSec();
}
} break;
}
}
if (NULL == pTargetSpell)
{
return cResult;
}
pTargetSpell->RemoveAffected(m_pOwner);
pTargetSpell = NULL;
++cResult;
}
return cResult;
}

View File

@@ -0,0 +1,107 @@
#ifndef _CAFFECTED_H_
#define _CAFFECTED_H_
#include "Spell.h"
// 전방 참조
class CAggresiveCreature;
class CAffectedSpell
{
public:
CAffectedSpell() : m_cInternalFlag(0), m_cChantNum(0), m_cEnchantNum(0)
{
int i;
for(i = 0; i < MAX_CHANT; ++i)
m_pChant[i] = NULL;
for(i = 0; i < MAX_ENCHANT; ++i)
m_pEnchant[i] = NULL; // 영향을 받고 있는 Enchant주문
}
~CAffectedSpell() { ClearAll(); }
void SetOwner(CAggresiveCreature* pOwner) { m_pOwner = pOwner; }
bool Add(CSpell* pSpell, unsigned short& wError);
bool Remove(CSpell* pSpell);
void ApplyPartyChant(CAggresiveCreature* pAffected);
void ApplyEnchant(CAggresiveCreature* pAffected);
void RemoveChantByCaster(CAggresiveCreature* pCaster);
void RemoveEnchantByCaster(CAggresiveCreature* pCaster);
void RemoveChantBySpellType(unsigned char cSpellType);
bool RemoveEnchantBySpellType(unsigned char cSpellType);
bool IsSpellOfEnemyCharacter(void);
bool IsSpellThisTargetType(Skill::SpellTarget::Type eTargetType);
unsigned char Disenchant(Skill::SpellType::Type eSpellType, Skill::SpellTarget::Type eTargetType,
Skill::Disenchant::Type eDisenchantType, unsigned short usSkillLevel, unsigned char cNum);
void ClearChant();
void ClearEnchant();
void EnableChant(unsigned long dwOperateFlag = 0);
void EnableEnchant(unsigned long dwOperateFlag = 0);
void DisableChant(unsigned long dwOperateFlag = 0);
void DisableEnchant(unsigned long dwOperateFlag = 0);
inline void ClearAll();
inline void EnableAll(unsigned long dwOperateFlag = 0);
inline void DisableAll(unsigned long dwOperateFlag = 0);
CSpell* GetSpell(unsigned short usSpellID);
CSpell* GetEnchant(int Index);
int GetEnchantNum() { return m_cEnchantNum; }
SPELL GetSpellInfo(BOOL bDead = FALSE);
enum
{
MAX_CHANT = 10,
// edith 2008.05.06 인첸트 최대 개수
MAX_ENCHANT = 30
};
protected:
bool RemoveOverlappedSpell(CSpell* pSpell);
CSpell* m_pChant[MAX_CHANT];
CSpell* m_pEnchant[MAX_ENCHANT]; // 영향을 받고 있는 Enchant주문
CAggresiveCreature* m_pOwner; // 영향을 받고 있는 캐릭터. 이 개체의 주인.
unsigned char m_cInternalFlag;
unsigned char m_cChantNum;
unsigned char m_cEnchantNum;
};
inline void CAffectedSpell::ClearAll()
{
ClearChant();
ClearEnchant();
}
inline void CAffectedSpell::EnableAll(unsigned long dwOperateFlag)
{
EnableChant(dwOperateFlag);
EnableEnchant(dwOperateFlag);
}
inline void CAffectedSpell::DisableAll(unsigned long dwOperateFlag)
{
DisableChant(dwOperateFlag);
DisableEnchant(dwOperateFlag);
}
#endif

View File

@@ -0,0 +1,221 @@
#include "stdafx.h"
#include <Skill/SkillMgr.h>
#include <Creature/AggresiveCreature.h>
#include "Spell.h"
#include "Casting.h"
bool CCastingSpell::Add(CSpell* pSpell)
{
CSpell* pRemoveSpell = 0;
CSpell** ppPastEnd = NULL;
switch(pSpell->GetSkillType())
{
case Skill::Type::CHANT:
if(m_cChantNum >= MAX_CHANT_CASTING)
{
pRemoveSpell = m_pChantCasting[0];
// 맨 처음에 캐스팅 한 주문을 지움.
ppPastEnd = m_pChantCasting + m_cChantNum;
std::copy(m_pChantCasting + 1, ppPastEnd, m_pChantCasting);
--m_cChantNum;
m_pChantCasting[m_cChantNum] = 0;
pRemoveSpell->ClearAll();
}
m_pChantCasting[m_cChantNum] = pSpell;
++m_cChantNum;
return true;
case Skill::Type::ENCHANT:
if(m_cEnchantNum >= MAX_ENCHANT_CASTING)
{
pRemoveSpell = m_pEnchantCasting[0];
// 맨 처음에 캐스팅 한 주문을 지움.
ppPastEnd = m_pEnchantCasting + m_cEnchantNum;
std::copy(m_pEnchantCasting + 1, ppPastEnd, m_pEnchantCasting);
--m_cEnchantNum;
m_pEnchantCasting[m_cEnchantNum] = 0;
pRemoveSpell->ClearAll();
}
/*
// edith 2008.10.16 오브 삭제시 로그 남김.
if(pSpell->GetSpellID() == Skill::SpellID::ExpOrb)
{
unsigned long time = pSpell->GetDurationSec();
if(m_pOwner)
SERLOG4(g_SkillLog, "UID:%d/CID:0x%08x CAffectedSpell::Add 경험치의 오브 생성 : Type:%d : %d Tick남음", m_pOwner->GetUID(), m_pOwner->GetCID(), pSpell->GetSpellType(), time);
else
SERLOG4(g_SkillLog, "UID:%d/CID:0x%08x CAffectedSpell::Add 경험치의 오브 생성 : Type:%d : %d Tick남음", 0, 0, pSpell->GetSpellType(), time);
}
else if(pSpell->GetSpellID() == Skill::SpellID::LuckyOrb)
{
unsigned long time = pSpell->GetDurationSec();
if(m_pOwner)
SERLOG4(g_SkillLog, "UID:%d/CID:0x%08x CAffectedSpell::Add 행운의 오브 생성 : Type:%d : %d Tick남음", m_pOwner->GetUID(), m_pOwner->GetCID(), pSpell->GetSpellType(), time);
else
SERLOG4(g_SkillLog, "UID:%d/CID:0x%08x CAffectedSpell::Add 행운의 오브 생성 : Type:%d : %d Tick남음", 0, 0, pSpell->GetSpellType(), time);
}
*/
m_pEnchantCasting[m_cEnchantNum] = pSpell;
++m_cEnchantNum;
return true;
};
return false;
}
bool CCastingSpell::Remove(CSpell* pSpell)
{
CSpell** ppBegin = NULL;
CSpell** ppPastEnd = NULL;
switch(pSpell->GetSkillType())
{
case Skill::Type::CHANT:
for(ppBegin = m_pChantCasting, ppPastEnd = m_pChantCasting + m_cChantNum;
ppBegin != ppPastEnd; ++ppBegin)
{
if((*ppBegin) == pSpell)
{
std::copy(ppBegin + 1, ppPastEnd, ppBegin);
--m_cChantNum;
m_pChantCasting[m_cChantNum] = 0;
return true;
}
}
break;
case Skill::Type::ENCHANT:
for(ppBegin = m_pEnchantCasting, ppPastEnd = m_pEnchantCasting + m_cEnchantNum;
ppBegin != ppPastEnd; ++ppBegin)
{
if((*ppBegin) == pSpell)
{
/*
// edith 2008.10.16 오브 삭제시 로그 남김.
if(pSpell->GetSpellID() == Skill::SpellID::ExpOrb)
{
unsigned long time = pSpell->GetDurationSec();
if(m_pOwner)
SERLOG4(g_SkillLog, "UID:%d/CID:0x%08x CCastingSpell::Remove 경험치의 오브 삭제 : Type:%d : %d Tick남음", m_pOwner->GetUID(), m_pOwner->GetCID(), pSpell->GetSpellType(), time);
else
SERLOG4(g_SkillLog, "UID:%d/CID:0x%08x CCastingSpell::Remove 경험치의 오브 삭제 : Type:%d : %d Tick남음", 0, 0, pSpell->GetSpellType(), time);
}
else if(pSpell->GetSpellID() == Skill::SpellID::LuckyOrb)
{
unsigned long time = pSpell->GetDurationSec();
if(m_pOwner)
SERLOG4(g_SkillLog, "UID:%d/CID:0x%08x CCastingSpell::Remove 행운의 오브 삭제 : Type:%d : %d Tick남음", m_pOwner->GetUID(), m_pOwner->GetCID(), pSpell->GetSpellType(), time);
else
SERLOG4(g_SkillLog, "UID:%d/CID:0x%08x CCastingSpell::Remove 행운의 오브 삭제 : Type:%d : %d Tick남음", 0, 0, pSpell->GetSpellType(), time);
}
*/
std::copy(ppBegin + 1, ppPastEnd, ppBegin);
--m_cEnchantNum;
m_pEnchantCasting[m_cEnchantNum] = 0;
return true;
}
}
break;
};
return false;
}
void CCastingSpell::ClearChant()
{
CSpell** pprBegin = m_pChantCasting + m_cChantNum - 1;
CSpell** pprPastEnd = m_pChantCasting - 1;
for(;pprBegin != pprPastEnd; --pprBegin)
{
(*pprBegin)->ClearAll();
}
}
void CCastingSpell::ClearEnchant()
{
CSpell** pprBegin = m_pEnchantCasting + m_cEnchantNum - 1;
CSpell** pprPastEnd = m_pEnchantCasting - 1;
for(;pprBegin != pprPastEnd; --pprBegin)
{
(*pprBegin)->ClearAll();
}
}
CSpell* CCastingSpell::GetSpell(unsigned short usSpellID)
{
CSpell** ppBegin = NULL;
CSpell** ppPastEnd = NULL;
// 챈트
ppBegin = m_pChantCasting;
ppPastEnd = m_pChantCasting + m_cChantNum;
for(;ppBegin != ppPastEnd; ++ppBegin)
{
if((*ppBegin)->GetSpellID() == usSpellID)
{
return *ppBegin;
}
}
// 인챈트
ppBegin = m_pEnchantCasting;
ppPastEnd = m_pEnchantCasting + m_cEnchantNum;
for(;ppBegin != ppPastEnd; ++ppBegin)
{
if((*ppBegin)->GetSpellID() == usSpellID)
{
return *ppBegin;
}
}
return NULL;
}
void CCastingSpell::EnableChant(unsigned long dwOperateFlag)
{
CSpell** ppBegin = m_pChantCasting;
CSpell** ppPastEnd = m_pChantCasting + m_cChantNum;
for(;ppBegin != ppPastEnd; ++ppBegin)
{
(*ppBegin)->Enable(dwOperateFlag);
}
}
void CCastingSpell::DisableChant(unsigned long dwOperateFlag)
{
CSpell** ppBegin = m_pChantCasting;
CSpell** ppPastEnd = m_pChantCasting + m_cChantNum;
for(;ppBegin != ppPastEnd; ++ppBegin)
{
(*ppBegin)->Disable(dwOperateFlag);
}
}

View File

@@ -0,0 +1,54 @@
#ifndef _CCASTING_H_
#define _CCASTING_H_
// 전방 참조
class CSpell;
class CAggresiveCreature;
class CCastingSpell
{
public:
CCastingSpell() : m_pOwner(NULL), m_usInternalFlag(0), m_cEnchantNum(0), m_cChantNum(0) { }
~CCastingSpell() { ClearAll(); }
inline void SetOwner(CAggresiveCreature* pOwner) { m_pOwner = pOwner; }
bool Add(CSpell* pSpell);
bool Remove(CSpell* pSpell);
void ClearChant();
void ClearEnchant();
inline void ClearAll();
CSpell* GetSpell(unsigned short usSkill_ID);
void EnableChant(unsigned long dwOperateFlag = 0);
void DisableChant(unsigned long dwOperateFlag = 0);
protected:
enum
{
MAX_ENCHANT_CASTING = 20,
MAX_CHANT_CASTING = 1
};
CSpell* m_pEnchantCasting[MAX_ENCHANT_CASTING]; // 캐스팅 한 주문
CSpell* m_pChantCasting[MAX_CHANT_CASTING]; // 캐릭터가 사용하고 있는 Chant주문.
CAggresiveCreature* m_pOwner;
unsigned short m_usInternalFlag;
unsigned char m_cEnchantNum;
unsigned char m_cChantNum;
};
inline void CCastingSpell::ClearAll()
{
ClearChant();
ClearEnchant();
}
#endif

View File

@@ -0,0 +1,84 @@
#include "stdafx.h"
#include <Community/Party/Party.h>
#include "Spell.h"
#include "GlobalSpellMgr.h"
CGlobalSpellMgr& CGlobalSpellMgr::GetInstance()
{
static CGlobalSpellMgr globalSpellMgr;
return globalSpellMgr;
}
CGlobalSpellMgr::CGlobalSpellMgr()
: m_nSpellNum(0)
{
}
CGlobalSpellMgr::~CGlobalSpellMgr()
{
Clear();
}
void CGlobalSpellMgr::Process()
{
CSpell* pCurrentSpell = m_HeadSpell.m_pNextSpell;
CSpell* pPrevSpell = &m_HeadSpell;
for (;NULL != pCurrentSpell;)
{
// 주문에 의해 영향을 받는 이가 없거나, operate에 실패하면 delete
// (영향을 받는 이가 없으면 operate할 필요 없음)
if (false == pCurrentSpell->IsValid() || false == pCurrentSpell->Operate())
{
pPrevSpell->m_pNextSpell = pCurrentSpell->m_pNextSpell;
delete pCurrentSpell;
pCurrentSpell = pPrevSpell->m_pNextSpell;
--m_nSpellNum;
}
else
{
pPrevSpell = pCurrentSpell;
pCurrentSpell = pCurrentSpell->m_pNextSpell;
}
}
}
void CGlobalSpellMgr::Add(CSpell* pSpell)
{
if(NULL != pSpell)
{
pSpell->m_pNextSpell = m_HeadSpell.m_pNextSpell;
m_HeadSpell.m_pNextSpell = pSpell;
++m_nSpellNum;
}
}
void CGlobalSpellMgr::Clear()
{
CSpell* pDelSpell = NULL;
CSpell* pPosSpell = m_HeadSpell.m_pNextSpell;
for (;NULL != pPosSpell;)
{
pDelSpell = pPosSpell;
pPosSpell = pPosSpell->m_pNextSpell;
delete pDelSpell;
pDelSpell = NULL;
}
m_nSpellNum = 0;
}

View File

@@ -0,0 +1,26 @@
#ifndef _CGLOBAL_SPELL_MGR_
#define _CGLOBAL_SPELL_MGR_
#include "NullSpell.h"
class CGlobalSpellMgr
{
public:
void Add(CSpell* pSpell); // Spell의 생성자에서 추가한다.
void Process(); // 매초마다 실행된다. 주문 처리 및 필요 없어진 주문을 제거한다.
void Clear(); // Spell들을 전부 제거한다.
size_t GetSpellNum() const { return m_nSpellNum; } // 현재 등록된 Spell개수를 리턴한다.
static CGlobalSpellMgr& GetInstance();
protected:
CGlobalSpellMgr();
~CGlobalSpellMgr();
size_t m_nSpellNum;
CNullSpell m_HeadSpell;
};
#endif

View File

@@ -0,0 +1,21 @@
#ifndef _CNULLSPELL_H_
#define _CNULLSPELL_H_
#include "Spell.h"
class CNullSpell : public CSpell
{
public:
CNullSpell() : CSpell(Spell_Info(Skill::ProtoType(), NULL,
Skill::SpellType::NONE, Skill::SpellID::None, 0, 0), Skill::Type::NONE) { }
virtual ~CNullSpell() { }
protected:
inline virtual bool Activate(CAggresiveCreature* pAffected, unsigned long dwOperateFlag) { return true; }
inline virtual bool Deactivate(CAggresiveCreature* pAffected, unsigned long dwOperateFlag) { return true; }
};
#endif

View File

@@ -0,0 +1,201 @@
#include "stdafx.h"
#include <Creature/AggresiveCreature.h>
#include "Spell.h"
#include "Affected.h"
#include "PartySpellMgr.h"
#include <Utility/Setup/ServerSetup.h>
#include <Community/Party/Party.h>
CPartySpellMgr::CPartySpellMgr()
: m_dwMemberNum(0), m_lpOwnerParty(0)
{
std::fill_n(&m_pPartyMember[0], int(MAX_MEMBER), reinterpret_cast<CAggresiveCreature*>(0));
}
CPartySpellMgr::~CPartySpellMgr()
{
ClearMember();
}
bool CPartySpellMgr::AddMember(CAggresiveCreature* lpNewMember)
{
if (m_dwMemberNum < MAX_MEMBER && NULL != lpNewMember)
{
// 멤버가 있는지 살핀다. 있으면 즐.
CAggresiveCreature** ppBegin = m_pPartyMember;
CAggresiveCreature** ppPastEnd = m_pPartyMember + m_dwMemberNum;
for (;ppBegin != ppPastEnd; ++ppBegin)
{
if(lpNewMember == (*ppBegin))
{
LogChantBug(lpNewMember, m_lpOwnerParty,
"멤버 추가에 실패했습니다. 멤버가 이미 있습니다.", LOG_FFLCHANT);
return false;
}
}
CAffectedSpell& newAffectedInfo = lpNewMember->GetSpellMgr().GetAffectedInfo();
ppBegin = m_pPartyMember;
ppPastEnd = m_pPartyMember + m_dwMemberNum;
for (;ppBegin != ppPastEnd; ++ppBegin)
{
// 현재 캐릭터가 가지고 있는 주문에, 새로운 캐릭터를 추가시킴.
CAggresiveCreature* lpOldMember = (*ppBegin);
CAffectedSpell& memberAffectedInfo = lpOldMember->GetSpellMgr().GetAffectedInfo();
memberAffectedInfo.ApplyPartyChant(lpNewMember);
// 새로 넣으려는 캐릭터가 가지고 있는 주문에, 현재 캐릭터들을 추가시킴.
newAffectedInfo.ApplyPartyChant(lpOldMember);
}
m_pPartyMember[m_dwMemberNum] = lpNewMember;
++m_dwMemberNum;
LogChantBug(lpNewMember, m_lpOwnerParty,
"멤버 추가에 성공했습니다", LOG_FFLCHANT);
return true;
}
return false;
}
bool CPartySpellMgr::RemoveMember(CAggresiveCreature* lpRemoveMember)
{
CAggresiveCreature** ppBegin = m_pPartyMember;
CAggresiveCreature** ppPastEnd = m_pPartyMember + m_dwMemberNum;
// 제거하려는 멤버를 검색한다.
for (;ppBegin != ppPastEnd; ++ppBegin)
{
if (0 != lpRemoveMember && (*ppBegin) == lpRemoveMember)
{
// 멤버 제거.
std::copy(ppBegin + 1, ppPastEnd, ppBegin);
--m_dwMemberNum;
// 멤버 제거한 후에, 0으로 채운다.
m_pPartyMember[m_dwMemberNum] = 0;
CAffectedSpell& removeAffectedInfo =
lpRemoveMember->GetSpellMgr().GetAffectedInfo();
ppBegin = m_pPartyMember;
ppPastEnd = m_pPartyMember + m_dwMemberNum;
for (; ppBegin != ppPastEnd; ++ppBegin)
{
CAggresiveCreature* lpOldMember = (*ppBegin);
// 제거하려는 멤버에게서, 다른 멤버들이 Caster로 있는 Chant를 전부 지운다.
removeAffectedInfo.RemoveChantByCaster(lpOldMember);
// 다른 멤버들에게서, 지우려고 하는 멤버가 Caster로 있는 Chant를 전부 지운다.
CAffectedSpell& memberAffectedInfo =
lpOldMember->GetSpellMgr().GetAffectedInfo();
memberAffectedInfo.RemoveChantByCaster(lpRemoveMember);
}
LogChantBug(lpRemoveMember, m_lpOwnerParty,
"멤버 제거에 성공했습니다", LOG_FFLCHANT);
return true;
}
}
return false;
}
void CPartySpellMgr::ClearMember()
{
CAggresiveCreature** ppExternalBegin = m_pPartyMember;
CAggresiveCreature** ppPastEnd = m_pPartyMember + m_dwMemberNum;
for (; ppExternalBegin != ppPastEnd; ++ppExternalBegin)
{
CAffectedSpell& memberAffectedInfo = (*ppExternalBegin)->GetSpellMgr().GetAffectedInfo();
CAggresiveCreature** ppInternalBegin = m_pPartyMember;
for (; ppInternalBegin != ppPastEnd; ++ppInternalBegin)
{
if (*ppInternalBegin != *ppExternalBegin)
{
memberAffectedInfo.RemoveChantByCaster(*ppInternalBegin);
}
}
}
std::fill_n(&m_pPartyMember[0], int(MAX_MEMBER),
reinterpret_cast<CAggresiveCreature*>(0));
m_dwMemberNum = 0;
LogChantBug(0, m_lpOwnerParty,
"멤버 전부 제거에 성공했습니다", LOG_FFLCHANT);
}
void CPartySpellMgr::AddAffectedToAllMember(CSpell* pSpell, unsigned short wMapIndex)
{
CAggresiveCreature** ppBegin = m_pPartyMember;
CAggresiveCreature** ppPastEnd = m_pPartyMember + m_dwMemberNum;
unsigned short wError = CSpell::NO_ENCHANT_ERROR;
for (;ppBegin != ppPastEnd; ++ppBegin)
{
CAggresiveCreature* lpCreature = (*ppBegin);
if (0 == lpCreature || lpCreature->GetMapIndex() != wMapIndex)
{
// Creature가 NULL이거나 맵이 다르면 무효
continue;
}
if (lpCreature->GetEnchantInfo().GetFlag(Skill::SpellID::Hide))
{
// Creature가 숨어 있으면 무효
continue;
}
if (0 == pSpell->GetCaster() ||
EnemyCheck::EC_FRIEND != pSpell->GetCaster()->IsEnemy(lpCreature))
{
// 시전자가 없거나, 시전자가 아군이 아니면 무효
continue;
}
pSpell->AddAffected(*ppBegin, wError);
}
}
// 챈트 관련 버그 로그를 찍는다. 문제 해결후 나중에 전부 제거한다.
void LogChantBug(CAggresiveCreature* lpCreature, CParty* lpParty,
const char* szMessage, const char* lpRtn, const char* lpFileName, int nLine)
{
if(0 == CServerSetup::GetInstance().GetServerGroup() && 0 != szMessage && 0 != lpParty)
{
if(0 != lpCreature)
{
// 테섭이고. Creature가 제대로 세팅되었을 때만 찍는다.
g_Log.DetailLog(LOG_DETAIL, lpRtn, lpFileName, nLine, "CID:0x%08x(0x%08x)/PID:0x%08x(0x%08x)/ChantBug - %s",
lpCreature->GetCID(), lpCreature, lpParty->GetUID(), lpParty, szMessage);
}
else
{
g_Log.DetailLog(LOG_DETAIL, lpRtn, lpFileName, nLine, "PID:0x%08x(0x%08x)/ChantBug - %s",
lpParty->GetUID(), lpParty, szMessage);
}
}
}

View File

@@ -0,0 +1,42 @@
#ifndef _CPARTY_SPELL_MGR_
#define _CPARTY_SPELL_MGR_
// 전방 참조
class CParty;
class CSpell;
class CAggresiveCreature;
#define LOG_FFLCHANT __FUNCTION__, __FILE__, __LINE__
// 챈트 관련 버그 로그를 찍는다. 문제 해결후 나중에 전부 제거한다.
void LogChantBug(CAggresiveCreature* lpCreature, CParty* lpParty,
const char* szMessage, const char* lpRtn, const char* lpFileName, int nLine);
class CPartySpellMgr
{
public:
CPartySpellMgr();
~CPartySpellMgr();
void SetOwner(CParty* lpParty) { m_lpOwnerParty = lpParty; }
bool AddMember(CAggresiveCreature* pNewMember);
bool RemoveMember(CAggresiveCreature* pRemoveMember);
void ClearMember();
void AddAffectedToAllMember(CSpell* pSpell, unsigned short wMapIndex=0);
protected:
enum { MAX_MEMBER = 10 };
CParty* m_lpOwnerParty;
CAggresiveCreature* m_pPartyMember[MAX_MEMBER];
unsigned long m_dwMemberNum;
};
#endif

View File

@@ -0,0 +1,442 @@
#include "stdafx.h"
#include <Network/Packet/PacketCommand.h>
#include <Network/Packet/WrapPacket.h>
#include <Network/Packet/PacketStruct/CharAttackPacket.h>
#include <Map/FieldMap/Cell.h>
#include <Creature/AggresiveCreature.h>
#include <Creature/Monster/Monster.h>
#include "../SkillMgr.h"
#include "SpellMgr.h"
#include "GlobalSpellMgr.h"
#include "Spell.h"
#define IS_SET(dwFlag, dwValue) ((dwValue) == ((dwFlag) & (dwValue)))
#define SEND_SPELL_INFO(dwOperateFlag, lpAffected, cSpellType, nEnchantLevel, dwEnchantTime, bOnOff) \
if(!IS_SET(dwOperateFlag, DO_NOT_SEND)) { SendSpellInfo(lpAffected, cSpellType, nEnchantLevel, dwEnchantTime, bOnOff); }
CSpell::CSpell(Spell_Info& spell_Info, Skill::Type::SkillType eSpellType)
: m_pNextSpell(NULL), m_ProtoType(spell_Info.m_SkillProtoType), m_pCaster(NULL), m_eSkillType(eSpellType),
m_wSpellID(spell_Info.m_wSpellID), m_wSpellLevel(spell_Info.m_wSpellLevel),
m_cSpellType(spell_Info.m_cSpellType), m_dwDurationSec(spell_Info.m_dwDurationSec),
m_dwActivateStatus(0), m_cAffectedNum(0), m_cInternalFlags(0),
m_cSkillLockCount(spell_Info.m_cSkillLockCount), m_cSkillLevel(spell_Info.m_cSkillLevel)
{
SetCaster(spell_Info.m_lpCaster);
}
void CSpell::SetCaster(CAggresiveCreature* pCaster)
{
if (NULL != m_pCaster)
{
// edith 2009.05.15 스킬 삭제로그 덤프
// SERLOG1(g_SkillLog, "CSpell::SetCaster %d", m_pCaster->GetCID());
m_pCaster->GetSpellMgr().GetCastingInfo().Remove(this);
}
m_pCaster = pCaster;
if (NULL != m_pCaster)
{
// edith 2009.05.15 스킬 삭제로그 덤프
// SERLOG1(g_SkillLog, "CSpell::SetCaster %d", m_pCaster->GetCID());
m_pCaster->GetSpellMgr().GetCastingInfo().Add(this);
}
}
// Caster, Affected정보를 전부 제거.
void CSpell::ClearAll(void)
{
if (NULL != m_pCaster)
{
// edith 2009.05.15 스킬 삭제로그 덤프
// SERLOG1(g_SkillLog, "CSpell::ClearAll %d", m_pCaster->GetCID());
m_pCaster->GetSpellMgr().GetCastingInfo().Remove(this);
m_pCaster = NULL;
}
ClearAffected();
}
void CSpell::Destroy(void)
{
if (DESTROYED != (DESTROYED & m_cInternalFlags))
{
ClearAll();
m_cInternalFlags |= DESTROYED;
}
}
bool CSpell::Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->GetEnchantInfo().SetFlag(static_cast<unsigned char>(m_wSpellID));
SEND_SPELL_INFO(dwOperateFlag, lpAffected, static_cast<unsigned char>(m_wSpellID), m_wSpellLevel, m_dwDurationSec, true);
return true;
}
bool CSpell::Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->GetEnchantInfo().ResetFlag(static_cast<unsigned char>(m_wSpellID));
SEND_SPELL_INFO(dwOperateFlag, lpAffected, static_cast<unsigned char>(m_wSpellID), m_wSpellLevel, 0, false);
return true;
}
// Affected관련
bool CSpell::AddAffected(CAggresiveCreature* lpAffected, unsigned short& wError)
{
if (NULL == lpAffected || m_cAffectedNum >= MAX_AFFECTED)
{
return false;
}
CAggresiveCreature** ppBegin = m_pAffected;
CAggresiveCreature** ppPastEnd = m_pAffected + m_cAffectedNum;
// 이미 있는 캐릭터를 또 넣으려는지 여부 검사.
for (;ppBegin != ppPastEnd; ++ppBegin)
{
if ((*ppBegin) == lpAffected)
{
return false;
}
}
m_pAffected[m_cAffectedNum] = lpAffected;
// edith 2009.05.15 스킬 삭제로그 덤프
// SERLOG1(g_SkillLog, "CSpell::AddAffected %d", lpAffected->GetCID());
// 상호참조 설정. 설정에 실패하면 넣지 않는다.
if (true == lpAffected->GetSpellMgr().GetAffectedInfo().Add(this, wError))
{
if (true == IsEnabled())
{
if (m_eSkillType == Skill::Type::CHANT)
{
CheckRange();
}
else
{
if (true == Activate(lpAffected, 0))
{
SetActivate(m_cAffectedNum);
}
}
}
++m_cAffectedNum;
return true;
}
return false;
}
bool CSpell::RemoveAffected(CAggresiveCreature* pRemoved)
{
CAggresiveCreature** ppBegin = m_pAffected;
CAggresiveCreature** ppPastEnd = m_pAffected + m_cAffectedNum;
unsigned char cIndex = 0;
for (;ppBegin != ppPastEnd; ++ppBegin, ++cIndex)
{
if ((*ppBegin) == pRemoved)
{
// Deactivate & Remove
if (true == IsActivate(cIndex))
{
if (true == Deactivate(pRemoved, 0))
{
SetDeactivate(cIndex);
}
}
// edith 2009.05.15 스킬 삭제로그 덤프
// SERLOG1(g_SkillLog, "CSpell::RemoveAffected %d", pRemoved->GetCID());
if (false == (*ppBegin)->GetSpellMgr().GetAffectedInfo().Remove(this))
{
SPLOG_ERRLEVEL(ERRLOG1(g_Log, "CID:0x%08x 상호참조에 문제가 있습니다! "
"캐릭터에서 주문을 제거할 수 없습니다.", (*ppBegin)->GetCID()));
}
std::copy(ppBegin + 1, ppPastEnd, ppBegin);
RemoveIndex(cIndex);
--m_cAffectedNum;
return true;
}
}
return false;
}
void CSpell::ClearAffected(void)
{
CAggresiveCreature** ppBegin = m_pAffected;
CAggresiveCreature** ppPastEnd = m_pAffected + m_cAffectedNum;
unsigned char cIndex = 0;
for (;ppBegin != ppPastEnd; ++ppBegin, ++cIndex)
{
// Deactivate & Remove
if (true == IsActivate(cIndex))
{
if (true == Deactivate(*ppBegin, 0))
{
SetDeactivate(cIndex);
}
}
// edith 2009.05.15 스킬 삭제로그 덤프
// SERLOG0(g_SkillLog, "CSpell::ClearAffected");
if (false == (*ppBegin)->GetSpellMgr().GetAffectedInfo().Remove(this))
{
SPLOG_ERRLEVEL(ERRLOG1(g_Log, "CID:0x%08x 상호참조에 문제가 있습니다! "
"캐릭터에서 주문을 제거할 수 없습니다.", (*ppBegin)->GetCID()));
}
}
m_cAffectedNum = 0;
}
bool CSpell::Operate(void)
{
if (INFINITE_DURATION != m_dwDurationSec)
{
if (0 == m_dwDurationSec)
{
return false;
}
--m_dwDurationSec;
}
if (m_eSkillType == Skill::Type::CHANT && true == IsEnabled())
{
CheckRange();
}
CAggresiveCreature** ppBegin = m_pAffected;
CAggresiveCreature** ppPastEnd = m_pAffected + m_cAffectedNum;
unsigned char cIndex = 0;
for (; ppBegin != ppPastEnd; ++ppBegin, ++cIndex)
{
if (true == IsActivate(cIndex))
{
Operate(*ppBegin);
}
}
return true;
}
void CSpell::CheckRange(void)
{
// Caster가 있을 경우에만 체크한다.
if (NULL != m_pCaster && true == IsEnabled())
{
const Position& CasterPos = m_pCaster->GetCurrentPos();
const float fRange = m_ProtoType.m_fEffectExtent;
CAggresiveCreature** ppBegin = m_pAffected;
CAggresiveCreature** ppPastEnd = m_pAffected + m_cAffectedNum;
unsigned char cIndex = 0;
for (; ppBegin != ppPastEnd; ++ppBegin, ++cIndex)
{
if (CasterPos.GetDistance((*ppBegin)->GetCurrentPos()) <= fRange)
{
if (false == IsActivate(cIndex))
{
CSpell* pSpell = (*ppBegin)->GetSpellMgr().GetAffectedInfo().GetSpell(m_wSpellID);
if (NULL == pSpell)
{
if (true == Activate(*ppBegin, 0))
{
SetActivate(cIndex);
}
}
else
{
if (pSpell->GetSpellLevel() < m_wSpellLevel)
{
if (true == pSpell->Deactivate(*ppBegin, 0))
{
unsigned char cAffectedIndex = pSpell->GetAffectedIndex(*ppBegin);
if (MAX_AFFECTED != cAffectedIndex)
{
pSpell->SetDeactivate(cAffectedIndex);
}
if (true == Activate(*ppBegin, 0))
{
SetActivate(cIndex);
}
}
}
}
}
}
else
{
if (true == IsActivate(cIndex))
{
if (true == Deactivate(*ppBegin, 0))
{
SetDeactivate(cIndex);
}
}
}
}
}
}
const Skill::SpellTarget::Type CSpell::GetSpellTarget(void)
{
if (Skill::Type::CHANT == m_eSkillType)
{
return Skill::SpellTarget::CHANT;
}
else if (Skill::Type::ENCHANT == m_eSkillType)
{
switch (m_ProtoType.m_eTargetType)
{
case Skill::Target::FRIEND:
case Skill::Target::FRIEND_EXCEPT_SELF:
case Skill::Target::FRIEND_OBJECT:
case Skill::Target::DEAD_FRIEND:
case Skill::Target::PARTY:
return Skill::SpellTarget::FRIEND_TARGET_ENCHANT;
case Skill::Target::MELEE:
case Skill::Target::ENEMY:
case Skill::Target::ENEMY_OBJECT:
case Skill::Target::DEAD_ENEMY:
return Skill::SpellTarget::ENEMY_TARGET_ENCHANT;
}
}
return Skill::SpellTarget::NONE;
}
void CSpell::Enable(unsigned long dwOperateFlag)
{
if (false == IsEnabled())
{
m_cInternalFlags &= ~DISABLED;
if (m_eSkillType == Skill::Type::CHANT)
{
CheckRange();
}
else
{
CAggresiveCreature** ppBegin = m_pAffected;
CAggresiveCreature** ppPastEnd = m_pAffected + m_cAffectedNum;
unsigned char cIndex = 0;
for (; ppBegin != ppPastEnd; ++ppBegin, ++cIndex)
{
if (false == IsActivate(cIndex))
{
if (true == Activate(*ppBegin, dwOperateFlag))
{
SetActivate(cIndex);
}
}
}
}
}
}
void CSpell::Disable(unsigned long dwOperateFlag)
{
if (true == IsEnabled())
{
CAggresiveCreature** ppBegin = m_pAffected;
CAggresiveCreature** ppPastEnd = m_pAffected + m_cAffectedNum;
unsigned char cIndex = 0;
for (; ppBegin != ppPastEnd; ++ppBegin, ++cIndex)
{
if (true == IsActivate(cIndex))
{
if (true == Deactivate(*ppBegin, dwOperateFlag))
{
SetDeactivate(cIndex);
}
}
}
m_cInternalFlags |= DISABLED;
}
}
unsigned char CSpell::GetAffectedIndex(CAggresiveCreature* lpAffected)
{
CAggresiveCreature** ppBegin = m_pAffected;
CAggresiveCreature** ppPastEnd = m_pAffected + m_cAffectedNum;
unsigned char cIndex = 0;
for (; ppBegin != ppPastEnd; ++ppBegin, ++cIndex)
{
if ((*ppBegin) == lpAffected)
{
return cIndex;
}
}
return MAX_AFFECTED;
}
void CSpell::SendSpellInfo(CAggresiveCreature* lpAffected, unsigned char cSpellType,
unsigned short nEnchantLevel, unsigned long dwEnchantTime, bool bOnOff)
{
CCell* pCell = lpAffected->GetCellPos().m_lpCell;
if (pCell != NULL)
{
PktSpInfo pktSpInfo;
memset(&pktSpInfo, 0, sizeof(PktSpInfo));
pktSpInfo.m_dwCharID = lpAffected->GetCID();
pktSpInfo.m_cSpellType = cSpellType;
pktSpInfo.m_nEnchantLevel = nEnchantLevel;
pktSpInfo.m_bOnOff = bOnOff;
pktSpInfo.m_dwEnchantTime = dwEnchantTime;
if (PacketWrap::WrapCrypt(reinterpret_cast<char*>(&pktSpInfo), sizeof(PktSpInfo), CmdCharSpellInfo, 0))
{
pCell->SendNowAllNearCellCharacter(reinterpret_cast<char*>(&pktSpInfo), sizeof(PktSpInfo), CmdCharSpellInfo);
}
}
}

View File

@@ -0,0 +1,239 @@
#ifndef _CSPELL_H_
#define _CSPELL_H_
#include <climits>
#include <Skill/SkillStructure.h>
#include "SpellKind.h"
// 로그 레벨 : x <--> (void*)0
// MAXLEVEL : 세부 로그
// ERRLEVEL : 에러 로그
// TESTLEVEL : 테스트 로그
#define SPLOG_MAXLEVEL(x) (void*)0
#define SPLOG_ERRLEVEL(x) (void*)0
#define SPLOG_TESTLEVEL(x) (void*)0
// 전방 참조
class CAggresiveCreature;
class CSpell
{
public:
enum EnchantError
{
NO_ENCHANT_ERROR = 0,
ENCHNAT_FAIL_ALREADY_AFFECTED = 1,
ENCHANT_FAIL_BY_ENEMY_ENCHANT = 2,
ENCHANT_FAIL_BY_RESIST = 3
};
enum Const
{
INFINITE_DURATION = ULONG_MAX,
REALM_TIME = 7200,
REDUCE_MANA_TURN = 5,
MAX_AFFECTED = 10
};
enum OperateFlag
{
DO_NOT_SEND = 1 << 0
};
struct Spell_Info
{
const Skill::ProtoType& m_SkillProtoType;
CAggresiveCreature* m_lpCaster;
unsigned long m_dwDurationSec;
unsigned short m_wSpellID;
unsigned short m_wSpellLevel;
unsigned char m_cSpellType;
unsigned char m_cPadding;
unsigned char m_cSkillLockCount;
unsigned char m_cSkillLevel;
Spell_Info(const Skill::ProtoType& SkillProtoType, CAggresiveCreature* lpCaster,
unsigned char cSpellType, unsigned short wSpellID, unsigned short wSpellLevel, unsigned long dwDurationSec,
unsigned char cSkillLockCount = 0, unsigned char cSkillLevel = 0);
};
virtual ~CSpell() { Destroy(); }
// Caster관련
void SetCaster(CAggresiveCreature* pCaster); // Caster가 바뀔 때 사용한다.
inline CAggresiveCreature* GetCaster(void) { return m_pCaster; }
// Affected관련. 주문의 Activate, Deactivate와 상호 참조 해제등의 역할을 한다.
bool AddAffected(CAggresiveCreature* lpAffected, unsigned short& wError);
bool RemoveAffected(CAggresiveCreature* pRemoved);
void ClearAffected(void);
// Caster, Affected정보를 전부 제거.
void ClearAll(void);
// 거리를 체크해서 주문 효과를 적용 및 해지.
void CheckRange(void);
// 기타
inline bool IsActivate(CAggresiveCreature* lpAffected);
inline bool IsValid(void) const { return (0 != m_cAffectedNum); }
inline unsigned short GetSpellID(void) const { return m_wSpellID; }
inline unsigned short GetSpellLevel(void) const { return m_wSpellLevel; }
inline unsigned long GetDurationSec(void) const { return m_dwDurationSec; }
inline unsigned char GetSpellType(void) const { return m_cSpellType; }
inline unsigned char GetSkillLockCount(void) const { return m_cSkillLockCount; }
inline unsigned char GetSkillLevel(void) const { return m_cSkillLevel; }
const Skill::SpellTarget::Type GetSpellTarget(void);
inline const Skill::Type::SkillType GetSkillType(void) const { return m_eSkillType; }
inline const bool IsPartySkill(void) const { return m_ProtoType.m_eTargetType == Skill::Target::PARTY; }
inline unsigned short DecreaseSkillLevel(unsigned short usDecreaseAmount);
// 주문 효과를 전부 켜고 끈다.
void Enable(unsigned long dwOperateFlag);
void Disable(unsigned long dwOperateFlag);
protected:
// 상속 받아야만 생성할 수 있다.
CSpell(Spell_Info& spell_Info, Skill::Type::SkillType eSpellType);
bool Operate(void); // 주문 시간 체크. 주문을 적용.
void Destroy(void); // ClearAll과 같은 역할을 하나, 소멸자에서 한번만 호출한다.
// 유도 클래스의 소멸자도 반드시 실행해 주어야 한다.
// --------------------------------------------------------------------------------------------
// 스킬 Opeartion 관련. Override 필요.
inline virtual void Operate(CAggresiveCreature* lpAffected) { };
virtual bool Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
virtual bool Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
// Activate 플래그 관련
inline bool IsActivate(unsigned char cAffectedIndex);
inline void SetActivate(unsigned char cAffectedIndex);
inline void SetDeactivate(unsigned char cAffectedIndex);
inline void RemoveIndex(unsigned char cAffectedIndex);
unsigned char GetAffectedIndex(CAggresiveCreature* lpAffected);
// Internal 플래그 관련
inline bool IsEnabled(void);
inline bool SetEnableStatus(bool bStatus);
// --------------------------------------------------------------------------------------------
// Send 관련
void SendSpellInfo(CAggresiveCreature* lpAffected, unsigned char cSpellType,
unsigned short nEnchantLevel, unsigned long dwEnchantTime, bool bOnOff);
enum InternalFlags
{
DISABLED = ( 1 << 0), // 주문이 Disabled되었는지 여부를 나타냄.
DESTROYED = ( 1 << 1) // 주문이 Destroy되었는지 여부룰 나타냄.
};
CSpell* m_pNextSpell; // 주문 리스트를 유지하기 위한 포인터.
const Skill::ProtoType& m_ProtoType;
CAggresiveCreature* m_pAffected[MAX_AFFECTED]; // 주문에 의해 영향을 받고 있는 캐릭터.
CAggresiveCreature* m_pCaster; // 주문 시전자.
Skill::Type::SkillType m_eSkillType; // See Namespace Type
unsigned long m_dwActivateStatus; // 주문의 Activate상태를 가지고 있는 Flag.
unsigned short m_wSpellID; // 주문 ID
unsigned short m_wSpellLevel; // 주문의 Level
unsigned long m_dwDurationSec; // 주문 지속시간
unsigned char m_cSpellType; // 주문의 타입 (마법형/물리형)
unsigned char m_cAffectedNum; // 주문에 의해 영향을 받는 사람의 수
unsigned char m_cInternalFlags; // 8bit Internal플래그
unsigned char m_cSkillLockCount; // 주문을 건 스킬의 락카운트
unsigned char m_cSkillLevel; // 주문을 건 스킬의 레벨
friend class CSpellMgr; // Caster와 Affected의 상호참조 관리를 외부로 노출시키지 않기 위함.
friend class CGlobalSpellMgr; // CGlobalSpellMgr에서 m_pNextSpell및 Protected함수를 사용하기 위함.
};
inline CSpell::Spell_Info::Spell_Info(const Skill::ProtoType& SkillProtoType, CAggresiveCreature* lpCaster,
unsigned char cSpellType, unsigned short wSpellID, unsigned short wSpellLevel, unsigned long dwDurationSec,
unsigned char cSkillLockCount, unsigned char cSkillLevel)
: m_SkillProtoType(SkillProtoType), m_lpCaster(lpCaster),
m_cSpellType(cSpellType), m_wSpellID(wSpellID), m_wSpellLevel(wSpellLevel), m_dwDurationSec(dwDurationSec),
m_cSkillLockCount(cSkillLockCount), m_cSkillLevel(cSkillLevel)
{
}
inline unsigned short CSpell::DecreaseSkillLevel(unsigned short usDecreaseAmount)
{
if (m_wSpellLevel < usDecreaseAmount)
{
m_wSpellLevel = 0;
return m_wSpellLevel;
}
m_wSpellLevel -= usDecreaseAmount;
return m_wSpellLevel;
}
inline bool CSpell::IsEnabled(void)
{
return (DISABLED != (DISABLED & m_cInternalFlags));
}
inline bool CSpell::IsActivate(CAggresiveCreature* lpAffected)
{
CAggresiveCreature** ppBegin = m_pAffected;
CAggresiveCreature** ppPastEnd = m_pAffected + m_cAffectedNum;
unsigned char cIndex = 0;
for (; ppBegin != ppPastEnd; ++ppBegin, ++cIndex)
{
if (*ppBegin == lpAffected)
{
return IsActivate(cIndex);
}
}
return false;
}
inline bool CSpell::IsActivate(unsigned char cAffectedIndex)
{
const unsigned long dwIndexValue = (1 << cAffectedIndex);
return (dwIndexValue == (m_dwActivateStatus & dwIndexValue));
}
inline void CSpell::SetActivate(unsigned char cAffectedIndex)
{
m_dwActivateStatus |= (1 << cAffectedIndex);
}
inline void CSpell::SetDeactivate(unsigned char cAffectedIndex)
{
m_dwActivateStatus &= ~(1 << cAffectedIndex);
}
inline void CSpell::RemoveIndex(unsigned char cAffectedIndex)
{
m_dwActivateStatus =
(((ULONG_MAX << (cAffectedIndex + 1)) & m_dwActivateStatus) >> 1) | // 인덱스 왼쪽 비트열(31~nIndex)
(((1 << cAffectedIndex) - 1) & m_dwActivateStatus); // 인덱스 오른쪽 비트열(nIndex~0)
}
#endif

View File

@@ -0,0 +1,145 @@
#ifndef _SPELL_KIND_H_
#define _SPELL_KIND_H_
namespace Skill
{
namespace SpellID
{
enum Type
{
None = 0,
BattleSong = 1,
MaintenanceChant = 2,
AccelerationChant = 3,
LifeAura = 4,
SpeedBuff = 5,
Regeneration = 6,
Slow = 7,
ArmorBroken = 8,
Blaze = 9,
Charging = 10,
Stealth = 11,
ManaShell = 12,
Encourage = 13,
EnchantWeapon = 14,
BrightArmor = 15,
HardenSkin = 16,
Flexibility = 17,
Guard = 18,
Hold = 19,
Stun = 20,
Frozen = 21,
Poisoned = 22,
LowerStrength = 23,
Invincible = 24,
Hide = 25,
StoneForm = 26,
CounterAttack = 27,
Envenom = 28,
BombSet = 29,
Fired = 30,
CurseOfBlind = 31,
DeCoolDown = 32,
ExpOrb = 33,
LuckyOrb = 34,
DemagePotion = 35,
ArmorPotion = 36,
HitRatePotion = 37,
EvadePotion = 38,
MaxHPPotion = 39,
MaxMPPotion = 40,
HPRegenPotion = 41,
MPRegenPotion = 42,
CriticalPotion = 43,
BlockPotion = 44,
SpeedPotion = 45,
DeCoolDownPotion = 46,
MagicPowerPotion = 47,
MagicResistPotion = 48,
PowerStatue = 49,
IntStatue = 50,
ExpStatue = 51,
WealthStatue = 52,
RealmHP = 53,
RealmMP = 54,
Concentration = 55,
StealHand = 56, // 어세 추가스킬
MichaelBless = 57,
TasteWine = 58,
WifeCracker = 59,
KarterantWorldBuff = 60,
MerkadiaWorldBuff = 61,
KarterantWorldDeBuff= 62,
MerkadiaWorldDeBuff = 63,
HundredLevel = 64,
Drunk = 65,
CD_8D12 = 66,
CD_8D14 = 67,
CD_8D16 = 68,
CD_99A1 = 69,
CD_99A2 = 70,
CD_99A3 = 71,
MAX_SPELL_TYPE = 72
};
}
namespace SpellTarget
{
enum Type
{
NONE = 0,
CHANT = 1,
FRIEND_TARGET_ENCHANT = 2,
ENEMY_TARGET_ENCHANT = 3,
ALL_ENCHANT = 4
};
};
namespace Disenchant
{
enum Type
{
NONE = 0,
LEVEL = 1,
DURATION = 2,
DEAD = 3
};
enum Const
{
INFINITE_NUM = UCHAR_MAX
};
};
namespace SpellType
{
enum Type
{
NONE = 0,
MAGICAL_SPELL = 1, // 마법형 주문
PHYSICAL_SPELL = 2, // 물리적 주문 (ex - 넷)
WORLDWEAPON_SPELL = 3, // 월드 웨폰 인챈트
REALM_SPELL = 4, // 국가전쟁 공헌훈장 효과 인첸트.
BUFF_SPELL = 5, // DB에 저장되는 버프관련 인첸트 (죽으면 삭제된다)
PAYBUFF_SPELL = 6, // 유료 아이템 이건 죽어도 삭제안된다.
STATUE_SPELL = 7, // 석상 보상 효과 인첸트
ETERNAL_SPELL = 8, // 영구적으로 유지되야 하는 인챈트 (ex - 100랩 이펙트)
};
};
};
#endif

View File

@@ -0,0 +1,117 @@
#include "stdafx.h"
#include "SpellUtil.h"
#include "Spell.h"
#include "SpellTable.h"
#include "SpellMgr.h"
#include <Skill/SkillTable.h>
using namespace Skill;
#define ADD_SPELL(SpellName) \
CAddSpell<##SpellName>(CSpell::Spell_Info(CProcessTable::ProcessInfo::m_NullProtoType, NULL, spell.Spells[cIndex].cSpellType, \
spell.Spells[cIndex].wSpellID, spell.Spells[cIndex].wEnchantLevel, spell.Spells[cIndex].dwDurationSec))(m_pOwner);
#define ADD_SPELLNEW(SpellName, SpellType) \
CAddSpell<##SpellName>(CSpell::Spell_Info(CProcessTable::ProcessInfo::m_NullProtoType, NULL, SpellType, \
spell.Spells[cIndex].wSpellID, spell.Spells[cIndex].wEnchantLevel, spell.Spells[cIndex].dwDurationSec))(m_pOwner);
CSpellMgr::CSpellMgr()
: m_pOwner(NULL)
{
}
CSpellMgr::~CSpellMgr()
{
}
void CSpellMgr::SetSpell(const SPELL spell)
{
int iCount = 0;
for (unsigned char cIndex = 0; cIndex < SPELL::MAX_SPELL_NUM; ++cIndex)
{
switch(spell.Spells[cIndex].wSpellID)
{
case Skill::SpellID::CD_8D12:
case Skill::SpellID::CD_8D14:
case Skill::SpellID::CD_8D16:
case Skill::SpellID::CD_99A1:
case Skill::SpellID::CD_99A2:
case Skill::SpellID::CD_99A3:
case Skill::SpellID::DemagePotion:
case Skill::SpellID::ArmorPotion:
case Skill::SpellID::HitRatePotion:
case Skill::SpellID::EvadePotion:
case Skill::SpellID::MaxHPPotion:
case Skill::SpellID::MaxMPPotion:
case Skill::SpellID::HPRegenPotion:
case Skill::SpellID::MPRegenPotion:
case Skill::SpellID::CriticalPotion:
case Skill::SpellID::BlockPotion:
case Skill::SpellID::SpeedPotion:
case Skill::SpellID::DeCoolDownPotion:
case Skill::SpellID::MagicPowerPotion:
case Skill::SpellID::MagicResistPotion:
ADD_SPELL(CBuffPotionSpell);
iCount++;
break;
case Skill::SpellID::ExpOrb :
ADD_SPELL(CExpOrbSpell);
// ADD_SPELLNEW(CExpOrbSpell, Skill::SpellType::PAYBUFF_SPELL);
// ADD_SPELL(CBuffPotionSpell);
iCount++;
break;
case Skill::SpellID::LuckyOrb :
ADD_SPELL(CLuckyOrbSpell);
// ADD_SPELLNEW(CLuckyOrbSpell, Skill::SpellType::PAYBUFF_SPELL);
// ADD_SPELL(CBuffPotionSpell);
iCount++;
break;
case Skill::SpellID::MichaelBless :
ADD_SPELL(CMichaelBlessSpell);
// ADD_SPELLNEW(CLuckyOrbSpell, Skill::SpellType::PAYBUFF_SPELL);
// ADD_SPELL(CBuffPotionSpell);
iCount++;
break;
case Skill::SpellID::PowerStatue :
ADD_SPELLNEW(CPowerStatueSpell, Skill::SpellType::STATUE_SPELL);
iCount++;
break;
case Skill::SpellID::IntStatue :
ADD_SPELLNEW(CIntStatueSpell, Skill::SpellType::STATUE_SPELL);
iCount++;
break;
case Skill::SpellID::ExpStatue :
ADD_SPELLNEW(CExpStatueSpell, Skill::SpellType::STATUE_SPELL);
iCount++;
break;
case Skill::SpellID::WealthStatue :
ADD_SPELLNEW(CWealthStatueSpell, Skill::SpellType::STATUE_SPELL);
iCount++;
break;
}
}
return;
// edith 100·¾ ´Þ¼ºÀÌÆÑÆ®
/*
for (unsigned char cIndex = 0; cIndex < SPELL::MAX_SPELL_NUM; ++cIndex)
{
switch(spell.Spells[cIndex].wSpellID)
{
case Skill::SpellID::HundredLevel: ADD_SPELL(CHundredLevelSpell); break;
}
}
*/
}

View File

@@ -0,0 +1,44 @@
#ifndef _CSPELL_MGR_H_
#define _CSPELL_MGR_H_
#include "Casting.h"
#include "Affected.h"
// 전방 참조
class CSpell;
class CAggresiveCreature;
class CSpellMgr
{
public:
CSpellMgr();
~CSpellMgr();
inline void SetOwner(CAggresiveCreature* pOwner); // 생성시 반드시 호출해 줄 것.
inline CAggresiveCreature* GetOwner() { return m_pOwner; }
inline CCastingSpell& GetCastingInfo() { return m_CastingInfo; }
inline CAffectedSpell& GetAffectedInfo() { return m_AffectedInfo; }
void SetSpell(const SPELL spell);
protected:
CAggresiveCreature* m_pOwner; // 현재 매니저를 소유하고 있는 Creature.(바뀌지 않음)
CCastingSpell m_CastingInfo;
CAffectedSpell m_AffectedInfo;
friend class CSpell; // Caster와 Affected의 상호참조 관리를 외부로 노출시키지 않기 위함.
};
inline void CSpellMgr::SetOwner(CAggresiveCreature* pOwner)
{
m_pOwner = pOwner;
m_CastingInfo.SetOwner(pOwner);
m_AffectedInfo.SetOwner(pOwner);
}
#endif

View File

@@ -0,0 +1,921 @@
#include "stdafx.h"
#include <Utility/Math/Math.h>
#include <Map/FieldMap/Cell.h>
#include <Skill/SkillMgr.h>
#include <Creature/AggresiveCreature.h>
#include <Creature/Character/Character.h>
#include <Network/Packet/PacketCommand.h>
#include <Network/Packet/PacketStruct/CharAttackPacket.h>
#include <Network/ClientSocket/ClientConstants.h>
#include <Network/Dispatch/GameClient/GameClientDispatch.h>
#include <Network/Dispatch/GameClient/SendCharAttack.h>
#include "SpellTable.h"
#include "SpellMgr.h"
#include "GlobalSpellMgr.h"
//-------------------------------------------------------------------------------------------------
// Chant Spell
void CChantSpell::Operate(CAggresiveCreature* lpAffected)
{
if (lpAffected == m_pCaster)
{
m_cOperateTurn++;
if (m_cOperateTurn == UCHAR_MAX)
{
m_cOperateTurn = 0;
}
if (0 == (m_cOperateTurn % CSpell::REDUCE_MANA_TURN))
{
CreatureStatus& affectedStatus = lpAffected->GetStatus();
CCastingSpell& affectedCastingInfo = lpAffected->GetSpellMgr().GetCastingInfo();
if (m_nConsumeMPAmount > affectedStatus.m_nNowMP)
{
affectedStatus.m_nNowMP = 0;
affectedCastingInfo.DisableChant();
}
else
{
affectedStatus.m_nNowMP -= m_nConsumeMPAmount;
affectedCastingInfo.EnableChant();
}
}
}
}
//-------------------------------------------------------------------------------------------------
// BattleSong Spell
bool CBattleSongSpell::Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), m_wSpellLevel);
lpAffected->CalculateEnchantStatus();
return CSpell::Activate(lpAffected, dwOperateFlag);
}
bool CBattleSongSpell::Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), 0);
lpAffected->CalculateEnchantStatus();
return CSpell::Deactivate(lpAffected, dwOperateFlag);
}
//-------------------------------------------------------------------------------------------------
// CStealHandSpell Spell
bool CStealHandSpell::Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), m_wSpellLevel);
lpAffected->CalculateEnchantStatus();
return CSpell::Activate(lpAffected, dwOperateFlag);
}
bool CStealHandSpell::Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), 0);
lpAffected->CalculateEnchantStatus();
return CSpell::Deactivate(lpAffected, dwOperateFlag);
}
//-------------------------------------------------------------------------------------------------
// MaintenanceChant Spell
void CMaintenanceChantSpell::Operate(CAggresiveCreature* lpAffected)
{
if (0 == m_cOperateTurn % 2)
{
lpAffected->RegenHPAndMP(m_wSpellLevel, 0, false);
}
CChantSpell::Operate(lpAffected);
}
bool CMaintenanceChantSpell::Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), m_wSpellLevel);
lpAffected->CalculateEnchantStatus();
return CSpell::Activate(lpAffected, dwOperateFlag);
}
bool CMaintenanceChantSpell::Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), 0);
lpAffected->CalculateEnchantStatus();
return CSpell::Deactivate(lpAffected, dwOperateFlag);
}
//-------------------------------------------------------------------------------------------------
// AccelerationChant Spell
void CAccelerationChantSpell::Operate(CAggresiveCreature* lpAffected)
{
if (0 == m_cOperateTurn % 2)
{
lpAffected->RegenHPAndMP(0, m_wSpellLevel, false);
}
CChantSpell::Operate(lpAffected);
}
bool CAccelerationChantSpell::Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), m_wSpellLevel);
lpAffected->CalculateEnchantStatus();
return CSpell::Activate(lpAffected, dwOperateFlag);
}
bool CAccelerationChantSpell::Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), 0);
lpAffected->CalculateEnchantStatus();
return CSpell::Deactivate(lpAffected, dwOperateFlag);
}
//-------------------------------------------------------------------------------------------------
// LifeAura Spell
void CLifeAuraSpell::Operate(CAggresiveCreature* lpAffected)
{
if (0 == m_cOperateTurn % 2)
{
lpAffected->RegenHPAndMP(m_wSpellLevel * 2, m_wSpellLevel * 2, false);
}
CChantSpell::Operate(lpAffected);
}
//-------------------------------------------------------------------------------------------------
// SpeedBuff Spell
bool CSpeedBuffChantSpell::Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), m_wSpellLevel);
lpAffected->CalculateEnchantStatus();
return CSpell::Activate(lpAffected, dwOperateFlag);
}
bool CSpeedBuffChantSpell::Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), 0);
lpAffected->CalculateEnchantStatus();
return CSpell::Deactivate(lpAffected, dwOperateFlag);
}
//-------------------------------------------------------------------------------------------------
// Regeneration Spell
void CRegenerationSpell::Operate(CAggresiveCreature* lpAffected)
{
if (0 == m_dwDurationSec % 2)
{
lpAffected->RegenHPAndMP(m_wSpellLevel * 2, 0, false);
}
}
//-------------------------------------------------------------------------------------------------
// CBuffPotionSpell Spell
bool CBuffPotionSpell::Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), m_wSpellLevel);
lpAffected->CalculateEnchantStatus();
return CSpell::Activate(lpAffected, dwOperateFlag);
}
bool CBuffPotionSpell::Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), 0);
lpAffected->CalculateEnchantStatus();
return CSpell::Deactivate(lpAffected, dwOperateFlag);
}
//-------------------------------------------------------------------------------------------------
// Blaze Spell
bool CBlazeSpell::Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), m_wSpellLevel);
lpAffected->CalculateEnchantStatus();
return CSpell::Activate(lpAffected, dwOperateFlag);
}
bool CBlazeSpell::Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), 0);
lpAffected->CalculateEnchantStatus();
return CSpell::Deactivate(lpAffected, dwOperateFlag);
}
//-------------------------------------------------------------------------------------------------
// Charging Spell
bool CChargingSpell::Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), m_wSpellLevel);
lpAffected->CalculateEnchantStatus();
return CSpell::Activate(lpAffected, dwOperateFlag);
}
bool CChargingSpell::Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), 0);
lpAffected->CalculateEnchantStatus();
return CSpell::Deactivate(lpAffected, dwOperateFlag);
}
//-------------------------------------------------------------------------------------------------
// Encourage Spell
bool CEncourageSpell::Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), m_wSpellLevel);
lpAffected->CalculateEnchantStatus();
return CSpell::Activate(lpAffected, dwOperateFlag);
}
bool CEncourageSpell::Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), 0);
lpAffected->CalculateEnchantStatus();
return CSpell::Deactivate(lpAffected, dwOperateFlag);
}
//-------------------------------------------------------------------------------------------------
// EnchantWeapon Spell
bool CEnchantWeaponSpell::Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), m_wSpellLevel);
lpAffected->CalculateEnchantStatus();
return CSpell::Activate(lpAffected, dwOperateFlag);
}
bool CEnchantWeaponSpell::Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), 0);
lpAffected->CalculateEnchantStatus();
return CSpell::Deactivate(lpAffected, dwOperateFlag);
}
//-------------------------------------------------------------------------------------------------
// BrightArmor Spell
bool CBrightArmorSpell::Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), m_wSpellLevel);
lpAffected->CalculateEnchantStatus();
return CSpell::Activate(lpAffected, dwOperateFlag);
}
bool CBrightArmorSpell::Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), 0);
lpAffected->CalculateEnchantStatus();
return CSpell::Deactivate(lpAffected, dwOperateFlag);
}
//-------------------------------------------------------------------------------------------------
// HardenSkin Spell
bool CHardenSkinSpell::Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), m_wSpellLevel);
lpAffected->CalculateEnchantStatus();
return CSpell::Activate(lpAffected, dwOperateFlag);
}
bool CHardenSkinSpell::Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), 0);
lpAffected->CalculateEnchantStatus();
return CSpell::Deactivate(lpAffected, dwOperateFlag);
}
//-------------------------------------------------------------------------------------------------
// Guard Spell
bool CGuardSpell::Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), m_wSpellLevel);
lpAffected->CalculateEnchantStatus();
return CSpell::Activate(lpAffected, dwOperateFlag);
}
bool CGuardSpell::Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), 0);
lpAffected->CalculateEnchantStatus();
return CSpell::Deactivate(lpAffected, dwOperateFlag);
}
//-------------------------------------------------------------------------------------------------
// CMichaelBlessSpell Spell
bool CMichaelBlessSpell::Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), m_wSpellLevel);
lpAffected->CalculateEnchantStatus();
return CSpell::Activate(lpAffected, dwOperateFlag);
}
bool CMichaelBlessSpell::Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), 0);
lpAffected->CalculateEnchantStatus();
return CSpell::Deactivate(lpAffected, dwOperateFlag);
}
//-------------------------------------------------------------------------------------------------
// CExpOrbSpell Spell
bool CExpOrbSpell::Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), m_wSpellLevel);
lpAffected->CalculateEnchantStatus();
return CSpell::Activate(lpAffected, dwOperateFlag);
}
bool CExpOrbSpell::Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), 0);
lpAffected->CalculateEnchantStatus();
return CSpell::Deactivate(lpAffected, dwOperateFlag);
}
//-------------------------------------------------------------------------------------------------
// CLuckyOrbSpell Spell
bool CLuckyOrbSpell::Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), m_wSpellLevel);
lpAffected->CalculateEnchantStatus();
return CSpell::Activate(lpAffected, dwOperateFlag);
}
bool CLuckyOrbSpell::Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), 0);
lpAffected->CalculateEnchantStatus();
return CSpell::Deactivate(lpAffected, dwOperateFlag);
}
//-------------------------------------------------------------------------------------------------
// Chocolate Spell
bool CChocolateSpell::Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), m_wSpellLevel);
lpAffected->CalculateEnchantStatus();
return CSpell::Activate(lpAffected, dwOperateFlag);
}
bool CChocolateSpell::Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), 0);
lpAffected->CalculateEnchantStatus();
return CSpell::Deactivate(lpAffected, dwOperateFlag);
}
//-------------------------------------------------------------------------------------------------
// CTasteWineSpell Spell
bool CTasteWineSpell::Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), m_wSpellLevel);
lpAffected->CalculateEnchantStatus();
return CSpell::Activate(lpAffected, dwOperateFlag);
}
bool CTasteWineSpell::Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), 0);
lpAffected->CalculateEnchantStatus();
return CSpell::Deactivate(lpAffected, dwOperateFlag);
}
//-------------------------------------------------------------------------------------------------
// ArmorBroken Spell
bool CArmorBrokenSpell::Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), m_wSpellLevel);
lpAffected->CalculateEnchantStatus();
return CSpell::Activate(lpAffected, dwOperateFlag);
}
bool CArmorBrokenSpell::Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), 0);
lpAffected->CalculateEnchantStatus();
return CSpell::Deactivate(lpAffected, dwOperateFlag);
}
//-------------------------------------------------------------------------------------------------
// Stun Spell
bool CStunSpell::Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->GetSpellMgr().GetCastingInfo().ClearChant();
return CSpell::Activate(lpAffected, dwOperateFlag);
}
//-------------------------------------------------------------------------------------------------
// Poisoned Spell
void CPoisonedSpell::Operate(CAggresiveCreature* lpAffected)
{
const short wDamage = static_cast<short>( (float)(m_wSpellLevel) * 1.0f );
const short wThreatAmount = (lpAffected->GetStatus().m_nNowHP < wDamage) ?
lpAffected->GetStatus().m_nNowHP : wDamage;
lpAffected->GetThreat().AddToThreatList(m_pCaster, wThreatAmount);
lpAffected->GetStatus().m_nNowHP = (lpAffected->GetStatus().m_nNowHP > wDamage) ?
lpAffected->GetStatus().m_nNowHP - wDamage : 0;
if (0 == lpAffected->GetStatus().m_nNowHP)
{
lpAffected->Dead(m_pCaster);
lpAffected->GetThreat().ClearAll();
}
DefenserNode node;
node.m_wDamage = wDamage;
node.m_dwCharID = lpAffected->GetCID();
node.m_sCurrHP = lpAffected->GetStatus().m_nNowHP;
node.m_sCurrMP = lpAffected->GetStatus().m_nNowMP;
node.m_wMaxHP = lpAffected->GetStatus().m_StatusInfo.m_nMaxHP;
node.m_wMaxMP = lpAffected->GetStatus().m_StatusInfo.m_nMaxMP;
node.m_wMPHeal = 0;
node.m_cJudge = ClientConstants::Judge_Poisoned;
AtType attackType;
attackType.m_wType = AtType::RIGHT_MELEE;
CCell* lpCell = lpAffected->GetCellPos().m_lpCell;
if (NULL != lpCell)
{
lpCell->SendAttackInfo(m_pCaster->GetCID(), attackType, 1, &node);
}
if (Creature::CT_PC == Creature::GetCreatureType(lpAffected->GetCID()))
{
AtType attackType;
attackType.m_wType = AtType::RIGHT_MELEE;
CCharacter* pAffectedCharacter = (CCharacter *)lpAffected;
CGameClientDispatch* pCharacterDispatcher = pAffectedCharacter->GetDispatcher();
if (NULL != pCharacterDispatcher)
{
GameClientSendPacket::SendCharAttacked(pCharacterDispatcher->GetSendStream(), m_pCaster, pAffectedCharacter,
attackType, 0, wDamage, ClientConstants::Judge_Poisoned, 0, PktBase::NO_SERVER_ERR);
}
}
}
bool CPoisonedSpell::Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), m_wSpellLevel);
lpAffected->CalculateEnchantStatus();
return CSpell::Activate(lpAffected, dwOperateFlag);
}
bool CPoisonedSpell::Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), 0);
lpAffected->CalculateEnchantStatus();
return CSpell::Deactivate(lpAffected, dwOperateFlag);
}
//-------------------------------------------------------------------------------------------------
// LowerStrength Spell
bool CLowerStrengthSpell::Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), m_wSpellLevel);
lpAffected->CalculateEnchantStatus();
return CSpell::Activate(lpAffected, dwOperateFlag);
}
bool CLowerStrengthSpell::Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), 0);
lpAffected->CalculateEnchantStatus();
return CSpell::Deactivate(lpAffected, dwOperateFlag);
}
//-------------------------------------------------------------------------------------------------
// StoneForm Spell
bool CStoneFormSpell::Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->GetSpellMgr().GetCastingInfo().ClearChant();
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), m_wSpellLevel);
lpAffected->CalculateEnchantStatus();
return CSpell::Activate(lpAffected, dwOperateFlag);
}
bool CStoneFormSpell::Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), 0);
lpAffected->CalculateEnchantStatus();
return CSpell::Deactivate(lpAffected, dwOperateFlag);
}
//-------------------------------------------------------------------------------------------------
// BombSet Spell
void CBombSetSpell::Operate(CAggresiveCreature* lpAffected)
{
if (0 == m_dwDurationSec)
{
AtType attackType;
attackType.m_wType = 0x8708; // Æø¹ß ½ºÅ³
attackType.m_cSkillLockCount = m_wSpellLevel / 6;
attackType.m_cSkillLevel = m_wSpellLevel % 6;
unsigned char cDefenceJudge[AtNode::MAX_DEFENDER_NUM] = { 0, };
m_pCaster->MultiAttack(attackType, 1, &lpAffected, cDefenceJudge,
lpAffected->GetCurrentPos(), 0, 12, Math::Const::PI * 2, Skill::Target::ENEMY);
}
}
//-------------------------------------------------------------------------------------------------
// Fired Spell
void CFiredSpell::Operate(CAggresiveCreature* lpAffected)
{
const short wDamage = static_cast<short>( (float)(m_wSpellLevel) * 1.5f );
const short wThreatAmount = (lpAffected->GetStatus().m_nNowHP < wDamage) ?
lpAffected->GetStatus().m_nNowHP : wDamage;
lpAffected->GetThreat().AddToThreatList(m_pCaster, wThreatAmount);
lpAffected->GetStatus().m_nNowHP = (lpAffected->GetStatus().m_nNowHP > wDamage) ?
lpAffected->GetStatus().m_nNowHP - wDamage : 0;
if (0 == lpAffected->GetStatus().m_nNowHP)
{
lpAffected->Dead(m_pCaster);
lpAffected->GetThreat().ClearAll();
}
DefenserNode node;
node.m_wDamage = wDamage;
node.m_dwCharID = lpAffected->GetCID();
node.m_sCurrHP = lpAffected->GetStatus().m_nNowHP;
node.m_sCurrMP = lpAffected->GetStatus().m_nNowMP;
node.m_wMaxHP = lpAffected->GetStatus().m_StatusInfo.m_nMaxHP;
node.m_wMaxMP = lpAffected->GetStatus().m_StatusInfo.m_nMaxMP;
node.m_wMPHeal = 0;
node.m_cJudge = ClientConstants::Judge_Fired;
AtType attackType;
attackType.m_wType = AtType::RIGHT_MELEE;
CCell* lpCell = lpAffected->GetCellPos().m_lpCell;
if (NULL != lpCell)
{
lpCell->SendAttackInfo(m_pCaster->GetCID(), attackType, 1, &node);
}
if (Creature::CT_PC == Creature::GetCreatureType(lpAffected->GetCID()))
{
AtType attackType;
attackType.m_wType = AtType::RIGHT_MELEE;
CCharacter* pAffectedCharacter = (CCharacter *)lpAffected;
CGameClientDispatch* pCharacterDispatcher = pAffectedCharacter->GetDispatcher();
if (NULL != pCharacterDispatcher)
{
GameClientSendPacket::SendCharAttacked(pCharacterDispatcher->GetSendStream(), m_pCaster, pAffectedCharacter,
attackType, 0, wDamage, ClientConstants::Judge_Fired, 0, PktBase::NO_SERVER_ERR);
}
}
}
bool CFiredSpell::Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), m_wSpellLevel);
lpAffected->CalculateEnchantStatus();
return CSpell::Activate(lpAffected, dwOperateFlag);
}
bool CFiredSpell::Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), 0);
lpAffected->CalculateEnchantStatus();
return CSpell::Deactivate(lpAffected, dwOperateFlag);
}
//-------------------------------------------------------------------------------------------------
// CurseOfBlind Spell
bool CCurseOfBlindSpell::Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), m_wSpellLevel);
lpAffected->CalculateEnchantStatus();
return CSpell::Activate(lpAffected, dwOperateFlag);
}
bool CCurseOfBlindSpell::Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), 0);
lpAffected->CalculateEnchantStatus();
return CSpell::Deactivate(lpAffected, dwOperateFlag);
}
//-------------------------------------------------------------------------------------------------
// KarterantWorldBuff Spell
bool CKarterantWorldBuffSpell::Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), m_wSpellLevel);
lpAffected->CalculateEnchantStatus();
return CSpell::Activate(lpAffected, dwOperateFlag);
}
bool CKarterantWorldBuffSpell::Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), 0);
lpAffected->CalculateEnchantStatus();
return CSpell::Deactivate(lpAffected, dwOperateFlag);
}
//-------------------------------------------------------------------------------------------------
// MerkadiaWorldBuff Spell
bool CMerkadiaWorldBuffSpell::Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), m_wSpellLevel);
lpAffected->CalculateEnchantStatus();
return CSpell::Activate(lpAffected, dwOperateFlag);
}
bool CMerkadiaWorldBuffSpell::Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), 0);
lpAffected->CalculateEnchantStatus();
return CSpell::Deactivate(lpAffected, dwOperateFlag);
}
//-------------------------------------------------------------------------------------------------
// KarterantWorldDeBuff Spell
bool CKarterantWorldDeBuffSpell::Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), m_wSpellLevel);
lpAffected->CalculateEnchantStatus();
return CSpell::Activate(lpAffected, dwOperateFlag);
}
bool CKarterantWorldDeBuffSpell::Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), 0);
lpAffected->CalculateEnchantStatus();
return CSpell::Deactivate(lpAffected, dwOperateFlag);
}
//-------------------------------------------------------------------------------------------------
// MerkadiaWorldDeBuff Spell
bool CMerkadiaWorldDeBuffSpell::Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), m_wSpellLevel);
lpAffected->CalculateEnchantStatus();
return CSpell::Activate(lpAffected, dwOperateFlag);
}
bool CMerkadiaWorldDeBuffSpell::Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), 0);
lpAffected->CalculateEnchantStatus();
return CSpell::Deactivate(lpAffected, dwOperateFlag);
}
//-------------------------------------------------------------------------------------------------
// PowerStatue Spell
bool CPowerStatueSpell::Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), m_wSpellLevel);
lpAffected->CalculateEnchantStatus();
return CSpell::Activate(lpAffected, dwOperateFlag);
}
bool CPowerStatueSpell::Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), 0);
lpAffected->CalculateEnchantStatus();
return CSpell::Deactivate(lpAffected, dwOperateFlag);
}
//-------------------------------------------------------------------------------------------------
// IntStatue Spell
bool CIntStatueSpell::Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), m_wSpellLevel);
lpAffected->CalculateEnchantStatus();
return CSpell::Activate(lpAffected, dwOperateFlag);
}
bool CIntStatueSpell::Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), 0);
lpAffected->CalculateEnchantStatus();
return CSpell::Deactivate(lpAffected, dwOperateFlag);
}
//-------------------------------------------------------------------------------------------------
// ExpStatue Spell
bool CExpStatueSpell::Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), m_wSpellLevel);
lpAffected->CalculateEnchantStatus();
return CSpell::Activate(lpAffected, dwOperateFlag);
}
bool CExpStatueSpell::Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), 0);
lpAffected->CalculateEnchantStatus();
return CSpell::Deactivate(lpAffected, dwOperateFlag);
}
//-------------------------------------------------------------------------------------------------
// WealthStatue Spell
bool CWealthStatueSpell::Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), m_wSpellLevel);
lpAffected->CalculateEnchantStatus();
return CSpell::Activate(lpAffected, dwOperateFlag);
}
bool CWealthStatueSpell::Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), 0);
lpAffected->CalculateEnchantStatus();
return CSpell::Deactivate(lpAffected, dwOperateFlag);
}
//-------------------------------------------------------------------------------------------------
// RealmHP Spell
bool CRealmHPSpell::Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), m_wSpellLevel);
lpAffected->CalculateEnchantStatus();
return CSpell::Activate(lpAffected, dwOperateFlag);
}
bool CRealmHPSpell::Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), 0);
lpAffected->CalculateEnchantStatus();
return CSpell::Deactivate(lpAffected, dwOperateFlag);
}
//-------------------------------------------------------------------------------------------------
// RealmMP Spell
bool CRealmMPSpell::Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), m_wSpellLevel);
lpAffected->CalculateEnchantStatus();
return CSpell::Activate(lpAffected, dwOperateFlag);
}
bool CRealmMPSpell::Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), 0);
lpAffected->CalculateEnchantStatus();
return CSpell::Deactivate(lpAffected, dwOperateFlag);
}
//-------------------------------------------------------------------------------------------------
// Hundred Spell
bool CHundredLevelSpell::Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), m_wSpellLevel);
lpAffected->CalculateEnchantStatus();
return CSpell::Activate(lpAffected, dwOperateFlag);
}
bool CHundredLevelSpell::Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), 0);
lpAffected->CalculateEnchantStatus();
return CSpell::Deactivate(lpAffected, dwOperateFlag);
}
//-------------------------------------------------------------------------------------------------
// Hundred Spell
bool CDeCoolDownSpell::Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), m_wSpellLevel);
lpAffected->CalculateEnchantStatus();
return CSpell::Activate(lpAffected, dwOperateFlag);
}
bool CDeCoolDownSpell::Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag)
{
lpAffected->SetEnchantLevel(static_cast<Skill::SpellID::Type>(m_wSpellID), 0);
lpAffected->CalculateEnchantStatus();
return CSpell::Deactivate(lpAffected, dwOperateFlag);
}

View File

@@ -0,0 +1,722 @@
#ifndef _SPELLTABLE_H_
#define _SPELLTABLE_H_
#include "Spell.h"
//-------------------------------------------------------------------------------------------------
// Chant Table
class CChantSpell : public CSpell
{
protected:
CChantSpell(Spell_Info& spell_Info, short nConsumeMPAmount)
: CSpell(spell_Info, Skill::Type::CHANT), m_cOperateTurn(0), m_nConsumeMPAmount(nConsumeMPAmount) { }
virtual void Operate(CAggresiveCreature* lpAffected);
char m_cOperateTurn;
short m_nConsumeMPAmount;
};
class CBattleSongSpell : public CChantSpell
{
public:
CBattleSongSpell(Spell_Info& spell_Info, short nConsumeMPAmount)
: CChantSpell(spell_Info, nConsumeMPAmount) { }
virtual ~CBattleSongSpell() { Destroy(); }
protected:
virtual bool Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
virtual bool Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
};
class CStealHandSpell : public CChantSpell
{
public:
CStealHandSpell(Spell_Info& spell_Info, short nConsumeMPAmount)
: CChantSpell(spell_Info, nConsumeMPAmount) { }
virtual ~CStealHandSpell() { Destroy(); }
protected:
virtual bool Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
virtual bool Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
};
class CMaintenanceChantSpell : public CChantSpell
{
public:
CMaintenanceChantSpell(Spell_Info& spell_Info, short nConsumeMPAmount)
: CChantSpell(spell_Info, nConsumeMPAmount) { }
virtual ~CMaintenanceChantSpell() { Destroy(); }
protected:
virtual void Operate(CAggresiveCreature* lpAffected);
virtual bool Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
virtual bool Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
};
class CAccelerationChantSpell : public CChantSpell
{
public:
CAccelerationChantSpell(Spell_Info& spell_Info, short nConsumeMPAmount)
: CChantSpell(spell_Info, nConsumeMPAmount) { }
virtual ~CAccelerationChantSpell() { Destroy(); }
protected:
virtual void Operate(CAggresiveCreature* lpAffected);
virtual bool Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
virtual bool Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
};
class CLifeAuraSpell : public CChantSpell
{
public:
CLifeAuraSpell(Spell_Info& spell_Info, short nConsumeMPAmount)
: CChantSpell(spell_Info, nConsumeMPAmount) { }
virtual ~CLifeAuraSpell() { Destroy(); }
protected:
virtual void Operate(CAggresiveCreature* lpAffected);
};
class CSpeedBuffChantSpell : public CChantSpell
{
public:
CSpeedBuffChantSpell(Spell_Info& spell_Info, short nConsumeMPAmount)
: CChantSpell(spell_Info, nConsumeMPAmount) { }
virtual ~CSpeedBuffChantSpell() { Destroy(); }
protected:
virtual bool Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
virtual bool Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
};
//-------------------------------------------------------------------------------------------------
// Friend Target Enchant Table
class CMichaelBlessSpell : public CSpell
{
public:
CMichaelBlessSpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT) { }
virtual ~CMichaelBlessSpell() { Destroy(); }
protected:
virtual bool Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
virtual bool Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
};
class CExpOrbSpell : public CSpell
{
public:
CExpOrbSpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT) { }
virtual ~CExpOrbSpell() { Destroy(); }
protected:
virtual bool Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
virtual bool Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
};
class CRegenerationSpell : public CSpell
{
public:
CRegenerationSpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT) { }
virtual ~CRegenerationSpell() { Destroy(); }
protected:
virtual void Operate(CAggresiveCreature* lpAffected);
};
class CBuffPotionSpell : public CSpell
{
public:
CBuffPotionSpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT) { }
virtual ~CBuffPotionSpell() { Destroy(); }
protected:
virtual bool Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
virtual bool Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
};
class CBlazeSpell : public CSpell
{
public:
CBlazeSpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT) { }
virtual ~CBlazeSpell() { Destroy(); }
protected:
virtual bool Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
virtual bool Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
};
class CChargingSpell : public CSpell
{
public:
CChargingSpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT) { }
virtual ~CChargingSpell() { Destroy(); }
protected:
virtual bool Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
virtual bool Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
};
class CStealthSpell : public CSpell
{
public:
CStealthSpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT) { }
virtual ~CStealthSpell() { Destroy(); }
};
class CManaShellSpell : public CSpell
{
public:
CManaShellSpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT) { }
virtual ~CManaShellSpell() { Destroy(); }
};
class CEncourageSpell : public CSpell
{
public:
CEncourageSpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT) { }
virtual ~CEncourageSpell() { Destroy(); }
protected:
virtual bool Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
virtual bool Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
};
class CEnchantWeaponSpell : public CSpell
{
public:
CEnchantWeaponSpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT) { }
virtual ~CEnchantWeaponSpell() { Destroy(); }
protected:
virtual bool Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
virtual bool Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
};
class CBrightArmorSpell : public CSpell
{
public:
CBrightArmorSpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT) { }
virtual ~CBrightArmorSpell() { Destroy(); }
protected:
virtual bool Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
virtual bool Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
};
class CHardenSkinSpell : public CSpell
{
public:
CHardenSkinSpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT) { }
virtual ~CHardenSkinSpell() { Destroy(); }
protected:
virtual bool Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
virtual bool Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
};
class CFlexibilitySpell : public CSpell
{
public:
CFlexibilitySpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT) { }
virtual ~CFlexibilitySpell() { Destroy(); }
};
class CGuardSpell : public CSpell
{
public:
CGuardSpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT), m_nOriginalBlocking(0) { }
virtual ~CGuardSpell() { Destroy(); }
protected:
virtual bool Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
virtual bool Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
short m_nOriginalBlocking;
};
class CLuckyOrbSpell : public CSpell
{
public:
CLuckyOrbSpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT) { }
virtual ~CLuckyOrbSpell() { Destroy(); }
protected:
virtual bool Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
virtual bool Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
};
class CChocolateSpell : public CSpell
{
public:
CChocolateSpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT) { }
virtual ~CChocolateSpell() { Destroy(); }
protected:
virtual bool Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
virtual bool Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
};
class CTasteWineSpell : public CSpell
{
public:
CTasteWineSpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT) { }
virtual ~CTasteWineSpell() { Destroy(); }
protected:
virtual bool Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
virtual bool Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
};
class CWifeCrackerSpell : public CSpell
{
public:
CWifeCrackerSpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT) { }
virtual ~CWifeCrackerSpell() { Destroy(); }
};
//-------------------------------------------------------------------------------------------------
// Enemy Target Enchant Table
class CSlowSpell : public CSpell
{
public:
CSlowSpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT) { }
virtual ~CSlowSpell() { Destroy(); }
};
class CArmorBrokenSpell : public CSpell
{
public:
CArmorBrokenSpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT) { }
virtual ~CArmorBrokenSpell() { Destroy(); }
protected:
virtual bool Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
virtual bool Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
};
class CHoldSpell : public CSpell
{
public:
CHoldSpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT) { }
virtual ~CHoldSpell() { Destroy(); }
};
class CStunSpell : public CSpell
{
public:
CStunSpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT) { }
virtual ~CStunSpell() { Destroy(); }
protected:
virtual bool Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
};
class CFrozenSpell : public CSpell
{
public:
CFrozenSpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT) { }
virtual ~CFrozenSpell() { Destroy(); }
};
class CPoisonedSpell : public CSpell
{
public:
CPoisonedSpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT) { }
virtual ~CPoisonedSpell() { Destroy(); }
protected:
virtual void Operate(CAggresiveCreature* lpAffected);
virtual bool Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
virtual bool Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
};
class CLowerStrengthSpell : public CSpell
{
public:
CLowerStrengthSpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT) { }
virtual ~CLowerStrengthSpell() { Destroy(); }
protected:
virtual bool Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
virtual bool Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
};
class CStoneFormSpell : public CSpell
{
public:
CStoneFormSpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT) { }
virtual ~CStoneFormSpell() { Destroy(); }
protected:
virtual bool Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
virtual bool Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
};
class CCounterAttackSpell : public CSpell
{
public:
CCounterAttackSpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT) { }
virtual ~CCounterAttackSpell() { Destroy(); }
};
class CEnvenomSpell : public CSpell
{
public:
CEnvenomSpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT) { }
virtual ~CEnvenomSpell() { Destroy(); }
};
class CBombSetSpell : public CSpell
{
public:
CBombSetSpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT) { }
virtual ~CBombSetSpell() { Destroy(); }
protected:
virtual void Operate(CAggresiveCreature* lpAffected);
};
class CFiredSpell : public CSpell
{
public:
CFiredSpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT) { }
virtual ~CFiredSpell() { Destroy(); }
protected:
virtual void Operate(CAggresiveCreature* lpAffected);
virtual bool Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
virtual bool Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
};
class CCurseOfBlindSpell : public CSpell
{
public:
CCurseOfBlindSpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT) { }
virtual ~CCurseOfBlindSpell() { Destroy(); }
protected:
virtual bool Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
virtual bool Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
};
//-------------------------------------------------------------------------------------------------
// Speacial Enchant Table
class CInvincibleSpell : public CSpell
{
public:
CInvincibleSpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT) { }
virtual ~CInvincibleSpell() { Destroy(); }
};
class CKarterantWorldBuffSpell : public CSpell
{
public:
CKarterantWorldBuffSpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT) { }
virtual ~CKarterantWorldBuffSpell() { Destroy(); }
protected:
virtual bool Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
virtual bool Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
};
class CMerkadiaWorldBuffSpell : public CSpell
{
public:
CMerkadiaWorldBuffSpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT) { }
virtual ~CMerkadiaWorldBuffSpell() { Destroy(); }
protected:
virtual bool Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
virtual bool Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
};
class CKarterantWorldDeBuffSpell : public CSpell
{
public:
CKarterantWorldDeBuffSpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT) { }
virtual ~CKarterantWorldDeBuffSpell() { Destroy(); }
protected:
virtual bool Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
virtual bool Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
};
class CMerkadiaWorldDeBuffSpell : public CSpell
{
public:
CMerkadiaWorldDeBuffSpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT) { }
virtual ~CMerkadiaWorldDeBuffSpell() { Destroy(); }
protected:
virtual bool Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
virtual bool Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
};
//-------------------------------------------------------------------------------------------------
// Statue
class CPowerStatueSpell : public CSpell // 힘의 석상.
{
public:
CPowerStatueSpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT) { }
virtual ~CPowerStatueSpell() { Destroy(); }
protected:
virtual bool Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
virtual bool Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
};
class CIntStatueSpell : public CSpell // 지능의 석상.
{
public:
CIntStatueSpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT) { }
virtual ~CIntStatueSpell() { Destroy(); }
protected:
virtual bool Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
virtual bool Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
};
class CExpStatueSpell : public CSpell // 경험의 석상.
{
public:
CExpStatueSpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT) { }
virtual ~CExpStatueSpell() { Destroy(); }
protected:
virtual bool Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
virtual bool Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
};
class CWealthStatueSpell : public CSpell // 부의 석상.
{
public:
CWealthStatueSpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT) { }
virtual ~CWealthStatueSpell() { Destroy(); }
protected:
virtual bool Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
virtual bool Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
};
//-------------------------------------------------------------------------------------------------
// Realm
class CRealmHPSpell : public CSpell // 국가전쟁 공헌훈장 포인트.
{
public:
CRealmHPSpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT) { }
virtual ~CRealmHPSpell() { Destroy(); }
protected:
virtual bool Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
virtual bool Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
};
class CRealmMPSpell : public CSpell // 국가전쟁 공헌훈장 포인트.
{
public:
CRealmMPSpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT) { }
virtual ~CRealmMPSpell() { Destroy(); }
protected:
virtual bool Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
virtual bool Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
};
class CHundredLevelSpell : public CSpell // 100랩 이펙트
{
public:
CHundredLevelSpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT) { }
virtual ~CHundredLevelSpell() { Destroy(); }
protected:
virtual bool Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
virtual bool Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
};
class CDeCoolDownSpell : public CSpell // 쿨타임 감소
{
public:
CDeCoolDownSpell(Spell_Info& spell_Info)
: CSpell(spell_Info, Skill::Type::ENCHANT) { }
virtual ~CDeCoolDownSpell() { Destroy(); }
protected:
virtual bool Activate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
virtual bool Deactivate(CAggresiveCreature* lpAffected, unsigned long dwOperateFlag);
};
#endif

View File

@@ -0,0 +1,78 @@
#ifndef _SPELL_UTIL_H_
#define _SPELL_UTIL_H_
#include <Skill/Spell/Spell.h>
#include <Creature/Monster/MonsterMgr.h>
#include <Creature/Siege/SiegeConstants.h>
namespace Skill
{
template<typename Spell_t>
class CAddSpell
{
public:
CAddSpell(const CSpell::Spell_Info& Spell_Info)
: m_Spell_Info(Spell_Info)
{
}
unsigned short operator() (CAggresiveCreature* lpCharacter)
{
unsigned short wError = CSpell::NO_ENCHANT_ERROR;
if (NULL != lpCharacter)
{
// 몬스터중 챈트/인챈트 무시 플래그가 있는 녀석은 스펠 무시
Creature::CreatureType eCreatureType = Creature::GetCreatureType(lpCharacter->GetCID());
if (Creature::CT_MONSTER == eCreatureType || Creature::CT_SUMMON == eCreatureType)
{
const CMonsterMgr::MonsterProtoType* lpProtoType =
CMonsterMgr::GetInstance().GetMonsterProtoType(lpCharacter->GetCID() & Creature::MONSTER_KIND_BIT);
if (lpProtoType && lpProtoType->m_MonsterInfo.m_bIgnoreEnchant)
{
return wError;
}
}
// 석상은 모든 챈트, 인챈트에 걸리지 않는다.
else if (Creature::CT_STRUCT == eCreatureType)
{
return CSpell::ENCHANT_FAIL_BY_RESIST;
}
// 공성 오브젝트는 모든 챈트, 인챈트에 걸리지 않는다.
else if (Creature::CT_SIEGE_OBJECT == eCreatureType)
{
// 성 상징물일 경우 무적 상태의 챈트만 허용한다. 나머지 오브젝트나 챈트, 인챈트는 허용하지 않는다.
if (!(Siege::EMBLEM == lpCharacter->GetObjectType() && Skill::SpellID::Invincible == m_Spell_Info.m_wSpellID))
{
return CSpell::ENCHANT_FAIL_BY_RESIST;
}
}
CSpell* lpSpell = new Spell_t(m_Spell_Info);
if (NULL != lpSpell)
{
if (true == lpSpell->AddAffected(lpCharacter, wError))
{
CGlobalSpellMgr::GetInstance().Add(lpSpell);
return wError;
}
delete lpSpell;
}
}
return wError;
}
private:
CSpell::Spell_Info m_Spell_Info;
};
}
#endif