Jump to content

Recommended Posts

  • Active+ Member

This is a trick I implemented on a player's suggestion, the idea is to block the "regen" (mobs respawning) in some areas until a specific monster is killed.

So if you want to prevent players from going AFK & macro in some areas you put a "regen blocking mob" there, preferably a range-based attacking one (magic / archer) so that this area's monsters will not be respawned until this monster is killed.

 

These monsters will be spawned via the regen system and you will be able to control the area covered by individual monster using it's spawn position and delta x & delta y coordinates.

 

regen.h

somewhere in this struct:

typedef struct regen

add:

bool is_anti_macro;

and add it in the initializers list:

	regen() :
		prev(NULL), next(NULL),
    ...
		is_anti_macro(false), // <-- this
		event(NULL),
		id(0)
	{}

 

add:

extern bool is_regen_in_anti_macro_position(LPREGEN tested_regen);

somewhere near:

extern void regen_reset(int x, int y);

 

regen.cpp

below:

LPREGEN regen_list = NULL;

add:

LPREGEN regen_anti_macro_list = NULL;

 

in this function:

static bool read_line(FILE* fp, LPREGEN regen)

edit this case-if block

			case MODE_TYPE:
				if (szTmp[0] == 'm')

to this:

...
		case MODE_TYPE:
			if (szTmp[0] == 'm')
			{
				regen->type = REGEN_TYPE_MOB;

				if (szTmp[1] == 'a' && szTmp[2] == 'm')
					regen->is_anti_macro = true;
			}
	...

 

add this function somewhere in the file:

bool is_regen_in_anti_macro_position(LPREGEN tested_regen)
{
	LPREGEN regen;

	for (regen = regen_anti_macro_list; regen; regen = regen->next)
	{
		// if "tested_regen" position is inside "regen" position
		if (regen->count)
			if (tested_regen->sx >= regen->sx &&
				tested_regen->ex <= regen->ex &&
				tested_regen->sy >= regen->sy &&
				tested_regen->ey <= regen->ey)
			{
				return true;
			}
	}

	return false;
}

 

in this function's definition:

static void regen_spawn(LPREGEN regen, bool bOnce)

edit the return type to bool and add the third input parameter:

static bool regen_spawn(LPREGEN regen, bool bOnce, bool bInitial = false)

change:

	if (!num)
		return;

to:

	if (!num)
		return true;

and add this just below:

	if (!bInitial && !regen->is_anti_macro)
	{
		if (is_regen_in_anti_macro_position(regen))
			return false;
	}

and finally add this return at the end:

return true;

 

the whole definition should look like this:

static bool regen_spawn(LPREGEN regen, bool bOnce, bool bInitial = false)
{
	DWORD	num;
	DWORD	i;

	num = (regen->max_count - regen->count);

	if (!num)
		return true;

	if (!bInitial && !regen->is_anti_macro)
	{
		if (is_regen_in_anti_macro_position(regen))
			return false;
	}

	for (i = 0; i < num; ++i)
	{
		LPCHARACTER ch = NULL;

		if (regen->type == REGEN_TYPE_ANYWHERE)
		{
			ch = CHARACTER_MANAGER::instance().SpawnMobRandomPosition(regen->vnum, regen->lMapIndex);

			if (ch)
				++regen->count;
		}
		else if (regen->sx == regen->ex && regen->sy == regen->ey)
		{
			ch = CHARACTER_MANAGER::instance().SpawnMob(regen->vnum,
					regen->lMapIndex,
					regen->sx,
					regen->sy,
					regen->z_section,
					false,
					regen->direction == 0 ? number(0, 7) * 45 : (regen->direction - 1) * 45);

			if (ch)
			  ++regen->count;
		}
		else
		{
			if (regen->type == REGEN_TYPE_MOB)
			{
				ch = CHARACTER_MANAGER::Instance().SpawnMobRange(regen->vnum, regen->lMapIndex, regen->sx, regen->sy, regen->ex, regen->ey, true, regen->is_aggressive, regen->is_aggressive );

				if (ch)
				  ++regen->count;
			}
			else if (regen->type == REGEN_TYPE_GROUP)
			{
				if (CHARACTER_MANAGER::Instance().SpawnGroup(regen->vnum, regen->lMapIndex, regen->sx, regen->sy, regen->ex, regen->ey, bOnce ? NULL : regen, regen->is_aggressive))
					++regen->count;
			}
			else if (regen->type == REGEN_TYPE_GROUP_GROUP)
			{
				if (CHARACTER_MANAGER::Instance().SpawnGroupGroup(regen->vnum, regen->lMapIndex, regen->sx, regen->sy, regen->ex, regen->ey, bOnce ? NULL : regen, regen->is_aggressive))
					++regen->count;
			}
		}

		if (ch && !bOnce)
			ch->SetRegen(regen);
	}

	return true;
}

 

in this function:

EVENTFUNC(regen_event)

edit this:

	regen_spawn(regen, false);
	return PASSES_PER_SEC(regen->time);

to:

	if (!regen_spawn(regen, false))
	{
		// if the regen failed (probably because there is a regen blocking mob alive in the regen area)
		// let's retry faster, NB: YOU CAN reduce this value further is you like
		return PASSES_PER_SEC(regen->time / 2);
	}
	
	return PASSES_PER_SEC(regen->time);

 

the whole definition should look like this:

EVENTFUNC(regen_event)
{
	regen_event_info* info = dynamic_cast<regen_event_info*>( event->info );

	if ( info == NULL )
	{
		sys_err( "regen_event> <Factor> Null pointer" );
		return 0;
	}

	LPREGEN	regen = info->regen;

	if (regen->time == 0)
		regen->event = NULL;

	if (!regen_spawn(regen, false))
	{
		// if the regen failed (probably because there is a regen blocking mob alive in the regen area)
		// let's retry faster, NB: YOU CAN reduce this value further is you like
		return PASSES_PER_SEC(regen->time / 2);
	}
	
	return PASSES_PER_SEC(regen->time);
}

 

in:

void regen_free(void)

add this add the end:

regen_anti_macro_list = NULL;

 

 

Now you can add the regen blocking monsters in your regen files as you would do for normal monsters & groups:

example below with the mob vnum 2132, the regen definition remains identical to normal monster one:

Spoiler

mam 140 75 25 50 0 0 90s 100 1 2132

details:

x: 140

y: 75

deltaX: 25

deltaY: 50

 

startX: 140 - 25 = 115

endX: 140 - 25 + (25 * 2) = 165

startY: 75 - 50 = 25

endY: 75 - 50 + (50 * 2) = 125

covered area: from (115, 25) to (165, 125) (= the rect: (115,25),(165,25),(115,125),(165,125) )

 

 

Bonus: if you want your regen blocking monsters to have custom hard-coded attacking range you could edit this function (in char.cpp):

WORD CHARACTER::GetMobAttackRange() const

to something like:

WORD CHARACTER::GetMobAttackRange() const
{ 
	switch (GetMobBattleType())
	{
		case BATTLE_TYPE_RANGE:
		case BATTLE_TYPE_MAGIC:
			if (m_pkRegen && m_pkRegen->is_anti_macro)
				return 2400; // put your custom value here

			return m_pkMobData->m_table.wAttackRange + GetPoint(POINT_BOW_DISTANCE);  
		default:
			return m_pkMobData->m_table.wAttackRange; 
	}
}

 

This is a simple example of implementing this idea, you can go further if you wish

  • Metin2 Dev 2
  • Love 1
Link to comment
https://metin2.dev/topic/33499-simple-anti-macro-regen-system/
Share on other sites

Don't use any images from : imgur, turkmmop, freakgamers, inforge, hizliresim... Or your content will be deleted without notice...
Use : https://metin2.download/media/add/

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
×
×
  • 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.