Jump to content
Tsukihime

Event Wrapper - scripting your events

Recommended Posts

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
YWWo9.jpg

 

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"

 

2vGa4.jpg

 

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)

 

NheNE.jpg

 

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.

 

YA7u6.jpg

 

Iz5mN.jpg

 

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 by Tsukihime

Share this post


Link to post
Share on other sites

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 by Tsukihime

Share this post


Link to post
Share on other sites

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

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

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 by Tsukihime

Share this post


Link to post
Share on other sites

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

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 by Tsukihime

Share this post


Link to post
Share on other sites

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? :P 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 by KilloZapit

Share this post


Link to post
Share on other sites

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 by Tsukihime

Share this post


Link to post
Share on other sites

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 by Tsukihime

Share this post


Link to post
Share on other sites

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 by Tsukihime

Share this post


Link to post
Share on other sites

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 by David Bergström

Share this post


Link to post
Share on other sites

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 by Tsukihime

Share this post


Link to post
Share on other sites

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

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 by Tsukihime

Share this post


Link to post
Share on other sites

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

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 by Tsukihime

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

×
Top ArrowTop Arrow Highlighted