Actors

From z64 wiki
Jump to: navigation, search

Intro

Actors are the various interactive pieces in the Zelda 64 engine, from enemies to static scenery. There are three major components to an actor:

  • The actor overlay, a file that contains the code for an actor
  • An actor instances, or an in memory representation of our actor.
  • Object files, one or more files that contain graphical assets for an actor, and can be shared by multiple actors.

Actor Overlay Table

The actor table manages the actor files (overlays). It defines an actor's number, maps the actor to a virtual address, and during gameplay is used to find the overlay in ram. In the Debug ROM it's located at B8D440 ROM and (where?) RAM, within code.zasm.

xxxxxxxx yyyyyyyy aaaaaaaa bbbbbbbb
pppppppp iiiiiiii nnnnnnnn ????cc??

This breaks down into-
x y: Start/End Virtual Rom addresses of the actor file
a b: Start/End Virtual Ram addresses of the actor file
p: Ram address of actor file (00000000 if overlay isn't loaded, or if in ROM)
i: Virtual Ram address of the start of the actor instance initialization variables, located within the file
n: Address of actor filename (Debug ROM only, value is 0 in commercial roms)
c: Number of actor instances of this type currently loaded (ram only)

Note: The record for Link's actor in rom (the first record in the table) only sets the vram address that points to the start of the variable info for Link's actor, and the actor file name pointer if it's the Debug Rom.

Overlay File

See Overlays for more information on the overlay format.

Actor Instances

For Ocarina of Time, the allocated actor structure is as follows. Alternate (better) versions here.

typedef struct {
	f32 x, y, z;
} Coord;

typedef struct {
	u16 x, y, z;
} rotation;

typedef struct
{
    /* 0x00 */ u16 actorNo;
    /* 0x02 */ u8 actorType;
    /* 0x03 */ u8 roomNo; //Room number the actor is part of. FF denotes that the actor won't despawn on a room change
    /* 0x04 */ u32 unk_01;
    /* 0x08 */ Coord Pos1;
    /* 0x14 */ rotation initRot;
    /* 0x1A */ u16 unk_02;
    /* 0x1C */ u16 actorVariable;
    /* 0x1E */ u16 unk_03;
    /* 0x20 */ u32 unk_04;
    /* 0x24 */ Coord Pos2;
    /* 0x30 */ char buff[8];
    /* 0x38 */ Coord Pos3;
    /* 0x44 */ rotation rot_1;
    /* 0x4A */ u16 unk_05;
    /* 0x4C */ f32 unk_06; /* I know this is a float from breakpointing it */
    /* 0x50 */ Coord Scale;
    /* 0x5C */ char buff2[0x58];
    /* 0xB4 */ rotation rot_2;
    /* 0xBA */ char buff3[0x66];
    /* 0x115 */ u8 runActor; // Determines if actor instance should be processed. 01 for yes, 00 for no.
    /* 0x120 */ z_ram_actor* actor_prev; /* Previous z_ram_actor of this type */
    /* 0x124 */ z_ram_actor* actor_next; /* Next z_ram_actor of this type */
    /* 0x128 */ u32 unk;
    /* 0x12C */ u32 ActorInit;
    /* 0x130 */ u32 ActorDraw;
    /* 0x134 */ u32 ActorMain;
    /* 0x138 */ u32 CodeEntry;
    /* 0x13C */
    /* From here on, the structure and size varies for each actor */
} z_ram_actor;

/* 8-10-2012 : Addition made by Jason777 */
/* For actors which contain a damage chart (example: Stalfos)... */
typedef struct
{
     ..
     /* 0x98 */ u32 DamageChart;  /* Pointer to the actor's Damage Chart in RAM. */
     ..
     /* 0xAF */ u8 Health;
     ..
} z_ram_actor;

The Majora's Mask actor structure is similar but not interchangeable.

Categories

Actor instances are added into a doubly-linked list based on a category id. Ids can be set in the overlay file, but can also be pro grammatically modified (ex. Skulltula/Gold Skulltula actor). There are 12 categories total. Majora's Mask may use 16 different categories.

char * actor_types[12] = {
    "Unknown",	"Prop (1)",	"Player",	"Bomb",
    "NPC",	"Enemy",	"Prop (2)",	"Item/Action",
    "Misc",	"Boss",		"Door",	"Chests"
};
Id Description Useage
0 Unknown
1 Prop (1) Typically larger, more complex set pieces
2 Player
3 Bomb Bombs, Bomchus
4 NPC
5 Enemy Used for triggering room clear state.
6 Prop
7 Item/Action
8 Misc
9 Boss
10 Door
11 Chests

Loading Actors

What is currently known about the loading and execution of code from actors in Zelda 64 is that:

  • The first time an actor is loaded (spawned), its actor overlay is transferred to RAM
    • The transferred file has its offsets relocated
    • The actor file remains allocated in ram until all instances of that actor have despawned
  • The game begins to create an instance of the actor
  • For each actor instance, actors are given a certain amount of memory as defined in the actor file. However, the minimum space required by the game's engine is 0x128 bytes in OoT (MM may vary).
    • Within this given memory is information such as
      • Location
      • Rotation
      • Scale
      • Pointer to damage chart (if the actor has one)
      • Pointers to actor functions
        • Initialization - run when actor instance is loaded.
        • Main - always run during gameplay.
        • Drawing - to be run when actor is close enough to the camera.
      • Pointer to Next/Previous actor(s) of this actor's category
      • Whatever else that actor needs (ex. instanced variables).

At 0x80213C50 within RAM (0x80212020 + 0x1C30) is a list of actor categories (see above), each entry being an integer and a pointer. The pointer points to the first allocated entry for an actor. The integer is the number of actors of that category, the first entry being type 0, and the last last being type 11 (chests). Actors after the first actor are pointed to through the next/previous pointers within each allocated actor.

Custom Actors

ZZT32 decided to get off his ass one day and write nOVL, a tool which converts MIPS elf binaries to Zelda 64 Overlays, also known as actors. Few actors have been (re)written using mips-gcc + nOVL, but there are a few:

  • En_Anim - An actor written to load any animation.
  • En_AnimVar - A fork of the above actor, uses variables.
  • en_vase - The simplest actor in OoT, re-written in C to test nOVL and to document functions.
  • En_Bird - The simplest animated actor in OoT, re-written for the same reason as En_Vase.

zovldis is the opposite of nOVL - it takes an overlay and disassembles it to an assembly file, which, combined with a proper makefile, produces an identical actor as the one which was disassembled. This makes hacking existing actors much more convenient. An example of actor modification using this approach is here (video)

Examples

Every actor in Debug MQ disassembled

Credits

Cendamos - Actor table information, misc stuff that got the ball rolling
Euler - Actor file structure
JayTheHam - His early work with Cendamos on actor information
ZZT32 - Explained some actor table stuff to me
spinout - Writing this article