Ever notice how most Zelda games only drop items from bushes if you've encountered that item before?
- You'll only get Deku seeds if you have the Fairy Slingshot
- You'll only get arrows if you have the Hero's Bow
- You'll only get magic pots if you have the sword-spin attack or a Goddess' spell
etc. etc.
Here's how to do that in Game Maker, and also simplify random-item-dropping in general, using a dynamic luck system. I developed this for Two Swords and just now got the crazy idea to share a version of it. There's no downloadable example here because A) There are too many options you can change as far as available items, and B) You need to understand it to use it.
Let's set it up!
First of all, somewhere around the beginning of the game, set your variables that affect which items will drop from bushes. Then, after those, call a script that's about to be made. Example:global.got_magic=false;
global.got_bow=false;
scrLuckInit();
Now, you need a script to initialize what items are available from bushes, and the "weight" given to each one. Note: weights are not percentages. If you have two items with a weight of 50, then each will have a 50/100 (50%) chance of being dropped. But if you have three items, all weighing 50, then the chance for each will be 50/150 (33.3%). This lets you adjust individual weights without having to fix all the others. Weights should be whole numbers.// scrLuckInit
var i,ii;
i=0;
// random item declaration:
global.luck[i,0]=300; global.luck[i,1]="none"; i+=1;
global.luck[i,0]=50; global.luck[i,1]=objRupeeGreen; i+=1;
global.luck[i,0]=18; global.luck[i,1]=objRupeeBlue; i+=1;
global.luck[i,0]=6; global.luck[i,1]=objRupeeRed; i+=1;
global.luck[i,0]=3; global.luck[i,1]=objRupeeBigGreen; i+=1;
global.luck[i,0]=22; global.luck[i,1]=objHeart; i+=1;
global.luck[i,0]=8; global.luck[i,1]=objHeartPiece; i+=1;
if global.got_magic {
global.luck[i,0]=15; global.luck[i,1]=objMagic3; i+=1;
}
if global.got_bow {
global.luck[i,0]=40; global.luck[i,1]=objArrow1; i+=1;
global.luck[i,0]=16; global.luck[i,1]=objArrow3; i+=1;
}
// random item preparation:
global.luckitems=i;
for (ii=1; ii<i; ii+=1) {
global.luck[ii,0]+=global.luck[ii-1,0];
global.lucktotal=global.luck[ii,0];
}
You can have as few or as many of those declaration lines as you like, but I strongly recommend keeping "none" as the first item. Note that the last three fall under conditions, so they'll only be included in the total if you have magic and/or the bow.
The first line of preparation saves the number of different random items (including "none"), since you'll need to know that for later. The loop following that accumulates the weights in a way that:
global.luck[0,0]=300
global.luck[1,0]=50
global.luck[2,0]=18
global.luck[3,0]=6
Becomes:
global.luck[0,0]=300
global.luck[1,0]=350
global.luck[2,0]=368
global.luck[3,0]=374
And so on. This is done to "tier" the items so that you can easily find which range a random number falls between. The last line also records the highest tier number to a global variable, so that a random number can be chosen between 0 and that number.
To make luck dynamic:
At any point in the game where you gain a new item or ability that would change which random items are available, just call the script scrLuckInit() again, and luck will be re-initialized.
So how do we use this?
Ah, I see you're a sharp one, we still need a way to turn a random number into an item. Make a new script called scrLuck. This script will be called from a bush's Destroy event, or any other event where a random item should drop.
// scrLuck
var lucknum,i;
lucknum=floor(random(global.lucktotal+argument0)-argument0);
for (i=0; i<global.luckitems; i+=1) {
if lucknum<global.luck[i,0] {
if !is_string(global.luck[i,1]) { instance_create(x,y,global.luck[i,1]); }
break;
}
}
lucknum is a random whole number, between 0 and (global.lucktotal-1) inclusive. What's argument0 doing there? Just an extra feature I added that I'll explain in a moment.
The loop then checks through each of the random items available, and sees if the random number falls under its tier. If it does, and the item is something other than a string ("none"), then it will be created. The break just ends the loop, since no more checks need to be made.
So don't forget:
scrLuckInit(); at the beginning of the game and any time when different luck items are available.
scrLuck(); any time you want to drop a random item. (it appears at the same position as the object which calls the script)
Back to that "extra feature":
argument0 allows you to offset the random number, making it more or less likely that you'll receive an item. In most cases you won't need to worry about entering an argument, since typing scrLuck(); is the same as typing scrLuck(0);.
The number you enter as argument0 is how much will be added to the first teir of items (this is why I recommended that "none" by the first). In Two Swords, you will be less likely to get a random item if the bush is burned, rather than cut. So if the bush is burned, it's Destroy event will contain: scrLuck(200);, which adds an extra 200 to the weight of "none" (not permanently - only for this random draw). Conversely, if you want to make sure that you always get an item, and the normal weight of "none" is 300, then do: scrLuck(-300);.
So that's about it. I'll post a few mods shortly and answer any questions.
Feel free to use, please give credit, and do me proud!