INTRODUCTION & PROBLEM
Hello, we will solve the famous "Cannot Find Tree" problem in the "CHARACTER::Sync" function in the server src and also the problems that may be caused by the "Dead();" section used for everything that is not a PC in this function.
WHAT DID WE CHANGE?
All of the currently shared fixes are actually incomplete, we will make a new arrangement to solve this problem at its root, thus we will fix the problem completely.
HOW TO DO?
Without going into details such as editing the reward mechanism of the existing dead function, we will simply create a new dead function and use it in Sync. The main purpose of this function, which can only be used for mobs and metins, is that it does not give a reward (drop) after the dead function, let's get started.
First, open "char_battle.cpp"
// FIND;
struct FuncSetLastAttacked
// Add ABOVE;
void CHARACTER::RewardlessDead() // DevFix 29
{
if (IsPC()) // This function only for mobs or stones, so if IsPC() exit the function before it start. - [MT2Dev Note] - 10/10/2024
{
return;
}
if (IsDead())
{
return;
}
if (IsMonster() || IsStone()) // Dead is only possible when victim is mob or stone. - [MT2Dev Note] - 10/10/2024
{
SetPosition (POS_DEAD);
ClearAffect (true);
ClearSync();
Reward (false); // No drop yang or item. - [MT2Dev Note]
if (m_pkStunEvent)
{
event_cancel (&m_pkStunEvent);
}
TPacketGCDead pack;
pack.header = HEADER_GC_DEAD;
pack.vid = m_vid;
PacketAround (&pack, sizeof (pack));
REMOVE_BIT (m_pointsInstant.instant_flag, INSTANT_FLAG_STUN);
sys_log (0, "Rewardless_DEAD: %s %p", GetName(), this);
// Create Dead event.. In the Dead event, for monsters, make them destroy after a few seconds. - [Ymir Dev Note]
if (m_pkDeadEvent)
{
event_cancel (&m_pkDeadEvent);
}
if (IsStone())
{
ClearStone();
}
if (GetDungeon())
{
GetDungeon()->DeadCharacter (this);
}
SCharDeadEventInfo* pEventInfo = AllocEventInfo<SCharDeadEventInfo>();
pEventInfo->isPC = false;
pEventInfo->dwID = this->GetVID();
m_pkDeadEvent = event_create (dead_event, pEventInfo, PASSES_PER_SEC (0));
sys_log (0, "Rewardless_DEAD_EVENT_CREATE: %s %p %p", GetName(), this, get_pointer (m_pkDeadEvent));
}
}
Then open "char.cpp"
// Find the function;
bool CHARACTER::Sync (long x, long y)
{
//xxx
}
// Change it completely;
// DevFix 29 - Necessary arrangement for scenarios where sync is not possible. - [MT2Dev Note] - 01/04/2024
// Moves to the specified x, y position regardless. - [Ymir Dev Note]
bool CHARACTER::Sync (long x, long y)
{
LPSECTREE current_tree = GetSectree(); // For a better performance, call it only once.. - [MT2Dev Note]
if (!current_tree)
{
sys_err ("<CHARACTER::Sync> Sectree is NULL! - Name: %s", GetName());
return false;
}
if (IsPC() && IsDead()) // DevFix 27 - Dead players not needed sync.. - [MT2Dev Note] - 01/04/2024
{
return false;
}
LPSECTREE new_tree = SECTREE_MANAGER::instance().Get (GetMapIndex(), x, y);
if (!new_tree)
{
if (GetDesc())
{
sys_err ("Cannot Find Tree at - X: %d Y: %d (Name: %s)", x, y, GetName());
x = GetX();
y = GetY();
new_tree = current_tree; // If there is no new tree, just use the old one. - [MT2Dev Note]
if (!new_tree)
{
sys_err ("[CRITICAL] - Cannot Find Tree at - X: %d Y: %d (Name: %s)", x, y, GetName());
GetDesc()->SetPhase (PHASE_CLOSE);
}
}
else
{
if (IsMonster() || IsStone()) // Dead is only possible when victim is mob or stone. - [MT2Dev Note] - 10/10/2024
{
sys_err ("[MOB or STONE]No Tree: %d %d %d", x, y, GetMapIndex());
RewardlessDead(); // In this special case, we don't want any reward so this is new function for it. - [MT2Dev Note] - 10/10/2024
}
else
{
sys_err ("[HOW IS THIS POSSIBLE?]No Tree: %d %d %d", x, y, GetMapIndex());
}
}
return false;
}
SetRotationToXY (x, y);
SetXYZ (x, y, 0);
if (GetDungeon())
{
// Dungeon event attribute change. - [Ymir Dev Note]
int iLastEventAttr = m_iEventAttr;
m_iEventAttr = new_tree->GetEventAttribute (x, y);
if (m_iEventAttr != iLastEventAttr)
{
if (GetParty())
{
quest::CQuestManager::instance().AttrOut (GetParty()->GetLeaderPID(), this, iLastEventAttr);
quest::CQuestManager::instance().AttrIn (GetParty()->GetLeaderPID(), this, m_iEventAttr);
}
else
{
quest::CQuestManager::instance().AttrOut (GetPlayerID(), this, iLastEventAttr);
quest::CQuestManager::instance().AttrIn (GetPlayerID(), this, m_iEventAttr);
}
}
}
if (current_tree != new_tree)
{
if (!IsNPC())
{
SECTREEID id = new_tree->GetID();
SECTREEID old_id = current_tree->GetID();
const float fDist = DISTANCE_SQRT (id.coord.x - old_id.coord.x, id.coord.y - old_id.coord.y);
sys_log (0, "SECTREE DIFFER: %s %dx%d was %dx%d dist %.1fm", GetName(), id.coord.x, id.coord.y, old_id.coord.x, old_id.coord.y, fDist); // DevFix 30
}
new_tree->InsertEntity (this);
}
return true;
}
Lastly, open "char.h"
// Find;
void Dead (LPCHARACTER pkKiller = NULL, bool bImmediateDead = false);
// Add under;
void RewardlessDead(); // DevFix 29