Files
Sun1602/Server/GameServer/GM/GMHandler_Formulas.cpp
2022-10-26 12:25:11 +08:00

399 lines
16 KiB
C++

#include "stdafx.h"
#include "GMCmdManager.h"
//
// @history
// CHANGES: f110103.4L, added file. this file is used to modify various formula constant values.
#include "CharacterFormula.h"
// Internal utilities
#include "./GMHandler_InterUtils.hxx"
namespace nsGM {
;
static bool ProcessFormulaList(DWORD player_key, const GmCmdTokens& cmd_tokens)
{
GMCmdManager* const gm_manager = GMCmdManager::Instance();
Player* player = gm_manager->GetGMPlayer(player_key);
if (player == NULL) {
return false;
}
#if !defined(_NA001605_EP2_ATTRIBUTES_RENEWAL_)
;{
MSG_CG_GM_STRING_CMD_NAK msg_nak;
msg_nak.m_byErrorCode = RC::RC_GM_CMD_FAILED;
player->SendPacket(&msg_nak, sizeof(msg_nak));
};
return false;
#endif
#ifdef _NA001605_EP2_ATTRIBUTES_RENEWAL_
MSG_CG_ETC_DEBUGINFO_CMD msg_cmd;
int written = _snprintf(msg_cmd.m_pszChatMsg, _countof(msg_cmd.m_pszChatMsg),
"List = { damage_formula, critical_formula }");
msg_cmd.m_pszChatMsg[_countof(msg_cmd.m_pszChatMsg) - 1] = '\0';
msg_cmd.m_byMsgLength = static_cast<uint8_t>(min(written, _countof(msg_cmd.m_pszChatMsg)));
player->SendPacket(&msg_cmd, msg_cmd.GetSize());
return true;
#endif
};
// query command
// '//damage_formula'
// '//데미지공식'
// change command
// '//damage_formula [C1] [C2] [C3.1] [C3.2]'
// '//데미지공식 [C1] [C2] [C3.1] [C3.2]'
// C1 = 공격자 레벨 가중치
// C2 = 공격/방어자 간의 레벨 차이
// C3.1 = PvP 데미지 차감률
// C3.2 = PvE 데미지 차감률
static bool ProcessDamageFormula(DWORD player_key, const GmCmdTokens& cmd_tokens)
{
GMCmdManager* const gm_manager = GMCmdManager::Instance();
Player* player = gm_manager->GetGMPlayer(player_key);
if (player == NULL) {
return false;
}
#if !defined(_NA001605_EP2_ATTRIBUTES_RENEWAL_)
;{
MSG_CG_GM_STRING_CMD_NAK msg_nak;
msg_nak.m_byErrorCode = RC::RC_GM_CMD_FAILED;
player->SendPacket(&msg_nak, sizeof(msg_nak));
};
return false;
#endif
#ifdef _NA001605_EP2_ATTRIBUTES_RENEWAL_
bool processed = false;
const int number_of_arguments = cmd_tokens.size();
if (number_of_arguments == 5)
{
processed = true;
ep2::DamageBalanceConstant constants = { 0, };
constants.attacker_level_weight = atof(cmd_tokens[1].c_str());
constants.diff_level_weight = atof(cmd_tokens[2].c_str());
constants.damage_deduction_pvp_weight = atof(cmd_tokens[3].c_str());
constants.damage_deduction_pve_weight = atof(cmd_tokens[4].c_str());
ep2::ModifyDamageBalanceConstant(constants);
}
// query command
if (number_of_arguments == 1 || number_of_arguments == 5)
{
processed = true;
ep2::DamageBalanceConstant constants;
ep2::GetCurrentDamageBalanceConstant(&constants);
MSG_CG_ETC_DEBUGINFO_CMD msg_cmd;
int written = _snprintf(msg_cmd.m_pszChatMsg, _countof(msg_cmd.m_pszChatMsg),
"AttackerWeight = %.4f, DiffLevelWeight = %.4f, "
"PvPdeduction = %.4f, PvEdeduction = %.4f",
constants.attacker_level_weight,
constants.diff_level_weight,
constants.damage_deduction_pvp_weight,
constants.damage_deduction_pve_weight);
msg_cmd.m_pszChatMsg[_countof(msg_cmd.m_pszChatMsg) - 1] = '\0';
msg_cmd.m_byMsgLength = static_cast<uint8_t>(min(written, _countof(msg_cmd.m_pszChatMsg)));
player->SendPacket(&msg_cmd, msg_cmd.GetSize());
return true;
}
//
;{
MSG_CG_GM_STRING_CMD_NAK msg_nak;
msg_nak.m_byErrorCode = RC::RC_GM_CMD_FAILED;
player->SendPacket(&msg_nak, sizeof(msg_nak));
};
if (processed == false)
{
MSG_CG_ETC_DEBUGINFO_CMD msg_cmd;
int written = _snprintf(msg_cmd.m_pszChatMsg, _countof(msg_cmd.m_pszChatMsg),
"Usage = "
"\"//damage_formula [AttackerWeight] [DiffLevelWeight] "
"[PvPdeduction] [PvEdeduction]\"");
msg_cmd.m_pszChatMsg[_countof(msg_cmd.m_pszChatMsg) - 1] = '\0';
msg_cmd.m_byMsgLength = static_cast<uint8_t>(min(written, _countof(msg_cmd.m_pszChatMsg)));
player->SendPacket(&msg_cmd, msg_cmd.GetSize());
}
return false;
#endif
};
// query command
// '//critical_formula'
// '//크리티컬공식'
// change command
// '//critical_formula [C1] [C2] [C3] [C4] [C5]'
// '//크리티컬공식 [C1] [C2] [C3] [C4] [C5]'
// C1 = 버서커
// C2 = 드래곤나이트
// C3 = 셰도우
// C4 = 발키리
// C5 = 엘리멘탈리스트
static bool ProcessCriticalFormula(DWORD player_key, const GmCmdTokens& cmd_tokens)
{
GMCmdManager* const gm_manager = GMCmdManager::Instance();
Player* player = gm_manager->GetGMPlayer(player_key);
if (player == NULL) {
return false;
}
#if !defined(_NA001605_EP2_ATTRIBUTES_RENEWAL_)
;{
MSG_CG_GM_STRING_CMD_NAK msg_nak;
msg_nak.m_byErrorCode = RC::RC_GM_CMD_FAILED;
player->SendPacket(&msg_nak, sizeof(msg_nak));
};
return false;
#endif
#ifdef _NA001605_EP2_ATTRIBUTES_RENEWAL_
bool processed = false;
const int number_of_arguments = cmd_tokens.size();
if (number_of_arguments == eCHAR_TYPE_MAX)
{
processed = true;
ns_formula::CriticalBalanceConstants constants = { 0, };
constants.kNumberatorWeight = -1.0f;
constants.kDenominatorWeight = -1.0f;
constants.base_probabilies[eCHAR_BERSERKER] = atof(cmd_tokens[1].c_str());
constants.base_probabilies[eCHAR_DRAGON] = atof(cmd_tokens[2].c_str());
constants.base_probabilies[eCHAR_SHADOW] = atof(cmd_tokens[3].c_str());
constants.base_probabilies[eCHAR_VALKYRIE] = atof(cmd_tokens[4].c_str());
constants.base_probabilies[eCHAR_ELEMENTALIST] = atof(cmd_tokens[5].c_str());
// _NA_004965_20120613_NEW_CHARACTER_MYSTIC
constants.base_probabilies[eCHAR_MYSTIC] = atof(cmd_tokens[6].c_str());
//_NA_000000_20130812_NEW_CHARACTER_HELLROID
constants.base_probabilies[eCHAR_HELLROID] = atof(cmd_tokens[7].c_str());
#ifdef _NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
constants.base_probabilies[eCHAR_WITCHBLADE] = atof(cmd_tokens[8].c_str());
#endif //_NA_007514_20140828_NEW_CHARACTER_WITCHBLADE
ns_formula::BalanceConstantsChangerInProgramCommon::ModifyCriticalChance(constants);
}
// query command
if (number_of_arguments == 1 || number_of_arguments == eCHAR_TYPE_MAX)
{
processed = true;
ns_formula::CriticalBalanceConstants constants;
ns_formula::BalanceConstantsChangerInProgramCommon::GetCriticalChance(&constants);
//
MSG_CG_ETC_DEBUGINFO_CMD msg_cmd;
int written = _snprintf(msg_cmd.m_pszChatMsg, _countof(msg_cmd.m_pszChatMsg),
"Berserker=(%.2f/100), DragonKnight=(%.2f/100), Shadow=(%.2f/100),"
"Valkyrie=(%.2f/100), Elementalist=(%.2f/100), Mystic=(%.2f/100)",
constants.base_probabilies[eCHAR_BERSERKER],
constants.base_probabilies[eCHAR_DRAGON],
constants.base_probabilies[eCHAR_SHADOW],
constants.base_probabilies[eCHAR_VALKYRIE],
constants.base_probabilies[eCHAR_ELEMENTALIST],
constants.base_probabilies[eCHAR_MYSTIC]);
msg_cmd.m_pszChatMsg[_countof(msg_cmd.m_pszChatMsg) - 1] = '\0';
msg_cmd.m_byMsgLength = static_cast<uint8_t>(min(written, _countof(msg_cmd.m_pszChatMsg)));
player->SendPacket(&msg_cmd, msg_cmd.GetSize());
return true;
}
//
;{
MSG_CG_GM_STRING_CMD_NAK msg_nak;
msg_nak.m_byErrorCode = RC::RC_GM_CMD_FAILED;
player->SendPacket(&msg_nak, sizeof(msg_nak));
};
if (processed == false)
{
MSG_CG_ETC_DEBUGINFO_CMD msg_cmd;
int written = _snprintf(msg_cmd.m_pszChatMsg, _countof(msg_cmd.m_pszChatMsg),
"Usage = "
"\"//critical_formula [Berserker:C1] [DragonKnight:C2] "
" [Shadow:C3] [Valkyrie:C4] [Elementalist:C5] [Mystic:C6]\"");
msg_cmd.m_pszChatMsg[_countof(msg_cmd.m_pszChatMsg) - 1] = '\0';
msg_cmd.m_byMsgLength = static_cast<uint8_t>(min(written, _countof(msg_cmd.m_pszChatMsg)));
player->SendPacket(&msg_cmd, msg_cmd.GetSize());
}
return false;
#endif
};
// query command
// '//element'
// '//원소'
// change command
// '//element [C1] [C2]'
// '//원소 [C1] [C2]'
// [C1] : '(불/물/바람/대지/암흑)공격' or '(불/물/바람/대지/암흑)저항'
// [C2] : 현 기준 변경할 수치
struct ElementMatchNode
{
uint8_t is_defense;
ulong key;
eATTR_TYPE attr_type;
};
static bool ProcessChangeElements(DWORD player_key, const GmCmdTokens& cmd_tokens)
{
GMCmdManager* const gm_manager = GMCmdManager::Instance();
Player* player = gm_manager->GetGMPlayer(player_key);
if (player == NULL) {
return false;
}
#if !defined(_NA001605_EP2_ATTRIBUTES_RENEWAL_)
;{
MSG_CG_GM_STRING_CMD_NAK msg_nak;
msg_nak.m_byErrorCode = RC::RC_GM_CMD_FAILED;
player->SendPacket(&msg_nak, sizeof(msg_nak));
};
return false;
#endif
#ifdef _NA001605_EP2_ATTRIBUTES_RENEWAL_
static const ElementMatchNode elements_matches[10 * 2] =
{
{ 0, util::StreamHashKey::GetStringHashKey("불공격"), eATTR_MAGICAL_FIRE_ATTACK_POWER },
{ 1, util::StreamHashKey::GetStringHashKey("불저항"), eATTR_DEL_FIRE_DAMAGE },
{ 0, util::StreamHashKey::GetStringHashKey("물공격"), eATTR_MAGICAL_WATER_ATTACK_POWER },
{ 1, util::StreamHashKey::GetStringHashKey("물저항"), eATTR_DEL_WATER_DAMAGE },
{ 0, util::StreamHashKey::GetStringHashKey("바람공격"), eATTR_MAGICAL_WIND_ATTACK_POWER },
{ 1, util::StreamHashKey::GetStringHashKey("바람저항"), eATTR_DEL_WIND_DAMAGE },
{ 0, util::StreamHashKey::GetStringHashKey("대지공격"), eATTR_MAGICAL_EARTH_ATTACK_POWER },
{ 1, util::StreamHashKey::GetStringHashKey("대지저항"), eATTR_DEL_EARTH_DAMAGE },
{ 0, util::StreamHashKey::GetStringHashKey("암흑공격"), eATTR_MAGICAL_DARKNESS_ATTACK_POWER },
{ 1, util::StreamHashKey::GetStringHashKey("암흑저항"), eATTR_DEL_DARKNESS_DAMAGE },
{ 0, util::StreamHashKey::GetStringHashKey("fireattack"), eATTR_MAGICAL_FIRE_ATTACK_POWER },
{ 1, util::StreamHashKey::GetStringHashKey("fireresist"), eATTR_DEL_FIRE_DAMAGE },
{ 0, util::StreamHashKey::GetStringHashKey("waterattack"), eATTR_MAGICAL_WATER_ATTACK_POWER },
{ 1, util::StreamHashKey::GetStringHashKey("waterresist"), eATTR_DEL_WATER_DAMAGE },
{ 0, util::StreamHashKey::GetStringHashKey("windattack"), eATTR_MAGICAL_WIND_ATTACK_POWER },
{ 1, util::StreamHashKey::GetStringHashKey("windresist"), eATTR_DEL_WIND_DAMAGE },
{ 0, util::StreamHashKey::GetStringHashKey("earthattack"), eATTR_MAGICAL_EARTH_ATTACK_POWER },
{ 1, util::StreamHashKey::GetStringHashKey("earthresist"), eATTR_DEL_EARTH_DAMAGE },
{ 0, util::StreamHashKey::GetStringHashKey("darkattack"), eATTR_MAGICAL_DARKNESS_ATTACK_POWER },
{ 1, util::StreamHashKey::GetStringHashKey("darkresist"), eATTR_DEL_DARKNESS_DAMAGE },
};
bool processed = false;
const int number_of_arguments = cmd_tokens.size();
const ElementMatchNode* match_node = NULL;
if (number_of_arguments > 1)
{
char token[20];
strncpy(token, cmd_tokens[1].c_str(), _countof(token));
token[_countof(token) - 1] = '\0';
_strlwr(token);
const ulong hash_key = util::StreamHashKey::GetStringHashKey(token);
match_node = elements_matches;
for ( ; match_node != &elements_matches[_countof(elements_matches)]; ++match_node)
{
if (match_node->key == hash_key) {
break;
}
}
if (match_node == &elements_matches[_countof(elements_matches)]) {
match_node = NULL; // not found
}
};
const Attributes& attributes = player->GetAttr();
if (match_node != NULL && number_of_arguments == 3)
{
processed = true;
const Attributes::Operation oper = { 0, };
Attributes::OperationRecord record = { 0, };
record.operate = oper.eOper_Add;
record.attr_kind = eATTR_KIND_BASE;
record.attr_type = static_cast<uint16_t>(match_node->attr_type);
record.attr_value = atoi(cmd_tokens[2].c_str());
const_cast<Attributes&>(attributes).GroupBatchOperate(&record, 1);
const_cast<Attributes&>(attributes).UpdateEx();
;{
int value = attributes[match_node->attr_type][eATTR_KIND_BASE];
MSG_CG_STATUS_STAT_SELECT_ACK msg_ack;
msg_ack.m_dwObjKey = player->GetObjectKey();
msg_ack.m_AttrType = match_node->attr_type;
msg_ack.m_dwValue = value;
player->SendPacket(&msg_ack, sizeof(msg_ack));
};
return true;
}
// query command
if (number_of_arguments == 1 || number_of_arguments == 3)
{
processed = true;
MSG_CG_ETC_DEBUGINFO_CMD msg_cmd;
int written = _snprintf(msg_cmd.m_pszChatMsg, _countof(msg_cmd.m_pszChatMsg),
"Element:(Attack/Resist) "
"Fire(%d,%d), Water(%d,%d), Wind(%d,%d), Earth(%d,%d), Dark(%d,%d)",
attributes[elements_matches[0].attr_type][eATTR_KIND_CALC],
attributes[elements_matches[1].attr_type][eATTR_KIND_CALC],
attributes[elements_matches[2].attr_type][eATTR_KIND_CALC],
attributes[elements_matches[3].attr_type][eATTR_KIND_CALC],
attributes[elements_matches[4].attr_type][eATTR_KIND_CALC],
attributes[elements_matches[5].attr_type][eATTR_KIND_CALC],
attributes[elements_matches[6].attr_type][eATTR_KIND_CALC],
attributes[elements_matches[7].attr_type][eATTR_KIND_CALC],
attributes[elements_matches[8].attr_type][eATTR_KIND_CALC],
attributes[elements_matches[9].attr_type][eATTR_KIND_CALC]);
msg_cmd.m_pszChatMsg[_countof(msg_cmd.m_pszChatMsg) - 1] = '\0';
msg_cmd.m_byMsgLength = static_cast<uint8_t>(min(written, _countof(msg_cmd.m_pszChatMsg)));
player->SendPacket(&msg_cmd, msg_cmd.GetSize());
return true;
}
//
;{
MSG_CG_GM_STRING_CMD_NAK msg_nak;
msg_nak.m_byErrorCode = RC::RC_GM_CMD_FAILED;
player->SendPacket(&msg_nak, sizeof(msg_nak));
};
if (processed == false)
{
MSG_CG_ETC_DEBUGINFO_CMD msg_cmd;
int written = _snprintf(msg_cmd.m_pszChatMsg, _countof(msg_cmd.m_pszChatMsg),
"Usage = \"//element ["
"fireattack|fireresist|"
"waterattack|waterresist|"
"windattack|windresist|"
"earthattack|earthresist|"
"darkattack|darkresist] "
"[(+/-)value]\"");
msg_cmd.m_pszChatMsg[_countof(msg_cmd.m_pszChatMsg) - 1] = '\0';
msg_cmd.m_byMsgLength = static_cast<uint8_t>(min(written, _countof(msg_cmd.m_pszChatMsg)));
player->SendPacket(&msg_cmd, msg_cmd.GetSize());
}
return false;
#endif
}
}; //end of namespace 'nsGM'
bool GMCmdManager::RegisterFomulas(const HandlerNode** node_array, size_t* result_array_count)
{
using namespace nsGM;
bool success = false;
#define GMHANDLER_MAPPING(activated, korean, english, handler) \
{ activated, eGM_GRADE_MAX, 0xFFFFFFFF, 0xFFFFFFFF, handler, korean, english }
static HandlerNode const_node_array[] =
{
GMHANDLER_MAPPING(true, "공식목록", "formula_list", &ProcessFormulaList),
GMHANDLER_MAPPING(true, "데미지공식", "damage_formula", &ProcessDamageFormula),
GMHANDLER_MAPPING(true, "크리티컬공식", "critical_formula", &ProcessCriticalFormula),
GMHANDLER_MAPPING(true, "원소", "element", &ProcessChangeElements),
}; //
ModifyGmHandlerNode(const_node_array, _countof(const_node_array));
*node_array = const_node_array;
*result_array_count = _countof(const_node_array);
success = true;
//
return success;
}