Blog Info: I originally started this blog with The Legend of Zelda: A Link to the Past in mind. I got hooked after reading this hacker’s blog. Sometimes teaching is the best way to learn, so I decided to do a series of “mini-tutorials”, each building on the previous one. I later decided to post any tutorial fitting this rubric, since the number of Zelda3 hackers is so small (and since my expertise lies far outside of ROM hacking). I hope to eventually post tutorials on Hyrule Magic, Lunar Magic, and maybe even the Exult engine.
Back-story: Forcing the player to press “Enter” simply to hear what an NPC has to say is rather obnoxious. Wouldn’t it be better if NPCs simply “shouted” their messages out loud? Xenosaga Episode 3 did something similar; how hard can it be in RPG Maker VX?
Goal: Make a light-weight Window that appears over an NPC’s head and shows what he’d normally say using the “Show Text” command.
Let’s start with a basic Window subclass, and an NPC that uses it.
#Show above an NPC
class Talkbox_Window < Window_Base
#npc is a GameEvent
def initialize(npc, txt)
super(0, 0, 100, 50)
self.z = 90
#Setup
self.contents.draw_text(0, 0, 100, 20, txt)
#Hide it
self.visible = false
end
#We actually need to show the balloon a
# small amount offset above the npc
def update_pos(npc)
self.x = npc.screen_x-47
self.y = npc.screen_y-84
end
end
For the Event (NPC), have page 1 be autorun. Give it the following commands:
Script:
me = get_character(0)
$myText = Talkbox_Window.new(me, "Howdy!")
$myText.visible = true
$myText.update_pos(me)
Set Switch 1: ON
Give the Event a second page, and make the condition be “Switch 1 is ON”. Give it no commands.
Start the game and talk to the NPC. The box appears to work, but as you approach the NPC, you’ll notice an obvious flaw: the box scrolls with the map!
A few interesting points, before we move on.
$game_interpreter.get_character(ID)will return the event with the specified ID. If ID is -1, it returns the Player. If it is 0, the method returns the event which is currently being executed. Check the documentation for Game_Interpreter; there’s a lot of interesting stuff you can do!- Recall that by using a dollar sign for
$myText, we make it globally accessible. - If you try to call
update_pos(me)before you set$myText.visibleto true, the window will show, but (under some conditions) the text will not. It’s a bit of a quirk, but easy to handle if you know about it.
Now, let’s fix up our program. The problem is, we’re using Windows in a way they weren’t designed for. Take a second and think: all other windows you see in the game are positioned statically at some point on the screen (not on the map, like NPCs are). This means we’re going to have to significantly alter the core coding of the game engine itself.
Don’t Run Away! This isn’t nearly as hard as it sounds. Just make sure you’re reading twice as much as you’re writing. For example, start by opening the source for Game_Map and reading the function update. See how it calls update_scroll, update_events, and so on? Presumably, the second of these will update every event on the board. So after that, we can re-assign the x/y co-ordinates of our new text boxes. Add a new function call to update_talkboxes right before the call to @screen.update.
Of course, now we have to define this function. Put it somewhere in the Game_Map file:
def update_talkboxes
if $myText
me = @events[1]
$myText.update_pos(me)
end
end
This code checks if $myText exists, and then updates its position with that of event 1. You should only have one event on the map, so event 1 is guaranteed to be our NPC. Try it out.
Congratulations, it works! But this was just a proof-of-concept; clearly you can’t make a global variable for each NPC you want to vocalize. Also, you need some way of directly attaching talk boxes to NPCs, so that our update_talkboxes code doesn’t get too bloated.
There are several options. You could just assign NPCs to talk boxes inside some RGSS “init” code, but this is tedious. Wouldn’t it be better if you could use the GUI itself to do it? My solution was to name a switch:
Switch 2 : FLAG! NPC Talkbox
Now, make an NPC with two pages:
Page 1 has as its condition that Switch 2 must be ON. Give it one command, a “Show Text” with some short message.
Page 2 has no conditions and no commands.
Now, find the source for setup(map_id) inside Game_Map. At the end of this function, add the following source:
for event in @events.values
event.init_npc_talkbox
end
This will call a function (init_npc_talkbox) for each map event when the map first loads. Go into the source for Game_Event, and add the following attribute reader in the “Public Instance Variables” section:
attr_reader :npc_talkbox
…and then add our new method:
def init_npc_talkbox
page = @event.pages[0]
if page.condition.switch1_id ==2
#Steal the message box's text and init it
if page.list.size>0 and page.list[0].code==101
txt = page.list[1].parameters[0]
@npc_talkbox = Talkbox_Window.new(self, txt)
@npc_talkbox.visible = true
end
end
end
This code is very elegant. It simply checks if page 1 of this event requires switch 2 to be on. If so, it takes the first line of text from the first event command (which should be a “Show Text” command) and initializes a talk box with that text. This approach might seem hackish, but it was designed for stability. It is now impossible to accidentally link a talk box to an NPC which doesn’t exist, or vice versa. Moreover, any event that happens to use switch 2 on page 1 (and also has a “Show Text” command as the first one) will be an easy glitch to detect —you’ll see an unexpected talkbox above the NPC.
There’s only one thing left to make this trick complete: let’s change our definition of update_talkboxes.
def update_talkboxes
for event in @events.values
if (event.npc_talkbox)
event.npc_talkbox.update_pos(event)
end
end
end
Very concise. Here’s a screenshot of our demo in action.
Possible Improvements: This system is quite nascent; there’s a lot you can do to improve or expand it. Be creative! Here are just a few ideas to get you started:
- For some reason, the boxes “jitter” a bit when you walk up/down. This has to be an “off-by-one” error, since it fixes itself when you stop moving. Try to pinpoint this bug and fix it.
- Talk boxes currently appear immediately after changing maps, which means they appear before the title screen has fully faded out. Find a solution for this.
- Enhance talk boxes with Window_Message’s ability to detect symbols and color. (Start looking at convert_special_characters).
- Enhance talk boxes with the ability to “open” and “close” like a normal window. For example, when you walk up to the person saying “Inn?” and hit Enter, their talk box should close and they should ask you if you want to pay 50G to sleep there.
Post-Posting Info:
A certain fact has come to light since originally posting this tutorial. Please update your projects if you receive this error.
- Your “Talkbox_Window” module needs to be in a location that the interpreter can find. For example, add it below the “Windows” tab, or “Materials”. If you add it on its own to the end of the file, you might get an error when you try to run the program.




