1
0
mirror of https://github.com/zeldaret/oot.git synced 2024-09-21 04:24:43 +00:00

Document elf_message scripting system (#1398)

* `cUpElfMsgs` -> `cUpMsgs`

Motivation:
ElfMessage is the name of the system that handles c-up messages from navi, but also messages from child/adult saria
so it would make sense to name this after the system name like "ElfMsg"
but "cUpElf" primarily reads like (to me) "c up navi" since the actor implementing navi is EnElf

I think it'd be better to clear that confusion between "navi" and "elfmsg system" by just not using "elf" in the name

* Standardize c-up navi messages ElfMessage data to be named after "CUp"

* -> "Navi"

* Make symbols in `elf_message_` segments static

* new docs

* change commands, format

* introduce navi file id

* use enum

* remove concat

* add clarifying comment for skip

* concat cmd type

* Hints -> QuestHint

* rename command header

* s -> g

* missed enum name

* singular

* missed one

Co-authored-by: Dragorn421 <Dragorn421@users.noreply.github.com>
This commit is contained in:
fig02 2022-10-15 13:24:13 -04:00 committed by GitHub
parent d42307561a
commit fd24ad6e67
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 343 additions and 290 deletions

View File

@ -797,8 +797,8 @@ void GetItem_Draw(PlayState* play, s16 drawId);
void SfxSource_InitAll(PlayState* play);
void SfxSource_UpdateAll(PlayState* play);
void SfxSource_PlaySfxAtFixedWorldPos(PlayState* play, Vec3f* worldPos, s32 duration, u16 sfxId);
u16 ElfMessage_GetSariaText(PlayState* play);
u16 ElfMessage_GetCUpText(PlayState* play);
u16 QuestHint_GetSariaTextId(PlayState* play);
u16 QuestHint_GetNaviTextId(PlayState* play);
u16 Text_GetFaceReaction(PlayState* play, u32 reactionSet);
void Flags_UnsetAllEnv(PlayState* play);
void Flags_SetEnv(PlayState* play, s16 flag);

View File

@ -1131,7 +1131,7 @@ typedef struct {
/* 0x01 */ u8 byte1;
/* 0x02 */ u8 byte2;
/* 0x03 */ u8 byte3;
} ElfMessage; // size = 0x4
} QuestHintCmd; // size = 0x4
typedef struct {
/* 0x00 */ u8 numActors;
@ -1193,7 +1193,7 @@ typedef struct PlayState {
/* 0x11E00 */ EntranceEntry* setupEntranceList;
/* 0x11E04 */ s16* setupExitList;
/* 0x11E08 */ Path* setupPathList;
/* 0x11E0C */ ElfMessage* cUpElfMsgs;
/* 0x11E0C */ QuestHintCmd* naviQuestHints;
/* 0x11E10 */ void* specialEffects;
/* 0x11E14 */ u8 skyboxId;
/* 0x11E15 */ s8 transitionTrigger; // "fade_direction"

View File

@ -1,129 +0,0 @@
#ifndef Z64ELF_MESSAGE_H
#define Z64ELF_MESSAGE_H
#include "ultra64.h"
// Checks the condition and exits the script if the check passes
#define ELF_MSG_TYPE_CHECK 0
// ? (unused)
#define ELF_MSG_TYPE_UNK_1 1
// ? (unused)
#define ELF_MSG_TYPE_UNK_2 2
// Checks the condition and skips forward by some number of commands if the check passes
#define ELF_MSG_TYPE_SKIP 3
// Always ends the script, returning the text id for this command
#define ELF_MSG_TYPE_END 7
// Check an eventChkInf flag
#define ELF_MSG_CONDITION_FLAG 0
// Check a dungeon item (map, compass, boss key)
#define ELF_MSG_CONDITION_DUNGEON_ITEM 1
// Check if an item is in an item slot
#define ELF_MSG_CONDITION_ITEM 2
// "Other" conditions described below
#define ELF_MSG_CONDITION_OTHER 3
// Check what strength upgrade has been obtained so far
#define ELF_MSG_CONDITION_STRENGTH_UPG 0
// Check if specific boots have been obtained so far
#define ELF_MSG_CONDITION_BOOTS 1
// Check if a particular song has been obtained
#define ELF_MSG_CONDITION_SONG 2
// Check if a particular medallion has been obtained
#define ELF_MSG_CONDITION_MEDALLION 3
// Check if the magic meter has been obtained
#define ELF_MSG_CONDITION_MAGIC 4
/*
* Bitpack byte 0
*/
#define ELF_MSG_B0(type, cond_type, tf) \
_SHIFTL(ELF_MSG_TYPE_##type, 5, 3) | \
_SHIFTL(ELF_MSG_CONDITION_##cond_type, 1, 4) | \
_SHIFTL(tf, 0, 1)
/*
* Bitpack byte 1
*/
#define ELF_MSG_B1(cond_type, data) \
_SHIFTL(ELF_MSG_CONDITION_##cond_type, 4, 4) | \
_SHIFTL(data, 0, 4)
/*
* Other bytes
*/
#define ELF_MSG_B(data) \
_SHIFTL(data, 0, 8)
/*
* Command macros
*/
#define ELF_MSG_FLAG(type, textId, tf, flag) \
{ \
ELF_MSG_B0(type, FLAG, tf), \
ELF_MSG_B(flag), \
ELF_MSG_B(textId), \
ELF_MSG_B(0), \
}
#define ELF_MSG_END(textId) \
ELF_MSG_FLAG(END, textId, false, 0)
#define ELF_MSG_DUNGEON_ITEM(type, textId, tf, itemId) \
{ \
ELF_MSG_B0(type, DUNGEON_ITEM, tf), \
ELF_MSG_B(itemId), \
ELF_MSG_B(textId), \
ELF_MSG_B(0), \
}
#define ELF_MSG_ITEM(type, textId, tf, slotItemId, itemId) \
{ \
ELF_MSG_B0(type, ITEM, tf), \
ELF_MSG_B(slotItemId), \
ELF_MSG_B(textId), \
ELF_MSG_B(itemId), \
}
#define ELF_MSG_STRENGTH_UPG(type, textId, tf, strUpg) \
{ \
ELF_MSG_B0(type, OTHER, tf), \
ELF_MSG_B1(STRENGTH_UPG, strUpg), \
ELF_MSG_B(textId), \
ELF_MSG_B(0), \
}
#define ELF_MSG_BOOTS(type, textId, tf, itemId) \
{ \
ELF_MSG_B0(type, OTHER, tf), \
ELF_MSG_B1(BOOTS, 0), \
ELF_MSG_B(textId), \
ELF_MSG_B(itemId), \
}
#define ELF_MSG_SONG(type, textId, tf, itemId) \
{ \
ELF_MSG_B0(type, OTHER, tf), \
ELF_MSG_B1(SONG, 0), \
ELF_MSG_B(textId), \
ELF_MSG_B(itemId), \
}
#define ELF_MSG_MEDALLION(type, textId, tf, itemId) \
{ \
ELF_MSG_B0(type, OTHER, tf), \
ELF_MSG_B1(MEDALLION, 0), \
ELF_MSG_B(textId), \
ELF_MSG_B(itemId), \
}
#define ELF_MSG_MAGIC(type, textId, tf) \
{ \
ELF_MSG_B0(type, OTHER, tf), \
ELF_MSG_B1(MAGIC, 0), \
ELF_MSG_B(textId), \
ELF_MSG_B(0), \
}
#endif

View File

@ -0,0 +1,150 @@
#ifndef Z64QUEST_HINT_COMMANDS_H
#define Z64QUEST_HINT_COMMANDS_H
#include "ultra64.h"
/*
* Hint Command Types
*/
// Checks the condition and exits the script if the check passes
#define QUEST_HINT_TYPE_CHECK 0
// Checks a chain of conditions and only evaluates the last entry
// if all conditions leading up to it were also true
#define QUEST_HINT_TYPE_CHAIN 1
// Checks a chain of conditionals and will return a randomly chosen entry among
// the conditions that evaluated to true
#define QUEST_HINT_TYPE_RANDOM 2
// Checks the condition and skips forward by specified number of commands if the check passes
// Note that the amount of entries to skip is specified in the field where the textId would usually go
#define QUEST_HINT_TYPE_SKIP 3
// Always ends the script, returning the text id for this command
#define QUEST_HINT_TYPE_END 7
/*
* Hint Condition Types
*/
// Check an eventChkInf flag
#define QUEST_HINT_CONDITION_FLAG 0
// Check a dungeon item (map, compass, boss key)
#define QUEST_HINT_CONDITION_DUNGEON_ITEM 1
// Check if an item is in an item slot
#define QUEST_HINT_CONDITION_ITEM 2
// "Other" conditions described below
#define QUEST_HINT_CONDITION_OTHER 3
/*
* "Other" Condition Types
*/
// Check what strength upgrade has been obtained so far
#define QUEST_HINT_CONDITION_STRENGTH_UPG 0
// Check if specific boots have been obtained so far
#define QUEST_HINT_CONDITION_BOOTS 1
// Check if a particular song has been obtained
#define QUEST_HINT_CONDITION_SONG 2
// Check if a particular medallion has been obtained
#define QUEST_HINT_CONDITION_MEDALLION 3
// Check if the magic meter has been obtained
#define QUEST_HINT_CONDITION_MAGIC 4
/*
* Byte pack macros
*/
#define HINT_B0(type, condType, tf) \
_SHIFTL(QUEST_HINT_TYPE_##type, 5, 3) | \
_SHIFTL(condType, 1, 4) | \
_SHIFTL(tf, 0, 1)
#define HINT_B1(condType, data) \
_SHIFTL(condType, 4, 4) | \
_SHIFTL(data, 0, 4)
#define HINT_B(data) \
_SHIFTL(data, 0, 8)
/*
* Command macros
*/
#define QUEST_HINT_FLAG(type, flag, tf, textId) \
{ \
HINT_B0(type, QUEST_HINT_CONDITION_FLAG, tf), \
HINT_B(flag), \
HINT_B(textId), \
HINT_B(0), \
}
#define QUEST_HINT_END(textId) \
QUEST_HINT_FLAG(END, 0, false, textId)
#define QUEST_HINT_DUNGEON_ITEM(type, itemId, tf, textId) \
{ \
HINT_B0(type, QUEST_HINT_CONDITION_DUNGEON_ITEM, tf), \
HINT_B(itemId), \
HINT_B(textId), \
HINT_B(0), \
}
#define QUEST_HINT_ITEM(type, slotItemId, itemId, tf, textId) \
{ \
HINT_B0(type, QUEST_HINT_CONDITION_ITEM, tf), \
HINT_B(slotItemId), \
HINT_B(textId), \
HINT_B(itemId), \
}
#define QUEST_HINT_STRENGTH_UPG(type, strUpg, tf, textId) \
{ \
HINT_B0(type, QUEST_HINT_CONDITION_OTHER, tf), \
HINT_B1(QUEST_HINT_CONDITION_STRENGTH_UPG, strUpg), \
HINT_B(textId), \
HINT_B(0), \
}
#define QUEST_HINT_BOOTS(type, itemId, tf, textId) \
{ \
HINT_B0(type, QUEST_HINT_CONDITION_OTHER, tf), \
HINT_B1(QUEST_HINT_CONDITION_BOOTS, 0), \
HINT_B(textId), \
HINT_B(itemId), \
}
#define QUEST_HINT_SONG(type, itemId, tf, textId) \
{ \
HINT_B0(type, QUEST_HINT_CONDITION_OTHER, tf), \
HINT_B1(QUEST_HINT_CONDITION_SONG, 0), \
HINT_B(textId), \
HINT_B(itemId), \
}
#define QUEST_HINT_MEDALLION(type, itemId, tf, textId) \
{ \
HINT_B0(type, QUEST_HINT_CONDITION_OTHER, tf), \
HINT_B1(QUEST_HINT_CONDITION_MEDALLION, 0), \
HINT_B(textId), \
HINT_B(itemId), \
}
#define QUEST_HINT_MAGIC(type, tf, textId) \
{ \
HINT_B0(type, QUEST_HINT_CONDITION_OTHER, tf), \
HINT_B1(QUEST_HINT_CONDITION_MAGIC, 0), \
HINT_B(textId), \
HINT_B(0), \
}
#endif

View File

@ -223,7 +223,7 @@ typedef struct {
typedef struct {
/* 0x00 */ u8 code;
/* 0x01 */ u8 cUpElfMsgNum;
/* 0x01 */ u8 naviQuestHintFileId;
/* 0x04 */ u32 keepObjectId;
} SCmdSpecialFiles;
@ -469,6 +469,14 @@ typedef enum {
#define SCENE_CAM_TYPE_FIXED_MARKET 0x40 // Camera exhibits fixed behaviors and delays textboxes by a small amount before they start to appear
#define SCENE_CAM_TYPE_SHOOTING_GALLERY 0x50 // Unreferenced in code, and used only by the main layer of the shooting gallery scene
// navi hints
// TODO: make ZAPD use this enum for `SCENE_CMD_SPECIAL_FILES`
typedef enum {
NAVI_QUEST_HINTS_NONE,
NAVI_QUEST_HINTS_OVERWORLD,
NAVI_QUEST_HINTS_DUNGEON
} NaviQuestHintFileId;
// Scene commands
typedef enum {
@ -522,8 +530,8 @@ typedef enum {
#define SCENE_CMD_ENTRANCE_LIST(entranceList) \
{ SCENE_CMD_ID_ENTRANCE_LIST, 0, CMD_PTR(entranceList) }
#define SCENE_CMD_SPECIAL_FILES(elfMessageFile, keepObjectId) \
{ SCENE_CMD_ID_SPECIAL_FILES, elfMessageFile, CMD_W(keepObjectId) }
#define SCENE_CMD_SPECIAL_FILES(naviQuestHintFileId, keepObjectId) \
{ SCENE_CMD_ID_SPECIAL_FILES, naviQuestHintFileId, CMD_W(keepObjectId) }
#define SCENE_CMD_ROOM_BEHAVIOR(curRoomUnk3, curRoomUnk2, showInvisActors, disableWarpSongs) \
{ SCENE_CMD_ID_ROOM_BEHAVIOR, curRoomUnk3, \

View File

@ -1,60 +1,69 @@
#include "global.h"
#include "z64elf_message.h"
#include "z64quest_hint_commands.h"
ElfMessage sChildSariaMsgs[] = {
ELF_MSG_STRENGTH_UPG(SKIP, 3, false, 0),
ELF_MSG_FLAG(CHECK, 0x61, false, EVENTCHKINF_37),
ELF_MSG_END(0x64),
ELF_MSG_FLAG(CHECK, 0x62, false, EVENTCHKINF_25),
ELF_MSG_FLAG(CHECK, 0x63, false, EVENTCHKINF_37),
ELF_MSG_FLAG(CHECK, 0x65, false, EVENTCHKINF_43),
ELF_MSG_MEDALLION(CHECK, 0x66, false, ITEM_MEDALLION_FOREST),
ELF_MSG_MEDALLION(CHECK, 0x66, false, ITEM_MEDALLION_FIRE),
ELF_MSG_MEDALLION(CHECK, 0x66, false, ITEM_MEDALLION_WATER),
ELF_MSG_SONG(CHECK, 0x67, false, ITEM_SONG_STORMS),
ELF_MSG_MEDALLION(CHECK, 0x68, false, ITEM_MEDALLION_SPIRIT),
ELF_MSG_MEDALLION(CHECK, 0x68, false, ITEM_MEDALLION_SHADOW),
ELF_MSG_END(0x69),
QuestHintCmd sChildSariaQuestHints[] = {
QUEST_HINT_STRENGTH_UPG(SKIP, 0, false, 3),
QUEST_HINT_FLAG(CHECK, EVENTCHKINF_37, false, 0x61),
QUEST_HINT_END(0x64),
QUEST_HINT_FLAG(CHECK, EVENTCHKINF_25, false, 0x62),
QUEST_HINT_FLAG(CHECK, EVENTCHKINF_37, false, 0x63),
QUEST_HINT_FLAG(CHECK, EVENTCHKINF_43, false, 0x65),
QUEST_HINT_MEDALLION(CHECK, ITEM_MEDALLION_FOREST, false, 0x66),
QUEST_HINT_MEDALLION(CHECK, ITEM_MEDALLION_FIRE, false, 0x66),
QUEST_HINT_MEDALLION(CHECK, ITEM_MEDALLION_WATER, false, 0x66),
QUEST_HINT_SONG(CHECK, ITEM_SONG_STORMS, false, 0x67),
QUEST_HINT_MEDALLION(CHECK, ITEM_MEDALLION_SPIRIT, false, 0x68),
QUEST_HINT_MEDALLION(CHECK, ITEM_MEDALLION_SHADOW, false, 0x68),
QUEST_HINT_END(0x69),
};
ElfMessage sAdultSariaMsgs[] = {
ELF_MSG_MEDALLION(CHECK, 0x6A, false, ITEM_MEDALLION_FOREST),
ELF_MSG_MEDALLION(CHECK, 0x6B, false, ITEM_MEDALLION_FIRE),
ELF_MSG_MEDALLION(CHECK, 0x6B, false, ITEM_MEDALLION_WATER),
ELF_MSG_MEDALLION(CHECK, 0x6C, false, ITEM_MEDALLION_SPIRIT),
ELF_MSG_MEDALLION(CHECK, 0x6C, false, ITEM_MEDALLION_SHADOW),
ELF_MSG_END(0x6D),
QuestHintCmd sAdultSariaQuestHints[] = {
QUEST_HINT_MEDALLION(CHECK, ITEM_MEDALLION_FOREST, false, 0x6A),
QUEST_HINT_MEDALLION(CHECK, ITEM_MEDALLION_FIRE, false, 0x6B),
QUEST_HINT_MEDALLION(CHECK, ITEM_MEDALLION_WATER, false, 0x6B),
QUEST_HINT_MEDALLION(CHECK, ITEM_MEDALLION_SPIRIT, false, 0x6C),
QUEST_HINT_MEDALLION(CHECK, ITEM_MEDALLION_SHADOW, false, 0x6C),
QUEST_HINT_END(0x6D),
};
u32 ElfMessage_CheckCondition(ElfMessage* msg) {
s32 type = msg->byte0 & 0x1E;
u32 QuestHint_CheckCondition(QuestHintCmd* hintCmd) {
s32 type = hintCmd->byte0 & 0x1E;
u16 flag;
switch (type) {
case (ELF_MSG_CONDITION_FLAG << 1):
flag = 1 << (msg->byte1 & 0x0F);
return ((msg->byte0 & 1) == 1) == ((flag & gSaveContext.eventChkInf[(msg->byte1 & 0xF0) >> 4]) != 0);
case (ELF_MSG_CONDITION_DUNGEON_ITEM << 1):
return ((msg->byte0 & 1) == 1) ==
(CHECK_DUNGEON_ITEM(msg->byte1 - ITEM_KEY_BOSS, gSaveContext.mapIndex) != 0);
case (ELF_MSG_CONDITION_ITEM << 1):
return ((msg->byte0 & 1) == 1) == (msg->byte3 == INV_CONTENT(msg->byte1));
case (ELF_MSG_CONDITION_OTHER << 1):
switch (msg->byte1 & 0xF0) {
case (ELF_MSG_CONDITION_STRENGTH_UPG << 4):
return ((msg->byte0 & 1) == 1) == ((msg->byte1 & 0x0F) == CUR_UPG_VALUE(UPG_STRENGTH));
case (ELF_MSG_CONDITION_BOOTS << 4):
return ((msg->byte0 & 1) == 1) ==
case (QUEST_HINT_CONDITION_FLAG << 1):
flag = 1 << (hintCmd->byte1 & 0x0F);
return ((hintCmd->byte0 & 1) == 1) ==
((flag & gSaveContext.eventChkInf[(hintCmd->byte1 & 0xF0) >> 4]) != 0);
case (QUEST_HINT_CONDITION_DUNGEON_ITEM << 1):
return ((hintCmd->byte0 & 1) == 1) ==
(CHECK_DUNGEON_ITEM(hintCmd->byte1 - ITEM_KEY_BOSS, gSaveContext.mapIndex) != 0);
case (QUEST_HINT_CONDITION_ITEM << 1):
return ((hintCmd->byte0 & 1) == 1) == (hintCmd->byte3 == INV_CONTENT(hintCmd->byte1));
case (QUEST_HINT_CONDITION_OTHER << 1):
switch (hintCmd->byte1 & 0xF0) {
case (QUEST_HINT_CONDITION_STRENGTH_UPG << 4):
return ((hintCmd->byte0 & 1) == 1) == ((hintCmd->byte1 & 0x0F) == CUR_UPG_VALUE(UPG_STRENGTH));
case (QUEST_HINT_CONDITION_BOOTS << 4):
return ((hintCmd->byte0 & 1) == 1) ==
(CHECK_OWNED_EQUIP(EQUIP_TYPE_BOOTS,
msg->byte3 - ITEM_BOOTS_KOKIRI + EQUIP_INV_BOOTS_KOKIRI) != 0);
case (ELF_MSG_CONDITION_SONG << 4):
return ((msg->byte0 & 1) == 1) ==
(CHECK_QUEST_ITEM(msg->byte3 - ITEM_SONG_MINUET + QUEST_SONG_MINUET) != 0);
case (ELF_MSG_CONDITION_MEDALLION << 4):
return ((msg->byte0 & 1) == 1) ==
(CHECK_QUEST_ITEM(msg->byte3 - ITEM_MEDALLION_FOREST + QUEST_MEDALLION_FOREST) != 0);
case (ELF_MSG_CONDITION_MAGIC << 4):
return ((msg->byte0 & 1) == 1) == (((void)0, gSaveContext.isMagicAcquired) != 0);
hintCmd->byte3 - ITEM_BOOTS_KOKIRI + EQUIP_INV_BOOTS_KOKIRI) != 0);
case (QUEST_HINT_CONDITION_SONG << 4):
return ((hintCmd->byte0 & 1) == 1) ==
(CHECK_QUEST_ITEM(hintCmd->byte3 - ITEM_SONG_MINUET + QUEST_SONG_MINUET) != 0);
case (QUEST_HINT_CONDITION_MEDALLION << 4):
return ((hintCmd->byte0 & 1) == 1) ==
(CHECK_QUEST_ITEM(hintCmd->byte3 - ITEM_MEDALLION_FOREST + QUEST_MEDALLION_FOREST) != 0);
case (QUEST_HINT_CONDITION_MAGIC << 4):
return ((hintCmd->byte0 & 1) == 1) == (((void)0, gSaveContext.isMagicAcquired) != 0);
}
}
@ -64,111 +73,126 @@ u32 ElfMessage_CheckCondition(ElfMessage* msg) {
return false;
}
u32 func_8006BE88(ElfMessage** msgp) {
u32 temp = true;
u32 QuestHint_CheckConditionChain(QuestHintCmd** hintCmdPtr) {
u32 allConditionsMet = true;
while (((*msgp)->byte0 & 0xE0) == (ELF_MSG_TYPE_UNK_1 << 5)) {
if (!ElfMessage_CheckCondition(*msgp)) {
temp = false;
while (((*hintCmdPtr)->byte0 & 0xE0) == (QUEST_HINT_TYPE_CHAIN << 5)) {
// if any of the conditions checked in the chain are not met,
// the whole chain is considered false
if (!QuestHint_CheckCondition(*hintCmdPtr)) {
allConditionsMet = false;
}
*msgp += 1;
*hintCmdPtr += 1;
}
if (temp) {
return ElfMessage_CheckCondition(*msgp);
if (allConditionsMet) {
return QuestHint_CheckCondition(*hintCmdPtr);
} else {
return false;
}
}
u32 func_8006BF1C(ElfMessage** msgp) {
ElfMessage* msg = *msgp;
u32 sp44[10];
s32 temp1 = 0;
s32 temp2 = 0;
s32 temp3;
u32 QuestHint_CheckRandomCondition(QuestHintCmd** hintCmdPtr) {
QuestHintCmd* hintCmd = *hintCmdPtr;
u32 conditions[10];
s32 i = 0;
s32 totalChecked = 0;
s32 rand;
do {
sp44[temp2] = ElfMessage_CheckCondition(msg);
temp1 += sp44[temp2];
temp2++;
msg++;
} while ((msg->byte0 & 0xE0) == (ELF_MSG_TYPE_UNK_2 << 5));
conditions[totalChecked] = QuestHint_CheckCondition(hintCmd);
// i is incremented if the condition was met
i += conditions[totalChecked];
totalChecked++;
hintCmd++;
} while ((hintCmd->byte0 & 0xE0) == (QUEST_HINT_TYPE_RANDOM << 5));
if (temp1 == 0) {
// if none of the conditions checked were satisfied, there are none to use
if (i == 0) {
return false;
}
temp3 = Rand_ZeroFloat(temp1);
for (temp1 = 0; temp1 < temp2; temp1++) {
if (sp44[temp1]) {
if (temp3 > 0) {
temp3--;
// choose a random number between 0 and the total amount of conditions met
rand = Rand_ZeroFloat(i);
for (i = 0; i < totalChecked; i++) {
// keep decrementing the random number until it reaches 0 then use that hint
if (conditions[i]) {
if (rand > 0) {
rand--;
} else {
return true;
}
}
*msgp += 1;
*hintCmdPtr += 1;
}
return false;
}
u16 ElfMessage_GetTextFromMsgs(ElfMessage* msg) {
u16 QuestHint_GetTextIdFromScript(QuestHintCmd* hintCmd) {
while (true) {
switch (msg->byte0 & 0xE0) {
case (ELF_MSG_TYPE_CHECK << 5):
if (ElfMessage_CheckCondition(msg)) {
return msg->byte2 | 0x100;
switch (hintCmd->byte0 & 0xE0) {
case (QUEST_HINT_TYPE_CHECK << 5):
if (QuestHint_CheckCondition(hintCmd)) {
return hintCmd->byte2 | 0x100;
}
break;
case (ELF_MSG_TYPE_UNK_1 << 5):
if (func_8006BE88(&msg)) {
return msg->byte2 | 0x100;
case (QUEST_HINT_TYPE_CHAIN << 5):
if (QuestHint_CheckConditionChain(&hintCmd)) {
return hintCmd->byte2 | 0x100;
}
break;
case (ELF_MSG_TYPE_UNK_2 << 5):
if (func_8006BF1C(&msg)) {
return msg->byte2 | 0x100;
case (QUEST_HINT_TYPE_RANDOM << 5):
if (QuestHint_CheckRandomCondition(&hintCmd)) {
return hintCmd->byte2 | 0x100;
}
break;
case (ELF_MSG_TYPE_SKIP << 5):
if (ElfMessage_CheckCondition(msg)) {
msg += msg->byte2;
msg--;
case (QUEST_HINT_TYPE_SKIP << 5):
if (QuestHint_CheckCondition(hintCmd)) {
hintCmd += hintCmd->byte2; // skip the specified amount
hintCmd--; // decrement by 1 because it will be incremented again below
}
break;
case (ELF_MSG_TYPE_END << 5):
return msg->byte2 | 0x100;
case (QUEST_HINT_TYPE_END << 5):
return hintCmd->byte2 | 0x100;
default:
LOG_STRING("企画外 条件", "../z_elf_message.c", 281); // "Unplanned conditions"
ASSERT(0, "0", "../z_elf_message.c", 282);
}
msg++;
hintCmd++;
}
}
u16 ElfMessage_GetSariaText(PlayState* play) {
u16 QuestHint_GetSariaTextId(PlayState* play) {
Player* player = GET_PLAYER(play);
ElfMessage* msgs;
QuestHintCmd* sariaQuestHints;
if (!LINK_IS_ADULT) {
if (Actor_FindNearby(play, &player->actor, ACTOR_EN_SA, 4, 800.0f) == NULL) {
msgs = sChildSariaMsgs;
sariaQuestHints = sChildSariaQuestHints;
} else {
return 0x0160; // Special text about Saria preferring to talk to you face-to-face
}
} else {
msgs = sAdultSariaMsgs;
sariaQuestHints = sAdultSariaQuestHints;
}
return ElfMessage_GetTextFromMsgs(msgs);
return QuestHint_GetTextIdFromScript(sariaQuestHints);
}
u16 ElfMessage_GetCUpText(PlayState* play) {
if (play->cUpElfMsgs == NULL) {
u16 QuestHint_GetNaviTextId(PlayState* play) {
if (play->naviQuestHints == NULL) {
return 0;
} else {
return ElfMessage_GetTextFromMsgs(play->cUpElfMsgs);
return QuestHint_GetTextIdFromScript(play->naviQuestHints);
}
}

View File

@ -1404,7 +1404,7 @@ void Play_InitScene(PlayState* this, s32 spawn) {
this->unk_11DFC = NULL;
this->setupEntranceList = NULL;
this->setupExitList = NULL;
this->cUpElfMsgs = NULL;
this->naviQuestHints = NULL;
this->setupPathList = NULL;
this->numSetupActors = 0;
Object_InitBank(this, &this->objectCtx);

View File

@ -1,7 +1,7 @@
#include "global.h"
#include "vt.h"
RomFile sNaviMsgFiles[];
RomFile sNaviQuestHintFiles[];
s32 Object_Spawn(ObjectContext* objectCtx, s16 objectId) {
u32 size;
@ -231,8 +231,8 @@ void Scene_CommandSpecialFiles(PlayState* play, SceneCmd* cmd) {
gSegments[5] = VIRTUAL_TO_PHYSICAL(play->objectCtx.status[play->objectCtx.subKeepIndex].segment);
}
if (cmd->specialFiles.cUpElfMsgNum != 0) {
play->cUpElfMsgs = Play_LoadFile(play, &sNaviMsgFiles[cmd->specialFiles.cUpElfMsgNum - 1]);
if (cmd->specialFiles.naviQuestHintFileId != NAVI_QUEST_HINTS_NONE) {
play->naviQuestHints = Play_LoadFile(play, &sNaviQuestHintFiles[cmd->specialFiles.naviQuestHintFileId - 1]);
}
}
@ -498,7 +498,7 @@ void (*gSceneCmdHandlers[SCENE_CMD_ID_MAX])(PlayState*, SceneCmd*) = {
Scene_CommandMiscSettings, // SCENE_CMD_ID_MISC_SETTINGS
};
RomFile sNaviMsgFiles[] = {
RomFile sNaviQuestHintFiles[] = {
ROM_FILE(elf_message_field),
ROM_FILE(elf_message_ydan),
ROM_FILE_UNSET,

View File

@ -1,33 +1,33 @@
#include "global.h"
#include "z64elf_message.h"
#include "z64quest_hint_commands.h"
ElfMessage gOverworldNaviMsgs[] = {
ELF_MSG_FLAG(CHECK, 0x40, false, EVENTCHKINF_05),
ELF_MSG_FLAG(CHECK, 0x41, false, EVENTCHKINF_09),
ELF_MSG_FLAG(CHECK, 0x42, false, EVENTCHKINF_12),
ELF_MSG_FLAG(CHECK, 0x43, false, EVENTCHKINF_TALON_RETURNED_FROM_CASTLE),
ELF_MSG_FLAG(CHECK, 0x44, false, EVENTCHKINF_40),
ELF_MSG_SONG(CHECK, 0x45, false, ITEM_SONG_SARIA),
ELF_MSG_STRENGTH_UPG(CHECK, 0x46, true, 0),
ELF_MSG_FLAG(CHECK, 0x47, false, EVENTCHKINF_25),
ELF_MSG_MAGIC(CHECK, 0x48, false),
ELF_MSG_FLAG(CHECK, 0x49, false, EVENTCHKINF_33),
ELF_MSG_FLAG(CHECK, 0x4A, false, EVENTCHKINF_37),
ELF_MSG_FLAG(CHECK, 0x4B, false, EVENTCHKINF_80),
ELF_MSG_FLAG(CHECK, 0x4C, false, EVENTCHKINF_43),
ELF_MSG_FLAG(CHECK, 0x4D, false, EVENTCHKINF_45),
ELF_MSG_ITEM(CHECK, 0x4E, true, ITEM_HOOKSHOT, ITEM_NONE),
ELF_MSG_MEDALLION(CHECK, 0x50, false, ITEM_MEDALLION_FOREST),
ELF_MSG_MEDALLION(CHECK, 0x51, false, ITEM_MEDALLION_FIRE),
ELF_MSG_BOOTS(CHECK, 0x52, false, ITEM_BOOTS_IRON),
ELF_MSG_MEDALLION(CHECK, 0x53, false, ITEM_MEDALLION_WATER),
ELF_MSG_FLAG(CHECK, 0x54, false, EVENTCHKINF_AA),
ELF_MSG_ITEM(CHECK, 0x55, true, ITEM_LENS, ITEM_NONE),
ELF_MSG_MEDALLION(CHECK, 0x57, false, ITEM_MEDALLION_SHADOW),
ELF_MSG_SONG(CHECK, 0x58, false, ITEM_SONG_REQUIEM),
ELF_MSG_STRENGTH_UPG(CHECK, 0x56, true, 1),
ELF_MSG_MEDALLION(CHECK, 0x5A, false, ITEM_MEDALLION_SPIRIT),
ELF_MSG_ITEM(CHECK, 0x5B, true, ITEM_ARROW_LIGHT, ITEM_NONE),
ELF_MSG_FLAG(CHECK, 0x5C, false, EVENTCHKINF_C3),
ELF_MSG_END(0x5F),
QuestHintCmd gOverworldNaviQuestHints[] = {
QUEST_HINT_FLAG(CHECK, EVENTCHKINF_05, false, 0x40),
QUEST_HINT_FLAG(CHECK, EVENTCHKINF_09, false, 0x41),
QUEST_HINT_FLAG(CHECK, EVENTCHKINF_12, false, 0x42),
QUEST_HINT_FLAG(CHECK, EVENTCHKINF_TALON_RETURNED_FROM_CASTLE, false, 0x43),
QUEST_HINT_FLAG(CHECK, EVENTCHKINF_40, false, 0x44),
QUEST_HINT_SONG(CHECK, ITEM_SONG_SARIA, false, 0x45),
QUEST_HINT_STRENGTH_UPG(CHECK, 0, true, 0x46),
QUEST_HINT_FLAG(CHECK, EVENTCHKINF_25, false, 0x47),
QUEST_HINT_MAGIC(CHECK, false, 0x48),
QUEST_HINT_FLAG(CHECK, EVENTCHKINF_33, false, 0x49),
QUEST_HINT_FLAG(CHECK, EVENTCHKINF_37, false, 0x4A),
QUEST_HINT_FLAG(CHECK, EVENTCHKINF_80, false, 0x4B),
QUEST_HINT_FLAG(CHECK, EVENTCHKINF_43, false, 0x4C),
QUEST_HINT_FLAG(CHECK, EVENTCHKINF_45, false, 0x4D),
QUEST_HINT_ITEM(CHECK, ITEM_HOOKSHOT, ITEM_NONE, true, 0x4E),
QUEST_HINT_MEDALLION(CHECK, ITEM_MEDALLION_FOREST, false, 0x50),
QUEST_HINT_MEDALLION(CHECK, ITEM_MEDALLION_FIRE, false, 0x51),
QUEST_HINT_BOOTS(CHECK, ITEM_BOOTS_IRON, false, 0x52),
QUEST_HINT_MEDALLION(CHECK, ITEM_MEDALLION_WATER, false, 0x53),
QUEST_HINT_FLAG(CHECK, EVENTCHKINF_AA, false, 0x54),
QUEST_HINT_ITEM(CHECK, ITEM_LENS, ITEM_NONE, true, 0x55),
QUEST_HINT_MEDALLION(CHECK, ITEM_MEDALLION_SHADOW, false, 0x57),
QUEST_HINT_SONG(CHECK, ITEM_SONG_REQUIEM, false, 0x58),
QUEST_HINT_STRENGTH_UPG(CHECK, 1, true, 0x56),
QUEST_HINT_MEDALLION(CHECK, ITEM_MEDALLION_SPIRIT, false, 0x5A),
QUEST_HINT_ITEM(CHECK, ITEM_ARROW_LIGHT, ITEM_NONE, true, 0x5B),
QUEST_HINT_FLAG(CHECK, EVENTCHKINF_C3, false, 0x5C),
QUEST_HINT_END(0x5F),
};

View File

@ -1,6 +1,6 @@
#include "global.h"
#include "z64elf_message.h"
#include "z64quest_hint_commands.h"
ElfMessage gDungeonNaviMsgs[] = {
ELF_MSG_END(0x5F),
QuestHintCmd gDungeonNaviQuestHints[] = {
QUEST_HINT_END(0x5F),
};

View File

@ -1267,7 +1267,7 @@ void func_80A05040(Actor* thisx, PlayState* play) {
if ((Message_GetState(&play->msgCtx) == TEXT_STATE_CHOICE) && Message_ShouldAdvance(play)) {
switch (play->msgCtx.choiceIndex) {
case 0: // yes
Message_ContinueTextbox(play, ElfMessage_GetSariaText(play));
Message_ContinueTextbox(play, QuestHint_GetSariaTextId(play));
this->actor.update = func_80A05114;
break;
case 1: // no
@ -1301,7 +1301,7 @@ void func_80A05188(Actor* thisx, PlayState* play) {
func_80A04DE4(this, play);
if ((Message_GetState(&play->msgCtx) == TEXT_STATE_EVENT) && Message_ShouldAdvance(play)) {
Message_ContinueTextbox(play, ElfMessage_GetSariaText(play));
Message_ContinueTextbox(play, QuestHint_GetSariaTextId(play));
this->actor.update = func_80A05114;
}
@ -1310,7 +1310,7 @@ void func_80A05188(Actor* thisx, PlayState* play) {
// ask to talk to navi
void func_80A05208(Actor* thisx, PlayState* play) {
s32 naviCUpText;
s32 naviTextId;
EnElf* this = (EnElf*)thisx;
func_80A04DE4(this, play);
@ -1318,10 +1318,10 @@ void func_80A05208(Actor* thisx, PlayState* play) {
if ((Message_GetState(&play->msgCtx) == TEXT_STATE_CHOICE) && Message_ShouldAdvance(play)) {
switch (play->msgCtx.choiceIndex) {
case 0: // yes
naviCUpText = ElfMessage_GetCUpText(play);
naviTextId = QuestHint_GetNaviTextId(play);
if (naviCUpText != 0) {
Message_ContinueTextbox(play, naviCUpText);
if (naviTextId != 0) {
Message_ContinueTextbox(play, naviTextId);
} else {
Message_ContinueTextbox(play, 0x15F);
}
@ -1379,7 +1379,7 @@ void func_80A053F0(Actor* thisx, PlayState* play) {
if (player->naviTextId == 0) {
if (player->unk_664 == NULL) {
if (((gSaveContext.naviTimer >= 600) && (gSaveContext.naviTimer <= 3000)) || (nREG(89) != 0)) {
player->naviTextId = ElfMessage_GetCUpText(play);
player->naviTextId = QuestHint_GetNaviTextId(play);
if (player->naviTextId == 0x15F) {
player->naviTextId = 0;
@ -1395,7 +1395,7 @@ void func_80A053F0(Actor* thisx, PlayState* play) {
func_800F4524(&gSfxDefaultPos, NA_SE_VO_SK_LAUGH, 0x20);
thisx->focus.pos = thisx->world.pos;
if (thisx->textId == ElfMessage_GetCUpText(play)) {
if (thisx->textId == QuestHint_GetNaviTextId(play)) {
this->fairyFlags |= 0x80;
gSaveContext.naviTimer = 3001;
}

View File

@ -210,32 +210,32 @@ def disas_elfmsgs(start):
if condition_type == 0:
if elf_message_type == 0xE0 and b1 == 0 and not (b0 & 1):
print(f"ELF_MSG_END({ARG_1}),")
print(f"QUEST_HINT_END({ARG_1}),")
else:
print(f"ELF_MSG_FLAG({ARG_0}, {ARG_1}, {ARG_2}, 0x{b1:02X}), /* eventChkInf[{(b1 >> 4) & 0xF}] & 0x{1 << (b1 & 0xF):X} */")
print(f"QUEST_HINT_FLAG({ARG_0}, {ARG_1}, {ARG_2}, 0x{b1:02X}), /* eventChkInf[{(b1 >> 4) & 0xF}] & 0x{1 << (b1 & 0xF):X} */")
assert b3 == 0
elif condition_type == 2:
print(f"ELF_MSG_DUNGEON_ITEM({ARG_0}, {ARG_1}, {ARG_2}, {item_ids[b1]}),")
print(f"QUEST_HINT_DUNGEON_ITEM({ARG_0}, {ARG_1}, {ARG_2}, {item_ids[b1]}),")
assert b3 == 0
elif condition_type == 4:
print(f"ELF_MSG_ITEM({ARG_0}, {ARG_1}, {ARG_2}, {item_ids[b1]}, {item_ids[b3]}),")
print(f"QUEST_HINT_ITEM({ARG_0}, {ARG_1}, {ARG_2}, {item_ids[b1]}, {item_ids[b3]}),")
elif condition_type == 6:
condition_other_type = b1 & 0xF0
if condition_other_type == 0:
print(f"ELF_MSG_STRENGTH_UPG({ARG_0}, {ARG_1}, {ARG_2}, {b1 & 0xF}),")
print(f"QUEST_HINT_STRENGTH_UPG({ARG_0}, {ARG_1}, {ARG_2}, {b1 & 0xF}),")
assert b3 == 0
elif condition_other_type == 0x10:
print(f"ELF_MSG_BOOTS({ARG_0}, {ARG_1}, {ARG_2}, {item_ids[b3]}),")
print(f"QUEST_HINT_BOOTS({ARG_0}, {ARG_1}, {ARG_2}, {item_ids[b3]}),")
assert (b1 & 0xF) == 0
elif condition_other_type == 0x20:
print(f"ELF_MSG_SONG({ARG_0}, {ARG_1}, {ARG_2}, {item_ids[b3]}),")
print(f"QUEST_HINT_SONG({ARG_0}, {ARG_1}, {ARG_2}, {item_ids[b3]}),")
assert (b1 & 0xF) == 0
elif condition_other_type == 0x30:
print(f"ELF_MSG_MEDALLION({ARG_0}, {ARG_1}, {ARG_2}, {item_ids[b3]}),")
print(f"QUEST_HINT_MEDALLION({ARG_0}, {ARG_1}, {ARG_2}, {item_ids[b3]}),")
assert (b1 & 0xF) == 0
elif condition_other_type == 0x40:
print(f"ELF_MSG_MAGIC({ARG_0}, {ARG_1}, {ARG_2}),")
print(f"QUEST_HINT_MAGIC({ARG_0}, {ARG_1}, {ARG_2}),")
assert (b1 & 0xF) == 0
assert b3 == 0
else: