SymCity is meant to be a sandbox game that allows player to explore the world at their own pace. To add variations to the world, it has to evolve with the player's exploration. The most obvious choice of variation is to modify the world with events - and naturally scheduled events plays a fundamental role.
The concept of schedule event is simple:
Player's actions advances time, and at designated times, events will be triggered: locations become accessible; character moves to different location etc.
There're different ways of doing this depending on the scale of the game - you could have nested conditions setup in your game if it's fairly linear. I suspect a lot of story driven RAGS games with "day" counters use this approach, by defining specific times when certain events will be triggered.
For a sandbox game, this is just won't do.... So let's try something else. For my approach to this problem (credits to Anonymous's suggestion as well on TPoC blog earlier this year), we'll need:
Time_now - A time variable.
This is a Date Time variable, so we can do simple operations like "add minutes" or "add hours" to it. This is basically what day and time it is in the game world.
Schedule_List - A multi-dimensional array that keeps track of the schedule.
The MDA holds the scheduled time, threshold time, schedule pattern, timer name and variable name. The list is always kept in ascending order. More explanations later.
Active Timer: Schedule-Checker - Checks the Time_Now against Schedule_List
As the schedule list is in ascending order, this timer just does a while loop to see if the first "scheduled time" on the array is due for processing, if so, it calls the next timer:
Inactive Timer: Schedule-Trigger - Manipulates the Schedule_List array
This is where the magic happens. This timer checks the "threshold time" to see whether we still want to execute the associated event. This is due to the nature of some actions / events potentially taking up several hours - by which point we might not actually want to execute the event anymore.
If we want to execute the event - then we simply execute the timer by name stored in the array, and supply suitable variable to it.
Next we need to remove the top item from the Schedule_List array, because it's been expired (whether we triggered the event or not). But first we have to determine the next scheduled time and threshold time, using the schedule pattern.
Since this next part is purely to manipulate the array data, I do it by javascript. Read the schedule pattern, calculate the next scheduled time and threshold, push it to the end of the array, sort the array and return it. Now we have the next scheduled event on the top of our list!
RAGS Code below.
Timer Schedule-Checker:
Variable: Set (Javascript): aStr1, [true if Time_Now > Schedule_List(1)(0)]
Loop: While: aStr1 Equals True
Timer: Execute Timer: Schedule-Trigger
Variable: Set (Javascript): aStr1, [true if Time_Now > Schedule_List(1)(0)]
Timer Schedule-Trigger:
Variable: Set (Javascript): aStr1, [true if Time_Now > Schedule_List(1)(1)] //passed threshold time yet?
Variable: Comparison: aStr1 Equals False
Variable: Set: TM_[v:Schedule_List(1)(8)], [v:Schedule_List(1)(9)]
Timer: Execute Timer: [v:Schedule_List(1)(8)]
Variable: Set (Javascript): Array: Schedule_List, [pop the first schedule, refill the schedule time if next available time exists, set threshold time, push back to array, sort and return]
Note 1: I actually cheat a little with my array by having titles on the first row, so rather than calling picking Schedule_List(0)(0) for the first scheduled time, I pick Schedule_List(1)(0) which is actually the second row.
Note 2: Rather than setting and retrieving Timer Custom Properties, I opted for using variable variables for quicker variables setting. All Timer's variables are named TM_[Timer Name]
I realised after writing this post that I should probably allow empty thresholds, and if threshold time is empty, then execute the event regardless. But hopefully this gives you some ideas of how to schedule events in your RAGS game.
I'm not releasing the code for this because the Javascript to calculate the next scheduled time is highly specific to SymCity's needs (I took some shortcuts) - so it's not a fully featured javascript function. If you're able to tweak it to your needs, you can probably code it from scratch (it's 2000 characters long); if you can't, then it's probably best you avoid it.
If you really want to play with scheduler but are not confident in coding the "next scheduled time" with javascript, you can always just build a list using actual time and skip the schedule pattern.
Hope this is of use to some of you guys :)