Complete SCD Scripting Guide ‐ Resident Evil 2 - biorand/biohazard-utils GitHub Wiki

SCD - Resident Evil 2

In Resident Evil 1-3, each room is stored a file (.RDT). One of the sections of the file is known as the .SCD which is a game script that will run while in the room. The script will setup all the doors, enemies, items, events and cutscenes that happen within that room.

Tables

Each room has several tables corresponding to different things within the room. Area of interests (AOTs), and enemies can be set up freely in the SCD. Messages must be setup up in the MSG section of the RDT, and object models in the object/texture section of the RDT. The SCD compiler allows you to edit these via preprocessor directives.

These tables are a fixed size, thus you can only have a limited number of each kind.

Table Instructions
AOT (area of interest) aot_set, aot_reset, aot_set_4p, door_aot_se, door_aot_set_4p, item_aot_set, item_aot_set_4p, aot_on
EM (enemy / npc) sce_em_set
MSG (message) message_on
OM (object) obj_model_set

Many instructions can be used to change the properties or behaviour of AOTs, EMs, or OMs. But rather than passing the table type and ID to each instruction, work_set is called which changes the current entity. Then any instruction following that will affect only the entity that was passed to work_set. For example:

work_set(WK_ENEMY, ID_EM_1);
pos_set(0, -21000, 0, -25000);
dir_set(0, 0, 1024, 0);
member_copy(V_TEMP, M_TYPE);
calc(0, OP_AND, V_TEMP, 0x7FFF);
member_set2(M_TYPE, V_TEMP);

A common pattern for enemies that walk into a room is to initialise the enemy in a frozen state out of bounds (-32000, -10000, -32000) where you can't see it. Then when the event for it walking in is triggered, this code snippet will set the current entity to work on, to the second enemy slot (EM 1), and then move the enemy to a certain position and orientation. It also unfreezes the enemy which is done by switching off a flag using a bit mask in the type member of the enemy.

AOTs (area of interest)

Area of interests are invisible rectangular areas within the room. The areas can be triggered by either the player entering the area, or the player using the action button within the area or facing the area. The trigger is controlled by a set of flags. The effect can either be a door/room change, an item pick up, a message, or running a subroutine. It is also used to mark areas where a key item can be used.

EM (enemies / npcs)

Enemies can be an enemy, NPC or partner. Partners use ID 255, and is reserved for Ada and Sherry usually resulting in their specific partner AI behaviour.

OM (objects)

Objects can be any 3D model that appears in the room. Some can be movable items such as statues or boxes, or the model of an item to pickup.

Messages

Question types

  • 0x00 - YES / NO
  • 0x01 - LEFT / RIGHT / NO
  • 0x02 - 1 / 2 / 3 / 4 / 5 / 6
  • 0x03 - UP / DOWN
  • 0x04 - LEFT / RIGHT / CANCEL
  • 0x05 - YES / NO / ORIGINAL
  • 0x06 - MG / SIDEPACK

To get the user's answer, you can assume the following flags as the bits that make up the answer index.

  • ck(FG_MESSAGE, 29, 1) (4)
  • ck(FG_MESSAGE, 30, 1) (2)
  • ck(FG_MESSAGE, 31, 1) (1)

For example to check if 3 was chosen, you would do:

if (ck(FG_MESSAGE, 29, 0)
    ck(FG_MESSAGE, 30, 1)
    ck(FG_MESSAGE, 31, 1))
{
    // 3 was chosen
}

because 3 is made up of 1 + 2, so you check 1 and 2 are set, and that 4 is not set.

Instructions

0x00: nop

A single byte instruction that does nothing. Useful for alignment, and removing instructions without alterating the address of others.

Example:

1C94:   evt_next
1C95:   nop
1C96:   set               FG_ROOM, 0, 0

Here a nop instruction is used to align the set instruction to an even address, due to evt_next only being one byte long. When writing a .bio file, nop instructions are not required as the compiler will insert them automatically when required.

0x01: evt_end(u8 padding)

Returns from the currently executing subroutine.

Example:

proc init
{
    door_aot_se(ID_AOT_0, SCE_DOOR, SAT_PL | SAT_MANUAL | SAT_FRONT, 0, 0, -23889, -26379, 1800, 2200, -26505, 0, -24896, 0, 0, 9, 6, 0, 0, 0, 0, 0, UNLOCKED, 0);
    if (ck(FG_STATUS, F_BONUS, 1))
    {
        sce_em_set(0, ID_EM_0, ENEMY_ZOMBIE_RANDOM, 6, AI_DEFAULT, 0, SBK_6, 0, 74, -24336, 0, -25994, 2859, 0, 0);
        sce_em_set(0, ID_EM_1, ENEMY_ZOMBIE_RANDOM, 0, AI_DEFAULT, 0, SBK_43, 0, 123, -23892, 0, -22831, 3125, 0, 0);
        evt_end(0);
    }
    sce_em_set(0, ID_EM_0, ENEMY_LICKER_RED, 1, AI_01, 0, SBK_14, 0, 76, -27000, -3000, -12400, 1024, 0, 0);
    sce_em_set(0, ID_EM_1, ENEMY_LICKER_RED, 0, AI_DEFAULT, 0, SBK_14, 0, 77, -22712, 0, -6235, 1800, 0, 0);
}

In this example, evt_end is used to terminate the initialization event after setting up the doors and enemies for 4th survivor. Avoids needing an else block for the remainder of the procedure.

If not writing in a .bio file, you must also end each subroutine with an evt_end instruction:

.proc init
1FDE:   door_aot_se             ID_AOT_0, SCE_DOOR, SAT_PL | SAT_MANUAL | SAT_FRONT, 0, 0, -19547, -23166, 1600, 2300, -25979, -14400, -21180, 3920, 0, 23, 3, 8, 13, 1, 0, 0, UNLOCKED, 0
1FFE:   door_aot_se             ID_AOT_1, SCE_DOOR, SAT_AUTO, 0, 0, 0, 0, 0, 0, 1425, 0, -21914, 3072, 1, 25, 1, 0, 51, 8, 0, 0, UNLOCKED, 0
201E:   evt_end                 0

0x02: evt_next

Suspends the current event until the next frame. This can be used instead of sleep(10, 1) to let the game advance one frame before continuing the subroutine. It is used occasionally for timing, but is used more often to create a loop that waits for a condition to be met without freezing the game.

Examples:

while (ck(FG_ROOM, 0, 0))
{
    evt_next();
}

Here, evt_next is used to let the game advance one frame before checking the condition again. Without it, the game would freeze as the loop would never end, and the game would never get the chance to run any other code.

work_set(WK_OBJECT, ID_OBJ_0);
speed_set(0, -150);
repeat (20)
{
    add_speed();
    evt_next();
}

In this example, an object is given a speed to move at and is moved at that speed for 20 frames.

0x03: evt_chain

Not certain yet how this instruction works. It possibly is used to run another event when the current one ends.

0x04: evt_exec(u8 evt_id, u8[] instruction)

Begins a new event and executes the following instruction. The instruction is always typically a gosub which makes evt_exec a four byte instruction. evt_exec is used to have multiple subroutines running simultaneously which is useful for cutscenes where multiple things are happening.

  • evt_id - used to specify the event slot that will be used for the new event. Usually 255 is specified which means that the event will automatically be given a spare event slot. If however you need to terminate the event prematurely, you can give the event an ID that you later pass to evt_kill.
  • instruction - the instruction to execute in a new event. Usually gosub.

Example:

.proc main
    evt_exec                255, I_GOSUB, leon
    evt_exec                255, I_GOSUB, claire
    evt_end                 0

.proc leon
    sleep                   10, 10
    work_set                WK_PLAYER, 0
    plc_neck                2, 0, -512, 0, 67, 67
    evt_end                 0

.proc claire
    sleep                   10, 30
    work_set                WK_ENEMY, ID_EM_0
    plc_neck                0, 0, 512, 0, 55, 55
    evt_end                 0

Here we kick off two new events that will run independently. One for controlling the player model, and another to control the NPC.

In a .bio file, you can use the fork statement:

proc main
{
    fork leon;
    fork {
        sleep(10, 30);
        work_set(WK_ENEMY, ID_EM_0);
        plc_neck(0, 0, 512, 0, 55, 55);
    }
}

proc leon
{
    sleep(10, 10);
    work_set(WK_PLAYER, 0);
    plc_neck(2, 0, -512, 0, 67, 67);
}

You can pass a procedure name to fork, or an inline anonymous procedure block as shown above.

0x05: evt_kill(u8 evt_id)

Used to terminate a running event created using evt_exec.

Example:

proc main
{
    evt_exec(9, I_GOSUB, shake_head);
    sleep(10, 300);
    evt_kill(9);
}

proc shake_head
{
    repeat {
        work_set(WK_PLAYER, 0);
        plc_neck(2, 0, -512, 0, 67, 67);
        sleep(10, 60);
        plc_neck(2, 0, 512, 0, 67, 67);
        sleep(10, 60);
    }
}

A new event (id 9) is created that repeated moves the player's head forever. But after 300 frames (10 seconds), the event is terminated using evt_kill.

0x2E: work_set(u8 kind, u8 id)

  • kind - The entity kind.
    • 0x00: WK_NONE - Presumably clears the current entity. Can't see any reason to use this.
    • 0x01: WK_PLAYER - The player model.
    • 0x02: WK_SPLAYER - The partner model set using sce_em_set and ID 255 (Ada / Sherry).
    • 0x03: WK_ENEMY - An enemy set using sce_em_set (do not use for the partner EM 255)
    • 0x04: WK_OBJECT - An object set using obj_model_set.
    • 0x05: WK_DOOR - A door set using door_aot_se, or door_aot_set_4p.
    • 0x06: WK_ALL - Not sure what this for.
  • id - The slot index if applicable.

Example:

work_set(WK_PLAYER, 0);
pos_set(0, -21000, 0, -25000);
dir_set(0, 0, 1024, 0);

Sets the current entity to work on to the player model, then sets the position and direction of it.

0x3F: plc_motion(u8 group, u8 animation, u8 flags)

  • group - The animation group.
    • 0 - Relevant EDD embedded in the RDT.
    • 1 - First EDD in PLD/EMD file.
    • 2 - Second EDD in PLD/EMD file.
  • mode - Flags that control how the animation is played.
    • 0x01 - Seems to apply some movement once
    • 0x02 - Seems to apply some movement once
    • 0x04 - Loop
    • 0x08 - x2 speed
    • 0x10 - x0.5 speed
    • 0x80 - Reversed

Example:

work_set(WK_PLAYER, 0);
plc_motion(1, 6, 0);

Causes the player model to play the crouching animation once (animation 6 from the first EDD of the PLD file).

0x44: sce_em_set(u8 padding, u8 id, u8 type, u8 pose, u8 behaviour, u8 floor, u8 sound, u8 texture, u8 globalId, s16 x, s16 y, s16 z, s16 d, u16 animation, u16 padding)

Initialises an enemy or NPC in the room. For the most part, this instruction alone is enough for an enemy, but any special behaviour or event requires further instructions that act on the enemy ID. This must be called on the first frame when loading the room, so do not use after any evt_next, sleep instructions or in a subroutine called from an AOT or evt_exec. It is good practice to initialise all your NPCs first, then enemies at the start of your script to avoid potential issues. You can have different sce_em_set for the same ID, but make sure they only run independently on a room load and not both together.

  • id - The EM slot ID. Each enemy / npc must have a unique ID in the room. 255 should be used for the partner.
  • type - The enemy type.
Enemies NPCs
0x10: ENEMY_ZOMBIE_COP 0x40: ENEMY_CHIEF_IRONS_1
0x11: ENEMY_ZOMBIE_BRAD 0x41: ENEMY_ADA_WONG_1
0x12: ENEMY_ZOMBIE_GUY_1 0x42: ENEMY_CHIEF_IRONS_2
0x13: ENEMY_ZOMBIE_GIRL 0x43: ENEMY_ADA_WONG_2
0x14: ENEMY_ZOMBIE_TEST_SUBJECT 0x44: ENEMY_BEN_BERTOLUCCI_1
0x15: ENEMY_ZOMBIE_SCIENTIST 0x45: ENEMY_SHERRY_PENDANT
0x16: ENEMY_ZOMBIE_NAKED 0x46: ENEMY_BEN_BERTOLUCCI_2
0x17: ENEMY_ZOMBIE_GUY_2 0x47: ENEMY_ANNETTE_BIRKIN_1
0x1E: ENEMY_ZOMBIE_GUY_3 0x48: ENEMY_ROBERT_KENDO
0x1F: ENEMY_ZOMBIE_RANDOM 0x49: ENEMY_ANNETTE_BIRKIN_2
0x20: ENEMY_ZOMBIE_DOG 0x4A: ENEMY_MARVIN_BRANAGH
0x21: ENEMY_CROW 0x4B: ENEMY_MAYORS_DAUGHTER
0x22: ENEMY_LICKER_RED 0x4F: ENEMY_SHERRY_JACKET
0x23: ENEMY_ALLIGATOR 0x50: ENEMY_LEON_KENNEDY_RPD
0x24: ENEMY_LICKER_GREY 0x51: ENEMY_CLAIRE_REDFIELD
0x25: ENEMY_SPIDER 0x54: ENEMY_LEON_KENNEDY_BANDAGED
0x26: ENEMY_BABY_SPIDER 0x55: ENEMY_CLAIRE_REDFIELD_NO_JACKET
0x27: ENEMY_G_EMBRYO 0x58: ENEMY_LEON_KENNEDY_CAP_TANK_TOP
0x28: ENEMY_G_ADULT 0x59: ENEMY_CLAIRE_REDFIELD_COW_GIRL
0x29: ENEMY_COCKROACH 0x5A: ENEMY_LEON_KENNEDY_BLACK_LEATHER
0x2A: ENEMY_TYRANT_1
0x2B: ENEMY_TYRANT_2
0x2D: ENEMY_ZOMBIE_ARMS
0x2E: ENEMY_IVY
0x2F: ENEMY_VINES
0x30: ENEMY_BIRKIN_1
0x31: ENEMY_BIRKIN_2
0x32: ENEMY_BIRKIN_3
0x33: ENEMY_BIRKIN_4
0x34: ENEMY_BIRKIN_5
0x39: ENEMY_IVY_PURPLE
0x3A: ENEMY_GIANT_MOTH
0x3B: ENEMY_MAGGOTS
  • pose - Known as the enemy pose, but is often the initial state of the enemy. Each enemy has different poses.

    • 0x00: POSE_ZOMBIE_WAIT
    • 0x01: POSE_ZOMBIE_LYING
    • 0x02: POSE_ZOMBIE_WAKE_UP
    • 0x03: POSE_ZOMBIE_CRAWL
    • 0x04: POSE_ZOMBIE_GET_UP
    • 0x05: POSE_ZOMBIE_DEAD_UP
    • 0x06: POSE_ZOMBIE_FOLLOW
    • 0x07: POSE_ZOMBIE_DEAD
    • 0x08: POSE_ZOMBIE_EATING
    • 0x40: POSE_ZOMBIE_40

    • 0x00: POSE_DOG_IDLE
    • 0x02: POSE_DOG_HOSTILE
    • 0x05: POSE_DOG_EATING
  • behaviour - Common flags that controls the enemy AI. Use bitwise-or to combine them.

    • 0x01: AI_01 -
    • 0x02: AI_02 -
    • 0x04: AI_04 -
    • 0x08: AI_08 -
    • 0x10: AI_10 -
    • 0x20: AI_20 -
    • 0x40: AI_40 - For some enemies, this flag will ignore the player until hurt. Useful for e.g. zombies that are eating a dead body.
    • 0x80: AI_INACTIVE - The enemy will be frozen. Use this for sleeping zombies or enemies not yet in the room.
  • floor - The initial floor the enemy is on. This is usually Y / -1800.

  • sound - The sound ID. Each enemy has a specific sound ID, but in rooms where multiple types of enemies exist, special sound IDs are required which contain all the required sounds. Only one enemy sound file can be loaded for a room. Using multiple IDs that require different files will result in silent enemies.

  • globalId - Each enemy in the game requires a unique global ID which is used to track which enemies you have killed or not. Sharing an ID would mean that killing one would prevent all others with the same global ID from spawning. 255 is a special ID that means that an enemy will always respawn. This means you can have 254 unique enemies, however the game uses a different group of flags for stages 1-4 and 5-7 which therefore gives you 508 across the whole game. If you require more, then you will need to selectively reset the enemy IDs after an event or point-of-no-return. Whether an enemy is killed or not can be checked with ck(FG_ENEMY, globalId, 1) (stage 1-4) or ck(FG_ENEMY_2, globalId, 1) (stage 5-7). You can reset the killed status using set(FG_ENEMY, globalId, 0).

  • texture - Usually 0, but some zombies can have this set to change their body texture for zombies that have multiple body textures in their file.

  • x - Initial position in the room on the X-axis. -32000 is usually used for out of bounds (not yet spawned in room).

  • y - Initial position in the room on the Y-axis. -10000 is usually used for out of bounds (not yet spawned in room).

  • z - Initial position in the room on the Z-axis. -32000 is usually used for out of bounds (not yet spawned in room).

  • d - Initial orientation of the enemy between 0 to 4096, or -2048 to +2048. 1024 is 90 degrees.

  • animation - Unsure what this is for, leave at 0.

Examples:

if (ck(FG_COMMON, 20, 0)) {
    sce_em_set(0, ID_EM_0, ENEMY_ZOMBIE_GUY1, 0, AI_DEFAULT, 0, SBK_5, 0, 66, -26174, 0, -178, 1208, 0, 0);
    sce_em_set(0, ID_EM_1, ENEMY_ZOMBIE_GIRL, 0, AI_DEFAULT, 0, SBK_10, 0, 67, -23477, 0, 2299, 920, 0, 0);
} else {
    sce_em_set(0, ID_EM_0, ENEMY_ZOMBIE_DOG, 0, AI_DEFAULT, 0, SBK_12, 0, 135, -17564, 0, -11339, 3053, 0, 0);
    sce_em_set(0, ID_EM_1, ENEMY_ZOMBIE_DOG, 0, AI_DEFAULT, 0, SBK_12, 0, 136, -23651, 0, -23105, 2421, 0, 0);
    sce_em_set(0, ID_EM_2, ENEMY_ZOMBIE_DOG, 0, AI_DEFAULT, 0, SBK_12, 0, 138, -22376, 0, -25015, 3381, 0, 0);
}

This example spawns two zombies, unless flag 20 is set, in which case three dogs spawn instead. Notice how the same enemy IDs, and incompatible sound IDs can be used because the instructions are mutually exclusive.

0x5B: plc_cnt(u8 frames)

Skips the specified number of frames in the currently playing animation started with plc_motion.

  • frames - The number of frames to skip.

Example:

work_set(WK_PLAYER, 0);
plc_motion(1, 2, 0);
plc_cnt(94);

Causes the player model to play the dying animation once starting from frame 94. The game will morph the player's model gradually from the current pose to frame 94 of the dying animation and then play the rest of the animation to the end.

0x51: sce_bgm_control(u8 channel, u8 operand1, u8 operand2, u8 left, u8 right)

Plays, stops, or adjusts the volume and panning of background music, or ambient sound effects. The game internally stores the loaded music in a channel which means that when switching rooms, if the room contains the same BGM track for the channel, it will continue playing and not restart from the beginning. This prevents the music repeatedly restarting when a whole area contains the same BGM.

  • channel - The BGM channel to change.
    • 0x00: BGM_CHANNEL_MAIN - Usually used for main background music.
    • 0x01: BGM_CHANNEL_SUB0 - Usually used for event / cutscene background music.
    • 0x02: BGM_CHANNEL_SUB1 - Usually used for ambient sound effects.
  • operand1 - The primary operation to perform for the channel.
    • 0x00: BGM_OP_NOP - Performs no operation.
    • 0x01: BGM_OP_START - Starts playing the channel.
    • 0x02: BGM_OP_STOP - Stops playing the channel.
    • 0x03: BGM_OP_RESTART - Seems to behave the same as BGM_OP_START. I can't find a way of actually restarting a track.
    • 0x04: BGM_OP_PAUSE - Seems to behave the same as BGM_OP_STOP.
    • 0x05: BGM_OP_FADEOUT - Like BGM_OP_STOP but fades out the BGM gradually.
  • operand2 - A secondary operation to perform.
    • 0x00: BGM_TYPE_MAIN_VOL - Controls the volume of the main track.
    • 0x01: BGM_TYPE_PROG0_VOL - Controls the volume of the secondary track 0.
    • 0x02: BGM_TYPE_PROG1_VOL - Controls the volume of the secondary track 1.
    • 0x03: BGM_TYPE_PROG2_VOL - Controls the volume of the secondary track 2.
  • left - The left speaker volume. Tends to be between 0 and 120. 64 is normal volume.
  • right - The right speaker volume. Tends to be between 0 and 120. 64 is normal volume.

Example 1:

proc main
{
    if (ck(FG_COMMON, 12, 0)) {
        sce_bgm_control(BGM_CHANNEL_MAIN, BGM_OP_START, 0, 0, 0)
        sce_bgm_control(BGM_CHANNEL_SUB0, BGM_OP_STOP, 0, 0, 0)
    } else {
        sce_bgm_control(BGM_CHANNEL_MAIN, BGM_OP_STOP, 0, 0, 0)
        sce_bgm_control(BGM_CHANNEL_SUB0, BGM_OP_START, 0, 0, 0)
    }
}

Plays the main BGM if flag 12 is not set, otherwise plays the secondary BGM.

Example 2:

proc bgm_loop
{
    repeat {
        switch (V_CUT) {
        case 0:
            sce_bgm_control(BGM_CHANNEL_MAIN, BGM_OP_NOP, BGM_TYPE_PROG0_VOL, 1, 65);
            sce_bgm_control(BGM_CHANNEL_MAIN, BGM_OP_NOP, BGM_TYPE_PROG1_VOL, 61, 65);
            sce_bgm_control(BGM_CHANNEL_MAIN, BGM_OP_NOP, BGM_TYPE_PROG2_VOL, 51, 65);
            break;
        case 1:
            sce_bgm_control(BGM_CHANNEL_MAIN, BGM_OP_NOP, BGM_TYPE_PROG0_VOL, 1, 65);
            sce_bgm_control(BGM_CHANNEL_MAIN, BGM_OP_NOP, BGM_TYPE_PROG1_VOL, 61, 65);
            sce_bgm_control(BGM_CHANNEL_MAIN, BGM_OP_NOP, BGM_TYPE_PROG2_VOL, 51, 65);
            break;
        case 2:
            sce_bgm_control(BGM_CHANNEL_MAIN, BGM_OP_NOP, BGM_TYPE_PROG0_VOL, 1, 65);
            sce_bgm_control(BGM_CHANNEL_MAIN, BGM_OP_NOP, BGM_TYPE_PROG1_VOL, 61, 65);
            sce_bgm_control(BGM_CHANNEL_MAIN, BGM_OP_NOP, BGM_TYPE_PROG2_VOL, 51, 65);
            break;
        }
        evt_next();
    }
}

Runs a continuous loop to adjust the ambient background music volume and panning depending on the camera angle.

0x57: sce_bgmtbl_set(u8 padding, u8 room, u8 stage, u16 id, u16 padding)

Sets the primary and secondary background music tracks for a given room. The game internally keeps a table of every room and the background music that should be loaded for it. This table is initialised when starting a new game using INIT_TBL.DAT. This instruction can update that table. Unfortunately this cannot update the BGM in realtime, thus if you update the table for the current room the player is in, it will not take effect until the player reloads the room.

Mods can either update INIT_TBL.DAT to initialise each room's BGM, or update all the required table entries in the very first room of the game.

  • room - The room number, e.g. 0x01 for Kendo's shop.
  • stage - The stage number, e.g. 0x00 for city / 2F RPD.
  • id - The file ID for the main channel and the secondary channel. 0xFF means no BGM / silent.

Example:

sce_bgmtbl_set(0, 0x01, 0x00, 0x3302, 0);

This sets ROOM1010 (Kendo's shop) to use 0x02: MAIN02.SAP (Library) for the main channel, and 0x33: SUB42.SAP (Brad) for the secondary channel. Most of the BGM IDs correspond to the .sap filenames, but some like 0x33 do not.

The following macro may be useful:

#define SET_BGM(room, bgm, mus)     sce_bgmtbl_set(0, room & 0xFF, (room >> 8) & 0xFF, bgm | mus, 0)

Which can be used as follows:

#define BGM_LIBRARY         0x0002
#define BGM_BASEMENT        0x0003
#define BGM_RPD_HALL        0x0005
#define BGM_NONE            0x00FF

#define MUS_ZOMBIE_ATTACK   0x0000
#define MUS_HAUNT           0x3300
#define MUS_NONE            0xFF00

proc main
{
    // Set room 200 (main hall) to library BGM, no secondary BGM
    SET_BGM(0x200, BGM_LIBRARY, MUS_NONE);
}

0x60: kage_set(3, u8 em_id, u8 red, u8 green, u8 blue, s16 x_size, s16 z_size, s16 x_offset, s16 z_offset)

Adds a coloured shadow under the enemy/npc, usually used to show blood (e.g. dying/dead Annette in ROOM6141.RDT).

  • em_id - The id of enemy/npc. Game will crash if em slot is empty.
  • red - Red component, 0 for 100%, 255 for 0%.
  • green - Green component, 0 for 100%, 255 for 0%.
  • blue - Blue component, 0 for 100%, 255 for 0%.
  • x_size - Diameter of shadow in X axis.
  • z_size - Diameter of shadow in Z axis.
  • x_offset - Offset of shadow in X axis from centre of enemy.
  • z_offset - Offset of shadow in Z axis from centre of enemy.

Example:

evt_next();
kage_set(3, ID_EM_0, 16, 191, 191, 1500, 1500, 0, 0);

Add a 1500x1500 red-ish shadow under the centre of Annette (ID_EM_0).

Note: kage_set must not be called on the first frame, doing this will result in a crash. Ensure you have a evt_next or sleep prior to this instruction if calling from room initialization.

0x83: heal()

Heals the player to full health.

Example:

heal();
message_on(0, ID_MSG_0, 0, 255, 255); // Your wounds have been treated.
evt_next();

0x86: poison_ck()

Returns true if the player is poisoned, otherwise false.

Example:

if (poison_ck()) {
    message_on(0, ID_MSG_0, 0, 255, 255); // I have treated your poisoned wounds.
    evt_next();
    poison_clr();
} else {
    message_on(0, ID_MSG_1, 0, 255, 255); // If you are ever poisoned, I can help you.
    evt_next();
}

0x87: poison_clr()

Clears the poison status if the player is poisoned.

Example:

message_on(0, ID_MSG_3, 0, 255, 255); // Blue herbs are growing here, will you use one?
evt_next();
if (ck(FG_MESSAGE, F_QUESTION, 0)) {
    poison_clr();
}

0x88: sce_item_ck_lost(u8 item, u8 count)

Removes an item from the player's inventory and returns true, or false if the player did not have the specified item.

  • item - The item to remove, e.g. ITEM_INKRIBBON.
  • count - The amount to remove, e.g. 1.

If the player has the specified item, but less that the specified count, the function still returns true and the item is fully lost.

Example:

sce_item_ck_lost(ITEM_INKRIBBON, 2);
if (sce_item_ck_lost(ITEM_BLUECARD, 1)) {
    message_on(0, ID_MSG_0, 0, 255, 255); // You used the key card
    evt_next();
} else {
    // Player did not have blue key card
    message_on(0, ID_MSG_0, 0, 255, 255); // A key card is required.
    evt_next();
}