Jump to content
Maintenance : Final step ×

Computing monster points.


Recommended Posts

  • Honorable Member

There is an issue in the ComputePoints function for monsters when adding affects and then removing them after a certain time.
Normally, we don't typically apply affects to monsters, but there are certain cases where it becomes necessary.

What is the issue, exactly?

First, let's analyze the SetProto function in the CHARACTER class, which is called when a monster is spawned:

void CHARACTER::SetProto(const CMob* pkMob)
{
	if (m_pkMobInst)
		M2_DELETE(m_pkMobInst);

	m_pkMobData = pkMob;
	m_pkMobInst = M2_NEW CMobInstance;

	m_bPKMode = PK_MODE_FREE;

	const TMobTable* t = &m_pkMobData->m_table;

	m_bCharType = t->bType;

	SetLevel(t->bLevel);
	SetEmpire(t->bEmpire);

	SetExp(t->dwExp);
	SetRealPoint(POINT_ST, t->bStr);
	SetRealPoint(POINT_DX, t->bDex);
	SetRealPoint(POINT_HT, t->bCon);
	SetRealPoint(POINT_IQ, t->bInt);

	ComputePoints();

	SetHP(GetMaxHP());
	SetSP(GetMaxSP());

	////////////////////
	m_pointsInstant.dwAIFlag = t->dwAIFlag;
	SetImmuneFlag(t->dwImmuneFlag);

	AssignTriggers(t);

	ApplyMobAttribute(t);

	if (IsStone())
	{
		DetermineDropMetinStone();
	}

	if (IsWarp() || IsGoto())
	{
		StartWarpNPCEvent();
	}

	[ more ... ]
}

In the function above, ComputePoints is called before ApplyMobAttribute, which is responsible for setting the monster's attributes, such as enchantments and resistances.
When setting points, they are stored in m_pointsInstant.points. If you call ComputePoints again on the monster, it will reset those points because the function clears them using memset(m_pointsInstant.points, 0, sizeof(m_pointsInstant.points));. Normally, this function is not called on monsters after they spawn. However, if you try to apply affects to monsters and then remove them using RemoveAffect or manually compute the monster's affects, it triggers this bug by removing the monster's attributes.

Why is this an the issue?

When removing the points added by ApplyMobAttribute, the monster will lose all of its enchantments and resistances, significantly affecting its behavior and balance in the game.
Here is the default implementation of the RemoveAffect:

bool CHARACTER::RemoveAffect(CAffect* pkAff)
{
	if (!pkAff)
		return false;

	// AFFECT_BUF_FIX
	m_list_pkAffect.remove(pkAff);
	// END_OF_AFFECT_BUF_FIX

	ComputeAffect(pkAff, false);

	// Bug fix for revive invisibility.
	// This bug occurred when using a buff skill, disguising, and then using a revive (AFFECT_REVIVE_INVISIBLE),
	// followed by immediate attacking. The issue was caused by ignoring buff effects during disguise.
	// When the revive was removed, both the disguise and buff effects would be applied.
	// To avoid unintended side effects, the fix ensures that ComputePoints is only called when necessary.
	if (AFFECT_REVIVE_INVISIBLE != pkAff->dwType)
	{
		ComputePoints();
	}
	CheckMaximumPoints();

	[ more ... ]
}

Solution

To fix this bug, modify the condition so that ComputePoints is only called for player characters, not monsters:

if (AFFECT_REVIVE_INVISIBLE != pkAff->dwType && IsPC())
{
	ComputePoints();
}

This change ensures that the point recalculation only affects player characters, preventing the unintended removal of attributes from monsters.
 

Edited by Owsap
  • Metin2 Dev 5
  • Good 3
  • muscle 2
  • Love 7
Link to comment
Share on other sites

×
×
  • Create New...

Important Information

Terms of Use / Privacy Policy / Guidelines / We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.