Files
2022-10-26 12:25:11 +08:00

710 lines
25 KiB
C++

#include "stdafx.h"
#include "SSQInfoStruct.h"
#include "SSQInfoParser.h"
#include "NPCInfoParser.h"
#include "ItemInfoParser.h"
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// <DEFINITIONs>
using namespace nsSSQ;
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// <IMPLEMENTATIONs>
SSQInfoParser::SSQInfoParser()
{
#ifdef _SERVER
m_pSSQTiles = 0;
#endif
};
SSQInfoParser::~SSQInfoParser()
{
#ifdef _SERVER
SAFE_DELETE_ARRAY(m_pSSQTiles);
#endif
};
VOID
SSQInfoParser::Init(const TCHAR* pszPackFileName)
{
SetPackFileName(pszPackFileName);
}
VOID
SSQInfoParser::Release()
{
FOREACH_CONTAINER(SSQINFO_TABLE::value_type& rSSQInfo, m_SSQInfoTable, SSQINFO_TABLE)
{
SSQInfo* pSSQInfo = rSSQInfo.second;
TAllocDelete(SSQInfo_Info::value_type, pSSQInfo);
}
FOREACH_CONTAINER(SSQPATTERN_TABLE::value_type& rSSQPattern, m_SSQPatternTable, SSQPATTERN_TABLE)
{
SSQPattern* pSSQPattern = rSSQPattern.second;
TAllocDelete(SSQPattern_Info::value_type, pSSQPattern);
}
m_SSQInfoTable.clear();
m_SSQPatternTable.clear();
#ifdef _SERVER
m_SSQTileInfoTable.clear();
SAFE_DELETE_ARRAY(m_pSSQTiles);
#endif
}
BOOL
SSQInfoParser::LoadScript(eSCRIPT_CODE scriptCode, BOOL bReload)
{
__UNUSED(bReload);
switch(scriptCode)
{
case SSQInfo_Info::value:
return _Load(SSQInfo_Info::category(), FALSE);
case SSQPattern_Info::value:
return _Load(SSQPattern_Info::category(), FALSE);
}
ASSERT(!"Invalid Type :Script Code");
return FALSE;
}
//────────────────────────────────────────────────────────────────
BOOLEAN
SSQInfoParser::_Load(const SSQInfo_Info::category&, BOOLEAN bReload)
{
const INT nRowSize = GetRowSize();
for(INT nRow = 0; nRow < nRowSize; ++nRow)
{
SSQInfo* const pSSQInfo = TAllocNew(SSQInfo_Info::value_type);
ZeroMemory(pSSQInfo, sizeof(SSQInfo));
pSSQInfo->m_Index = GetDataWORD("Index", nRow);
pSSQInfo->m_SSQName.CopyFrom(GetDataString("SSQName", nRow));
const MAPCODE CodeOfSSQ = GetDataWORD("MapCode", nRow);
pSSQInfo->m_MapCode = CodeOfSSQ;
SSQINFO_TABLE::iterator itFind = m_SSQInfoTable.find(CodeOfSSQ);
if(itFind == m_SSQInfoTable.end())
m_SSQInfoTable.insert(std::make_pair(CodeOfSSQ, pSSQInfo));
else if(bReload)
{
SSQINFO_TABLE::value_type& rPair = *itFind;
SSQInfo* const pSSQInfoTmp = rPair.second;
TAllocDelete(SSQInfo_Info::value_type, pSSQInfoTmp);
rPair.second = pSSQInfo;
}
else
{
FASSERT(!"SSQInfo::Load-Duplicated ID");
return FALSE;
}
SSQInfo::LEVEL_RANGE& rLevels = pSSQInfo->m_LevelRange;
rLevels[SSQInfo::LV_MIN] = GetDataWORD("EnterableMinLevel", nRow);
rLevels[SSQInfo::LV_MAX] = GetDataWORD("EnterableMaxLevel", nRow);
pSSQInfo->m_Cost = GetDataInt("Cost", nRow);
TCHAR string_buffer0[32];
TCHAR string_buffer1[32];
{
ZeroMemory(string_buffer0, sizeof(string_buffer0));
const INT str0_tail_index = _sntprintf(string_buffer0, _countof(string_buffer0), "EnteranceTime");
SSQInfo::TIME_RANGE& rTimeRange = pSSQInfo->m_TimeRange;
for(DWORD idx = 0; idx < SSQInfo::MI_ENTER_TIME_SECTION_MAX; ++idx)
{
string_buffer0[ str0_tail_index ] = (TCHAR)('1' + idx);
SSQInfo::TimeRange& rNode = rTimeRange[idx];
rNode.Start = GetDataWORD(string_buffer0, nRow);
// rNode.End <- 이것은 나중에 계산된다.
}
};
pSSQInfo->m_WatingTime = GetDataBYTE("WaitingTime", nRow);
pSSQInfo->m_QuestPlayTime = GetDataBYTE("QuestPlayTime", nRow);
SSQInfo::PLAYER_COUNT_LIMIT& rCountLimit = pSSQInfo->m_PlayerCountInfo;
rCountLimit[SSQInfo::PCL_MIN] = GetDataBYTE("MinUserCount", nRow);
rCountLimit[SSQInfo::PCL_MAX] = GetDataBYTE("MaxUserCount", nRow);
SSQInfo::GAMBLE_INFO& rGambleInfo = pSSQInfo->m_GamebleInfo;
rGambleInfo.m_ChargeRatio = GetDataBYTE("GambleCharge", nRow);
{
ZeroMemory(string_buffer0, sizeof(string_buffer0));
ZeroMemory(string_buffer1, sizeof(string_buffer1));
const INT str0_tail_index = _sntprintf(string_buffer0, _countof(string_buffer0), "EQCondTime");
const INT str1_tail_index = _sntprintf(string_buffer1, _countof(string_buffer1), "EQCondUsers");
SSQInfo::EARTHQUAKE_INFO& rEarth = pSSQInfo->m_EarthquakeInfo;
for(DWORD idx = 0; idx < SSQInfo::MI_EARTHQUAKE_SECTION_MAX; ++idx)
{
string_buffer0[ str0_tail_index ] = (TCHAR)('1' + idx);
string_buffer1[ str1_tail_index ] = (TCHAR)('1' + idx);
SSQInfo::EARTHQUAKE_NODE& rNode = rEarth[idx];
rNode.m_ElapsedTime = GetDataBYTE(string_buffer0, nRow);
rNode.m_RemainPlayers = GetDataBYTE(string_buffer1, nRow);
}
};
SSQInfo::THUNDERBOLT_NODE& rThunder = pSSQInfo->m_ThunderboltInfo;
rThunder.m_PlayerDamage = GetDataInt("ThunderboltDamagePC", nRow);
rThunder.m_NpcDamage = GetDataInt("ThunderboltDamageNPC", nRow);
rThunder.m_RaisePerXsec = GetDataBYTE("ThunderboltInterval", nRow);
//SSQInfo::CLOSED_SPACE_NODE& rCSpace = pSSQInfo->m_ClosedSpaceInfo;
//rCSpace.m_PlayerDamage = GetDataWORD("ClosedSpaceDamagePC", nRow);
//rCSpace.m_NpcDamage = GetDataWORD("ClosedSpaceDamageNPC", nRow);
//rCSpace.m_RaisePerXsec = GetDataBYTE("ClosedSpaceDamageInterval", nRow);
{
ZeroMemory(string_buffer0, sizeof(string_buffer0));
ZeroMemory(string_buffer1, sizeof(string_buffer1));
const INT str0_tail_index = _sntprintf(string_buffer0, _countof(string_buffer0), "ClosedSpaceDamagePC");
const INT str1_tail_index = _sntprintf(string_buffer1, _countof(string_buffer1), "ClosedSpaceDamageNPC");
SSQInfo::CLOSED_SPACE_NODE& rCSpace = pSSQInfo->m_ClosedSpaceInfo;
for(DWORD idx = 0; idx < SSQInfo::MI_EARTHQUAKE_SECTION_MAX; ++idx)
{
string_buffer0[ str0_tail_index ] = (TCHAR)('1' + idx);
string_buffer1[ str1_tail_index ] = (TCHAR)('1' + idx);
rCSpace.m_PlayerDamages[idx]= GetDataFloat(string_buffer0, nRow);
rCSpace.m_NpcDamages[idx] = GetDataFloat(string_buffer1, nRow);
}
rCSpace.m_RaisePerXsec = GetDataBYTE("ClosedSpaceDamageInterval", nRow);
};
{
ZeroMemory(string_buffer0, sizeof(string_buffer0));
ZeroMemory(string_buffer1, sizeof(string_buffer1));
const INT str0_tail_index = _sntprintf(string_buffer0, _countof(string_buffer0), "NpcCode");
const INT str1_tail_index = _sntprintf(string_buffer1, _countof(string_buffer1), "NpcRegenRatio");
SSQInfo::SUMMONDED_NPC_INFO& rMobInfo = pSSQInfo->m_SummonedNpcInfo;
for(DWORD idx = 0; idx < SSQInfo::MI_SUMMONED_NPC_SECTION_MAX; ++idx)
{
const BYTE remain = (BYTE)((idx + 1) % 10);
const BYTE carry = (BYTE)((idx + 1) / 10);
string_buffer0[ str0_tail_index ] = (TCHAR)('0' + carry);
string_buffer0[ str0_tail_index+1 ] = (TCHAR)('0' + remain);
string_buffer1[ str1_tail_index ] = (TCHAR)('0' + carry);
string_buffer1[ str1_tail_index+1 ] = (TCHAR)('0' + remain);
rMobInfo.List[idx].m_NPCCode = GetDataWORD(string_buffer0, nRow);
const FLOAT regen_ratio_f = GetDataFloat(string_buffer1, nRow);
rMobInfo.List[idx].m_SumRatio = (SSQInfo::RATIO_SUM_T)(regen_ratio_f*100.f);
if(rMobInfo.List[idx].m_NPCCode) ++rMobInfo.Count;
}
};
{
ZeroMemory(string_buffer0, sizeof(string_buffer0));
_sntprintf(string_buffer0, _countof(string_buffer0), "HuntingPointPC");
__ReadHuntingPoint(nRow, string_buffer0, pSSQInfo->m_PlayerHuntingInfo);
}
{
ZeroMemory(string_buffer0, sizeof(string_buffer0));
_sntprintf(string_buffer0, _countof(string_buffer0), "HuntingPointNPC");
__ReadHuntingPoint(nRow, string_buffer0, pSSQInfo->m_NpcHuntingInfo);
}
{
ZeroMemory(string_buffer0, sizeof(string_buffer0));
const INT str0_tail_index = _sntprintf(string_buffer0, _countof(string_buffer0), "HuntineExpRatio");
SSQInfo::EXP_RATIO_INFO& rExpRatio = pSSQInfo->m_ExpRatioInfo;
for(DWORD idx = eCHAR_NONE+1; idx < eCHAR_TYPE_MAX; ++idx)
{ // 해당 배열은 0을 포함 6개로 이루어져 있다.
string_buffer0[ str0_tail_index ] = (TCHAR)('0' + idx);
FLOAT exp_ratio = 0.0f;
if (GetSafeNumericData(
__FUNCTION__, __LINE__, nRow, exp_ratio, string_buffer0) == false)
{
continue;
}
rExpRatio[idx].m_FloatPoint = exp_ratio;
}
}
{
ZeroMemory(string_buffer0, sizeof(string_buffer0));
const INT str0_tail_index = _sntprintf(string_buffer0, _countof(string_buffer0), "SuccessPoint");
SSQInfo::SUCCESS_POINT_INFO& rSuccessInfo = pSSQInfo->m_SuccessPointInfo;
for(DWORD idx = 0; idx < SSQInfo::MI_SUCCESS_POINT_BY_GRADE; ++idx)
{
string_buffer0[ str0_tail_index ] = (TCHAR)('1' + idx);
rSuccessInfo[idx].m_FloatPoint = GetDataFloat(string_buffer0, nRow);
}
};
#ifdef _NA000000_100427_SSQ_DEFAULT_REWARD_
;{
SSQInfo::REWARD_NODE* reward = &pSSQInfo->m_DefaultRewardInfo;
reward->m_RewardCode = GetDataWORD("BasicItemCode", nRow);
reward->m_RewardLimit = GetDataBYTE("BasicItemNum", nRow);
};
#endif
{ // 경품 OnMonsterKill
ZeroMemory(string_buffer0, sizeof(string_buffer0));
ZeroMemory(string_buffer1, sizeof(string_buffer1));
const INT str0_tail_index = _sntprintf(string_buffer0, _countof(string_buffer0), "DropItemCode");
const INT str1_tail_index = _sntprintf(string_buffer1, _countof(string_buffer1), "DropItemLimit");
SSQInfo::REWARD_DROP_INFO& rReward = pSSQInfo->m_RewardDropInfo;
for(DWORD idx = 0; idx < SSQInfo::MI_REWARD_DROP_INFO_SECTION_MAX; ++idx)
{
string_buffer0[ str0_tail_index ] = (TCHAR)('1' + idx);
string_buffer1[ str1_tail_index ] = (TCHAR)('1' + idx);
SSQInfo::REWARD_NODE& rNode = rReward.List[idx];
rNode.m_RewardCode = GetDataWORD(string_buffer0, nRow);
rNode.m_RewardLimit = GetDataBYTE(string_buffer1, nRow);
if(rNode.m_RewardCode) ++rReward.Count;
}
};
{ // 최종 우승자
ZeroMemory(string_buffer0, sizeof(string_buffer0));
const INT str0_tail_index = _sntprintf(string_buffer0, _countof(string_buffer0), "RewardItemCode");
for(DWORD idx = 0; idx < SSQInfo::MI_REWARD_WINNER_INFO_SECTION_MAX; ++idx)
{
string_buffer0[ str0_tail_index ] = (TCHAR)('1' + idx);
string_buffer0[ str0_tail_index+1 ] = (TCHAR)('_');
__ReadWinnerRewardInfo(nRow, string_buffer0, pSSQInfo->m_RewardWinnerInfo[idx]);
}
};
//{ // 최종 우승자
// ZeroMemory(string_buffer0, sizeof(string_buffer0));
// const INT str0_tail_index = _sntprintf(string_buffer0, _countof(string_buffer0), "RewardItemCode");
// SSQInfo::REWARD_WINNER_INFO& rReward = pSSQInfo->m_RewardWinnerInfo;
// for(DWORD idx=0 ; idx<SSQInfo::MI_REWARD_WINNER_INFO_SECTION_MAX ; ++idx)
// {
// string_buffer0[ str0_tail_index ] = (TCHAR)('1' + idx);
// SSQInfo::REWARD_NODE& rNode = rReward.List[idx];
// rNode.m_RewardCode = GetDataWORD(string_buffer0, nRow);
// rNode.m_RewardLimit = 1;
// if(rNode.m_RewardCode) ++rReward.Count;
// }
//};
{
ZeroMemory(string_buffer0, sizeof(string_buffer0));
const INT str0_tail_index = _sntprintf(string_buffer0, _countof(string_buffer0), "LimitSkillGroup");
SSQInfo::RESTRICT_SKILL_GROUP_INFO& rSkill = pSSQInfo->m_RestrictSkillGroupInfo;
for(DWORD idx=0 ; idx<SSQInfo::MI_RESTRICT_SKILL_SECTION_MAX ; ++idx)
{
const BYTE remain = (BYTE)((idx + 1) % 10);
const BYTE carry = (BYTE)((idx + 1) / 10);
string_buffer0[ str0_tail_index ] = (TCHAR)('0' + carry);
string_buffer0[ str0_tail_index+1 ] = (TCHAR)('0' + remain);
rSkill.SkillGroupCodes[idx] = GetDataWORD(string_buffer0, nRow);
if(rSkill.SkillGroupCodes[idx]) ++rSkill.Count;
}
}
{
ZeroMemory(string_buffer0, sizeof(string_buffer0));
const INT str0_tail_index = _sntprintf(string_buffer0, _countof(string_buffer0), "LimitItemType");
SSQInfo::RESTRICT_ITEM_TYPE_INFO& rItems = pSSQInfo->m_RestrictItemTypeInfo;
for(DWORD idx = 0; idx < SSQInfo::MI_RESTRICT_ITEM_SECTION_MAX; ++idx)
{
const BYTE remain = (BYTE)((idx + 1) % 10);
const BYTE carry = (BYTE)((idx + 1) / 10);
string_buffer0[ str0_tail_index ] = (TCHAR)('0' + carry);
string_buffer0[ str0_tail_index+1 ] = (TCHAR)('0' + remain);
rItems.ItemTypes[idx] = GetDataWORD(string_buffer0, nRow);
if(rItems.ItemTypes[idx]) ++rItems.Count;
}
}
// LastSection value calculate & validate
_Validate(pSSQInfo);
}
return TRUE;
}
//────────────────────────────────────────────────────────────────
BOOLEAN
SSQInfoParser::_Load(const SSQPattern_Info::category&, BOOLEAN bReload)
{
const INT nRowSize = GetRowSize();
for(INT nRow=0; nRow<nRowSize ; ++nRow)
{
SSQPattern* const pSSQPattern = TAllocNew(SSQPattern_Info::value_type);
ZeroMemory(pSSQPattern, sizeof(SSQPattern));
const SSQPattern::INDEX_T PatternIDofSSQ = GetDataWORD("Index", nRow);
SSQPATTERN_TABLE::iterator itFind = m_SSQPatternTable.find(PatternIDofSSQ);
if(itFind == m_SSQPatternTable.end())
m_SSQPatternTable.insert(std::make_pair(PatternIDofSSQ, pSSQPattern));
else if(bReload)
{
SSQPATTERN_TABLE::value_type& rPair = *itFind;
SSQPattern* const pSSQPatternTmp = rPair.second;
TAllocDelete(SSQPattern_Info::value_type, pSSQPatternTmp);
rPair.second = pSSQPattern;
}
else
{
FASSERT(!"SSQInfo::Load-Duplicated ID");
return FALSE;
}
pSSQPattern->m_Index = PatternIDofSSQ;
//SSQ_NAME sTmpName; <- 이름은 스킵한다.
//sTmpName.CopyFrom(sr.GetTokenString());
pSSQPattern->m_BanLiftStep = GetDataBYTE("BanLiftStep", nRow);
TCHAR string_buffer0[32];
TCHAR string_buffer1[32];
{
ZeroMemory(string_buffer0, sizeof(string_buffer0));
ZeroMemory(string_buffer1, sizeof(string_buffer1));
const INT str0_tail_index = _sntprintf(string_buffer0, _countof(string_buffer0), "PatternStep");
const INT str1_tail_index = _sntprintf(string_buffer1, _countof(string_buffer1), "Step");
const INT str2_tail_index = _sntprintf(&string_buffer1[str1_tail_index+1], _countof(string_buffer1), "_ID_") + str1_tail_index + 1;
SSQPattern::STEP_GROUP& rStepGroup = pSSQPattern->m_StepGroup;
for(DWORD step_idx = 0; step_idx < SSQPattern::MI_STEP_MAX; ++step_idx)
{
string_buffer0[ str0_tail_index ] = (TCHAR)('1' + step_idx);
SSQPattern::sSINGLE_STEP& rSingle = rStepGroup[step_idx];
rSingle.m_Step = GetDataBYTE(string_buffer0, nRow);
rSingle.m_ListSize = 0;
for(DWORD obj_idx = 0; obj_idx < SSQPattern::MI_OBJECT_COUNT_MAX; ++obj_idx)
{
const BYTE remain = (BYTE)((obj_idx + 1) % 10);
const BYTE carry = (BYTE)((obj_idx + 1) / 10);
string_buffer1[ str1_tail_index ] = (TCHAR)('1' + step_idx);
string_buffer1[ str2_tail_index ] = (TCHAR)('0' + carry);
string_buffer1[ str2_tail_index+1 ] = (TCHAR)('0' + remain);
rSingle.m_List[obj_idx] = GetDataInt(string_buffer1, nRow);
if(rSingle.m_List[obj_idx]) ++rSingle.m_ListSize;
}
}
};
//
}
return TRUE;
}
//────────────────────────────────────────────────────────────────
BOOLEAN SSQInfoParser::__ReadHuntingPoint(const DWORD nRow, TCHAR INOUT string_buffer[32],
SSQInfo::HUNTING_POINT_NODE OUT pNODE[eCHAR_TYPE_MAX])
{
const INT str0_tail_index = (INT)_tcslen(string_buffer);
for (int idx = eCHAR_BERSERKER; idx < eCHAR_TYPE_MAX; ++idx)
{
string_buffer[ str0_tail_index ] = (TCHAR)('0' + idx); // idx == eCHAR_TYPE
pNODE[idx].m_HuntingPoint = GetDataBYTE(string_buffer, nRow);
}
return TRUE;
}
BOOLEAN SSQInfoParser::__ReadWinnerRewardInfo(const DWORD nRow, TCHAR INOUT string_buffer[32],
SSQInfo::CHAR_REWARD_NODE& OUT rNODE)
{
const INT str0_tail_index = (INT)_tcslen(string_buffer);
for (int idx = eCHAR_BERSERKER; idx < eCHAR_TYPE_MAX; ++idx)
{
string_buffer[ str0_tail_index ] = (TCHAR)('0' + idx); // idx == eCHAR_TYPE
rNODE[idx].m_RewardCode = GetDataWORD(string_buffer, nRow);
rNODE[idx].m_RewardLimit = 1;
}
string_buffer[ str0_tail_index ] = '\0';
return TRUE;
}
//───────────────────────────────────────────────────────────
BOOLEAN
SSQInfoParser::_Validate(SSQInfo* const pSSQInfo)
{
// 추가할 내역
// - 몬스터 및 아이템 의존도
// - 인원 관련
// - MIN<MAX
// - 입장제어 시간
//────────────────────────────────────────────
// - MIN<MAX, 인원 관련
{
ASSERT(pSSQInfo->m_GamebleInfo.m_ChargeRatio <= 100); // %단위로 MAX(100)
SSQInfo::PLAYER_COUNT_LIMIT& rNumLimits = pSSQInfo->m_PlayerCountInfo;
ASSERT(rNumLimits[SSQInfo::PCL_MIN] && rNumLimits[SSQInfo::PCL_MAX] &&
rNumLimits[SSQInfo::PCL_MIN] &&
rNumLimits[SSQInfo::PCL_MIN] < rNumLimits[SSQInfo::PCL_MAX]);
};
//────────────────────────────────────────────
// - Monster Integrity
{
SSQInfo::SUMMONDED_NPC_INFO& rNpcInfo = pSSQInfo->m_SummonedNpcInfo;
ASSERT(rNpcInfo.Count);
NPCInfoParser* const pParser = NPCInfoParser::Instance();
SSQInfo::SUMMONED_NPC_NODE* pIt = rNpcInfo.List;
SSQInfo::SUMMONED_NPC_NODE* const pItEnd = &rNpcInfo.List[rNpcInfo.Count];
BOOLEAN bRatioIntegrity = FALSE;
DWORD ratio_sum = 0;
for( ; pIt != pItEnd; ++pIt)
{
SSQInfo::SUMMONED_NPC_NODE& rNode = *pIt;
const BASE_NPCINFO* const pNpcInfo = pParser->GetNPCInfo(rNode.m_NPCCode);
ASSERT(pNpcInfo && (pNpcInfo->m_byGrade == eNPC_SSQ_MONSTER)); // Ratio는 0일 수 있다...
if(!bRatioIntegrity) bRatioIntegrity = !!rNode.m_SumRatio;
rNode.m_SumRatio += (WORD)ratio_sum; // 증분확률로 전환
ratio_sum = rNode.m_SumRatio;
}
ASSERT(bRatioIntegrity && ratio_sum < 60000); // 최소한 하나라도 확률이 있어야 한다.
rNpcInfo.MaxRegenValue = (SSQInfo::RATIO_SUM_T)ratio_sum;
}
////────────────────────────────────────────────
//// - Item Integrity << - type이 너무 많다. 조사할 수 없다.
//FLOWCONTROL_START() {
// SSQInfo::RESTRICT_ITEM_TYPE_INFO& rInfo = pSSQInfo->m_RestrictItemTypeInfo;
// const SSQInfo::COUNT_T upperbound = rInfo.Count;
// if(!upperbound)
// break;
// typedef WORD ITEMTYPE;
// const ITEMTYPE* pIt = rInfo.ItemTypes;
// const ITEMTYPE* const pItEnd = &rInfo.ItemTypes[upperbound];
// for(; pIt!=pItEnd ; ++pIt)
// {
// }
//} }
//────────────────────────────────────────────
// - Skill Integrity << - type이 너무 많다. 조사할 수 없다.
// - 캐릭터별 스킬 그룹이 될 것이다. 분리할 수는 없는가?
//────────────────────────────────────────────
// - 입장 제어 시간 검사 및 변환
SSQInfo::TIME_RANGE& INOUT rScriptT = pSSQInfo->m_TimeRange;
const SSQInfo::MINUTE_T waiting = pSSQInfo->m_WatingTime;
const SSQInfo::MINUTE_T playing = pSSQInfo->m_QuestPlayTime;
SSQInfo::TIME_RANGE& rNotice = pSSQInfo->m_CTimeNotice;
SSQInfo::TIME_RANGE& rWaiting = pSSQInfo->m_CTimeWaiting;
SSQInfo::TIME_RANGE& rBattle = pSSQInfo->m_CTimeBattle;
BOOLEAN acceptTimeField[SSQInfo::MI_ENTER_TIME_SECTION_MAX] = { FALSE, };
for(DWORD idx = 0; idx < SSQInfo::MI_ENTER_TIME_SECTION_MAX; ++idx)
{
// +10은 관련 시간 이벤트(공지관련) 시작 시간을 감안한 여유있는 수치, 0'10"
acceptTimeField[idx] = !!rScriptT[idx].Start;
if(acceptTimeField[idx])
{
ASSERT(10 < rScriptT[idx].Start);
}
_ConvertWzTmFmt2AcmTime(rScriptT[idx]);
}
// Acm Time Check
ASSERT(waiting && (waiting == 7) && playing); // 현재 시간 이벤트는 waiting시간이 틀리면 꼬인다.
const WORD acmTime24 = 24 * 60;
const WORD safe_range = waiting + playing + 10;
for(DWORD idx = 0; idx < (SSQInfo::MI_ENTER_TIME_SECTION_MAX - 1); ++idx)
{
if(acceptTimeField[idx] == FALSE)
continue;
const WORD check_time = rScriptT[idx].Start + safe_range;
ASSERT(check_time < acmTime24);
if(acceptTimeField[idx + 1])
{
ASSERT(check_time < rScriptT[idx + 1].Start);
}
}
{
util::AssertCompileTimeVariableTypeEqual(&rScriptT[0], &rNotice[0]);
util::AssertCompileTimeVariableTypeEqual(&rScriptT[0], &rWaiting[0]);
util::AssertCompileTimeVariableTypeEqual(&rScriptT[0], &rBattle[0]);
BOOST_STATIC_ASSERT(_countof(rScriptT) == _countof(rNotice) &&
_countof(rScriptT) == _countof(rWaiting) &&
_countof(rScriptT) == _countof(rBattle));
CopyMemory(&rNotice[0], &rScriptT[0], sizeof(rScriptT));
CopyMemory(&rWaiting[0], &rScriptT[0], sizeof(rScriptT));
CopyMemory(&rBattle[0], &rScriptT[0], sizeof(rScriptT));
};
for(DWORD idx=0 ; idx<SSQInfo::MI_ENTER_TIME_SECTION_MAX ; ++idx)
{
if(acceptTimeField[idx] == FALSE)
continue;
{ // 스크립트 시작 시간 기준 -5'~ 0'("포탈 생성할 수 있는 시간까지 5분 남았어용~")
SSQInfo::TimeRange& rNode = rNotice[idx];
rNode.End = rNode.Start;
rNode.Start -= SSQInfo::TIME_NOTICE_START;
};
{ // 스크립트 시작 시간 기준 0'~ 7'(waiting) (스크립트 정보: 7')
SSQInfo::TimeRange& rNode = rWaiting[idx];
rNode.End = rNode.Start + waiting;
};
{ // 시작시간 (스크립트 시작 시간 기준 + 대기 시간)
// 7'~22'(playing) (스크립트 정보:15')
SSQInfo::TimeRange& rNode = rBattle[idx];
rNode.Start += waiting;
rNode.End = rNode.Start + playing;
};
{
rScriptT[idx].End = rBattle[idx].End;
};
}
for(DWORD idx = 0; idx < SSQInfo::MI_ENTER_TIME_SECTION_MAX; ++idx)
{
if(acceptTimeField[idx] == FALSE)
continue;
ASSERT(rScriptT[idx].End + 10 < acmTime24); // +10은 관련 시간 사후 처리 시간을 감안한 여유있는 수치
}
for(DWORD idx = 0; idx < SSQInfo::MI_ENTER_TIME_SECTION_MAX; ++idx)
{
_ConvertAcmTime2WzTmFmt(rScriptT[idx]);
_ConvertAcmTime2WzTmFmt(rNotice[idx]);
_ConvertAcmTime2WzTmFmt(rWaiting[idx]);
_ConvertAcmTime2WzTmFmt(rBattle[idx]);
}
//────────────────────────────────────────────
return TRUE;
}
#ifdef _SERVER
BOOLEAN
SSQInfoParser::_LoadWat(const TCHAR* pszWatFilePath, const BOOLEAN isPack)
{
__UNUSED(isPack);
CAreaTileHelper* const pLoader = TAllocNew(CAreaTileHelper);
pLoader->LoadAreaTile(const_cast<TCHAR*>(pszWatFilePath));
const DWORD totalTiles = pLoader->GetTotalTileCount();
SAFE_DELETE_ARRAY(m_pSSQTiles);
m_pSSQTiles = new INT[totalTiles];
memset(m_pSSQTiles, -1, sizeof(INT)*totalTiles);
INT* pTileIT = m_pSSQTiles;
AREATILEINFO_ITERATOR it=pLoader->Begin(), itend=pLoader->End();
for(; it!=itend ; ++it)
{
AREA_TILE_INFO* const pINFO = *it;
const INT id = pINFO->iAreaID;
_AREA_TILE_INFO& rDest = m_SSQTileInfoTable[id];
rDest.iAreaID = id;
rDest.wNumberOfTiles = pINFO->wNumberOfTiles;
rDest.piTileIndex = pTileIT;
INT* pSrcIt = pINFO->piTileIndex;
INT* pTileEnd = pTileIT+rDest.wNumberOfTiles;
for(; pTileIT != pTileEnd ; ++pTileIT)
*pTileIT = *pSrcIt++;
}
TAllocDelete(CAreaTileHelper, pLoader);
return TRUE;
}
BOOLEAN
SSQInfoParser::GM_SpecialControl_OpenStart(const MAPCODE CodeOfSSQ, const SSQInfo::WzTmFmt retape,
BOOLEAN isFastTrack)
{
SSQINFO_TABLE::iterator itFind = m_SSQInfoTable.find(CodeOfSSQ);
SSQInfo* const pSSQInfo = itFind != m_SSQInfoTable.end() ? itFind->second : NULL;
if(!pSSQInfo)
return FALSE;
const SSQInfo::MINUTE_T waiting = isFastTrack == 0 ? pSSQInfo->m_WatingTime : 1;
const SSQInfo::MINUTE_T playing = pSSQInfo->m_QuestPlayTime;
const WORD acmTime24 = 24 * 60;
const WORD safe_range = waiting + playing + 20;
if(retape + safe_range >= acmTime24)
return FALSE;
SSQInfo::TIME_RANGE& rNotice = pSSQInfo->m_CTimeNotice;
SSQInfo::TIME_RANGE& rWaiting = pSSQInfo->m_CTimeWaiting;
SSQInfo::TIME_RANGE& rBattle = pSSQInfo->m_CTimeBattle;
ZeroMemory(&rNotice, sizeof(rNotice));
ZeroMemory(&rWaiting, sizeof(rWaiting));
ZeroMemory(&rBattle, sizeof(rBattle));
rNotice[0].Start = retape;
rNotice[0].End = retape + (isFastTrack == 0 ? SSQInfo::TIME_NOTICE_START : 0);
rWaiting[0].Start = rNotice[0].End;
rWaiting[0].End = rWaiting[0].Start + waiting;
rBattle[0].Start = rWaiting[0].End;
rBattle[0].End = rBattle[0].Start += playing;
_ConvertAcmTime2WzTmFmt(rNotice[0]);
_ConvertAcmTime2WzTmFmt(rWaiting[0]);
_ConvertAcmTime2WzTmFmt(rBattle[0]);
return TRUE;
}
#endif
//━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// <IMPLEMENTATION><UTILITY>
//
const SSQInfo* const
SSQInfoParser::FindSSQInfoEnterableLevel(const LEVELTYPE level) const
{
SSQINFO_TABLE::const_iterator itFind =
std::find_if(m_SSQInfoTable.begin(), m_SSQInfoTable.end()
, boost::bind(&SSQInfo::IsAcceptLevel
, boost::bind(select2nd<SSQINFO_TABLE::value_type>(), _1)
, level
)
);
return itFind != m_SSQInfoTable.end() ? itFind->second : NULL;
}