Tsukihime 1,487 Posted July 17, 2012 (edited) Event Wrapper -Tsukihime Overview This script provides a wrapper for the RPG::Event class and other related classes. It adds additional methods to allow you to create event commands directly without having to go through the event editor, and provides intuitive names that are based on the command names available on the event editor. This is mainly a scripting tool, and is not intended to replace the event editor. If something can be achieved using the event editor, use it. You will typically use this in your own scripts when you need to create events on the spot, especially if the event will be complex. Features Easily create events using scripts An Event Builder that helps you create your list of command events Use the Event Builder to mix scripting with event commands to create all sorts of event processing Create move routes using a Move Builder, using the same syntax as the Event Builder with intuitive move commands and some custom move commands for convenience (eg: move strings) Downloads Get it at Hime Works! If you are not sure where to start, I've provided some examples in the demo. Usage Currently, your scripted events are just scripts, so they are not very accessible. You must have an event on the map to be able to use a script call to create more events, though after that your custom events can create their own events provided that you've written the logic into their command list. You can choose to write methods in Game_Interpreter or just a custom module. As long as you can call the methods that will create the event. class Game_Interpreter def make_my_event # your event building code end end Creating an event is simple. 1. Instantiate an Event object, passing in x,y coordinates event = Event.new(2, 4)2. Set some page properties. For a list of properties, refer to the help manual, or look through the Event class. You can either access the properties directly, or use some convenience methods defined in the Event class. So for example, assuming we are on page 0, event.page[0].character_name = "actor1" event.character_name = "actor1" Both do the same thing.Some common properties you might set are event.priority_type = 1 # 1 is "same as characters". You can choose 0, 1, or 2 event.trigger = 2 # 2 is "event touch". It goes from 0 to 4, same order as in the editor event.direction_fix = true Note that the convenience methods always operate on the "current" page.When you first initialize a new event, the "current" page is 0. You can change the page by calling event.set_page(n)For some integer n. Thus, you may want to work on one page a time, as such: event.set_page(0) #do stuff for page 0 event.set_page(1) # do stuff for page 1 event.set_page(2) # do stuff for page 2 3. Set some page conditions. Refer to the Event_Condition class for details. event.condition.switch1_id = 2 # this means switch 2 must be ON event.condition.switch2_id = 3 # remember that the event supports two switches event.condition.actor_id = 4 # actor 4 must be in party 4. Add the event to the map $game_map.add_event(event) That should create an event on the map at the designated x,y coords when we make a script call to create this event, but it's not very useful. We want to add some event commands. I've provided an "Event Builder" that allows you to use a custom syntax to create your events in addition to regular ruby syntax. Simple example I have written a set of methods that essentially alias Game_Interpreter methods, except instead of using command codes, I use the common editor names to identify what the command is. All of the methods are available in the EventCommands class. So for example, let's write an event that will display a simple message event = Event.new(3, 3) event.character_name = "actor1" event.character_index = 2 event.build { show_text("actor1", 2) add_message("Hello World") } $game_map.add_event(event) When you create this event, you can talk to it and it will say "Hello World" Note that `add_message` can take multiple strings. Each string will be treated as a new line. event.build { show_text("actor1", 2) add_message("Hello World", "Goodbye") } Branching your commands The event builder supports branching, which is used in various commands such as showing a list of choices, conditional branching, and other things. event.build { show_text("actor1", 1) add_message("What do you like?") show_choices(["Health", "Mana"], 0) choice_branch(0) { show_text("actor1", 1) add_message("So you prefer health") } choice_branch(1) { show_text("actor1", 1) add_message("Mana is ok too") } } This example demonstrates how to using branching to create a list of choices that the player can select from, and how to define the commands that should be executed depending on the choice. Naturally, you can provide an unlimited number of branches, though the choice window is not designed for that (meaning, you might have choices that are drawn outside the screen if there are just too many) Mixing ruby with event commands It is also possible to use typical ruby syntax when building your commands. You know, take advantage of loops and variables. event = Event.new(x, y) event.character_name = "actor2" event.character_index = 5 event.build { show_text("actor2", 5) add_message("Which party member do you wish to view?") actors = $game_party.members.collect {|actor| actor.name } show_choices(actors, 0) $game_party.members.each_with_index { |actor, i| choice_branch(i) { show_text(actor.face_name, actor.face_index) add_message("%s is a level %d %s" %[actor.name, actor.level, actor.class.name]) } } } $game_map.add_event(event) This example demonstrates how you would write an event that will go through all of the actors in your party, display their names in a choice list, and then when you select an actor, it will display information about the actor in a text box. However, note that because this code is run only when the event is created, the event commands have already been hardcoded into the event. It is no different from manually creating an event and writing your own choice branches and such. Move routes Working with move routes is very similar to event commands. You create a MoveRoute object, and then build some move commands. event.build { route = MoveRoute.new route.build { move_up move_down(2) move("2L2R") } set_move_route(-1, route) } The move commands are pretty much the same as what you have in the editor, except I've added some additional options that make the lists easier to build. All methods are available in the MoveCommands class. Notes Conditional branches use the following commands cond_if (condition) cond_else I have decided to only support ruby statements as the condition to satisfy, rather than trying to map a dozen different options which would take some time to reference just to figure out which to use. Aside from using event.build, which might be too restrictive, I've provided an `EventBuilder` if you only want to create a list a commands. For example, if you are creating some custom quick events. command_list = EventBuilder.build { show_text add_message("hello") } You can then take that list and assign it to an event using event.list = command_list Reference The objects of interest are RPG::Event RPG::Event::Page RPG::Event::Page::Condition RPG::Event::Page::Graphic RPG::EventCommand RPG::MoveRoute RPG::MoveCommand All of these are described in the help manual under RGSS Reference Manual -> Game Library -> RPGVXAce Data Structures. Edited March 2, 2015 by Tsukihime 5 Allusion, Death10, oriceles and 2 others reacted to this Share this post Link to post Share on other sites
Death10 12 Posted July 18, 2012 (edited) Great, I miss the House System script in XP It just like this one Edited July 18, 2012 by Death10 Share this post Link to post Share on other sites
Tsukihime 1,487 Posted July 18, 2012 (edited) I'm not familiar with that system but I'm assuming it has something to do asking the user to make selections and then you create events and stuff on the spot. In theory, you could create arbitrarily anything into the game provided that you design the events to interact with the user flexibly. For example, a decoration system can be built by defining a set of "decoration" objects that are assigned to certain items. When you turn those items in, you can specify where to put the item, and then an event (or set of events) are dynamically created to represent the decoration. Each decoration would automatically be constructed with an event page that allows you to "retrieve" the decoration so that you can put it back in your inventory if you want to renovate your space. Rather than using a conventional event approach where you would have possibly 100 conditional branches, you can just use a single check and then create the decoration using an icon or a picture. Edited July 18, 2012 by Tsukihime Share this post Link to post Share on other sites
Kayzee 3,863 Posted July 18, 2012 So this is basically finished now? Neato! I think it would be helpful though if there was a command to load event pages from different events on the map... or even load event commands form common events, though how that would be more useful then just calling the common event I am not sure... unless perhaps you could modify the event commands? Share this post Link to post Share on other sites
Tsukihime 1,487 Posted July 18, 2012 I have not added support for modifying event commands at run-time. It can get messy... The general idea is to set a "rebuild" flag so that when the event refreshes, it also rebuilds its list of events. However, you have to use event.build { ... } rather than the standalone EventBuilder, because I need to store the block inside the event itself so that I can run it again when needed. Share this post Link to post Share on other sites
Kayzee 3,863 Posted July 18, 2012 What happens if you run self.build during a script command? Share this post Link to post Share on other sites
Tsukihime 1,487 Posted July 18, 2012 (edited) I don't think it would work. But I don't really know how instance_eval works well enough to say that without testing. Does it recurse? My response would probably be "don't do stupid things". It's not like people are going to go complain to microsoft for allowing them to write recursive code. Edited July 18, 2012 by Tsukihime Share this post Link to post Share on other sites
Kayzee 3,863 Posted July 18, 2012 I haven't tried it, it really depends on how it steps though the command list I would think. If it steps through and retrieves the command by index from the array each step, it could actually work. It would just get the next command in the list and continue where it left off. If it instead retrieves the command from the array's memory location without bothering to check if it was changed, it would fail until the next time the command is run or crash. Share this post Link to post Share on other sites
Tsukihime 1,487 Posted July 18, 2012 (edited) Interpreter gets the list and then starts iterating from there. So you can replace the list and it doesn't care. def run wait_for_message while @list[@index] do execute_command @index += 1 end Fiber.yield @fiber = nil end Only thing that you'd have to watch out for is the fact that if you replace a list, the page is still cached in the event, so you need to explicitly tell it to clear out its page and get a new one (which will probably be the same one since the conditions likely haven't changed) I would like to write a script that demonstrates how one would use this event wrapper, but I can't think of anything interesting to write. Edited July 18, 2012 by Tsukihime Share this post Link to post Share on other sites
Kayzee 3,863 Posted July 18, 2012 (edited) Oh yeah I forgot, you can give the interpreter any list you want, so changing the event page wouldn't effect the interceptor's list. How about writing a script that changes your followers into events for cut scenes? You could even make them sit around and do stuff. Yeah I know you could just use events that check if the actor exists but... Edited July 18, 2012 by KilloZapit Share this post Link to post Share on other sites
Tsukihime 1,487 Posted August 2, 2012 (edited) Script updated. I have finally decided on how to implement conditional branches, and I basically decided to take the easy way out. All conditions are just regular script conditions (eg: ruby statements) For example, def make_condition_event(x, y) event = Event.new(x, y) event.character_name = "actor1" event.character_index = 2 event.build { cond_if("$game_actors[1].level >= 5") { show_text("actor1", 2) add_message("Hello \\n[1]", "You have satisfied the level requirements!") change_followers(true) } cond_else { show_text("actor1", 2) add_message("Your level is below 5") } } $game_map.add_event(event) end You just pass in a string as your script call. I don't really want to bother with having a dozen different cases for every possible condition when you could just script it directly. My assumption is that if you're already writing scripted events, then you should be familiar enough with ruby to be able to write if/else conditions. Edited August 3, 2012 by Tsukihime Share this post Link to post Share on other sites
Tsukihime 1,487 Posted August 16, 2012 (edited) I've implemented a new way to work with the Event builder. It was a bad idea to make everything static variables and methods, because it just means you only have one command list stored in the builder at anytime. Of course, each command list is unique, so you didn't have to worry about different events holding references to the same array of event commands. I've made it so that you can now instantiate an EventBuilder object. This was primarily to allow me to combine different event builders together. It allows you to easily re-use event lists and allows for more modular code. Here is an example: module Quick def self.test_list return EventBuilder.new { show_text add_message("intercept") } end def self.test event = Event.new(1, 1) eb = EventBuilder.new { process_method(Quick, :test_list) show_text add_message("What do you want to do?") } # we need to explicitly grab the builder's list event.list = eb.list end end I have one method that simply shows the message "intercept" I have another method that actually builds an event. I would like to re-use my intercept message inside the event, so I use the `process_method` command to tell the event builder to call another method. `process method` requires the target method to return an EventBuilder object, and I combine the two command lists into one. This allows me to re-use event commands. Because they are separate methods, you can extend them if needed. You can still use the original event.list = EventBuilder.build { stuff } but keep in mind that if you use the static method, you won't be able to pass your event builder around. Edited August 16, 2012 by Tsukihime Share this post Link to post Share on other sites
eshra 53 Posted August 21, 2012 OMG this is great ty! Share this post Link to post Share on other sites
AeghtyAteKees 11 Posted June 2, 2013 I'm sorry that post is old, but it's still very useful. Anyhow, I was wondering why my event doesn't move when I set move_type=(Random). Share this post Link to post Share on other sites
Tsukihime 1,487 Posted June 2, 2013 Are you setting move type to 1? Share this post Link to post Share on other sites
AeghtyAteKees 11 Posted June 2, 2013 Yeah...nothing happens. Share this post Link to post Share on other sites
Tsukihime 1,487 Posted June 2, 2013 (edited) Works for me. module TH def self.move_event e = Event.new(1, 1) e.character_name = "actor1" e.move_type = 1 $game_map.add_event(e) end end After calling it, the event appears in (1,1) and starts moving around randomly Edited June 2, 2013 by Tsukihime Share this post Link to post Share on other sites
AeghtyAteKees 11 Posted June 2, 2013 Oh, I didn't have the "event." before the command. Thank you. Share this post Link to post Share on other sites
Tsukihime 1,487 Posted June 2, 2013 Yes, setting the move type for the event page is not the same as using the event builder to put together the event list. Share this post Link to post Share on other sites
David Bergström 0 Posted October 6, 2013 (edited) I'm sorry to be necromancing this thread, but I was wondering if there is a way, once you have specified which character index is used with 'event.character_index = 1', is there a way to specify which image within that set is shown? Say, I want to use index 1, but I want to use the fifth image in that set, is there a way it can be done without setting a move_route within the event's build?Thank you so much in advance!As a note, this script is fantastic, it has solved so many game breaking problems I have been having! Edited October 6, 2013 by David Bergström Share this post Link to post Share on other sites
Tsukihime 1,487 Posted October 6, 2013 (edited) The specific graphic on a character sheet is accessed as follows 1: the character index, which determines which block to use 2: the direction, which determines which row to use 3: the pattern, which determines which column to use. You can use the following calls to set those: event.direction = 2 event.pattern = 1 Assuming the default character sheet specs, direction uses the numpad directions (2, 4, 6, 8), pattern is just (0, 1, 2) for left-column, mid-column, right-column. Edited October 6, 2013 by Tsukihime Share this post Link to post Share on other sites
moco 0 Posted October 7, 2013 Is it possible to add a comment box on the command list of the event?For example, scripts that need a comment box with a tag for work. Share this post Link to post Share on other sites
Tsukihime 1,487 Posted October 7, 2013 (edited) Yes, use the "add_comment" function in the event builder event.list = EventBuilder.build { add_comment("your comment") } However the real problem you need to consider is whether the scripts you are using actually parse these new events. There are many scripts that assume all data is created on load-time. Edited October 7, 2013 by Tsukihime Share this post Link to post Share on other sites
moco 0 Posted October 7, 2013 Yes, use the "add_comment" function in the event builder event.list = EventBuilder.build { add_comment("your comment") } Great, this script is amazing. Thank you. However the real problem you need to consider is whether the scripts you are using actually parse these new events. There are many scripts that assume all data is created on load-time. You're right, thanks for the warning. Another question, can you also erase an event? Share this post Link to post Share on other sites
Tsukihime 1,487 Posted October 7, 2013 (edited) All of the event commands provided by the event editor are supported. Because you are scripting your events, you can even define your own event commands. I should probably write up a proper reference. For now you can look at the methods in the EventCommands and MoveCommands classes. To erase an event use the `erase` function event.list = EventBuilder.build { erase } You can also delete events using the `delete` function, which permanently removes it from the map. event.list = EventBuilder.build { delete } Edited October 7, 2013 by Tsukihime Share this post Link to post Share on other sites