What I’m trying to accomplish is getting more control over my random event selection system. I’ve already come up with something that produces decent-ish results. It picks a random event from my event folder, then saves that event in a variable. When it comes time to pick a new event, it refers back to that variable so it can avoid picking the same event twice in a row.
Below is the code for it:
function pickEvent()
local p -- soon to be the chosen event
local ch = evFolder:GetChildren() -- evFolder is a folder with all the events
local n = 1
-- the variable prevEvent stores the numerical value of the last event
-- it defaults to -1 if there hasn't been a previous event
if prevEvent ~= -1 then
-- hacky solution to "skip" the previously selected event
n = math.random(1, #ch-1)
if n >= prevEvent then n += 1 end
else
-- don't bother with that if there was no previous event
n = math.random(1, #ch)
end
-- set prevEvent so it doesn't get chosen next time
prevEvent = n
-- and set p to the actual event object
p = ch[n]
--miscellaneous attribute stuff just ignore this bit
local des = p:GetAttribute("DestroyOnEnd")
local dur = p:GetAttribute("Duration")
local icon = p:GetAttribute("IconAsset")
return {p, des, dur, icon}
end
This seems alright until you get a sequence of events like this:
Blotch
Laser
Blotch
Barrage
…Blotch
Conveyor
…Blotch again.
You get the picture. What I want is to make a new random event picker that keeps track of all events and how long it’s been since they’ve been picked, allowing me to set a “round counter” for every event that prevents it from being chosen again and ticks down each round. That way, I can say something like “after an event is chosen, 5 new events will need to pass before it can be chosen again.”
I’ve thought of a possible solution that would require a 2d table where every event has a numerical value that starts at zero, gets set to some numerical value when the event is chosen, then increments down after every subsequent event. The event picker would only pick events that have a zero for their value.
I want to know if this is a good solution, how possible it is to make, and possibly even how I’d go about making it. Thank you!
I dont know what the variable prevEvent holds, so I just made a new function to make it.
local cooldownDuration = 5 -- Set the desired cooldown duration
local lastEvents = {}
function pickEvent()
local events = evFolder:GetChildren()
local availableEvents = {}
-- Get list of available events (not in the last cooldownDuration events)
for increment, event in ipairs(events) do
if #lastEvents < cooldownDuration or not table.find(lastEvents, increment) then
table.insert(availableEvents, increment)
end
end
-- If all events have been chosen in the last cooldownDuration events, reset the lastEvents table
if #availableEvents == 0 then
lastEvents = {}
availableEvents = events
end
-- Randomly select an event from the available ones
local chosenEvent = math.random(1, #availableEvents)
-- Add the chosen event to the lastEvents table
table.insert(lastEvents, chosenEvent)
-- Remove the oldest event if the lastEvents table exceeds the cooldownDuration
if #lastEvents > cooldownDuration then
table.remove(lastEvents, 1)
end
return chosenEvent
end
-- Example usage
for _ = 1, 8 do
print(pickEvent())
end
This just in, I was able to find a solution on my own, just took a bit of brainstorming.
Here’s the code:
-- this choiceList would be the children of the event folder in an actual use case
local choiceList = {"A","B","C","D","E"}
-- this table stores every choice as well as a "current cooldown" value
-- assigned to every event -- A.K.A. where the magic happens
local lastEvents = {}
-- initialize the lastEvents table
for _, v in pairs(choiceList) do
table.insert(lastEvents, {v, 0})
end
-- the table should now look like this:
-- {{"A",0},
-- {"B",0},
-- {"C",0},
-- {"D",0},
-- {"E",0}}
-- how long an event must wait until it's picked again
local cooldown = 1
function pickEvent()
local availableEvents = {}
local chosenEvent
-- initialize the availableEvents table
for i, v in pairs(lastEvents) do
if v[2] == 0 then
-- if an event's current cooldown is zero, it is a valid choice
-- and can be added to the pool of available events
table.insert(availableEvents, {v[1], i})
-- we also store the event's position in the lastEvents list
-- so we can access it later
else
-- if an event has a non-zero cooldown value, it's currently
-- on cooldown and can't be picked, instead decrease it's cooldown by one
v[2] -= 1
end
end
-- choose a random item from the list of availableEvents
chosenEvent = availableEvents[math.random(1, #availableEvents)]
-- using the table position we saved when initializing availableEvents we can go
-- back to lastEvents and set the chosen event's cooldown to our cooldown value
lastEvents[chosenEvent[2]][2] = cooldown
return chosenEvent[1]
end
while wait(1.75) do
print(pickEvent())
print(lastEvents)
end
I’ll keep this post open for the time being if anyone has any further questions about this code.