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>
671 lines
22 KiB
C++
671 lines
22 KiB
C++
|
|
#include "stdafx.h"
|
|
|
|
#include <Creature/Character/CharacterStructure.h>
|
|
#include <Network/Packet/PacketStruct/CharStatusPacketStruct.h>
|
|
|
|
#include "CharacterClass.h"
|
|
#include "GMMemory.h"
|
|
|
|
|
|
// 홀수 레벨일 때 증가량을 기준으로 작성.
|
|
CClass ClassTable[CClass::MAX_CLASS] =
|
|
{
|
|
CClass(),
|
|
CClass(CClass::Fighter, CClass::Fighter, CClass::DEFAULT_CLASS, CClass::HUMAN, CClass::STR, 1, CClass::CON, 1, false),
|
|
CClass(CClass::Rogue, CClass::Rogue, CClass::DEFAULT_CLASS, CClass::HUMAN, CClass::DEX, 1, CClass::STR, 1, false),
|
|
CClass(CClass::Mage, CClass::Mage, CClass::DEFAULT_CLASS, CClass::HUMAN, CClass::INT, 1, CClass::DEX, 1, false),
|
|
CClass(CClass::Acolyte, CClass::Acolyte, CClass::DEFAULT_CLASS, CClass::HUMAN, CClass::WIS, 1, CClass::CON, 1, false),
|
|
CClass(CClass::Defender, CClass::Fighter, CClass::JOB_CHANGE_1ST, CClass::HUMAN, CClass::STR, 2, CClass::CON, 1, true),
|
|
CClass(CClass::Warrior, CClass::Fighter, CClass::JOB_CHANGE_1ST, CClass::HUMAN, CClass::STR, 2, CClass::CON, 1, false),
|
|
CClass(CClass::Assassin, CClass::Rogue, CClass::JOB_CHANGE_1ST, CClass::HUMAN, CClass::DEX, 2, CClass::STR, 1, false),
|
|
CClass(CClass::Archer, CClass::Rogue, CClass::JOB_CHANGE_1ST, CClass::HUMAN, CClass::DEX, 2, CClass::STR, 1, true),
|
|
CClass(CClass::Sorcerer, CClass::Mage, CClass::JOB_CHANGE_1ST, CClass::HUMAN, CClass::INT, 2, CClass::DEX, 1, false),
|
|
CClass(CClass::Enchanter, CClass::Mage, CClass::JOB_CHANGE_1ST, CClass::HUMAN, CClass::INT, 2, CClass::DEX, 1, true),
|
|
CClass(CClass::Priest, CClass::Acolyte, CClass::JOB_CHANGE_1ST, CClass::HUMAN, CClass::WIS, 2, CClass::CON, 1, true),
|
|
CClass(CClass::Cleric, CClass::Acolyte, CClass::JOB_CHANGE_1ST, CClass::HUMAN, CClass::WIS, 2, CClass::CON, 1, false),
|
|
CClass(),
|
|
CClass(),
|
|
CClass(),
|
|
CClass(),
|
|
CClass(CClass::Combatant, CClass::Combatant, CClass::DEFAULT_CLASS, CClass::AKHAN, CClass::STR, 1, CClass::NONE_STAT, 0, false),
|
|
CClass(CClass::Officiator, CClass::Officiator, CClass::DEFAULT_CLASS, CClass::AKHAN, CClass::DEX, 1, CClass::NONE_STAT, 0, false),
|
|
CClass(CClass::Templar, CClass::Combatant, CClass::JOB_CHANGE_1ST, CClass::AKHAN, CClass::STR, 2, CClass::CON, 1, true),
|
|
CClass(CClass::Attacker, CClass::Combatant, CClass::JOB_CHANGE_1ST, CClass::AKHAN, CClass::STR, 2, CClass::CON, 1, false),
|
|
CClass(CClass::Gunner, CClass::Combatant, CClass::JOB_CHANGE_1ST, CClass::AKHAN, CClass::DEX, 2, CClass::STR, 1, true),
|
|
CClass(CClass::RuneOff, CClass::Officiator, CClass::JOB_CHANGE_1ST, CClass::AKHAN, CClass::INT, 2, CClass::DEX, 1, false),
|
|
CClass(CClass::LifeOff, CClass::Officiator, CClass::JOB_CHANGE_1ST, CClass::AKHAN, CClass::WIS, 2, CClass::DEX, 1, false),
|
|
CClass(CClass::ShadowOff, CClass::Officiator, CClass::JOB_CHANGE_1ST, CClass::AKHAN, CClass::DEX, 2, CClass::STR, 1, false)
|
|
};
|
|
|
|
|
|
CClass::CClass(const JobType eJobType, const JobType ePrevJobType, const JobLevel eJobLevel, const RaceType eRace,
|
|
const CClass::StatusType eType1, const unsigned char cIncrement1,
|
|
const CClass::StatusType eType2, const unsigned char cIncrement2,
|
|
const bool bLevelSwap)
|
|
: m_eJobType(eJobType), m_ePrevJobType(ePrevJobType), m_eJobLevel(eJobLevel),
|
|
m_eRace(eRace), m_bLevelSwap(bLevelSwap)
|
|
{
|
|
m_eIncrementType[0] = eType1; m_eIncrementType[1] = eType2;
|
|
m_cIncrementValue[0] = cIncrement1; m_cIncrementValue[1] = cIncrement2;
|
|
}
|
|
|
|
CClass::CClass()
|
|
: m_eJobType(NONE_JOB), m_ePrevJobType(NONE_JOB),
|
|
m_eJobLevel(DEFAULT_CLASS), m_eRace(MAX_RACE), m_bLevelSwap(false)
|
|
{
|
|
m_eIncrementType[0] = NONE_STAT; m_eIncrementType[1] = NONE_STAT;
|
|
m_cIncrementValue[0] = 0; m_cIncrementValue[1] = 0;
|
|
}
|
|
|
|
void CClass::LevelUp(CHAR_INFOST* InfoSt)
|
|
{
|
|
unsigned char cIndex1 = m_bLevelSwap ? ((1 == InfoSt->Level % 2) ? 0 : 1) : 0;
|
|
unsigned char cIndex2 = m_bLevelSwap ? ((1 == InfoSt->Level % 2) ? 1 : 0) : 1;
|
|
IncrementByType(InfoSt, 0, cIndex1);
|
|
IncrementByType(InfoSt, 1, cIndex2);
|
|
|
|
if (AKHAN == GetRace(static_cast<unsigned char>(InfoSt->Class)))
|
|
{
|
|
if (JOB_CHANGE_1ST == GetJobLevel(static_cast<unsigned char>(InfoSt->Class)))
|
|
{
|
|
InfoSt->IP += 2;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
InfoSt->IP += 2;
|
|
}
|
|
}
|
|
|
|
unsigned char CClass::GetRequiredIP(unsigned short usClass, unsigned char cType)
|
|
{
|
|
if (usClass >= MAX_CLASS || cType >= MAX_TYPE) { return 0xFF; }
|
|
|
|
if (ClassTable[usClass].m_eJobLevel == JOB_CHANGE_1ST)
|
|
{
|
|
return (ClassTable[usClass].m_eIncrementType[0] == cType ||
|
|
ClassTable[usClass].m_eIncrementType[1] == cType) ? 2 : 1;
|
|
}
|
|
|
|
for (int nClassIndex = 0; nClassIndex < MAX_CLASS; nClassIndex++)
|
|
{
|
|
if (ClassTable[nClassIndex].m_eJobType == usClass)
|
|
{
|
|
if (ClassTable[nClassIndex].m_eIncrementType[0] == cType ||
|
|
ClassTable[nClassIndex].m_eIncrementType[1] == cType)
|
|
{
|
|
return 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
bool CClass::JobChange(CharacterDBData* DBData, unsigned char cClassType)
|
|
{
|
|
if (DBData->m_Info.Level < 10) { return false; }
|
|
|
|
switch (m_eJobLevel)
|
|
{
|
|
case DEFAULT_CLASS: return DowngradeClass(DBData, cClassType);
|
|
case JOB_CHANGE_1ST: return UpgradeClass(DBData, cClassType);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// edith 2008.02.18 아칸전직시 스탯을 주는걸 인간과 동일, 아칸도 랩업당 +2의 스킬포인트주어지고 전직시에 주지 않는다.
|
|
bool CClass::UpgradeClass(CharacterDBData* DBData, unsigned char cClassType)
|
|
{
|
|
if (DBData->m_Info.Class != ClassTable[cClassType].m_ePrevJobType ||
|
|
ClassTable[DBData->m_Info.Class].m_eJobLevel != DEFAULT_CLASS)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// 환원되는 IP 계산을 위한 임시 변수들
|
|
unsigned short StatusA = 0;
|
|
unsigned short StatusB = 0;
|
|
unsigned short StatusC = 0;
|
|
|
|
switch (cClassType)
|
|
{
|
|
// 인간
|
|
case Defender:
|
|
DBData->m_Info.STR += static_cast<int>((DBData->m_Info.Level - 1) / 2.0f);
|
|
DBData->m_Info.CON += static_cast<int>((DBData->m_Info.Level - 1) / 2.0f + 0.5f);
|
|
|
|
StatusA = DBData->m_Info.STR - (20 + static_cast<int>((DBData->m_Info.Level - 1) * 1.5f));
|
|
StatusB = DBData->m_Info.CON - (20 + static_cast<int>((DBData->m_Info.Level - 1) * 1.5f + 0.5f));
|
|
StatusC = DBData->m_Info.DEX + DBData->m_Info.INT + DBData->m_Info.WIS - 60;
|
|
|
|
DBData->m_Info.Class = Defender;
|
|
break;
|
|
|
|
case Warrior:
|
|
DBData->m_Info.STR += DBData->m_Info.Level - 1;
|
|
|
|
StatusA = DBData->m_Info.STR - (20 + (DBData->m_Info.Level - 1) * 2);
|
|
StatusB = DBData->m_Info.CON - (20 + DBData->m_Info.Level - 1);
|
|
StatusC = DBData->m_Info.DEX + DBData->m_Info.INT + DBData->m_Info.WIS - 60;
|
|
|
|
DBData->m_Info.Class = Warrior;
|
|
break;
|
|
|
|
case Assassin:
|
|
DBData->m_Info.DEX += DBData->m_Info.Level - 1;
|
|
|
|
StatusA = DBData->m_Info.DEX - (20 + (DBData->m_Info.Level - 1) * 2);
|
|
StatusB = DBData->m_Info.STR - (20 + DBData->m_Info.Level - 1);
|
|
StatusC = DBData->m_Info.CON + DBData->m_Info.INT + DBData->m_Info.WIS - 60;
|
|
|
|
DBData->m_Info.Class = Assassin;
|
|
break;
|
|
|
|
case Archer:
|
|
DBData->m_Info.DEX += static_cast<int>((DBData->m_Info.Level - 1) / 2.0f);
|
|
DBData->m_Info.STR += static_cast<int>((DBData->m_Info.Level - 1) / 2.0f + 0.5f);
|
|
|
|
StatusA = DBData->m_Info.DEX - (20 + static_cast<int>((DBData->m_Info.Level - 1) * 1.5f));
|
|
StatusB = DBData->m_Info.STR - (20 + static_cast<int>((DBData->m_Info.Level - 1) * 1.5f + 0.5f));
|
|
StatusC = DBData->m_Info.CON + DBData->m_Info.INT + DBData->m_Info.WIS - 60;
|
|
|
|
DBData->m_Info.Class = Archer;
|
|
break;
|
|
|
|
case Sorcerer:
|
|
DBData->m_Info.INT += DBData->m_Info.Level - 1;
|
|
|
|
StatusA = DBData->m_Info.INT - (20 + (DBData->m_Info.Level - 1) * 2);
|
|
StatusB = DBData->m_Info.DEX - (20 + DBData->m_Info.Level - 1);
|
|
StatusC = DBData->m_Info.STR + DBData->m_Info.CON + DBData->m_Info.WIS - 60;
|
|
|
|
DBData->m_Info.Class = Sorcerer;
|
|
break;
|
|
|
|
case Enchanter:
|
|
DBData->m_Info.INT += static_cast<int>((DBData->m_Info.Level - 1) / 2.0f);
|
|
DBData->m_Info.DEX += static_cast<int>((DBData->m_Info.Level - 1) / 2.0f + 0.5f);
|
|
|
|
StatusA = DBData->m_Info.INT - (20 + static_cast<int>((DBData->m_Info.Level - 1) * 1.5f));
|
|
StatusB = DBData->m_Info.DEX - (20 + static_cast<int>((DBData->m_Info.Level - 1) * 1.5f + 0.5f));
|
|
StatusC = DBData->m_Info.STR + DBData->m_Info.CON + DBData->m_Info.WIS - 60;
|
|
|
|
DBData->m_Info.Class = Enchanter;
|
|
break;
|
|
|
|
case Priest:
|
|
DBData->m_Info.WIS += static_cast<int>((DBData->m_Info.Level - 1) / 2.0f);
|
|
DBData->m_Info.CON += static_cast<int>((DBData->m_Info.Level - 1) / 2.0f + 0.5f);
|
|
|
|
StatusA = DBData->m_Info.WIS - (20 + static_cast<int>((DBData->m_Info.Level - 1) * 1.5f));
|
|
StatusB = DBData->m_Info.CON - (20 + static_cast<int>((DBData->m_Info.Level - 1) * 1.5f + 0.5f));
|
|
StatusC = DBData->m_Info.STR + DBData->m_Info.DEX + DBData->m_Info.INT - 60;
|
|
|
|
DBData->m_Info.Class = Priest;
|
|
break;
|
|
|
|
case Cleric:
|
|
DBData->m_Info.WIS += DBData->m_Info.Level - 1;
|
|
|
|
StatusA = DBData->m_Info.WIS - (20 + (DBData->m_Info.Level - 1) * 2);
|
|
StatusB = DBData->m_Info.CON - (20 + DBData->m_Info.Level - 1);
|
|
StatusC = DBData->m_Info.STR + DBData->m_Info.DEX + DBData->m_Info.INT - 60;
|
|
|
|
DBData->m_Info.Class = Cleric;
|
|
break;
|
|
|
|
// 아칸
|
|
case Templar:
|
|
DBData->m_Info.STR += static_cast<int>((DBData->m_Info.Level - 1) / 2.0f + 0.5f);
|
|
DBData->m_Info.CON += static_cast<int>((DBData->m_Info.Level - 1) * 1.5f);
|
|
DBData->m_Info.IP += (DBData->m_Info.Level - 1) * 2;
|
|
|
|
StatusA = DBData->m_Info.STR - (20 + static_cast<int>((DBData->m_Info.Level - 1) * 1.5f));
|
|
StatusB = DBData->m_Info.CON - (20 + static_cast<int>((DBData->m_Info.Level - 1) * 1.5f + 0.5f));
|
|
StatusC = DBData->m_Info.DEX + DBData->m_Info.INT + DBData->m_Info.WIS - 60;
|
|
|
|
DBData->m_Info.Class = Templar;
|
|
break;
|
|
|
|
case Attacker:
|
|
DBData->m_Info.STR += DBData->m_Info.Level - 1;
|
|
DBData->m_Info.CON += DBData->m_Info.Level - 1;
|
|
DBData->m_Info.IP += (DBData->m_Info.Level - 1) * 2;
|
|
|
|
StatusA = DBData->m_Info.STR - (20 + (DBData->m_Info.Level - 1) * 2);
|
|
StatusB = DBData->m_Info.CON - (20 + DBData->m_Info.Level - 1);
|
|
StatusC = DBData->m_Info.DEX + DBData->m_Info.INT + DBData->m_Info.WIS - 60;
|
|
|
|
DBData->m_Info.Class = Attacker;
|
|
break;
|
|
|
|
case Gunner:
|
|
DBData->m_Info.DEX += static_cast<int>((DBData->m_Info.Level - 1) * 1.5f);
|
|
DBData->m_Info.STR += static_cast<int>((DBData->m_Info.Level - 1) / 2.0f + 0.5f);
|
|
DBData->m_Info.IP += (DBData->m_Info.Level - 1) * 2;
|
|
|
|
StatusA = DBData->m_Info.DEX - (20 + static_cast<int>((DBData->m_Info.Level - 1) * 1.5f));
|
|
StatusB = DBData->m_Info.STR - (20 + static_cast<int>((DBData->m_Info.Level - 1) * 1.5f + 0.5f));
|
|
StatusC = DBData->m_Info.CON + DBData->m_Info.INT + DBData->m_Info.WIS - 60;
|
|
|
|
DBData->m_Info.Class = Gunner;
|
|
break;
|
|
|
|
case RuneOff:
|
|
DBData->m_Info.INT += (DBData->m_Info.Level - 1) * 2;
|
|
DBData->m_Info.IP += (DBData->m_Info.Level - 1) * 2;
|
|
|
|
StatusA = DBData->m_Info.INT - (20 + (DBData->m_Info.Level - 1) * 2);
|
|
StatusB = DBData->m_Info.DEX - (20 + DBData->m_Info.Level - 1);
|
|
StatusC = DBData->m_Info.STR + DBData->m_Info.CON + DBData->m_Info.WIS - 60;
|
|
|
|
DBData->m_Info.Class = RuneOff;
|
|
break;
|
|
|
|
case LifeOff:
|
|
DBData->m_Info.WIS += (DBData->m_Info.Level - 1) * 2;
|
|
DBData->m_Info.IP += (DBData->m_Info.Level - 1) * 2;
|
|
|
|
StatusA = DBData->m_Info.WIS - (20 + (DBData->m_Info.Level - 1) * 2);
|
|
StatusB = DBData->m_Info.DEX - (20 + DBData->m_Info.Level - 1);
|
|
StatusC = DBData->m_Info.STR + DBData->m_Info.CON + DBData->m_Info.INT - 60;
|
|
|
|
DBData->m_Info.Class = LifeOff;
|
|
break;
|
|
|
|
case ShadowOff:
|
|
DBData->m_Info.STR += DBData->m_Info.Level - 1;
|
|
DBData->m_Info.DEX += DBData->m_Info.Level - 1;
|
|
|
|
StatusA = DBData->m_Info.DEX - (20 + (DBData->m_Info.Level - 1) * 2);
|
|
StatusB = DBData->m_Info.STR - (20 + DBData->m_Info.Level - 1);
|
|
StatusC = DBData->m_Info.CON + DBData->m_Info.INT + DBData->m_Info.WIS - 60;
|
|
|
|
/*
|
|
DBData->m_Info.STR += static_cast<int>((DBData->m_Info.Level - 1) * 1.5f + 0.5f);
|
|
DBData->m_Info.DEX += static_cast<int>((DBData->m_Info.Level - 1) / 2.0f);
|
|
DBData->m_Info.IP += (DBData->m_Info.Level - 1) * 2;
|
|
|
|
StatusA = DBData->m_Info.STR - (20 + static_cast<int>((DBData->m_Info.Level - 1) * 1.5f));
|
|
StatusB = DBData->m_Info.DEX - (20 + static_cast<int>((DBData->m_Info.Level - 1) * 1.5f + 0.5f));
|
|
StatusC = DBData->m_Info.CON + DBData->m_Info.INT + DBData->m_Info.WIS - 60;
|
|
*/
|
|
DBData->m_Info.Class = ShadowOff;
|
|
break;
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
DBData->m_Info.IP += 10 + (DBData->m_Info.Level - 1) * 2 - ((StatusA + StatusB) * 2 + StatusC) - DBData->m_Info.IP;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CClass::DowngradeClass(CharacterDBData* DBData, unsigned char cClassType)
|
|
{
|
|
// 현재는 거너만 가능하다.
|
|
if (Gunner != DBData->m_Info.Class) { return false; }
|
|
|
|
if (cClassType != ClassTable[DBData->m_Info.Class].m_ePrevJobType ||
|
|
ClassTable[DBData->m_Info.Class].m_eJobLevel != JOB_CHANGE_1ST)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// 레벨이 10% 감소한다.
|
|
DBData->m_Info.Level -= static_cast<char>(DBData->m_Info.Level * 0.1f);
|
|
DBData->m_Info.Level = max(DBData->m_Info.Level, 10);
|
|
DBData->m_Info.Exp = 0;
|
|
|
|
// 명성치가 0이 된다.
|
|
DBData->m_Info.Fame = 0;
|
|
|
|
// 스탯이 초기화된다.
|
|
switch (cClassType)
|
|
{
|
|
case Combatant:
|
|
DBData->m_Info.STR = 20 + DBData->m_Info.Level - 1;
|
|
DBData->m_Info.DEX = 20;
|
|
DBData->m_Info.CON = 20;
|
|
DBData->m_Info.INT = 20;
|
|
DBData->m_Info.WIS = 20;
|
|
|
|
DBData->m_Info.Class = Combatant;
|
|
DBData->m_Info.IP = 10;
|
|
break;
|
|
|
|
default: return false;
|
|
}
|
|
|
|
// 스킬, 퀵슬롯 초기화
|
|
DBData->m_Skill = SKILL::SKILL();
|
|
DBData->m_Quick = QUICK::QUICK();
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool CClass::InitializeClass(CharacterDBData* DBData, unsigned char cClassType)
|
|
{
|
|
if (ClassTable[cClassType].m_eJobLevel != DEFAULT_CLASS)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// 레벨이 10% 감소한다.
|
|
DBData->m_Info.Level = 1;
|
|
DBData->m_Info.Exp = 0;
|
|
|
|
// 명성치가 0이 된다.
|
|
DBData->m_Info.Fame = 0;
|
|
|
|
// 스탯이 초기화된다.
|
|
DBData->m_Info.STR = 20;
|
|
DBData->m_Info.DEX = 20;
|
|
DBData->m_Info.CON = 20;
|
|
DBData->m_Info.INT = 20;
|
|
DBData->m_Info.WIS = 20;
|
|
DBData->m_Info.IP = 10;
|
|
DBData->m_Info.Class = cClassType;
|
|
|
|
// 스킬, 퀵슬롯 초기화
|
|
DBData->m_Skill = SKILL::SKILL();
|
|
DBData->m_Quick = QUICK::QUICK();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CClass::CheckState(ChState& State, unsigned char cLevel)
|
|
{
|
|
// unsigned short이면 해킹으로 인해 65535가 되면 검출할수 있는 방법이 없다. int로 바꾸자.
|
|
// unsigned short wTIP = State.m_wIP;
|
|
int wTIP = State.m_wIP;
|
|
|
|
switch (m_eJobType)
|
|
{
|
|
case Fighter:
|
|
wTIP += (State.m_wSTR - 20 - (cLevel - 1)) * 2;
|
|
wTIP += (State.m_wDEX - 20);
|
|
wTIP += (State.m_wCON - 20 - (cLevel - 1)) * 2;
|
|
wTIP += (State.m_wINT - 20);
|
|
wTIP += (State.m_wWIS - 20);
|
|
|
|
if (wTIP > (10 + (cLevel - 1) * 2)) { return false; }
|
|
break;
|
|
|
|
case Rogue:
|
|
wTIP += (State.m_wSTR - 20 - (cLevel - 1)) * 2;
|
|
wTIP += (State.m_wDEX - 20 - (cLevel - 1)) * 2;
|
|
wTIP += (State.m_wCON - 20);
|
|
wTIP += (State.m_wINT - 20);
|
|
wTIP += (State.m_wWIS - 20);
|
|
|
|
if (wTIP > (10 + (cLevel - 1) * 2)) { return false; }
|
|
break;
|
|
|
|
case Mage:
|
|
wTIP += (State.m_wSTR - 20);
|
|
wTIP += (State.m_wDEX - 20 - (cLevel - 1)) * 2;
|
|
wTIP += (State.m_wCON - 20);
|
|
wTIP += (State.m_wINT - 20 - (cLevel - 1)) * 2;
|
|
wTIP += (State.m_wWIS - 20);
|
|
|
|
if (wTIP > (10 + (cLevel - 1) * 2)) { return false; }
|
|
break;
|
|
|
|
case Acolyte:
|
|
wTIP += (State.m_wSTR - 20);
|
|
wTIP += (State.m_wDEX - 20);
|
|
wTIP += (State.m_wCON - 20 - (cLevel - 1)) * 2;
|
|
wTIP += (State.m_wINT - 20);
|
|
wTIP += (State.m_wWIS - 20 - (cLevel - 1)) * 2;
|
|
|
|
if (wTIP > (10 + (cLevel - 1) * 2)) { return false; }
|
|
break;
|
|
|
|
case Defender:
|
|
wTIP += (State.m_wSTR - 20 - static_cast<unsigned short>((cLevel - 1) * 1.5f)) * 2;
|
|
wTIP += (State.m_wDEX - 20);
|
|
wTIP += (State.m_wCON - 20 - static_cast<unsigned short>((cLevel - 1) * 1.5f + 0.5f)) * 2;
|
|
wTIP += (State.m_wINT - 20);
|
|
wTIP += (State.m_wWIS - 20);
|
|
|
|
if (wTIP > (10 + (cLevel - 1) * 2)) { return false; }
|
|
break;
|
|
|
|
case Warrior:
|
|
wTIP += (State.m_wSTR - 20 - (cLevel - 1) * 2) * 2;
|
|
wTIP += (State.m_wDEX - 20);
|
|
wTIP += (State.m_wCON - 20 - (cLevel - 1) * 1) * 2;
|
|
wTIP += (State.m_wINT - 20);
|
|
wTIP += (State.m_wWIS - 20);
|
|
|
|
if (wTIP > (10 + (cLevel - 1) * 2)) { return false; }
|
|
break;
|
|
|
|
case Assassin:
|
|
wTIP += (State.m_wSTR - 20 - (cLevel - 1) * 1) * 2;
|
|
wTIP += (State.m_wDEX - 20 - (cLevel - 1) * 2) * 2;
|
|
wTIP += (State.m_wCON - 20);
|
|
wTIP += (State.m_wINT - 20);
|
|
wTIP += (State.m_wWIS - 20);
|
|
|
|
if (wTIP > (10 + (cLevel - 1) * 2)) { return false; }
|
|
break;
|
|
|
|
case Archer:
|
|
wTIP += (State.m_wSTR - 20 - static_cast<unsigned short>((cLevel - 1) * 1.5f + 0.5f)) * 2;
|
|
wTIP += (State.m_wDEX - 20 - static_cast<unsigned short>((cLevel - 1) * 1.5f)) * 2;
|
|
wTIP += (State.m_wCON - 20);
|
|
wTIP += (State.m_wINT - 20);
|
|
wTIP += (State.m_wWIS - 20);
|
|
|
|
if (wTIP > (10 + (cLevel - 1) * 2)) { return false; }
|
|
break;
|
|
|
|
case Sorcerer:
|
|
wTIP += (State.m_wSTR - 20);
|
|
wTIP += (State.m_wDEX - 20 - (cLevel - 1) * 1) * 2;
|
|
wTIP += (State.m_wCON - 20);
|
|
wTIP += (State.m_wINT - 20 - (cLevel - 1) * 2) * 2;
|
|
wTIP += (State.m_wWIS - 20);
|
|
|
|
if (wTIP > (10 + (cLevel - 1) * 2)) { return false; }
|
|
break;
|
|
|
|
case Enchanter:
|
|
wTIP += (State.m_wSTR - 20);
|
|
wTIP += (State.m_wDEX - 20 - static_cast<unsigned short>((cLevel - 1) * 1.5f + 0.5f)) * 2;
|
|
wTIP += (State.m_wCON - 20);
|
|
wTIP += (State.m_wINT - 20 - static_cast<unsigned short>((cLevel - 1) * 1.5f)) * 2;
|
|
wTIP += (State.m_wWIS - 20);
|
|
|
|
if (wTIP > (10 + (cLevel - 1) * 2)) { return false; }
|
|
break;
|
|
|
|
case Priest:
|
|
wTIP += (State.m_wSTR - 20);
|
|
wTIP += (State.m_wDEX - 20);
|
|
wTIP += (State.m_wCON - 20 - static_cast<unsigned short>((cLevel - 1) * 1.5f + 0.5f)) * 2;
|
|
wTIP += (State.m_wINT - 20);
|
|
wTIP += (State.m_wWIS - 20 - static_cast<unsigned short>((cLevel - 1) * 1.5f)) * 2;
|
|
|
|
if (wTIP > (10 + (cLevel - 1) * 2)) { return false; }
|
|
break;
|
|
|
|
case Cleric:
|
|
wTIP += (State.m_wSTR - 20);
|
|
wTIP += (State.m_wDEX - 20);
|
|
wTIP += (State.m_wCON - 20 - (cLevel - 1) * 1) * 2;
|
|
wTIP += (State.m_wINT - 20);
|
|
wTIP += (State.m_wWIS - 20 - (cLevel - 1) * 2) * 2;
|
|
|
|
if (wTIP > (10 + (cLevel - 1) * 2)) { return false; }
|
|
break;
|
|
|
|
case Combatant:
|
|
wTIP += (State.m_wSTR - 20 - (cLevel - 1)) * 2;
|
|
wTIP += (State.m_wDEX - 20);
|
|
wTIP += (State.m_wCON - 20);
|
|
wTIP += (State.m_wINT - 20);
|
|
wTIP += (State.m_wWIS - 20);
|
|
|
|
if (wTIP > 10) { return false; }
|
|
break;
|
|
|
|
case Officiator:
|
|
wTIP += (State.m_wSTR - 20);
|
|
wTIP += (State.m_wDEX - 20 - (cLevel - 1)) * 2;
|
|
wTIP += (State.m_wCON - 20);
|
|
wTIP += (State.m_wINT - 20);
|
|
wTIP += (State.m_wWIS - 20);
|
|
|
|
if (wTIP > 10) { return false; }
|
|
break;
|
|
|
|
case Templar:
|
|
wTIP += (State.m_wSTR - 20 - static_cast<unsigned short>((cLevel - 1) * 1.5f)) * 2;
|
|
wTIP += (State.m_wDEX - 20);
|
|
wTIP += (State.m_wCON - 20 - static_cast<unsigned short>((cLevel - 1) * 1.5f + 0.5f)) * 2;
|
|
wTIP += (State.m_wINT - 20);
|
|
wTIP += (State.m_wWIS - 20);
|
|
|
|
if (wTIP > (10 + (cLevel - 1) * 2)) { return false; }
|
|
break;
|
|
|
|
case Attacker:
|
|
wTIP += (State.m_wSTR - 20 - (cLevel - 1) * 2) * 2;
|
|
wTIP += (State.m_wDEX - 20);
|
|
wTIP += (State.m_wCON - 20 - (cLevel - 1) * 1) * 2;
|
|
wTIP += (State.m_wINT - 20);
|
|
wTIP += (State.m_wWIS - 20);
|
|
|
|
if (wTIP > (10 + (cLevel - 1) * 2)) { return false; }
|
|
break;
|
|
|
|
case Gunner:
|
|
wTIP += (State.m_wSTR - 20 - static_cast<unsigned short>((cLevel - 1) * 1.5f + 0.5f)) * 2;
|
|
wTIP += (State.m_wDEX - 20 - static_cast<unsigned short>((cLevel - 1) * 1.5f)) * 2;
|
|
wTIP += (State.m_wCON - 20);
|
|
wTIP += (State.m_wINT - 20);
|
|
wTIP += (State.m_wWIS - 20);
|
|
|
|
if (wTIP > (10 + (cLevel - 1) * 2)) { return false; }
|
|
break;
|
|
|
|
case RuneOff:
|
|
wTIP += (State.m_wSTR - 20);
|
|
wTIP += (State.m_wDEX - 20 - (cLevel - 1) * 1) * 2;
|
|
wTIP += (State.m_wCON - 20);
|
|
wTIP += (State.m_wINT - 20 - (cLevel - 1) * 2) * 2;
|
|
wTIP += (State.m_wWIS - 20);
|
|
|
|
if (wTIP > (10 + (cLevel - 1) * 2)) { return false; }
|
|
break;
|
|
|
|
case LifeOff:
|
|
wTIP += (State.m_wSTR - 20);
|
|
wTIP += (State.m_wDEX - 20 - (cLevel - 1) * 1) * 2;
|
|
wTIP += (State.m_wCON - 20);
|
|
wTIP += (State.m_wINT - 20);
|
|
wTIP += (State.m_wWIS - 20 - (cLevel - 1) * 2) * 2;
|
|
|
|
if (wTIP > (10 + (cLevel - 1) * 2)) { return false; }
|
|
break;
|
|
|
|
case ShadowOff:
|
|
wTIP += (State.m_wSTR - 20 - (cLevel - 1) * 1) * 2;
|
|
wTIP += (State.m_wDEX - 20 - (cLevel - 1) * 2) * 2;
|
|
wTIP += (State.m_wCON - 20);
|
|
wTIP += (State.m_wINT - 20);
|
|
wTIP += (State.m_wWIS - 20);
|
|
|
|
if (wTIP > (10 + (cLevel - 1) * 2)) { return false; }
|
|
/*
|
|
wTIP += (State.m_wSTR - 20 - static_cast<unsigned short>((cLevel - 1) * 1.5f + 0.5f)) * 2;
|
|
wTIP += (State.m_wDEX - 20 - static_cast<unsigned short>((cLevel - 1) * 1.5f)) * 2;
|
|
wTIP += (State.m_wCON - 20);
|
|
wTIP += (State.m_wINT - 20);
|
|
wTIP += (State.m_wWIS - 20);
|
|
|
|
if (wTIP > (10 + (cLevel - 1) * 2)) { return false; }
|
|
*/
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CClass::CheckMinState(ChState& State, unsigned char cLevel)
|
|
{
|
|
if (State.m_wSTR < GetMinState(STR, cLevel)) { return false; }
|
|
if (State.m_wDEX < GetMinState(DEX, cLevel)) { return false; }
|
|
if (State.m_wCON < GetMinState(CON, cLevel)) { return false; }
|
|
if (State.m_wINT < GetMinState(INT, cLevel)) { return false; }
|
|
if (State.m_wWIS < GetMinState(WIS, cLevel)) { return false; }
|
|
|
|
return true;
|
|
}
|
|
|
|
unsigned short CClass::GetMinState(StatusType eType, unsigned char cLevel)
|
|
{
|
|
// 스탯 기본값
|
|
unsigned short wResult = 20;
|
|
|
|
cLevel = cLevel - 1;
|
|
|
|
if (eType == m_eIncrementType[0] || eType == m_eIncrementType[1])
|
|
{
|
|
// 레벨에 관계없이 똑같이 성장하는 경우
|
|
if (false == m_bLevelSwap)
|
|
{
|
|
if (eType == m_eIncrementType[0])
|
|
{
|
|
wResult += cLevel * m_cIncrementValue[0];
|
|
}
|
|
|
|
if (eType == m_eIncrementType[1])
|
|
{
|
|
wResult += cLevel * m_cIncrementValue[1];
|
|
}
|
|
}
|
|
// 레벨에 따라 스탯이 번갈아가며 성장하는 경우
|
|
else
|
|
{
|
|
if (eType == m_eIncrementType[0])
|
|
{
|
|
wResult += static_cast<unsigned short>(cLevel * 1.5f);
|
|
}
|
|
|
|
if (eType == m_eIncrementType[1])
|
|
{
|
|
wResult += static_cast<unsigned short>(cLevel * 1.5f + 0.5f);
|
|
}
|
|
}
|
|
}
|
|
|
|
return wResult;
|
|
}
|
|
|
|
CClass::JobLevel CClass::GetJobLevel(unsigned char cClass)
|
|
{
|
|
if (cClass >= MAX_CLASS) { return DEFAULT_CLASS; }
|
|
return ClassTable[cClass].m_eJobLevel;
|
|
}
|
|
|
|
unsigned char CClass::GetPreviousJob(unsigned char cClass)
|
|
{
|
|
if (cClass >= MAX_CLASS) { return NONE_JOB; }
|
|
return ClassTable[cClass].m_ePrevJobType;
|
|
}
|
|
|
|
CClass::RaceType CClass::GetRace(unsigned char cClass)
|
|
{
|
|
if (cClass >= MAX_CLASS) { return MAX_RACE; }
|
|
return ClassTable[cClass].m_eRace;
|
|
}
|