Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/pmret/papermario/llms.txt

Use this file to discover all available pages before exploring further.

Paper Mario uses two distinct object types to populate its worlds: NPCs (Npc) and entities (Entity). NPCs are sprite-based characters with position, animation, AI scripts, and collision. Entities are geometry-based interactive objects — blocks, switches, chests, springs — that run a lightweight bytecode interpreter. Both systems share the same coordinate space but are managed through separate lists and update paths.

The Npc struct

The Npc struct is defined in include/common_structs.h starting at line 221. It is 0x340 bytes in size.
typedef struct Npc {
    /* 0x000 */ s32 flags;
    /* 0x004 */ void (*onUpdate)(struct Npc*);  // called first in update_npcs()
    /* 0x008 */ void (*onRender)(struct Npc*);  // called after display list build
    /* 0x00C */ f32 yaw;
    /* 0x018 */ f32 moveSpeed;
    /* 0x01C */ f32 jumpVel;
    /* 0x020 */ union { void* any; NpcFollowData* followData;
                        struct Npc* keepAwayNpc; /* ... */ } blur;
    /* 0x024 */ s32 spriteInstanceID;
    /* 0x028 */ AnimID curAnim;
    /* 0x030 */ f32 animationSpeed;
    /* 0x038 */ Vec3f pos;
    /* 0x044 */ Vec3f rot;
    /* 0x054 */ Vec3f scale;
    /* 0x060 */ Vec3f moveToPos;
    /* 0x06C */ Vec3f colliderPos;
    /* 0x078 */ s32 shadowIndex;
    /* 0x080 */ s32 collisionChannel;
    /* 0x084 */ s16 curFloor;   // collider ID of floor underfoot
    /* 0x086 */ s16 curWall;    // collider ID of wall in contact
    /* 0x088 */ b16 isFacingAway;
    /* 0x0A4 */ s8 npcID;
    /* 0x0A6 */ s16 collisionDiameter;
    /* 0x0A8 */ s16 collisionHeight;
    /* 0x0AC */ u8 alpha;
    /* 0x0AD */ u8 hideAlpha;   // multiplied with alpha when hiding the NPC
    /* 0x090 */ Vec3s homePos;
    /* 0x320 */ f32 verticalStretch;
    /* 0x324 */ struct EffectInstance* decorations[MAX_NPC_DECORATIONS];
} Npc; // size = 0x340
The blur union at offset 0x020 serves double duty. During normal movement it holds a pointer to NpcFollowData (for partner follow behaviour) or motion-blur data. The actual field name is blur because the original use case was motion-blur effects for certain NPCs.

NPC data definition

You describe an NPC in a map file using NpcData (defined in include/npc.h). Each NpcData contains:
typedef struct NpcData {
    /* 0x000 */ s32 id;
    /* 0x004 */ NpcSettings* settings;   // AI scripts, height, radius, flags
    /* 0x008 */ Vec3f pos;               // initial world position
    /* 0x014 */ s32 flags;
    /* 0x018 */ EvtScript* init;         // runs once when the NPC is created
    /* 0x024 */ s32 yaw;                 // initial facing direction
    /* 0x028 */ EnemyDrops drops;        // item/heart/flower drop tables
    /* 0x0E0 */ EnemyTerritory territory; // wander/patrol zone definition
    /* 0x1A0 */ struct { s32 idle; s32 walk; s32 run; s32 chase;
                         /* ... 16 animation slots total ... */
                         s32 death; s32 hit; } animations;
} NpcData; // size = 0x1F0
Group NPCs together with NpcGroup and spawn them all at once using MakeNpcs from an EVT script.

NpcSettings

NpcSettings (in include/npc.h) ties an NPC to its behaviour scripts:
typedef struct NpcSettings {
    /* 0x00 */ AnimID defaultAnim;
    /* 0x04 */ s16 height;
    /* 0x06 */ s16 radius;
    /* 0x0C */ EvtScript* onInteract;   // runs when Mario talks to this NPC
    /* 0x10 */ EvtScript* ai;           // AI main loop
    /* 0x14 */ EvtScript* onHit;        // runs on first strike
    /* 0x18 */ EvtScript* aux;          // auxiliary script slot
    /* 0x1C */ EvtScript* onDefeat;     // runs after the battle is won
    /* 0x20 */ s32 flags;
    /* 0x28 */ s16 level;
    /* 0x2A */ s16 actionFlags;         // 1 = jump on seeing player
} NpcSettings; // size = 0x2C

The Entity struct

The Entity struct is defined in include/common_structs.h starting at line 553. It is 0xF8 bytes in size.
typedef struct Entity {
    /* 0x00 */ s32 flags;
    /* 0x04 */ u8 listIndex;
    /* 0x06 */ u8 collisionFlags;
    /* 0x07 */ s8 collisionTimer;
    /* 0x09 */ u8 scriptDelay;       // frames to wait between script steps
    /* 0x0A */ u8 type;              // entity type enum
    /* 0x0B */ u8 alpha;
    /* 0x0C */ Vec3s aabb;           // axis-aligned bounding box
    /* 0x14 */ s16 virtualModelIndex;
    /* 0x16 */ s16 shadowIndex;
    /* 0x18 */ s32* scriptReadPos;   // current position in EntityScript
    /* 0x1C */ EntityCallback updateScriptCallback;
    /* 0x24 */ Evt* boundScript;     // EVT script bound via es_RestartBoundScript
    /* 0x28 */ EvtScript* boundScriptBytecode;
    /* 0x38 */ EntityBlueprint* blueprint;
    /* 0x40 */ EntityData dataBuf;   // union of per-type data structs
    /* 0x44 */ void* gfxBaseAddr;    // base of loaded geometry data
    /* 0x48 */ Vec3f pos;
    /* 0x54 */ Vec3f scale;
    /* 0x60 */ Vec3f rot;
    /* 0x70 */ Matrix4f inverseTransformMatrix; // world-to-local
    /* 0xB8 */ Mtx transformMatrix;
} Entity; // size = 0xF8

Entity script opcodes

Entities run a tiny bytecode interpreter. The available opcodes are defined in include/entity.h:
ENTITY_SCRIPT_OP_End              // terminate the script
ENTITY_SCRIPT_OP_Jump             // jump to another EntityScript
ENTITY_SCRIPT_OP_Call             // call a C function
ENTITY_SCRIPT_OP_SetCallback      // schedule a callback after N frames
ENTITY_SCRIPT_OP_Goto             // goto a label
ENTITY_SCRIPT_OP_Label            // define a label
ENTITY_SCRIPT_OP_RestartBoundScript  // restart the bound EVT script
ENTITY_SCRIPT_OP_SetFlags         // set flags bits
ENTITY_SCRIPT_OP_ClearFlags       // clear flags bits
ENTITY_SCRIPT_OP_PlaySound        // play a sound effect
Convenience macros (es_Call, es_Jump, es_SetCallback, etc.) let you write entity scripts as C arrays without specifying raw opcode integers.

Entity types

The following blueprints are declared in include/entity.h and cover all entity types in the game:
Entity_BrickBlock, Entity_MulticoinBlock, Entity_YellowBlock, Entity_HiddenYellowBlock, Entity_RedBlock, Entity_HiddenRedBlock, Entity_TriggerBlock, Entity_HeartBlock, Entity_SuperBlock, Entity_PushBlock, Entity_PowBlockHammer-required variants: Entity_Hammer1Block, Entity_Hammer2Block, Entity_Hammer3Block — each also has WideX, WideZ, and Tiny variants.
Entity_SavePoint, Entity_RedSwitch, Entity_BlueSwitch, Entity_HugeBlueSwitch, Entity_GreenStompSwitch, Entity_BoardedFloor, Entity_BombableRock, Entity_BombableRockWide, Entity_BlueWarpPipe, Entity_Signpost, Entity_ArrowSign, Entity_HiddenPanel
Entity_Chest, Entity_GiantChest, Entity_WoodenCrate
Entity_Tweester, Entity_StarBoxLauncher, Entity_CymbalPlant, Entity_PinkFlower, Entity_SpinningFlower, Entity_BellbellPlant, Entity_TrumpetPlant, Entity_Munchlesia, Entity_SimpleSpring, Entity_ScriptSpring
Entity_Padlock, Entity_PadlockRedFrame, Entity_PadlockRedFace, Entity_PadlockBlueFace

NPCs vs entities: key differences

AspectNPCEntity
Visual representationSprite (2D billboard)3D geometry via display list
Script systemEVT scripts (EvtScript)Entity bytecode (EntityScript)
AI supportYes — MobileAISettings, GuardAISettingsNo built-in AI
Collision systemCylinder/sphere against world, player, and other NPCsAABB against player only
Used forCharacters, enemies, partnersBlocks, switches, chests, interactive scenery
List typeNpcList (world or battle)EntityList

AI systems

Enemy NPCs use one of two AI setting structs.

MobileAISettings

Used for enemies that wander and chase:
typedef struct MobileAISettings {
    /* 0x00 */ f32 moveSpeed;
    /* 0x04 */ s32 moveTime;
    /* 0x08 */ s32 waitTime;
    /* 0x0C */ f32 alertRadius;         // detection sphere radius
    /* 0x10 */ f32 alertOffsetDist;     // directional sight offset
    /* 0x14 */ s32 playerSearchInterval; // frames between player checks
    /* 0x18 */ f32 chaseSpeed;
    /* 0x1C */ s32 chaseTurnRate;       // degrees turned per frame while chasing
    /* 0x20 */ s32 chaseUpdateInterval; // frames between chase re-acquisitions
    /* 0x24 */ f32 chaseRadius;
} MobileAISettings; // size = 0x30

GuardAISettings

Used for stationary enemies that only chase when the player enters their detection zone:
typedef struct GuardAISettings {
    /* 0x00 */ f32 alertRadius;
    /* 0x04 */ f32 alertOffsetDist;
    /* 0x08 */ s32 playerSearchInterval;
    /* 0x0C */ f32 chaseSpeed;
    /* 0x10 */ s32 chaseTurnRate;
    /* 0x14 */ s32 chaseUpdateInterval;
    /* 0x18 */ f32 chaseRadius;
} GuardAISettings; // size = 0x24
The BasicAI_Main callable (from include/script_api/map.h) implements the standard patrol-detect-chase loop using whichever settings struct the NPC’s AI script passes to it.

Collision functions

NPC collision is handled by three functions in src/npc.c:
  • npc_do_world_collision(Npc*) — tests the NPC against map geometry
  • npc_do_other_npc_collision(Npc*) — tests against other NPCs in the list
  • npc_do_player_collision(Npc*) — tests against Mario; returns true if a collision occurred
World collision uses the collisionChannel field to filter which geometry the NPC interacts with.

Partner NPCs

The active partner is an NPC managed by src/world/partners.c. It uses the NpcFollowData pointer in Npc::blur to track Mario’s position and mirror his movement with a short delay. Partner-specific overworld behaviour scripts are stored in src/world/partner/. In battle, the partner becomes an actor rather than an NPC. The transition is handled by EVS_BtlBringPartnerOut and EVS_BtlPutPartnerAway.

Battle system

See how enemy NPCs become battle actors when an encounter begins.

Visual effects system

Learn how NPC decorations and status effects are implemented using the effects system.

Build docs developers (and LLMs) love