Jump to content

Problem with mob races


Recommended Posts

hi,
today when i was trying my new element bonuses system i noticed that the elements cannot be with another race flag like RACE_FLAG_DEVIL for example so i went to the jungles of my source and i discoverd a little crime 

 

in battle.cpp

		if (pkVictim->IsRaceFlag(RACE_FLAG_ANIMAL))
			iAtk += (iAtk * pkAttacker->GetPoint(POINT_ATTBONUS_ANIMAL)) / 100;
		else if (pkVictim->IsRaceFlag(RACE_FLAG_UNDEAD))
			iAtk += (iAtk * pkAttacker->GetPoint(POINT_ATTBONUS_UNDEAD)) / 100;
		else if (pkVictim->IsRaceFlag(RACE_FLAG_DEVIL))
			iAtk += (iAtk * pkAttacker->GetPoint(POINT_ATTBONUS_DEVIL)) / 100;
		else if (pkVictim->IsRaceFlag(RACE_FLAG_HUMAN))
			iAtk += (iAtk * pkAttacker->GetPoint(POINT_ATTBONUS_HUMAN)) / 100;
		else if (pkVictim->IsRaceFlag(RACE_FLAG_ORC))
			iAtk += (iAtk * pkAttacker->GetPoint(POINT_ATTBONUS_ORC)) / 100;
		else if (pkVictim->IsRaceFlag(RACE_FLAG_MILGYO))
			iAtk += (iAtk * pkAttacker->GetPoint(POINT_ATTBONUS_MILGYO)) / 100;
		else if (pkVictim->IsRaceFlag(RACE_FLAG_INSECT))
			iAtk += (iAtk * pkAttacker->GetPoint(POINT_ATTBONUS_INSECT)) / 100;
		else if (pkVictim->IsRaceFlag(RACE_FLAG_FIRE))
			iAtk += (iAtk * pkAttacker->GetPoint(POINT_ATTBONUS_FIRE)) / 100;
		else if (pkVictim->IsRaceFlag(RACE_FLAG_ICE))
			iAtk += (iAtk * pkAttacker->GetPoint(POINT_ATTBONUS_ICE)) / 100;
		else if (pkVictim->IsRaceFlag(RACE_FLAG_DESERT))
			iAtk += (iAtk * pkAttacker->GetPoint(POINT_ATTBONUS_DESERT)) / 100;
		else if (pkVictim->IsRaceFlag(RACE_FLAG_TREE))
			iAtk += (iAtk * pkAttacker->GetPoint(POINT_ATTBONUS_TREE)) / 100;

 

the redundancy in here is not just preventing the flags to be together it's affecting the performance too..

so i've changed the entire thing in order to make it less messy, and more readable & performance friendly (considering that this is one of the functions that should be triggered with each attack !!)

Spoiler
		struct RacePointPair {
			int raceFlag;
			uint8_t pointAttribute;
		};

		RacePointPair racePointTable[] = {
			{ RACE_FLAG_ANIMAL, POINT_ATTBONUS_ANIMAL },
			{ RACE_FLAG_UNDEAD, POINT_ATTBONUS_UNDEAD },
			{ RACE_FLAG_DEVIL, POINT_ATTBONUS_DEVIL },
			{ RACE_FLAG_HUMAN, POINT_ATTBONUS_HUMAN },
			{ RACE_FLAG_ORC, POINT_ATTBONUS_ORC },
			{ RACE_FLAG_MILGYO, POINT_ATTBONUS_MILGYO },
			{ RACE_FLAG_INSECT, POINT_ATTBONUS_INSECT },
			{ RACE_FLAG_FIRE, POINT_ATTBONUS_FIRE },
			{ RACE_FLAG_ICE, POINT_ATTBONUS_ICE },
			{ RACE_FLAG_DESERT, POINT_ATTBONUS_DESERT },
			{ RACE_FLAG_TREE, POINT_ATTBONUS_TREE }
		};

		for (uint8_t i = 0; i < _countof(racePointTable); i++) {
			if (pkVictim->IsRaceFlag(racePointTable[i].raceFlag))
				iAtk += (iAtk * pkAttacker->GetPoint(racePointTable[i].pointAttribute)) / 100;
		}

 

 

you can adjust it based on your bonuses and all .. Thx

 

 

Edited by CONTROL
  • Good 1
Link to comment
Share on other sites

  • Contributor

Pretty good, but this shouldn't be in support, G.

Also, you should break after you find your race, otherwise you'll loop over the rest for no reason(unless you have multiple races for the same mob).

The performance part makes no difference in release, since the compiler is smart enough to optimize the fuck out of them, but it does a bit of a difference in debug.

 

Here's some profiles(in debug, with optimizations disabled) for 10 million iterations:

Exact copy/paste of your code with raceFlag(for both) = RACE_FLAG_ANIMAL(first match) :

[BRANCHES] Execution x 10000000 took [29.618000]

[ARRAY] Execution x 10000000 took [283.952606]

Exact copy/paste of your code with raceFlag(for both) = RACE_FLAG_TREE(last match)

[BRANCHES] Execution x 10000000 took [287.451385]

[ARRAY] Execution x 10000000 took [345.841217]

 

 

With raceFlag(for both) = RACE_FLAG_ANIMAL(first match) + break after match:

[BRANCHES] Execution x 10000000 took [29.319500]

[ARRAY] Execution x 10000000 took [47.762199]

With raceFlag(for both) = RACE_FLAG_TREE(last match) + break after match(useless here):

[BRANCHES] Execution x 10000000 took [295.321716]

[ARRAY] Execution x 10000000 took [282.486206]

 

 

With raceFlag(for both) = RACE_FLAG_ANIMAL(first match) + break after match + static array:

[BRANCHES] Execution x 10000000 took [29.350700]

[ARRAY] Execution x 10000000 took [32.444702]

 

With raceFlag(for both) = RACE_FLAG_TREE(first match) + break after match(useless here) + static array:

[BRANCHES] Execution x 10000000 took [298.241302]

[ARRAY] Execution x 10000000 took [272.202393]

 

 

Using a switch with raceFlag =  RACE_FLAG_ANIMAL(first match)

[BRANCHES] Execution x 10000000 took [31.487902]

[ARRAY] Execution x 10000000 took [32.890202]

[SWITCH] Execution x 10000000 took [31.182301]

 

Using a switch with raceFlag =  RACE_FLAG_TREE(last match). Something like RACE_FLAG_ATT_ELEC(which isn't checked) brings the switch down to 16ms.

[BRANCHES] Execution x 10000000 took [289.458801]

[ARRAY] Execution x 10000000 took [271.130280]

[SWITCH] Execution x 10000000 took [46.620998]

 

Yeah, I'm bored, how did you know?

 

Take these with a grain of salt btw, the numbers are influenced by what's going on on my pc at the time of running the program, but I guess they're good for a quick "lemme have a look at this shit".

  • Metin2 Dev 1
  • kekw 1
  • Love 1
Link to comment
Share on other sites

1 hour ago, Amun said:

Pretty good, but this shouldn't be in support, G.

Also, you should break after you find your race, otherwise you'll loop over the rest for no reason(unless you have multiple races for the same mob).

The performance part makes no difference in release, since the compiler is smart enough to optimize the fuck out of them, but it does a bit of a difference in debug.

 

Here's some profiles(in debug, with optimizations disabled) for 10 million iterations:

Exact copy/paste of your code with raceFlag(for both) = RACE_FLAG_ANIMAL(first match) :

[BRANCHES] Execution x 10000000 took [29.618000]

[ARRAY] Execution x 10000000 took [283.952606]

Exact copy/paste of your code with raceFlag(for both) = RACE_FLAG_TREE(last match)

[BRANCHES] Execution x 10000000 took [287.451385]

[ARRAY] Execution x 10000000 took [345.841217]

 

 

With raceFlag(for both) = RACE_FLAG_ANIMAL(first match) + break after match:

[BRANCHES] Execution x 10000000 took [29.319500]

[ARRAY] Execution x 10000000 took [47.762199]

With raceFlag(for both) = RACE_FLAG_TREE(last match) + break after match(useless here):

[BRANCHES] Execution x 10000000 took [295.321716]

[ARRAY] Execution x 10000000 took [282.486206]

 

 

With raceFlag(for both) = RACE_FLAG_ANIMAL(first match) + break after match + static array:

[BRANCHES] Execution x 10000000 took [29.350700]

[ARRAY] Execution x 10000000 took [32.444702]

 

With raceFlag(for both) = RACE_FLAG_TREE(first match) + break after match(useless here) + static array:

[BRANCHES] Execution x 10000000 took [298.241302]

[ARRAY] Execution x 10000000 took [272.202393]

 

 

Using a switch with raceFlag =  RACE_FLAG_ANIMAL(first match)

[BRANCHES] Execution x 10000000 took [31.487902]

[ARRAY] Execution x 10000000 took [32.890202]

[SWITCH] Execution x 10000000 took [31.182301]

 

Using a switch with raceFlag =  RACE_FLAG_TREE(last match). Something like RACE_FLAG_ATT_ELEC(which isn't checked) brings the switch down to 16ms.

[BRANCHES] Execution x 10000000 took [289.458801]

[ARRAY] Execution x 10000000 took [271.130280]

[SWITCH] Execution x 10000000 took [46.620998]

 

Yeah, I'm bored, how did you know?

 

Take these with a grain of salt btw, the numbers are influenced by what's going on on my pc at the time of running the program, but I guess they're good for a quick "lemme have a look at this shit".

thx for ur time & sry about the section it's just my first topic in here

when i said performance friendly i didn't really meant something that huge lmao XD

and about the (break) it's not just a me thing most or even all pvm servers

have (race + element) on some mobs and 1 of them will be disabled if they have the old code written above

so i think it would be better to make 2 loops and use break on each one of them

to get a single ( race + element )

		struct RacePointPair {
			int raceFlag;
			uint8_t pointAttribute;
		};

		RacePointPair racePointTable[] = {
			{ RACE_FLAG_ANIMAL, POINT_ATTBONUS_ANIMAL },
			{ RACE_FLAG_UNDEAD, POINT_ATTBONUS_UNDEAD },
			{ RACE_FLAG_DEVIL, POINT_ATTBONUS_DEVIL },
			{ RACE_FLAG_HUMAN, POINT_ATTBONUS_HUMAN },
			{ RACE_FLAG_ORC, POINT_ATTBONUS_ORC },
			{ RACE_FLAG_MILGYO, POINT_ATTBONUS_MILGYO },
			{ RACE_FLAG_INSECT, POINT_ATTBONUS_INSECT },
			{ RACE_FLAG_DESERT, POINT_ATTBONUS_DESERT },
			{ RACE_FLAG_TREE, POINT_ATTBONUS_TREE }
#ifdef ENABLE_NEW_ATTR
			,{ RACE_FLAG_METIN, POINT_ATTBONUS_METIN }
#endif
#ifdef ENABLE_ZODIAC_ATTR
			,{ RACE_FLAG_ZODIAC, POINT_ATTBONUS_ZODIAC }
#endif
#ifdef ENABLE_LEGENDARY_ATTR
			,{ RACE_FLAG_LEGENDARY, POINT_ATTBONUS_LEGENDARY }
#endif
		};

		for (uint8_t i = 0; i < _countof(racePointTable); i++) {
			if (pkVictim->IsRaceFlag(racePointTable[i].raceFlag)) {
				iAtk += (iAtk * pkAttacker->GetPoint(racePointTable[i].pointAttribute)) / 100;
				break;
			}
		}

		RacePointPair elementPointTable[] = {
			{ RACE_FLAG_FIRE, POINT_ATTBONUS_FIRE },
			{ RACE_FLAG_ICE, POINT_ATTBONUS_ICE }
#ifdef ELEMENT_NEW_BONUSES
			,{ RACE_FLAG_ELEC, POINT_ATTBONUS_ELEC }
			,{ RACE_FLAG_WIND, POINT_ATTBONUS_WIND }
			,{ RACE_FLAG_EARTH, POINT_ATTBONUS_EARTH }
			,{ RACE_FLAG_DARK, POINT_ATTBONUS_DARK }
#endif
		};

		for (uint8_t i = 0; i < _countof(elementPointTable); i++) {
			if (pkVictim->IsRaceFlag(elementPointTable[i].raceFlag)) {
				iAtk += (iAtk * pkAttacker->GetPoint(elementPointTable[i].pointAttribute)) / 100;
				break;
			}
		}

 

Link to comment
Share on other sites

  • 2 weeks later...
  • Contributor
On 2/9/2024 at 3:13 PM, CONTROL said:

thx for ur time & sry about the section it's just my first topic in here

when i said performance friendly i didn't really meant something that huge lmao XD

and about the (break) it's not just a me thing most or even all pvm servers

have (race + element) on some mobs and 1 of them will be disabled if they have the old code written above

so i think it would be better to make 2 loops and use break on each one of them

to get a single ( race + element )

		struct RacePointPair {
			int raceFlag;
			uint8_t pointAttribute;
		};

		RacePointPair racePointTable[] = {
			{ RACE_FLAG_ANIMAL, POINT_ATTBONUS_ANIMAL },
			{ RACE_FLAG_UNDEAD, POINT_ATTBONUS_UNDEAD },
			{ RACE_FLAG_DEVIL, POINT_ATTBONUS_DEVIL },
			{ RACE_FLAG_HUMAN, POINT_ATTBONUS_HUMAN },
			{ RACE_FLAG_ORC, POINT_ATTBONUS_ORC },
			{ RACE_FLAG_MILGYO, POINT_ATTBONUS_MILGYO },
			{ RACE_FLAG_INSECT, POINT_ATTBONUS_INSECT },
			{ RACE_FLAG_DESERT, POINT_ATTBONUS_DESERT },
			{ RACE_FLAG_TREE, POINT_ATTBONUS_TREE }
#ifdef ENABLE_NEW_ATTR
			,{ RACE_FLAG_METIN, POINT_ATTBONUS_METIN }
#endif
#ifdef ENABLE_ZODIAC_ATTR
			,{ RACE_FLAG_ZODIAC, POINT_ATTBONUS_ZODIAC }
#endif
#ifdef ENABLE_LEGENDARY_ATTR
			,{ RACE_FLAG_LEGENDARY, POINT_ATTBONUS_LEGENDARY }
#endif
		};

		for (uint8_t i = 0; i < _countof(racePointTable); i++) {
			if (pkVictim->IsRaceFlag(racePointTable[i].raceFlag)) {
				iAtk += (iAtk * pkAttacker->GetPoint(racePointTable[i].pointAttribute)) / 100;
				break;
			}
		}

		RacePointPair elementPointTable[] = {
			{ RACE_FLAG_FIRE, POINT_ATTBONUS_FIRE },
			{ RACE_FLAG_ICE, POINT_ATTBONUS_ICE }
#ifdef ELEMENT_NEW_BONUSES
			,{ RACE_FLAG_ELEC, POINT_ATTBONUS_ELEC }
			,{ RACE_FLAG_WIND, POINT_ATTBONUS_WIND }
			,{ RACE_FLAG_EARTH, POINT_ATTBONUS_EARTH }
			,{ RACE_FLAG_DARK, POINT_ATTBONUS_DARK }
#endif
		};

		for (uint8_t i = 0; i < _countof(elementPointTable); i++) {
			if (pkVictim->IsRaceFlag(elementPointTable[i].raceFlag)) {
				iAtk += (iAtk * pkAttacker->GetPoint(elementPointTable[i].pointAttribute)) / 100;
				break;
			}
		}

 

No worries, man, I just mentioned the break because that's how it works on the "clean" source/proto. Everyone is free to modify to suit their needs and it's not like a few more iterations will make any difference in real life anyway.

Anyhow, don't mind me, I was just bored :kekw:

Link to comment
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now

Announcements



×
×
  • 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.