Randomizing the Randomizer

Enpherdaen
06 Oct 2017, 03:00

So I have a function that causes different objects to spawn randomly in different rooms. Thing is, it only spawns one of them in. I could manually tell the function the add more than just 1, but then it'd spawn in the exact number I typed in every time that object has been chosen to spawn in. How do I get Quest to randomly decide whether it will spawn in 1, 2, 3, etc.of the same object rather than just one?


Amochure
06 Oct 2017, 06:47

I noticed it has a dice roll function. Could that be helpful?


The Pixie
06 Oct 2017, 07:39

Spawn then inside a loop:

for (i, 1, GetRandomInt(1, 3)) {
  SpawnThing
}

mrangel
06 Oct 2017, 09:43

(sorry, this post ended up being longer than I intended. Feel free to ignore. Also, edited for typo)

There are different ways to generate a random number. And different ways might "feel" more random to the player in different situations. I normally end up trying different methods until I hit on the one that seems natural. Here's some of the ones I've used:

while (RandomChance(60)) {
  code that spawns a thing goes here
}

↑ Means there's a 60% chance of getting one or more objects, 36% of getting 2+, 21.6% change of 3+, and so on.

Or with independent items:

if (RandomChance(50)) {
  CloneObjectAndMove (stick, room)
}
if (RandomChance(30)) {
  CloneObjectAndMove (stone, room)
}
if (RandomChance(3)) {
  CloneObjectAndMove (gold nugget, room)
}

The system I'm currently poking on my own has an unreachable room called "prototypes" containing all the objects that I might want to clone into the forest; and I've given them an attribute "spawn_chance_forest" that determines their chance of showing up in any given room, and "spawn_multiple" which governs the chance of showing up more than once in the same room. Then I use:

foreach (room, list_of_forest_rooms) {
  possible_objects = NewObjectList()
  objects_created = 0
  foreach (o, GetDirectChildren(prototypes)) {
    if (HasInt(o, "spawn_chance_forest")) {
      list add (possible_objects, o)
      if (not HasInt(o, "number_spawned")) {
        o.number_spawned = 0
      }
    }
  }
  while (ListCount(possible_objects) > 0) {
    objects_created = objects_created + 1
    object = PickOneObject(possible_objects)
    list remove (possible_objects, object)
    count = o.number_spawned
    if (object.spawn_chance_forest < GetRandomInt(count, 15*objects_created)) {
      o.number_spawned = count + 1
      CloneObjectAndMove (o, room)
      if (HasInt(object, "spawn_multiple")) {
        if (RandomChance(object.spawn_multiple)) {
          list add (possible_objects, object)
        }
      }
    }
  }
}

... that's a pretty complex way to do it, but efficiently handles scattering multiple objects through multiple rooms.


Enpherdaen
06 Oct 2017, 15:50

This is how my function looks like:

  CloneObjectAndMove (Large Leaves, player.parent)
}
if (RandomChance(50)) {
  CloneObjectAndMove (Stones, player.parent)
}
if (RandomChance(50)) {
  CloneObjectAndMove (Sticks, player.parent)
}
if (RandomChance(10)) {
  CloneObjectAndMove (Aloe Vera, player.parent)
}
if (RandomChance(10)) {
  CloneObjectAndMove (Sap Tree, player.parent)
}
if (RandomChance(10)) {
  CloneObjectAndMove (Boar, player.parent)
}
CloneObjectAndMove (Trees, player.parent)
if (RandomChance(50)) {
  CloneObjectAndMove (Worm, player.parent)
}
if (RandomChance(10)) {
  CloneObjectAndMove (Thorn Bush, player.parent)
} 

Mrangel, are you saying I should do while (RandomChange(60)) {in the room itself, and then add then call this function within it?


mrangel
06 Oct 2017, 19:28

On the random chances, changing "if" to "while" will allow more than one of the same item to appear, in a way that can feel like a natural distribution. There are more complex ways to do it, but you might find that's all you need.


Enpherdaen
06 Oct 2017, 20:06

Yes but, what else? Are you saying I should do while (RandomChange(60)) {in the room itself, and then add then call this function within it?


hegemonkhan
06 Oct 2017, 21:02

wow, ingenious use of 'while' with 'RandomChance', that's really cool, never knew this could be done!

the RandomChance continues, so long as its successful, that's really cool!


another simple use of the randomization functions:

(the common 'item drop' functionality in rpgs)

use 'GetRandomInt' to select an item from a list, and then you can use 'RandomChance' to determine whether you actually get that item or not.


mrangel
06 Oct 2017, 21:13

Yes but, what else?

I don't think there is any else.

I posted a couple of different methods. Now that I've seen your original code, I think the simplest one is going to be changing "if" to "while". So you get something like:

while (RandomChance(50)) {
  CloneObjectAndMove (Stones, player.parent)
}
while (RandomChance(50)) {
  CloneObjectAndMove (Sticks, player.parent)
}
while (RandomChance(10)) {
  CloneObjectAndMove (Aloe Vera, player.parent)
}
while (RandomChance(10)) {
  CloneObjectAndMove (Sap Tree, player.parent)
}
while (RandomChance(10)) {
  CloneObjectAndMove (Boar, player.parent)
}
CloneObjectAndMove (Trees, player.parent)
while (RandomChance(50)) {
  CloneObjectAndMove (Worm, player.parent)
}
while (RandomChance(10)) {
  CloneObjectAndMove (Thorn Bush, player.parent)
} 

Enpherdaen
06 Oct 2017, 23:02

What does changing one word do though?


jmnevil54
07 Oct 2017, 15:04

While = doing everything at the same time.

Minor, but important difference!


mrangel
07 Oct 2017, 15:11

Changing 'if' to 'while' just means it can happen more than once. Imagine tossing a coin for it; every time you get heads, you add a stone and flip again. When you get tails, it's time to move on to the next type of item.

While = doing everything at the same time.

Not in programming.


Enpherdaen
07 Oct 2017, 15:28

But how does it know what the chance of spawning in more than 1 of the same item is?


mrangel
07 Oct 2017, 16:27

Same as the chance of spawning the original. It keeps on using the same RandomChance.
You can make them different if you want, it just takes a little more code.


hegemonkhan
07 Oct 2017, 17:55

for example:

while (RandomChance(50)) {
  CloneObjectAndMove (Stones, player.parent)
}

you got a 50% chance ('effectively a coin toss') of the 'cloneobjectandmove' happening, and so long as you're successful, it'll keep doing the 50% chance ('coin flip') for more chances of doing the 'cloneobjectandmove', but the moment it fails (the 50% chance / 'coin flip' fails to do the 'cloneobjectandmove'), it ends, no more 'flipping of the coin'.

so, if you had godly-luck, it'd keep succeeding forever... and crash quest as an infinite loop, lol.


jmnevil54
07 Oct 2017, 19:34

My mistake.

Why would you do it multiple times, though?


Enpherdaen
07 Oct 2017, 22:11

Oh! I see now. Wow such a simple and clever solution.