PRD (Pseudo Random Distribution) is a randomness mechanism widely employed in various games, enhancing the uniformity and smoothness of random outcomes.
Taking the example of "a 10% critical hit probability," if it were a true random distribution, it might seem like a critical hit occurs once every ten attacks, but in reality, there are always unlucky players who might attack hundreds or even thousands of times without landing a single critical hit, because the probability remains 10% for each individual attempt. These unlucky players will have a very poor gaming experience.
The principle of PRD is that the initial probability is set below 10% (in this case is 1.5%). If a critical hit does not occur, the probability for the next attempt is significantly increased, and this process continues until a critical hit is successfully landed, at which point the probability resets. As a result, PRD mitigates many extreme scenarios, preventing both streaks of continuous critical hits and misses. You can find a more detailed explanation on the
DOTA2 wiki.
CODE:
PHP Code:
//Pseudo Random Distribution
#define PRD_5 0.003801658303553139101756466
#define PRD_10 0.014745844781072675877050816
#define PRD_15 0.032220914373087674975117359
#define PRD_20 0.055704042949781851858398652
#define PRD_25 0.084744091852316990275274806
#define PRD_30 0.118949192725403987583755553
#define PRD_35 0.157983098125747077557540462
#define PRD_40 0.201547413607754017070679639
#define PRD_45 0.249306998440163189714677100
#define PRD_50 0.302103025348741965169160432
#define PRD_55 0.360397850933168697104686803
#define PRD_60 0.422649730810374235490851220
#define PRD_65 0.481125478337229174401911323
#define PRD_70 0.571428571428571428571428572
#define PRD_75 0.666666666666666666666666667
#define PRD_80 0.750000000000000000000000000
#define PRD_85 0.823529411764705882352941177
#define PRD_90 0.888888888888888888888888889
#define PRD_95 0.947368421052631578947368421
enum struct PRD
{
float factor;
float round;
void SetFactor(float factor)
{
this.factor = factor;
this.round = 1.0;
}
void ResetRound()
{
this.round = 1.0;
}
bool IsHit()
{
if(GetRandomFloat(0.0,1.0) <= this.factor * this.round)
{
this.round = 1.0;
return true;
}
this.round += 1.0;
return false;
}
}
EXSAMPLE:
PHP Code:
PRD crit_prd[MAXPLAYERS+1];
//Init all players' critical hit rate to 10%.
public void OnPluginStart()
{
for(int i = 1;i < MaxClients+1;i++)
{
crit_prd[i].SetFactor(PRD_10);
}
}
//Reset all players' PRD cumulative status as needed (on player respawn, end of round, etc.)
public void OnMapStart()
{
for(int i = 1;i < MaxClients+1;i++)
{
crit_prd[i].ResetRound();
}
}
Action Command_TestPRD(int client, int args)
{
if(crit_prd[client].IsHit())
{
PrintToChatAll("Critical Hit!");
}
else
{
PrintToChatAll("Not Critical Hit.");
}
//Test And Print PRD Nominal Chance
TestPRD(PRD_5);
TestPRD(PRD_10);
TestPRD(PRD_15);
TestPRD(PRD_20);
TestPRD(PRD_25);
TestPRD(PRD_30);
TestPRD(PRD_35);
TestPRD(PRD_40);
TestPRD(PRD_45);
TestPRD(PRD_50);
TestPRD(PRD_55);
TestPRD(PRD_60);
TestPRD(PRD_65);
TestPRD(PRD_70);
TestPRD(PRD_75);
TestPRD(PRD_80);
TestPRD(PRD_85);
TestPRD(PRD_90);
TestPRD(PRD_95);
return Plugin_Handled;
}
void TestPRD(float factor)
{
PRD prd;
prd.SetFactor(factor);
int total;
int r;
int min= 999999999,max = 0;
for(int i = 0;i < 10000;i++)
{
r = 0;
while(!prd.IsHit())
{
r ++;
}
r ++;
if(min > r)
{
min = r;
}
if(max < r)
{
max = r;
}
total += r;
}
PrintToServer("Avg P = %.2f%%, min round = %i, max round = %i",(10000.0/total)*100.0,min,max);
}