RMDC #1: Dynamically Ordered Choice Selections
Suppose you have an NPC that displays a list of options for the player to select from. The catch: each option has a condition that must be satisfied to appear, and the order that the options appear is based on the order that the conditions were satisfied.
Introduction
The RMDev Challenge is a series of articles that presents a problem for RPG Maker developers and the objective is to find a solution.
The purpose is to engage RPG Maker developers in some (possibly practical) problem-solving that will allow them to explore more of what the engine has to offer, and also to see how others implement the same solution.
The rules are simple: provide a solution that works in a version of RPG Maker of your choice. You can use anything at your disposal: events, pictures, ruby scripts, external libraries, etc.
You may present your solution however you wish (comment, blog post, video, etc) and wherever you wish, but I ask that you leave a link back to this article if you are sharing a solution on external sites. I also recommend sharing the solution on external sites and leaving a link in the comments because the comment section is too small for details. Remember: you want to share with others your solution.
Challenge
Suppose you have three villages in your world creatively named Village A, Village B, and Village C. I will refer to these villages as A, B, and C for brevity.
To make traveling around the world faster, you have a teleportation device in your castle that allows you to teleport to a village that you have visited. Initially, none of the villages are available.
Once you visit a village and record its position, you may now teleport to that village using the device.
The order that the villages appear in the teleport menu is based on the order that you visited the villages. For example, if you visited A, then B, then C, the options would appear in that order.
On the other hand, if you visited A, then C, the A would appear first, followed by C.
You can see that Village B isn’t available. This is because you haven’t visited it yet.
Finally, after you visit B, you would now see A, followed by C, followed by B.
This reflects the order that the villages were visited during your game.
Note that the solution does not strictly need to be presented as the default choice selection (these images were generated for illustration purposes only)
Here’s my solution: http://himeworks.com/2014/12/my-solution-to-rdmc-1/
And here’s mine. Fully functional demo download here…
http://s000.tinyupload.com/?file_id=15873384021531113518
And if you’re only interested in seeing the script work on it’s own that’s here.
http://pastebin.com/AzwyVmC1
I don’t think it’s too bad for two days of work, all the code in there is original. It was a little trickier to implement than I had originally anticipated. The main function runs off a single script call and meets all of the challenge criteria.
This looks really simple in principle. Duck-typing FTW. It could be done by a one-time condition triggered upon entering a village that pushes a variable into an array. Not sure where I’d stick the instance variable just yet. Probably the same module I’ll stick the custom methods in. Reference the specific positions in the unsorted array directly at the choice selection/effect method. Only thing I’m uncertain about is how to generate the choice boxes via a custom method. I’ll need to see about figuring out how to generate choices via a custom method in a script call.
Ought to be interesting, it’s on my to-do list and I’ve only seen info take glancing blows at this sort of thing because it’s “too complicated” and there’s no way anyone could possibly want to actually do it.
The choice box is what I consider to be the hardest part of the challenge. Keeping track of visit order is mainly just an exercise.
Looking at the various entries, I think in general there is some consensus on how visit order should be tracked, either explicitly using numbers or just an array. But a lot of different approaches have been used to display the correct choices.
I think I have a rudimentary understanding of how the choices work and know how to hijack most of the functions for displaying it. I’m mainly trying to figure out the best way to create the when choice branches. So long as I can figure out that part I can either encapsulate each choice in it’s own method and use a series of one line if statements to control the choice creation or try something a little more minimalist by initializing the array as a series of nil values, use the falsey as a condition and the array value as a method argument. Probably try the latter first since it seems like a more functional approach.
I’m not exactly sure how this would be achieved (I’m not a coder), but here’s some pseudocode/flow of events.
First we need a few things.
mapsVisited = 0
mapsOrder[]
mapsName[]
For RM’s sake (and my incompetency), let’s say these three are actually $game_variables[10], $game_variables[11], $game_variables[12] respectively.
Create an autorun event on each map that is teleport-enabled, that only runs once.
Have the autorun call a common event (for convenience) that writes the map’s ID and name, to the mapsOrder and mapsName array, like so:
$game_variables[11][$game_variables[10]] = $game_map.map_id
$game_variables[12][$game_variables[10]] = $game_map.name
This records the map’s id and name that you just visited, and stores it into their Arrays.
Then, have the event increments mapsVisited by 1.
$game_variables[10] = $game_variables[10] + 1
Make sure the autorun turns on a self-switch to disable it from running again.
This makes it so it “saves” the map order, letting you write the next map into the second/third slot and so on.
Now, on your teleporter NPC script call:
This is a script call to create choices. It’s recommended against, so probably scripting a Command Window would be much more efficient.
i = 0
max = $game_variables[10]
params = []
choices = []
while i < max do
choices.push($game_map.$game_variables[12][i].to_s)
i += 1
end
choices.push("Cancel")
params.push(choices)
params.push(max+1)
setup_choices(params)
This sets up the choices. The loop generates choices pulling them out of the array until the max is reached. Remember, $game_variables[12] is the mapsName array. The cancel command is placed after all the warp choices are created.
This next part I’m not entirely sure on, and may need to be scripted.
I know the choice command returns 0/1/2/3/whatever depending on which choice is selected. Let’s say this variable is called warp_choice_id. When the choice is executed:
$game_player.reserve_transfer($game_variable[11][warp_choice_id], 50, 50, 2)
This script call will move the player to the set map_id, at 50, 50, facing downwards. In this way, the first choice would return 0, which is the first map we’ve visited. 1 is the second. So on. The coordinates to be warped to can be also stored in another array, assuming all portals aren’t at 50, 50 on their respective map.
I hope this somewhat makes sense, it’s not a full solution, however.
Oops, that should be:
choices.push($game_variables[12][i].to_s)]
$game_map doesn’t work there, haha.
I forgot to mention in my eventing (above) that after the total of Visit A, Visit B, and Visit C are calculated in each village… the one of the three that corresponded with the present village would then increase by one. Like if all 3 were at zero, but then you visited village B… The calculation above would occur, but before the event shut off, Visit B would take on a +1. Then once you visited Village C… the totals of Visit A, Visit B, and Village C would be 1 during calculation, but toward the end of the event, Visit C would take on a +1. etc
Sadly, I am not good at scripting… but I can event like there’s no tomorrow. So if I was unable to pluck a script from somewhere that would allow me to accomplish this… I would rely strictly on eventing:
It would require a transfer event with 16 pages (conditional). There are only 15 possible orders, and one more page for if none are visited. Possible orders include: (A) (B) (C) (AB) (BA) (AC) (CA) (BC) (CB) (ABC) (ACB) (BAC) (BCA) (CAB) (CBA). One variable would be used to determine the correct page.
We will call this variable: Port Choice.
Three additional variables will be used for each village, they should be a range (Ex – 0020, 0021, 0022) We will call these: Visit A, Visit B, Visit C.
Each town would have a parallel process map event, with 2 pages. The first would add the values of Visit A, Visit B, and Visit C. In Village A, if the total is zero, then +1 to Port Choice. If the total was 1, then +10 to port choice, and if the total was 2, then +100 to Port Choice.
After this, the Paralell process would have a self switch to turn itself off.
Village B would have the same conditional, except that total zero would be +2, total one would be +20, and total 2 would be +200.
Village C, total zero would be +3, total one would be plus 30, and total 2 would be +300.
Thus, depending on the order you visit the villages, Variable Port Choice total would be one of 15 possibilities: (1) (2) (3) (12) (13) (21) (23) (31) (32) (123) (132) (213) (231) (312) (321).
Create the transfer event with 16 pages, the first being non-responsive as no villages have been visited. The rest are based on variable Port Choice, and the resulting number.
Finally, each page would have the appropriate Choices/order available to display.
This would work well so long as we are only dealing with 3 choices. 4 would be more difficult. 5 or more and the system becomes nearly impossible.
But… this challenge as is it is stated, is solved.
Yes, while the solution is not scalable, depending on the situation it might not be worth the effort to try and come up with a scalable solution when you know that you're not going to need it anyways. In other situations, you might not even have the option of introducing things like scripts.
I'd like to say I took this into consideration when I wrote the challenge but it was mainly because I didn't want to have to create 4 or more villages in my examples. In the future, however, I will take into consideration event limitations and attempt to make it so that evented solutions are feasible enough to do so it wouldn't be biased things towards scripting.
As a coder, I’d probably do some tinkering in code, and create a selection box that reads from a hashmap in the order that each element is added in. Each hash points towards the map id, x, and y coordinates for teleportation. http://matthew.mceachen.us/blog/multi-value-hashes-in-ruby-1114.html
I don’t think this is the easiest or most streamlined approach, and I definitely haven’t tried it out, but in theory it should work.