Jump to content

Support for manual probabilities in item blend


Recommended Posts

  • Contributor

Hello, good people!

 

I was writing something to validate the server data(like blend.txt, cube, etc) and stumbled upon this lovely comment:

Quote

// Choong Ki-hwan's probability table
// It would be neat if we fix it so that it also receives the probability from blend.txt
// by rtsummit

So then I asked myself "Why not?" 🙂

Anyhow, here's the code(everything is in blend_item.cpp):

// after the last #include, add
#include <random>
  
// Optional: You can add this after the last import if you want.
// I've replaced the "Token" thing because Visual Studio was playing tricks with the tabs and it was too annoying.
#define str_match(s1,s2) _stricmp(s1,s2)==0
// or, if you want, you can just completely replace the Token stuff, like I did. Up to you, it's just optional stuff..

// Anyhow, now edit this struct:
struct BLEND_ITEM_INFO
{
	DWORD	item_vnum;
	int		apply_type;
	int		apply_value[MAX_BLEND_ITEM_VALUE];
	int		apply_duration[MAX_BLEND_ITEM_VALUE];
  
  // add these
	int     apply_prob[MAX_BLEND_ITEM_VALUE];
	int     duration_prob[MAX_BLEND_ITEM_VALUE];
	int     apply_prob_sum;// we'll just do the sum straight away
	int     duration_prob_sum;// since we have to check if it has probability or not
};

 

// search for
static int FN_random_index()

// add these before(or after.. whatever)
// You don't really have to add this, you can just use number(min, max) if you want to
int Randomi(int minx, int maxx) {
	std::random_device rd; // obtain a random number from hardware
	std::mt19937 gen(rd()); // seed the generator
	std::uniform_int_distribution<> distr(minx, maxx); // define the range

	return distr(gen);
}

int RandomFromProbs(int probs[], int probsSum)
{
	int rand = Randomi(1, probsSum);
	int accumulated = 0;
	
	for (int i = 0; i < MAX_BLEND_ITEM_VALUE; i++)
	{
		// this is just a fallback in case someone puts 0 for all of them
		// or maybe we should call FN_random_index from here instead?
        // up to you..
		if (i == MAX_BLEND_ITEM_VALUE - 1)
			return i;

		// if the probability is 0, then it's disabled, skip it
		if (!probs[i])
			continue;

		accumulated += probs[i];
		if (rand <= accumulated)
			return i;
	}
}

 

// search for 
else Token("end")

// Add this before
// if you didn't add that define, change these to Token
// here: else Token("apply_prob")
// and the second one: else Token("duration_prob")

		else if (0 == strcmp(key, "apply_prob"))
			{
				for (int i = 0; i < MAX_BLEND_ITEM_VALUE; ++i)
				{
					v = strtok(NULL, delim);
					if (!v)
					{
						fclose(fp);
						return false;
					}

					blend_item_info->apply_prob_sum += std::stoi(v);
					str_to_number(blend_item_info->apply_prob[i], v);
				}
			}
			else if (0 == strcmp(key, "duration_prob"))
			{
				for (int i = 0; i < MAX_BLEND_ITEM_VALUE; ++i)
				{
					v = strtok(NULL, delim);
					if (!v)
					{
						fclose(fp);
						return false;
					}

					blend_item_info->duration_prob_sum += std::stoi(v);
					str_to_number(blend_item_info->duration_prob[i], v);
				}
			}

 

// Search for
bool	Blend_Item_set_value(LPITEM item)

// Inside look for:
			if (item->GetVnum() == 51002) // energy crystal
			{
				apply_type = blend_info->apply_type;
				apply_value = blend_info->apply_value[FN_ECS_random_index()];
				apply_duration = blend_info->apply_duration[FN_ECS_random_index()];
			}
			else
			{
				apply_type = blend_info->apply_type;
				apply_value = blend_info->apply_value[FN_random_index()];
				apply_duration = blend_info->apply_duration[FN_random_index()];
			}


// Comment them or just replace them with this:
			apply_type = blend_info->apply_type;

			if (blend_info->apply_prob_sum)
			{
				apply_value = blend_info->apply_value[RandomFromProbs(blend_info->apply_prob, blend_info->apply_prob_sum)];
			}
			else
			{
				if (item->GetVnum() == 51002) // energy crystal
					apply_value = blend_info->apply_value[FN_ECS_random_index()];
				else
					apply_value = blend_info->apply_value[FN_random_index()];
			}

			if (blend_info->duration_prob_sum)
			{
				apply_duration = blend_info->apply_value[RandomFromProbs(blend_info->duration_prob, blend_info->duration_prob_sum)];
			}
			else
			{
				if (item->GetVnum() == 51002) // energy crystal
					apply_duration = blend_info->apply_duration[FN_ECS_random_index()];
				else
					apply_duration = blend_info->apply_duration[FN_random_index()];
			}

 

That's it, you're good to go.

I should mention that I didn't try it on the live server, just in the validation app, but everything should work just fine.

 

Example usage:

# this is just to prove that you don't have to add the probability stuff in all of them
# you can just add where you want to
#Blue Dew
section
	item_vnum	50825
	apply_type	ATT_BONUS
	apply_value	30	50	70	90	120
	apply_duration	60	120	180	300	600
end

#white dew
section
	item_vnum	50826
	apply_type	DEF_BONUS
	apply_value	40	70	100	150	200
# you can also add values like 0 1000 20 500 0
# it will just ignore the 0 and do the math for the other ones
	apply_prob	0	1000	200	150	90
# if you have something like this it will ignore the 0 
# and just give the one with a "valid" probability(the fifth, in this case - apply_value 200)
#	apply_prob 0 0 0 0 1
	apply_duration	60	120	180	300	600
	duration_prob	1	2	3	4	5
end

#energy crystal
section
	item_vnum	51002
	apply_type	ENERGY
	apply_value	1	3	5	7	10
	apply_duration	7200	7200	7200	7200	7200
# and you don't have to add both probabilities(for duration and apply), you can just use one.. or none!
	apply_prob	10	50	10	20	10
end

 

Have fun and let me know if you have any problems with it!

Cheers!

 

Edited by Amun
More details about Randomi function
  • Metin2 Dev 5
  • Good 3
Link to comment
Share on other sites

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.