Events: Into the guts

##THIS IS DEPRECATED AND WILL BE NUKED + UPDATED AT A LATER DATE

Cam, what are you doing? Get off the soapbox!

Well, your first thought when reading this would be that, “hey, a decent-enough event tutorial already exists, why do we need a new one?” And you would be right, I suppose. Arch’s Guide to Chapter Construction does a decent enough job of outlining what code does what, and where to go to do this, and so-and-so. On the other hand, I get a decent enough stream of people complaining that events from scratch are overwhelming, and they don’t know what to do (etc), that I figured someone needs to write a from-scratch, honest-to-god tutorial on “how the heck do i make chapter?

Table of Contents

2 Likes

The Toolbox

(disclaimer: this is copypasted verbatim from Arch’s tutorial)

[quote]When it comes to tools, eventing is pretty straightforward. You’ll need Nintenlord’s Event Assembler, his .MAR Array Inserter (or Tiled Inserter if you prefer that format for custom maps), the standard package of Nightmare Modules, and a .txt file editor (Notepad++ and other souped-up alternatives exist, but I just us MS Notepad).

The Event Assembler’s interface is itself pretty self-explanatory. You select the text file, the ROM to write to, the game, and hit “assemble.” For disassembly, most of what you’ll need is covered by the whole chapter button and the offset (the source code of events from the base games has already been ripped and is in the download).

As things pertain to chapter construction, these two modules will be central. On the left is FE# Event References.nmm, and on the right is the Chapter Data Editor.nmm.

Terminology

Before we get started actually writing anything, let’s make sure we’re clear on what certain words mean. I personally use a slightly different set of words to refer to certain things than some people (if i had my way other people would use these words too /arms), so we’re going to get that out of the way first. Many of these should be common knowledge for those of you who are up to date ROMhackers, a few more will be familiar to you programmers at home, but some of these are event-specific so I recommend you glance over this no matter your background.

Pointer: In its general definition (hackers and programmers may already be aware of this), a pointer is the location in memory of a certain thing, be it code, an object, or just raw data. For those of you who have no idea what that means, as far as events are concerned, a pointer is a physical place in the code, like the line number. See the section on technical details if you want to know more.

Scene: A scene is the most basic part of events - it’s when things happen. And by that, I mean something obvious happening, like text displaying, or music playing, or units appearing. For the most part, if the player sees it, it’s part of a scene.

Trigger: Triggers are, loosely, reasons for a scene to happen. When you tell the game to load reinforcements when you step on square [X,Y], the game knows when to do that through a trigger. Same if you play text when selecting “Talk”. This will hopefully be clearer once we get to that section. You may also hear me refer to this as an event.

Array: An array is just a list of things. A “trigger array”, for example, is a list of triggers. As you might expect, a unit array is a list of units, etc.

Macro: Macros are ways to make your code look nicer (and easier to remember!). To quote Arch:

[quote]They’re what allow me to turn code that looks like this: CHES 0x00 0x6C [2,4] 0x14

Into code that looks like this: Chest(Elixir,2,4)[/quote]

While we’re on the subject, macros are actually a superset of definitions, which are basically text replacements for numbers I don’t care to remember. For example, if you have the line #include "FE7 Definitions.txt" (or the appropriate for your game of choice), you can do clever things like using “Marcus” instead of 0x1A, or “Iron Sword” instead of 0x1.

Label: Instead of remembering “the scene is located at address 0x08D81340” (or, for you less-tech savvy out there, “the scene starts on line 10”), we can use labels to mark certain places in our code. They’re basically nice-looking pointers (you’ll see why this is necessary in a bit).

Getting Started

Fair warning: While the concepts and general process outlined in this tutorial are not FE7-only, the specific things I’ll be telling you to do are. I’m actually making the actual prologue to my own project as I write this, so there’s no dummy data or whatever here.

In terms of setting up the map and all, I’m going to point you at Arch’s excellent explanation instead of explaining myself. Come back here once you’ve gotten that worked out!

The first thing you’ll want to do is copy down this template here. For you FE8 or FE6 hackers out there, there are other templates out there. Before you start tapping away, let’s go over some of the things in that file. We’ll start with the event file’s header, which contains things like the chapter’s pointer array and other various processing things that make our life easier.

[code]#ifndef FE7
ERROR This file is meant for FE7!
#endif

#define DISABLE_TUTORIALS
#include “EAstdlib.event”[/code]

These are assembler directives. You don’t need to worry about them for now (see technical notes if you want more).

EventPointerTable(EvID, Pointers)

Aha, here’s something you’ll want to change. Pointers is just a label to the pointer array referenced later in the code, don’t mess with that. EvID, however, is an index in the Chapter Data Table (please note that, although it may sound similar, this is not the same thing as the data in the chapter data editor in nightmare; you may have heard of this instead as the “Event References Table”). FE6 and FE8 users can find similar lists by looking at their appropriate Event Reference nightmare module (it’s probably named “Pointers.txt” or something). By looking through that list, we see that “Prologue Events” is at 0x6, so we change the line to read EventPointerTable(0x6, Pointers). Obviously, if you’re doing a chapter that’s not the prologue, you’ll use that chapter’s event slot. Moving on!

ORG offs

This is the offset of your code in the ROM. If you’re going to be a ROMhacker, you should figure out what that means; it’s where your code goes in the ROM. I like to use 0xD80000 as my event space (this was a habit instilled in me by reading Arch’s tutorials way back in the day), but you can consult the free space list for your respective game to find out where’s safe for you. Alternatively, you can write to expanded space (this is not the place to explain that), if that works for you.

// The pointer array for the chapter // Warning: Don't edit this! Pointers: POIN TurnEvents POIN TalkEvents POIN LocationEvents POIN MovementEvents POIN MapData MapData POIN Bad Bad Bad Bad POIN Good Good Good Good POIN OpeningScene EndingScene

The last part of note in the header is the pointer array for the chapter. You’ll notice that the line on top reads “Pointers”, which is mirrored in our EventPointerTable macro above. This is because we want the game to know that our chapter’s pointer table is here, instead of some other random place. I’ll explain what each of those words means in a bit. But first, on to the actual chapter writing!

Baby’s First Scene

The obvious place to start, it seems, would be with the opening scene. Personally, I prefer to insert the trigger before writing the scene, so that’s what we’re going to be doing here. So when would our opening scene play, anyway? Well, it might be unintuitive, but the opening scene actually plays at the start of the first turn, right? So let’s put a trigger in our TurnEvents array to play the OpeningScene before turn 1 player phase:

TurnEvents: TurnEventPlayer(0x0, OpeningScene, 1) TURN

There are actually quite a few things going on in these three lines. The first line (TurnEvents) is a label, which we’ve gone over (it’s the same TurnEvents that exists in the pointer array). Next is TurnEventPlayer(0x0, OpeningScene, 1). This is a macro that, as you might expect, tells the game to play a scene on some turn, at the start of player phase. The macro itself has three parameters (the following information can and should be looked up in EA Macro and Command List.txt): TurnEventPlayer(EventID, ScenePointer, StTurn). The Event ID, in this case, is zero (see the section on triggers for more on that); you can set it to something else but TurnBasedEvents typically use zero. ScenePointer is, unsurprisingly, the pointer to the scene we want played. Notice that we used the label (or even the name) of our scene as a pointer. For the last param, there’s “StTurn”, which should be self-explanatory. The final thing to note is the blank TURN at the end of the array. That blank TURN (you may see END_MAIN or WORD 0x00 on other templates) tells the game where the end of our trigger array is, so it knows to stop checking. You’ll want to leave that (as well as the blank AFEVs and CHARs) Onwards, to the actual scene!

OpeningEvent: ENDA

…doesn’t look very exciting, does it? And you’d be right, at the moment this “scene” doesn’t do anything whatsoever. So what usually happens during the OpeningScene? Maybe we can play some text?

OpeningEvent: TEX1 0x0813 REMA ENDA

What about a background?

OpeningEvent: FADI 0x10 BACG 0x02 FADU 0x10 TEX1 0x0813 REMA ENDA

Does that make a lot of sense to you? Not really? Well, I don’t blame you. What if we put in comments?

OpeningEvent: FADI 0x10 // Fade in town background BACG 0x02 FADU 0x10 TEX1 0x0813 // Prologue opening text (get this number from FEditor!) REMA // Clear faces from screen once text is finished ENDA // Return control to player

Better? No? What if I used a macro?

OpeningEvent: Text(0x02, 0x0813) // Load text and background REMA ENDA

Ah, that’s better. Now, we have a fully functional scene, and a way to make the game play it, aren’t you proud? That being said, however, this is kind of a dull chapter with no units on the map…

Give me units to play with!

The standard UNIT command looks like this:

UNIT unitID jobID leader level [stX, stY] [endX, endY] [inventory] AI

Of course, to make things more confusing, these don’t actually go into scene data. It’s okay though, the game provides a default unit array (or “unit group”, as I may accidentally refer to it as) for you to put both “Good” (player) and “Bad” (enemy) units into! However, for our scene, let’s put units into a different array, because why not?

PlayerUnits: UNIT Eliwood EliwoodLord 0x0 Level(5,Ally,false) [14, 12] [14, 12] [Rapier, Vulnerary] NoAI UNIT Hector HectorLord Eliwood Level(5,Ally,false) [14, 8] [14, 8] [WolfBeil, Elixir] NoAI UNIT Lyn LynLord Eliwood Level(5,Ally,false) [12, 9] [12, 9] [ManiKatti, Vulnerary] NoAI UNIT

Whoa, whoa, slow down, a lot of things just happened. The first thing to note is my use of definitions (really a form of macro) to load “Eliwood” instead of “0x1”. On the same note, there’s an actual macro in the form of Level(5,Ally,false). This does what you’d expect; it loads a level 5 ally (it accepts “Ally”, “Enemy” and “NPC”), but what does false mean? The third parameter in Level macro is “autolevel”, it takes “true” or “false” (if you’ve played with Nightmare a bit, you should know what that means). Next up are the loading and final coordinates. What this means is that the unit will spawn at the first pair of coordinates and move to the second pair (where they’ll stay until they’re commanded to move again). While in this case it doesn’t matter, it’s useful to make units (say, enemies) seem like they’re all, say, leaving a building or something. Inventory is self-explanatory (it holds up to four items; supplying less than four is allowed). For AI, there are a series of AI definitions in EAstdlib, I’ve provided them for reference below.

//AI helpers
#ifdef _FE6_
#define NoAI 			[0x00,0x00,0x00,0x00]
#define AttackInRange		[0x00,0x03,0x09,0x00]
#endif

#ifdef _FE7_
#define NoAI 			[0x00,0x00,0x00,0x00]
#define PursueWithoutHeed 	[0x00,0x02,0x02,0x00]
#define GuardTile 		[0x03,0x03,0x09,0x20]
#define Guard 			[0x00,0x03,0x00,0x20]
#define AttackInRange 		[0x00,0x03,0x09,0x00]
#define DestroyVillages 	[0x00,0x04,0x01,0x00]
#define HealUnits 		[0x0F,0x04,0x00,0x00]
#define StealFromUnits 		[0x10,0x05,0x09,0x00]
#define StealFromChests 	[0x06,0x05,0x09,0x00]
#define TalkToLord 		[0x06,0x0B,0x0A,0x00]
#define AttackWall 		[0x00,0x1B,0x01,0x00]
#define SeizeThrone 		[0x00,0x1E,0x00,0x00]
#endif

#ifdef _FE8_
#define NoAI 			[0x00,0x00,0x00,0x00]
#define SummonMonsters 		[0x14,0x03,0x09,0x00]
#endif

This should all be very familiar for those of you who’ve used the Chapter Unit Editors (or Army Editors, as some older versions are called); that’s good, because those modules are actually just editors for this data! Keep that in mind, because your chapter unit editors won’t work anymore after assembling these events.

The last thing to note about this group is that, similar to our TurnEvents array, we end with an empty UNIT.

Finally, the command to load units is LOU1 (followed by ENUN, which means to wait until units stop moving); this would qualify as “something happening”, so that goes in your scene (opening scene, in this case). While we’re at it, let’s make and load some enemies. Here’s the whole file once we’re done with that, for reference:

// Template written by CT075, based off the original by markyjoe
#ifndef _FE7_
ERROR This file is meant for FE7!
#endif

#define DISABLE_TUTORIALS
#include "EAstdlib.event"
#include "FE7 Definitions.txt"

EventPointerTable(0x6, Pointers)

ORG offs
// The pointer array for the chapter
// Warning: Don't edit this!
Pointers:
POIN TurnEvents
POIN TalkEvents
POIN LocationEvents
POIN MovementEvents
POIN MapData MapData
POIN Bad Bad Bad Bad
POIN Good Good Good Good
POIN OpeningScene EndingScene

// Units

Bad:
UNIT Batta Brigand 0x0 Level(6,Enemy,false) [3, 16] [3, 16] [IronAxe] GuardTile
UNIT 0x88 Brigand Batta Level(6,Enemy,true) [8, 7] [8, 7] [IronAxe] AttackInRange
UNIT 0x88 Brigand Batta Level(6,Enemy,true) [2, 12] [2, 12] [SteelAxe] NoAI
UNIT 0x88 Brigand Batta Level(6,Enemy,true) [12, 3] [12, 3] [IronAxe] AttackInRange
UNIT 0x88 Brigand Batta Level(6,Enemy,true) [13, 14] [13, 14] [IronAxe] NoAI
UNIT 0x88 Brigand Batta Level(6,Enemy,true) [7, 17] [7, 17] [SteelAxe] AttackInRange
UNIT

Good:
UNIT

PlayerUnits:
UNIT Eliwood EliwoodLord 0x0 Level(5,Ally,false) [14, 12] [14, 12] [Rapier, Vulnerary] NoAI
UNIT Hector HectorLord Eliwood Level(5,Ally,false) [14, 8] [14, 8] [WolfBeil, Elixir] NoAI
UNIT Lyn LynLord Eliwood Level(5,Ally,false) [12, 9] [12, 9] [ManiKatti, Vulnerary] NoAI
UNIT

// Trigger arrays

TurnEvents:
TurnEventPlayer(0x0, OpeningScene, 1)
TURN

TalkEvents:
CHAR

LocationEvents:
LOCA

MovementEvents:
CauseGameOverIfLordDies
AFEV

MapData:
BLST
ALIGN 4

// Scene data

OpeningScene:
Text(0x2, 0x0813) // Load text at FEditor index 0x0813 with house background
REMA // Clear faces
LOU1 PlayerUnits Bad // Load all units
ENUN // Wait for unit movement to end
ENDA

EndingScene:
ENDA

MESSAGE events end at offset currentOffset

I’d recommend you glance at that for a bit to gain your bearings (although, if you’ve been following along, there shouldn’t be too many changes from the last step). Notice how, even though it’s empty, our POIN array still has Good listed, and doesn’t have anything for PlayerUnits. This is not a mistake and is very much intentional; you should never adjust the POIN array unless you know very well what you’re doing.

#RESERVED
triggers

#RESERVED
get more scenic

#RESERVED
tech stuff

#RESERVED
final word

#RESERVED
just in case

RESERVED

one more 'cause i think i missed one