issue-7: add stone refine queue command

This commit is contained in:
server
2026-04-16 20:03:01 +02:00
parent 9f5851dac6
commit 9e5bd67979
5 changed files with 263 additions and 0 deletions

View File

@@ -215,6 +215,7 @@ void CHARACTER::Initialize()
m_pkFireEvent = NULL;
m_pkCheckSpeedHackEvent = NULL;
m_pkAutoPickupEvent = NULL;
m_pkStoneQueueEvent = NULL;
m_speed_hack_count = 0;
m_pkAffectEvent = NULL;
@@ -305,6 +306,11 @@ void CHARACTER::Initialize()
// REFINE_NPC
m_dwRefineNPCVID = 0;
// END_OF_REFINE_NPC
m_bStoneQueueScrollCell = 0;
m_iStoneQueueCurrentIndex = 0;
m_iStoneQueueSuccessCount = 0;
m_iStoneQueueFailCount = 0;
m_vecStoneQueueSlots.clear();
m_dwPolymorphRace = 0;
@@ -563,6 +569,7 @@ void CHARACTER::Destroy()
event_cancel(&m_pkMiningEvent);
// END_OF_MINING
event_cancel(&m_pkAutoPickupEvent);
event_cancel(&m_pkStoneQueueEvent);
for (itertype(m_mapMobSkillEvent) it = m_mapMobSkillEvent.begin(); it != m_mapMobSkillEvent.end(); ++it)
@@ -6535,6 +6542,166 @@ void CHARACTER::RefreshAutoPickup()
SendAutoPickupState();
}
namespace
{
const int kStoneQueueTick = PASSES_PER_SEC(1);
enum
{
HYUNIRON_CHN = 1,
MUSIN_SCROLL = 3,
BDRAGON_SCROLL = 6,
};
int GetStoneQueueRefineType(LPITEM scrollItem, LPITEM targetItem)
{
if (!scrollItem || !targetItem)
return -1;
if (scrollItem->GetType() != ITEM_USE || scrollItem->GetSubType() != USE_TUNING)
return -1;
if (scrollItem->GetValue(0) == MUSIN_SCROLL)
return REFINE_TYPE_MUSIN;
if (scrollItem->GetValue(0) == HYUNIRON_CHN)
return REFINE_TYPE_HYUNIRON;
if (scrollItem->GetValue(0) == BDRAGON_SCROLL)
{
if (targetItem->GetRefineSet() != 702)
return -1;
return REFINE_TYPE_BDRAGON;
}
if (targetItem->GetRefineSet() == 501)
return -1;
return REFINE_TYPE_SCROLL;
}
EVENTFUNC(stone_queue_event)
{
char_event_info* info = dynamic_cast<char_event_info*>(event->info);
if (!info)
{
sys_err("stone_queue_event> <Factor> Null pointer");
return 0;
}
LPCHARACTER ch = info->ch;
if (!ch)
return 0;
return ch->ProcessStoneQueueTick() ? kStoneQueueTick : 0;
}
}
int CHARACTER::GetStoneQueueMax() const
{
return GetPremiumRemainSeconds(PREMIUM_GOLD) > 0 ? 8 : 3;
}
void CHARACTER::SendStoneQueueState()
{
ChatPacket(CHAT_TYPE_COMMAND,
"StoneQueueState %d %d %d %d %d",
GetStoneQueueMax(),
m_pkStoneQueueEvent ? 1 : 0,
m_iStoneQueueCurrentIndex,
m_iStoneQueueSuccessCount,
m_iStoneQueueFailCount);
}
void CHARACTER::CancelStoneQueue(bool resetResults)
{
event_cancel(&m_pkStoneQueueEvent);
m_vecStoneQueueSlots.clear();
m_bStoneQueueScrollCell = 0;
if (resetResults)
{
m_iStoneQueueCurrentIndex = 0;
m_iStoneQueueSuccessCount = 0;
m_iStoneQueueFailCount = 0;
}
SendStoneQueueState();
}
void CHARACTER::StartStoneQueue(const std::vector<BYTE>& slots, BYTE scrollCell)
{
CancelStoneQueue();
m_vecStoneQueueSlots = slots;
m_bStoneQueueScrollCell = scrollCell;
char_event_info* info = AllocEventInfo<char_event_info>();
info->ch = this;
m_pkStoneQueueEvent = event_create(stone_queue_event, info, 1);
SendStoneQueueState();
}
void CHARACTER::OnStoneQueueRefineResult(bool success)
{
if (!m_pkStoneQueueEvent)
return;
if (success)
++m_iStoneQueueSuccessCount;
else
++m_iStoneQueueFailCount;
++m_iStoneQueueCurrentIndex;
if (m_iStoneQueueCurrentIndex >= static_cast<int>(m_vecStoneQueueSlots.size()))
{
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Stone queue finished. Success: %d Fail: %d"), m_iStoneQueueSuccessCount, m_iStoneQueueFailCount);
CancelStoneQueue(false);
return;
}
SendStoneQueueState();
}
bool CHARACTER::ProcessStoneQueueTick()
{
if (!IsPC() || IsDead())
{
CancelStoneQueue();
return false;
}
if (m_iStoneQueueCurrentIndex >= static_cast<int>(m_vecStoneQueueSlots.size()))
{
CancelStoneQueue();
return false;
}
LPITEM scrollItem = GetInventoryItem(m_bStoneQueueScrollCell);
if (!scrollItem)
{
CancelStoneQueue();
return false;
}
const BYTE targetSlot = m_vecStoneQueueSlots[m_iStoneQueueCurrentIndex];
LPITEM targetItem = GetInventoryItem(targetSlot);
const int refineType = GetStoneQueueRefineType(scrollItem, targetItem);
if (!targetItem || targetItem->GetType() != ITEM_METIN || refineType < 0)
{
OnStoneQueueRefineResult(false);
return m_pkStoneQueueEvent != NULL;
}
SetRefineMode(m_bStoneQueueScrollCell);
SetRefineTime();
if (!DoRefineWithScroll(targetItem, refineType))
{
OnStoneQueueRefineResult(false);
return m_pkStoneQueueEvent != NULL;
}
return true;
}
bool CHARACTER::IsGuardNPC() const
{
return IsNPC() && (GetRaceNum() == 11000 || GetRaceNum() == 11002 || GetRaceNum() == 11004);

View File

@@ -759,6 +759,12 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
bool HasAutoPickupVip() const;
int GetAutoPickupRadius() const;
bool ShouldAutoPickupItem(LPITEM item) const;
int GetStoneQueueMax() const;
void SendStoneQueueState();
void StartStoneQueue(const std::vector<BYTE>& slots, BYTE scrollCell);
void CancelStoneQueue(bool resetResults = true);
void OnStoneQueueRefineResult(bool success);
bool ProcessStoneQueueTick();
bool IsPolymorphed() const { return m_dwPolymorphRace>0; }
bool IsPolyMaintainStat() const { return m_bPolyMaintainStat; } // 이전 스텟을 유지하는 폴리모프.
@@ -1179,6 +1185,11 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
int m_iRefineAdditionalCell;
bool m_bUnderRefine;
DWORD m_dwRefineNPCVID;
std::vector<BYTE> m_vecStoneQueueSlots;
BYTE m_bStoneQueueScrollCell;
int m_iStoneQueueCurrentIndex;
int m_iStoneQueueSuccessCount;
int m_iStoneQueueFailCount;
public:
////////////////////////////////////////////////////////////////////////////////////////
@@ -1785,6 +1796,7 @@ class CHARACTER : public CEntity, public CFSM, public CHorseRider
LPEVENT m_pkCheckSpeedHackEvent;
LPEVENT m_pkDestroyWhenIdleEvent;
LPEVENT m_pkAutoPickupEvent;
LPEVENT m_pkStoneQueueEvent;
LPEVENT m_pkPetSystemUpdateEvent;
bool IsWarping() const { return m_pkWarpEvent ? true : false; }

View File

@@ -1030,6 +1030,7 @@ void NotifyRefineSuccess(LPCHARACTER ch, LPITEM item, const char* way, int iType
if (NULL != ch && item != NULL)
{
ch->ChatPacket(CHAT_TYPE_COMMAND, "RefineSuceeded %d", iType);
ch->OnStoneQueueRefineResult(true);
LogManager::instance().RefineLog(ch->GetPlayerID(), item->GetName(), item->GetID(), item->GetRefineLevel(), 1, way);
}
@@ -1040,6 +1041,7 @@ void NotifyRefineFail(LPCHARACTER ch, LPITEM item, const char* way, int iType, i
if (NULL != ch && NULL != item)
{
ch->ChatPacket(CHAT_TYPE_COMMAND, "RefineFailed %d", iType);
ch->OnStoneQueueRefineResult(false);
LogManager::instance().RefineLog(ch->GetPlayerID(), item->GetName(), item->GetID(), item->GetRefineLevel(), success, way);
}

View File

@@ -210,6 +210,7 @@ ACMD(do_special_item);
ACMD(do_biolog_submit);
ACMD(do_teleport_system);
ACMD(do_autopickup);
ACMD(do_stone_queue);
ACMD(do_click_mall);
@@ -469,6 +470,7 @@ struct command_info cmd_info[] =
{ "biolog_submit", do_biolog_submit, 0, POS_DEAD, GM_PLAYER },
{ "teleport_system", do_teleport_system, 0, POS_DEAD, GM_PLAYER },
{ "autopickup", do_autopickup, 0, POS_DEAD, GM_PLAYER },
{ "stone_queue", do_stone_queue, 0, POS_DEAD, GM_PLAYER },
{ "siege", do_siege, 0, POS_DEAD, GM_LOW_WIZARD },
{ "temp", do_temp, 0, POS_DEAD, GM_IMPLEMENTOR },
{ "frog", do_frog, 0, POS_DEAD, GM_HIGH_WIZARD },

View File

@@ -1,5 +1,6 @@
#include "stdafx.h"
#include <sodium.h>
#include <set>
#include "utils.h"
#include "config.h"
@@ -1963,6 +1964,85 @@ ACMD(do_autopickup)
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Usage: /autopickup [sync|enable|mode|mask]"));
}
ACMD(do_stone_queue)
{
char arg1[256];
argument = one_argument(argument, arg1, sizeof(arg1));
if (!*arg1 || !strcmp(arg1, "sync"))
{
ch->SendStoneQueueState();
return;
}
if (!strcmp(arg1, "cancel"))
{
ch->CancelStoneQueue();
return;
}
if (strcmp(arg1, "start"))
{
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Usage: /stone_queue [sync|cancel|start]"));
return;
}
char scrollArg[256];
argument = one_argument(argument, scrollArg, sizeof(scrollArg));
int scrollCell = -1;
str_to_number(scrollCell, scrollArg);
if (scrollCell < 0 || scrollCell >= INVENTORY_MAX_NUM)
{
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Invalid stone queue scroll slot."));
return;
}
LPITEM scrollItem = ch->GetInventoryItem(scrollCell);
if (!scrollItem || scrollItem->GetType() != ITEM_USE || scrollItem->GetSubType() != USE_TUNING)
{
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Invalid stone queue scroll item."));
return;
}
std::vector<BYTE> slots;
std::set<int> uniqueSlots;
char slotArg[256];
while (*argument)
{
argument = one_argument(argument, slotArg, sizeof(slotArg));
if (!*slotArg)
break;
int slot = -1;
str_to_number(slot, slotArg);
if (slot < 0 || slot >= INVENTORY_MAX_NUM)
continue;
if (uniqueSlots.find(slot) != uniqueSlots.end())
continue;
LPITEM targetItem = ch->GetInventoryItem(slot);
if (!targetItem || targetItem->GetType() != ITEM_METIN)
continue;
if (slots.size() >= static_cast<size_t>(ch->GetStoneQueueMax()))
break;
uniqueSlots.insert(slot);
slots.push_back(static_cast<BYTE>(slot));
}
if (slots.empty())
{
ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Stone queue is empty."));
return;
}
ch->StartStoneQueue(slots, static_cast<BYTE>(scrollCell));
}
ACMD(do_in_game_mall)
{
if (LC_IsYMIR() == true || LC_IsKorea() == true)