RPG drop chance using irandom

emicarra

Member
Hello, i have a question, i'm using irandom when monsters die to make them drop ceratin items:

if(irandom(20)==1){
//drop sword
}
if(irandom(300)==1){
//drop ultra rare object
}

The problem is, sometimes only after killing a few monsters, i get one or two ultra rare objects, where that should be almost impossible if the chances of dropping 1 ultra rare object is 1 in 300, does anyone know what could be happening?
 

TsukaYuriko

☄️
Forum Staff
Moderator
A low chance of something happening doesn't mean that it will never happen.

If you suspect something is wrong, run the drop code in a loop some tens of thousands of times and tally how much of what is being dropped in total. Then compare this to how frequently it is supposed to be dropping.
 

emicarra

Member
A low chance of something happening doesn't mean that it will never happen.

If you suspect something is wrong, run the drop code in a loop some tens of thousands of times and tally how much of what is being dropped in total. Then compare this to how frequently it is supposed to be dropping.
Thanks for the response, yeah i did that, and it worked as intended, got 6 ultra rare items in 1200 tries, i just thought it might be something wrong with using irandom(chance)==1 because the chances of that happening is like %0.01, i killed like 10 monsters and got 3 ultra rare items which chance is 1 in 300 and one item which chance is 1 in 80, idk, maybe i just got a very lucky seed
 

Neptune

Member
I try to avoid == wherever possible, not because you can't use it... but <= is a lot of time preventative for errors.
Honestly your code looks fine though. Often times the closer you get to true random, the less random it seems to the human brain.
GML:
if random(100) <= 1 {} //1 in 100

if random(300) <= 1 {} //1 in 300
 
I try to avoid == wherever possible, not because you can't use it... but <= is a lot of time preventative for errors.
Honestly your code looks fine though. Often times the closer you get to true random, the less random it seems to the human brain.
GML:
if random(100) <= 1 {} //1 in 100

if random(300) <= 1 {} //1 in 300
he's using irandom, so that makes no difference.
The point is 1/300 is not rare at all, let alone "Uber-ultra-rare".
Diablo had drop rates of 1/100000+ on the rarest items, Pokemon has a 1/4000+ chance of being Shiny, and you have 1/millions chances of winning the lottery...
 

Neptune

Member
Well you don't expect 3 / 10 with odds of 1/300 ... But that's how random works. It doesnt like to stick to exactly 1 in 300... It is chaotic. But usually over the course of a few thousand data sets, it will average out to about 1 in 300 :)

The rarest drop in my game is 1 in 240,000 and when I crunch the numbers, it often doesnt happen until after millions of tries.
 
Well you don't expect 3 / 10 with odds of 1/300 ... But that's how random works. It doesnt like to stick to exactly 1 in 300... It is chaotic. But usually over the course of a few thousand data sets, it will average out to about 1 in 300 :)

The rarest drop in my game is 1 in 240,000 and when I crunch the numbers, it often doesnt happen until after millions of tries.
Agree, GM is notoriously shady in the random department.
There's ways to make it a little better, tho, like averaging a couple of rolls, and stuff like that.
True randomness in CS is totally a subject of it's own.
 

Neptune

Member
A roll average is pretty clever.
I don't mind the chaotic random, if it averages out to the odds I intended over large data sets, that's good enough for most everything I do.

Humans expect more orderly random a lot of time.
I think I read Apple ipod users complaining their shuffle playlist kept playing the same song... So they changed the random to make it smart-random 😂
 
I think I read Apple ipod users complaining their shuffle playlist kept playing the same song... So they changed the random to make it smart-random 😂
I remember that!! The first generation of those iPods mini (or nano...those with a screen), they would shuffle in "range"...say you were on track 24, the next one would always be within 14-34...that was quite annoying, indeed
 

woods

Member
yeah i would deff up the numbers for the "uber-awesome-epic-rare-drop"

1 in a million sounds legit..
can even drop things into separate loot tables..
ex:
1 in 1000 = rare drop
then in the rare drop table, you'd have 1 in 1000 again to get X item


===
its not ultra rare if everyone has one ;o)
 
Also, building loot drops for RPGs is usually a bit more complicated than simply rolling a random number. Generally there's pools within pools and things like guaranteed drops (though what the guaranteed drop will be is selected from a sub-pool), as well as shaping the randomness with functions, etc, etc. Here's a brief overview of the sort of things that are commonly used (though it can get waaay more complex than this): https://www.gamasutra.com/blogs/DanielCook/20141215/232300/Loot_drop_best_practices.php
 

FrostyCat

Member
he's using irandom, so that makes no difference.
The point is 1/300 is not rare at all, let alone "Uber-ultra-rare".
Diablo had drop rates of 1/100000+ on the rarest items, Pokemon has a 1/4000+ chance of being Shiny, and you have 1/millions chances of winning the lottery...
It does make a difference, and the original poster got it wrong.

irandom(N) returns integers from 0 to N inclusive, which anyone familiar with counting patterns knows is N+1 different outcomes. Assuming that it is a uniform distribution, checking irandom(N) <= 1 has an actual probability of 2/(N+1), not the desired 1/N.

random(N) returns real numbers from 0 (inclusive) to N (exclusive). Assuming again that it is a uniform distribution, checking random(N) <= 1 is almost exactly reflective of 1/N.

On top of that, the original poster has a yin-yang if block problem, which in rare situations will trigger both drops at once.

A better strategy is a categorical distribution dependent on a single random variable.
GML:
var rand = random(1);
if (rand < 1/300) {
    // Drop ultra rare (1 in 300)
} else if (rand < 1/300+1/20) {
    // Drop sword (15 in 300)
}
 
It does make a difference, and the original poster got it wrong.
Yeah, but I meant that in the sense that "try to avoid == because of possible errors" is more or less relevant if he uses irandom, as it will always return an integer.
Maybe I was assuming, but I thought @Neptune was referring to such behavior as when using "==" with, say, image_index, or some such, which can unintuitively be float.
 

TheouAegis

Member
1 in 300 itself isn"t too bad for rarity's sake. Yeah, nowadays we have drop rates in the micropercentiles, but anyone who played an old Final Fantasy or IGAvania game knows how brutal 1 in 256 can be, or even 1 in 8.

There are frequently drop tables used, usually for each enemy. A goblin might only "carry" a potion and a dagger, so its drop table will be just those two items. When the goblin is defeated, the game could roll a d8, giving the rarer drop if the result is 1 (or 0 in coding terms). A tougher enemy might have just one item in its drop table, with that item listed in the "rare" position, so there would be a 7 in 8 chance of getting nothing from that enemy. Those might seem like ridiculously high odds, but they were mitigated by low encounter rates. You might have a 1 in 8 chance of finding an Economizer on a Brachiosaurus, but you only have a 1 in 16 chance of encountering said enemy in one particular location, with a 7 in 8 chance of getting nothing at all. And those dropless encounters can get demoralizing.

If all your enemies have a 1 in 300 chance to drop a rare sword, it's not that rare, is it? But if only one enemy can drop it, then that 1 in 300 chance is significant. And if that enemy is challenging or has a very low appearance rate, 1 in 300 is nothing to scoff at. Diablo needs ridiculously low drop rates because every enemy shares the same inventory and there are thousands upon thousands of enemy encounters, with even bosses able to be farmed like livestock.
 
Top