This commit is contained in:
mckinlee 2024-04-13 04:02:28 -05:00 committed by GitHub
commit 8b2e96166a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 751 additions and 29 deletions

View File

@ -1117,6 +1117,7 @@ void func_8008EC70(Player* player);
void Player_SetEquipmentData(PlayState* play, Player* player);
void Player_UpdateBottleHeld(PlayState* play, Player* player, s32 item, s32 actionParam);
void func_80837C0C(PlayState* play, Player* this, s32 arg2, f32 arg3, f32 arg4, s16 arg5, s32 arg6);
void Player_StartTalking(PlayState* play, Actor* actor);
void func_8008EDF0(Player* player);
void func_8008EE08(Player* player);
void func_8008EEAC(PlayState* play, Actor* actor);

View File

@ -1481,8 +1481,10 @@ typedef struct PlayState {
/* 0x1242B */ u8 unk_1242B;
/* 0x1242C */ SceneTableEntry* loadedScene;
/* 0x12430 */ char unk_12430[0xE8];
} PlayState; // size = 0x12518
// New members for banker overlay
/* 0x12518 */ s16 value;
/* 0x1251A */ s16 selectedDigit;
} PlayState; // size = 0x1251C
typedef struct {
/* 0x0000 */ GameState state;
/* 0x00A8 */ View view;

View File

@ -324,6 +324,12 @@ typedef struct {
/* */ u8 mqDungeonCount;
/* */ u16 adultTradeItems;
/* */ u8 triforcePiecesCollected;
/* */ s32 playerBalance;
/* */ u8 hasWarpTransfer;
/* */ u8 hasFee;
/* */ u8 hasPieceOfHeart;
/* */ u8 excessRupees;
/* */ u8 rupeesFee;
// #endregion
} SaveContext; // size = 0x1428

View File

@ -0,0 +1,323 @@
#include <stdlib.h>
#include "z64.h"
#include "macros.h"
#include "libultraship/libultra/gbi.h"
#include "../soh/assets/textures/parameter_static/parameter_static.h"
#include "variables.h"
#include "custom-message/CustomMessageTypes.h"
#include "functions.h"
#include "soh/OTRGlobals.h"
#include "luslog.h"
#define DIGIT_WIDTH 8
#define DIGIT_HEIGHT 16
#define HUNDREDS_OFFSET -16
#define TENS_OFFSET 8
#define ONES_OFFSET 8
#define BLINK_DURATION 10
#define COOLDOWN_FRAMES 3
#define FADE_DURATION 5
static s16 bankerValue = 0;
static s16 selectedDigit = 0;
static s16 blinkTimer = 0;
static bool isGivingHeart = false;
static bool isGivingCharm = false;
static bool canContinue = false;
static bool prevTextboxHeart = false;
/*static*/ bool prevTextboxCharm = false; //Temporarily global until GI_PIRATE_CHARM is implemented
static Actor* bankerActor = NULL;
static s16 OptionChoice = -1;
static s16 fadeTimer = 0;
extern const char* digitTextures[];
Color_RGBA8 highlightColor = { 255, 255, 0, 255 };
void UpdateBankerOverlay(PlayState* play, Gfx** gfx, s16 value, s16 selectedDigit) {
s16 posX = 160 - 76;
s16 posY = 180 - 20;
s16 digits[3] = {value / 100, (value % 100) / 10, value % 10};
s16 offsets[3] = {HUNDREDS_OFFSET, TENS_OFFSET, ONES_OFFSET};
if (fadeTimer < FADE_DURATION) {
fadeTimer++;
}
for (int i = 0; i < 3; i++) {
posX += offsets[i];
s16 digit = digits[i];
bool isSelected = selectedDigit == 2 - i;
gDPPipeSync((*gfx)++);
gDPLoadTextureBlock((*gfx)++, ((u8*)digitTextures[digit]), G_IM_FMT_I, G_IM_SIZ_8b, DIGIT_WIDTH, DIGIT_HEIGHT, 0,
G_TX_WRAP | G_TX_NOMIRROR, G_TX_WRAP | G_TX_NOMIRROR, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD,
G_TX_NOLOD);
u8 fadeAlpha = fadeTimer < FADE_DURATION ? (255 * fadeTimer) / FADE_DURATION : 255;
Color_RGBA8 primColor = isSelected && blinkTimer < BLINK_DURATION ?
(Color_RGBA8){highlightColor.r, highlightColor.g, highlightColor.b, fadeAlpha} :
(Color_RGBA8){255, 255, 255, fadeAlpha};
gDPSetPrimColor((*gfx)++, 0, 0, primColor.r, primColor.g, primColor.b, primColor.a);
gDPSetCombineMode((*gfx)++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM);
gDPSetRenderMode((*gfx)++, G_RM_XLU_SURF, G_RM_XLU_SURF2);
gSPTextureRectangle((*gfx)++, posX << 2, posY << 2, (posX + DIGIT_WIDTH) << 2, (posY + DIGIT_HEIGHT) << 2,
G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10);
}
}
s16 CalculateSelectedValue(s16 value, s16 selectedDigit, bool increase, s16 min, s16 max) {
s16 digitValues[3];
digitValues[0] = value % 10;
digitValues[1] = (value / 10) % 10;
digitValues[2] = value / 100;
if (increase) {
digitValues[selectedDigit] = (digitValues[selectedDigit] + 1) % 10;
} else {
digitValues[selectedDigit] = (digitValues[selectedDigit] + 9) % 10;
}
s16 newValue = digitValues[2] * 100 + digitValues[1] * 10 + digitValues[0];
return (newValue < min) ? min : (newValue > max) ? max : newValue;
}
void ProcessInput(PlayState* play, s16* value, s16* selectedDigit) {
static s16 inputCooldownTimer = 0;
Input* input = &play->state.input[0];
bool playSound = false;
if (play->msgCtx.textId != TEXT_BANKER_WITHDRAWAL_AMOUNT && play->msgCtx.textId != TEXT_BANKER_DEPOSIT_AMOUNT) {
return;
}
if (inputCooldownTimer > 0) {
inputCooldownTimer--;
return;
} if (abs(input->rel.stick_y) > 30) {
*value = CalculateSelectedValue(*value, *selectedDigit, input->rel.stick_y > 0, 0, 999);
bankerValue = *value;
playSound = true;
}
if (abs(input->rel.stick_x) > 30) {
*selectedDigit = (input->rel.stick_x < 0) ? (*selectedDigit + 1) % 3 : (*selectedDigit - 1 + 3) % 3;
playSound = true;
}
if (playSound) {
Audio_PlaySoundGeneral(NA_SE_SY_RUPY_COUNT, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8);
}
inputCooldownTimer = playSound ? COOLDOWN_FRAMES : 0;
}
static void HandleBankerInteraction(PlayState* play, MessageContext* msgCtx) {
uint16_t currentTextId = msgCtx->textId;
if (msgCtx->msgMode != MSGMODE_TEXT_DONE && msgCtx->msgMode != MSGMODE_TEXT_CLOSING) {
return;
}
if (!Message_ShouldAdvance(play)) {
return;
}
s16 nextTextId;
switch (currentTextId) {
case TEXT_BEGGAR_VANILLA:
canContinue = false;
Actor* playerActor = &GET_PLAYER(play)->actor;
Actor* foundActor = Actor_FindNearby(play, playerActor, ACTOR_EN_HY, ACTORCAT_NPC, 80.0f);
if (foundActor != NULL) {
bankerActor = foundActor;
}
Message_ContinueTextbox(play, TEXT_BANKER_OPTIONS);
break;
case TEXT_BANKER_OPTIONS:
if (msgCtx->choiceIndex == 0 || msgCtx->choiceIndex == 1) {
OptionChoice = msgCtx->choiceIndex;
if (gSaveContext.hasFee == 0) {
Message_ContinueTextbox(play, TEXT_BANKER_TRANSACTION_FEE);
} else {
Message_ContinueTextbox(play, TEXT_BANKER_BALANCE);
}
} else if (msgCtx->choiceIndex == 2) {
Message_CloseTextbox(play);
}
fadeTimer = 0;
break;
case TEXT_BANKER_BALANCE:
if (gSaveContext.playerBalance >= 200 && !gSaveContext.hasWarpTransfer) {
gSaveContext.hasWarpTransfer = 1;
Message_ContinueTextbox(play, TEXT_BANKER_REWARD_WARP_TRANSFER_INTRO);
} else if (gSaveContext.playerBalance >= 1000 && !gSaveContext.hasFee) {
gSaveContext.hasFee = 1;
Message_ContinueTextbox(play, TEXT_BANKER_REWARD_FEE);
} else if (gSaveContext.playerBalance >= 5000 && !gSaveContext.hasPieceOfHeart) {
gSaveContext.hasPieceOfHeart = 1;
Message_ContinueTextbox(play, TEXT_BANKER_REWARD_PIECE_OF_HEART);
} else {
nextTextId = (OptionChoice == 0) ? TEXT_BANKER_DEPOSIT_AMOUNT : TEXT_BANKER_WITHDRAWAL_AMOUNT;
Message_StartTextbox(play, nextTextId, bankerActor);
}
break;
case TEXT_BANKER_WITHDRAWAL_AMOUNT:
if (bankerValue == 0) {
Message_ContinueTextbox(play, TEXT_BANKER_ERROR_ZERO_AMOUNT);
} else if (bankerValue + (gSaveContext.hasFee ? 0 : gSaveContext.rupeesFee) > gSaveContext.playerBalance) {
Message_ContinueTextbox(play, TEXT_BANKER_ERROR_INSUFFICIENT_BALANCE);
} else if (bankerValue + gSaveContext.rupees > CUR_CAPACITY(UPG_WALLET)) {
Message_ContinueTextbox(play, TEXT_BANKER_ERROR_WALLET_FULL);
} else {
Rupees_ChangeBy(bankerValue);
gSaveContext.playerBalance -= bankerValue + (gSaveContext.hasFee ? 0 : gSaveContext.rupeesFee);
Message_ContinueTextbox(play, TEXT_BANKER_WITHDRAWAL_CONFIRM);
}
break;
case TEXT_BANKER_DEPOSIT_AMOUNT:
if (bankerValue == 0) {
Message_ContinueTextbox(play, TEXT_BANKER_ERROR_ZERO_AMOUNT);
} else if ((gSaveContext.playerBalance + bankerValue) > 5000) {
Message_ContinueTextbox(play, TEXT_BANKER_ERROR_MAX_BALANCE);
} else if (bankerValue > gSaveContext.rupees) {
Message_ContinueTextbox(play, TEXT_BANKER_ERROR_INSUFFICIENT_BALANCE);
} else if (gSaveContext.hasFee == 0 && (gSaveContext.playerBalance + bankerValue - gSaveContext.rupeesFee) < 1) {
Message_ContinueTextbox(play, TEXT_BANKER_ERROR_DEPOSIT_NOT_WORTHWHILE);
} else {
Rupees_ChangeBy(-bankerValue);
gSaveContext.playerBalance += bankerValue - (gSaveContext.hasFee ? 0 : gSaveContext.rupeesFee);
Message_ContinueTextbox(play, TEXT_BANKER_DEPOSIT_CONFIRM);
}
break;
case TEXT_BANKER_WITHDRAWAL_CONFIRM:
case TEXT_BANKER_DEPOSIT_CONFIRM:
bankerValue = 0;
canContinue = true;
if (gSaveContext.playerBalance >= 200 && !gSaveContext.hasWarpTransfer) {
gSaveContext.hasWarpTransfer = 1;
Message_ContinueTextbox(play, TEXT_BANKER_REWARD_WARP_TRANSFER_INTRO);
} else if (gSaveContext.playerBalance >= 1000 && !gSaveContext.hasFee) {
gSaveContext.hasFee = 1;
Message_ContinueTextbox(play, TEXT_BANKER_REWARD_FEE);
} else if (gSaveContext.playerBalance >= 5000 && !gSaveContext.hasPieceOfHeart) {
gSaveContext.hasPieceOfHeart = 1;
Message_ContinueTextbox(play, TEXT_BANKER_REWARD_PIECE_OF_HEART);
}
break;
case TEXT_BANKER_REWARD_WARP_TRANSFER_INTRO:
Message_ContinueTextbox(play, TEXT_BANKER_REWARD_WARP_TRANSFER_ITEM);
break;
case TEXT_BANKER_REWARD_WARP_TRANSFER_ITEM:
Message_CloseTextbox(play);
isGivingCharm = true;
break;
//TEXT_BLUE_RUPEE is a placeholder for TEXT_BANKER_REWARD_WARP_TRANSFER_LORE_1. GI_PIRATE_CHARM has not been implemented yet.
case TEXT_BLUE_RUPEE:
Message_CloseTextbox(play);
prevTextboxCharm = true;
break;
case TEXT_BANKER_REWARD_WARP_TRANSFER_LORE_2:
Message_ContinueTextbox(play, TEXT_BANKER_REWARD_WARP_TRANSFER_LORE_3);
break;
case TEXT_BANKER_REWARD_WARP_TRANSFER_LORE_3:
if (gSaveContext.playerBalance >= 1000 && !gSaveContext.hasFee) {
gSaveContext.hasFee = 1;
Message_ContinueTextbox(play, TEXT_BANKER_REWARD_FEE);
} else if (canContinue) {
canContinue = false;
} else {
nextTextId = (OptionChoice == 0) ? TEXT_BANKER_DEPOSIT_AMOUNT : TEXT_BANKER_WITHDRAWAL_AMOUNT;
Message_StartTextbox(play, nextTextId, bankerActor);
}
break;
case TEXT_BANKER_REWARD_FEE:
if (gSaveContext.playerBalance >= 5000 && !gSaveContext.hasPieceOfHeart) {
gSaveContext.hasPieceOfHeart = 1;
Message_ContinueTextbox(play, TEXT_BANKER_REWARD_PIECE_OF_HEART);
} else if (canContinue) {
canContinue = false;
} else {
nextTextId = (OptionChoice == 0) ? TEXT_BANKER_DEPOSIT_AMOUNT : TEXT_BANKER_WITHDRAWAL_AMOUNT;
Message_StartTextbox(play, nextTextId, bankerActor);
}
break;
case TEXT_BANKER_REWARD_PIECE_OF_HEART:
Message_CloseTextbox(play);
isGivingHeart = true;
break;
case TEXT_HEART_PIECE:
Message_CloseTextbox(play);
prevTextboxHeart = true;
break;
case TEXT_BANKER_ERROR_ZERO_AMOUNT:
case TEXT_BANKER_ERROR_INSUFFICIENT_BALANCE:
case TEXT_BANKER_ERROR_WALLET_FULL:
case TEXT_BANKER_ERROR_MAX_BALANCE:
case TEXT_BANKER_ERROR_DEPOSIT_NOT_WORTHWHILE:
Message_ContinueTextbox(play, TEXT_BANKER_OPTIONS);
break;
case TEXT_BANKER_TRANSACTION_FEE:
if (msgCtx->choiceIndex == 0) {
Message_ContinueTextbox(play, TEXT_BANKER_BALANCE);
} else if (msgCtx->choiceIndex == 1) {
Message_CloseTextbox(play);
}
break;
default:
break;
}
}
void DrawBankerOverlay(PlayState* play, Gfx** gfx) {
UpdateBankerOverlay(play, gfx, bankerValue, selectedDigit);
}
void BankerMain(PlayState* play, GraphicsContext* gfxCtx) {
static s16 prevMsgMode = MSGMODE_NONE;
bool isMsgModeActive = play->msgCtx.msgMode != MSGMODE_NONE;
bool wasMsgModeActive = prevMsgMode != MSGMODE_NONE;
if (!isMsgModeActive && !wasMsgModeActive) {
return;
}
if (isMsgModeActive) {
ProcessInput(play, &bankerValue, &selectedDigit);
blinkTimer = (blinkTimer + 1) % (BLINK_DURATION * 2);
bool isBankerTextId = play->msgCtx.textId == TEXT_BANKER_WITHDRAWAL_AMOUNT || play->msgCtx.textId == TEXT_BANKER_DEPOSIT_AMOUNT;
if (isBankerTextId) {
Gfx** gfx = &gfxCtx->overlay.p;
}
}
if (wasMsgModeActive && !isMsgModeActive) {
if (isGivingHeart) {
isGivingHeart = GiveItemEntryWithoutActor(play, ItemTable_Retrieve(GI_HEART_PIECE)) ? false : true;
} else if (isGivingCharm) {
//GI_RUPEE_BLUE is a placeholder for GI_PIRATE_CHARM, which has not been implemented yet.
isGivingCharm = GiveItemEntryWithoutActor(play, ItemTable_Retrieve(GI_RUPEE_BLUE)) ? false : true;
} else if (!canContinue && prevTextboxHeart) {
s16 nextTextId = OptionChoice == 0 ? TEXT_BANKER_DEPOSIT_AMOUNT : TEXT_BANKER_WITHDRAWAL_AMOUNT;
bankerActor->textId = nextTextId;
Player_StartTalking(play, bankerActor);
Message_StartTextbox(play, nextTextId, bankerActor);
prevTextboxHeart = false;
canContinue = true;
} else if (prevTextboxCharm) {
s16 charmTextID = TEXT_BANKER_REWARD_WARP_TRANSFER_LORE_2;
bankerActor->textId = charmTextID;
Player_StartTalking(play, bankerActor);
Message_StartTextbox(play, charmTextID, bankerActor);
prevTextboxCharm = false;
}
}
prevMsgMode = play->msgCtx.msgMode;
if (isMsgModeActive) {
HandleBankerInteraction(play, &play->msgCtx);
}
}

View File

@ -71,6 +71,30 @@ typedef enum {
TEXT_BEAN_SALESMAN_SET_A_BEAN_TO_C = 0x406A,
TEXT_BEAN_SALESMAN_SOLD_OUT = 0x406B,
TEXT_BEAN_SALESMAN_WANT_TO_PLANT = 0x406C,
TEXT_BEGGAR_VANILLA = 0x70ED, //Please...with [C]... Please sell me something... Please...with [C]...
TEXT_BANKER_GREETING = 0x9303,
TEXT_BANKER_OPTIONS = 0x9304,
TEXT_BANKER_BALANCE = 0x9305,
TEXT_BANKER_WITHDRAWAL_AMOUNT = 0x9306,
TEXT_BANKER_WITHDRAWAL_CONFIRM = 0x9307,
TEXT_BANKER_DEPOSIT_AMOUNT = 0x9308,
TEXT_BANKER_DEPOSIT_CONFIRM = 0x9309,
TEXT_BANKER_REWARD_WARP_TRANSFER_INTRO = 0x9310,
TEXT_BANKER_REWARD_WARP_TRANSFER_ITEM = 0x9311,
TEXT_BANKER_REWARD_WARP_TRANSFER_LORE_1 = 0x9312,
TEXT_BANKER_REWARD_WARP_TRANSFER_LORE_2 = 0x9313,
TEXT_BANKER_REWARD_WARP_TRANSFER_LORE_3 = 0x9314,
TEXT_BANKER_REWARD_FEE = 0x9315,
TEXT_BANKER_REWARD_PIECE_OF_HEART = 0x9316,
TEXT_BANKER_ERROR_ZERO_AMOUNT = 0x9400,
TEXT_BANKER_ERROR_INSUFFICIENT_BALANCE = 0x9401,
TEXT_BANKER_ERROR_WALLET_FULL = 0x9402,
TEXT_BANKER_ERROR_MAX_BALANCE = 0x9403,
TEXT_BANKER_ERROR_DEPOSIT_NOT_WORTHWHILE = 0x9404,
TEXT_BANKER_TRANSACTION_FEE = 0x9405,
TEXT_BANKER_EXCESS = 0x9406,
TEXT_BANKER_EXCESS_FULL = 0x9407,
TEXT_BANKER_EXCESS_FEE = 0x9408,
} TextIDs;
#ifdef __cplusplus

View File

@ -402,6 +402,35 @@ void DrawInfoTab() {
ImGui::InputScalar("Rupees", ImGuiDataType_S16, &gSaveContext.rupees);
UIWidgets::InsertHelpHoverText("Current rupees");
if (CVarGetInteger("gBanker", 0)) {
ImGui::InputScalar("Bank Balance", ImGuiDataType_S32, &gSaveContext.playerBalance);
UIWidgets::InsertHelpHoverText("Current bank balance");
if (gSaveContext.playerBalance > 5000) {
gSaveContext.playerBalance = 5000;
}
bool rewardsStatus[] = {
gSaveContext.hasWarpTransfer,
gSaveContext.hasFee,
gSaveContext.hasPieceOfHeart
};
const char* labels[] = {"Warp Transfer", "Transaction Fee", "Bank Heart Piece Reward"};
const char* helpTexts[] = {
"If checked, will have ability to warp transfer.",
"If checked, will not be charged a fee.",
"If checked, won't received Heart Piece reward."
};
for (int i = 0; i < sizeof(rewardsStatus)/sizeof(rewardsStatus[0]); ++i) {
if (ImGui::Checkbox(labels[i], &rewardsStatus[i])) {
switch (i) {
case 0: gSaveContext.hasWarpTransfer = rewardsStatus[i] ? 1 : 0; break;
case 1: gSaveContext.hasFee = rewardsStatus[i] ? 1 : 0; break;
case 2: gSaveContext.hasPieceOfHeart = rewardsStatus[i] ? 1 : 0; break;
}
}
UIWidgets::InsertHelpHoverText(helpTexts[i]);
}
}
const uint16_t dayTimeMin = 0;
const uint16_t dayTimeMax = 0xFFFF;
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 15);

View File

@ -27,6 +27,8 @@
#include "objects/object_link_boy/object_link_boy.h"
#include "objects/object_link_child/object_link_child.h"
#include "custom-message/CustomMessageTypes.h"
extern "C" {
#include <z64.h>
#include "align_asset_macro.h"
@ -42,6 +44,11 @@ extern SaveContext gSaveContext;
extern PlayState* gPlayState;
extern void Overlay_DisplayText(float duration, const char* text);
uint32_t ResourceMgr_IsSceneMasterQuest(s16 sceneNum);
extern int balanceUpdated;
extern int balanceMaxed;
extern int balanceWasMaxed;
extern bool prevTextboxCharm; //This will be removed later once TEXT_PIRATE_CHARM has been implemented
}
// GreyScaleEndDlist
@ -1394,6 +1401,23 @@ void RegisterPauseMenuHooks() {
});
}
void RegisterBankUpdate() {
auto handleBankUpdate = []() {
if (prevTextboxCharm) { //This will be removed when TEXT_PIRATE_CHARM has been implemented. TEXT_BLUE_RUPEE is being used as a placeholder in banker.c and conflicts with this logic.
return;
}
uint16_t messageIndex = gPlayState->msgCtx.textId;
bool isBankerActive = CVarGetInteger("gBanker", 0);
bool isRupeeMessage = (messageIndex == TEXT_BLUE_RUPEE) || (messageIndex == TEXT_RED_RUPEE) || (messageIndex == TEXT_PURPLE_RUPEE) || (messageIndex == TEXT_HUGE_RUPEE);
if (isBankerActive && isRupeeMessage && balanceUpdated && Message_ShouldAdvance(gPlayState)) {
uint16_t messageToShow = balanceWasMaxed ? TEXT_BANKER_EXCESS_FULL : TEXT_BANKER_EXCESS;
Message_ContinueTextbox(gPlayState, messageToShow);
balanceMaxed = balanceUpdated = balanceWasMaxed = 0;
}
};
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnDialogMessage>(handleBankUpdate);
}
void InitMods() {
RegisterTTS();
RegisterInfiniteMoney();
@ -1433,4 +1457,5 @@ void InitMods() {
RegisterPatchHandHandler();
RegisterHurtContainerModeHandler();
RegisterPauseMenuHooks();
RegisterBankUpdate();
}

View File

@ -178,6 +178,8 @@ typedef enum {
HEART_CONTAINER,
ICE_TRAP,
MILK,
PIRATES_CHARM,
BOMBS_5,
BOMBS_10,

View File

@ -299,7 +299,7 @@ void InitTrickNames() {
Text{"Cave Charm", "Charme de grotte", "Amuleto de la cueva"},
Text{"Stone of Agahnim", "Fragment d'Agahnim", "Piedra de Agahnim"},
Text{"Shard of Agony", "Fragment de Souffrance", "Piedra de la Agonía"},
Text{"Pirate's Charm", "Pierre de Pirate", "Amuleto Pirata"}};
Text{"Stone of Misery", "Pierre de Misère", "Piedra de la Miseria"}};
trickNameTable[GI_DINS_FIRE] = {
Text{"Eldin's Fire", "Feu d'Eldin", "Fuego de Eldin"},
Text{"Din's Blaze", "Flamme de Din", "Poder de Din"},

View File

@ -1272,6 +1272,7 @@ typedef enum {
RG_HEART_CONTAINER,
RG_ICE_TRAP,
RG_MILK,
RG_PIRATES_CHARM,
RG_BOMBS_5,
RG_BOMBS_10,
RG_BOMBS_20,

View File

@ -2618,7 +2618,7 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) {
messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_HEART_CONTAINER);
messageEntry.Replace("{{heartContainerCount}}", std::to_string(gSaveContext.sohStats.heartContainers + 1));
}
if (textId == TEXT_HEART_PIECE && CVarGetInteger("gInjectItemCounts", 0)) {
if (textId == TEXT_HEART_PIECE && (CVarGetInteger("gInjectItemCounts", 0) || CVarGetInteger("gBanker", 0))) {
messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_HEART_PIECE);
messageEntry.Replace("{{heartPieceCount}}", std::to_string(gSaveContext.sohStats.heartPieces + 1));
}
@ -2628,6 +2628,91 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) {
if (textId == TEXT_FISHERMAN_LEAVE && CVarGetInteger("gQuitFishingAtDoor", 0)) {
messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_FISHERMAN_LEAVE);
}
if (textId == TEXT_BEGGAR_VANILLA && CVarGetInteger("gBanker", 0)) {
messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_BANKER_GREETING);
}
if (textId == TEXT_BANKER_OPTIONS && CVarGetInteger("gBanker", 0)) {
messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_BANKER_OPTIONS);
}
if (textId == TEXT_BANKER_BALANCE && CVarGetInteger("gBanker", 0)) {
s32 playerBalance = gSaveContext.playerBalance;
messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_BANKER_BALANCE);
messageEntry.Replace("{{playerBalance}}", std::to_string(playerBalance));
}
if (textId == TEXT_BANKER_WITHDRAWAL_AMOUNT && CVarGetInteger("gBanker", 0)) {
messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_BANKER_WITHDRAWAL_AMOUNT);
}
if (textId == TEXT_BANKER_WITHDRAWAL_CONFIRM && CVarGetInteger("gBanker", 0)) {
s32 playerBalance = gSaveContext.playerBalance;
messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_BANKER_WITHDRAWAL_CONFIRM);
messageEntry.Replace("{{playerBalance}}", std::to_string(playerBalance));
}
if (textId == TEXT_BANKER_DEPOSIT_AMOUNT && CVarGetInteger("gBanker", 0)) {
messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_BANKER_DEPOSIT_AMOUNT);
}
if (textId == TEXT_BANKER_DEPOSIT_CONFIRM && CVarGetInteger("gBanker", 0)) {
s32 playerBalance = gSaveContext.playerBalance;
messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_BANKER_DEPOSIT_CONFIRM);
messageEntry.Replace("{{playerBalance}}", std::to_string(playerBalance));
}
if (textId == TEXT_BANKER_REWARD_WARP_TRANSFER_INTRO && CVarGetInteger("gBanker", 0)) {
messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_BANKER_REWARD_WARP_TRANSFER_INTRO);
}
if (textId == TEXT_BANKER_REWARD_WARP_TRANSFER_ITEM && CVarGetInteger("gBanker", 0)) {
messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_BANKER_REWARD_WARP_TRANSFER_ITEM);
}
if (textId == TEXT_BANKER_REWARD_WARP_TRANSFER_LORE_1 && CVarGetInteger("gBanker", 0)) {
messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_BANKER_REWARD_WARP_TRANSFER_LORE_1);
}
if (textId == TEXT_BANKER_REWARD_WARP_TRANSFER_LORE_2 && CVarGetInteger("gBanker", 0)) {
messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_BANKER_REWARD_WARP_TRANSFER_LORE_2);
}
if (textId == TEXT_BANKER_REWARD_WARP_TRANSFER_LORE_3 && CVarGetInteger("gBanker", 0)) {
messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_BANKER_REWARD_WARP_TRANSFER_LORE_3);
}
if (textId == TEXT_BANKER_REWARD_FEE && CVarGetInteger("gBanker", 0)) {
messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_BANKER_REWARD_FEE);
}
if (textId == TEXT_BANKER_REWARD_PIECE_OF_HEART && CVarGetInteger("gBanker", 0)) {
messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_BANKER_REWARD_PIECE_OF_HEART);
}
if (textId == TEXT_BANKER_ERROR_ZERO_AMOUNT && CVarGetInteger("gBanker", 0)) {
messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_BANKER_ERROR_ZERO_AMOUNT);
}
if (textId == TEXT_BANKER_ERROR_INSUFFICIENT_BALANCE && CVarGetInteger("gBanker", 0)) {
messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_BANKER_ERROR_INSUFFICIENT_BALANCE);
}
if (textId == TEXT_BANKER_ERROR_WALLET_FULL && CVarGetInteger("gBanker", 0)) {
messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_BANKER_ERROR_WALLET_FULL);
}
if (textId == TEXT_BANKER_ERROR_MAX_BALANCE && CVarGetInteger("gBanker", 0)) {
messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_BANKER_ERROR_MAX_BALANCE);
}
if (textId == TEXT_BANKER_ERROR_DEPOSIT_NOT_WORTHWHILE && CVarGetInteger("gBanker", 0)) {
s32 rupeesFee = gSaveContext.rupeesFee;
messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_BANKER_ERROR_DEPOSIT_NOT_WORTHWHILE);
messageEntry.Replace("{{rupeesFee}}", std::to_string(rupeesFee));
}
if (textId == TEXT_BANKER_TRANSACTION_FEE && CVarGetInteger("gBanker", 0)) {
s32 rupeesFee = gSaveContext.rupeesFee;
messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_BANKER_TRANSACTION_FEE);
messageEntry.Replace("{{rupeesFee}}", std::to_string(rupeesFee));
}
if (textId == TEXT_BANKER_EXCESS && CVarGetInteger("gBanker", 0)) {
s32 playerBalance = gSaveContext.playerBalance;
s32 excessRupees = gSaveContext.excessRupees;
messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_BANKER_EXCESS);
messageEntry.Replace("{{playerBalance}}", std::to_string(playerBalance));
messageEntry.Replace("{{excessRupees}}", std::to_string(excessRupees));
}
if (textId == TEXT_BANKER_EXCESS_FULL && CVarGetInteger("gBanker", 0)) {
messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_BANKER_EXCESS_FULL);
}
if (textId == TEXT_BANKER_EXCESS_FEE && CVarGetInteger("gBanker", 0)) {
s32 rupeesFee = gSaveContext.rupeesFee;
messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_BANKER_EXCESS_FEE);
messageEntry.Replace("{{rupeesFee}}", std::to_string(rupeesFee));
}
font->charTexBuf[0] = (messageEntry.GetTextBoxType() << 4) | messageEntry.GetTextBoxPosition();
switch (gSaveContext.language) {
case LANGUAGE_FRA:

View File

@ -616,6 +616,9 @@ void SaveManager::InitFileNormal() {
gSaveContext.pendingSaleMod = MOD_NONE;
gSaveContext.isBossRushPaused = 0;
gSaveContext.pendingIceTrapCount = 0;
gSaveContext.playerBalance = 0;
gSaveContext.excessRupees = 0;
gSaveContext.rupeesFee = 5;
// Init with normal quest unless only an MQ rom is provided
gSaveContext.questId = OTRGlobals::Instance->HasOriginal() ? QUEST_NORMAL : QUEST_MASTER;
@ -736,6 +739,9 @@ void SaveManager::InitFileDebug() {
gSaveContext.entranceIndex = ENTR_HYRULE_FIELD_0;
gSaveContext.magicLevel = 0;
gSaveContext.sceneFlags[5].swch = 0x40000000;
gSaveContext.playerBalance = 999;
gSaveContext.excessRupees = 0;
gSaveContext.rupeesFee = 5;
}
void SaveManager::InitFileMaxed() {
@ -1314,6 +1320,11 @@ void SaveManager::LoadBaseVersion1() {
SaveManager::Instance->LoadArray("randomizerInf", ARRAY_COUNT(gSaveContext.randomizerInf), [](size_t i) {
SaveManager::Instance->LoadData("", gSaveContext.randomizerInf[i]);
});
SaveManager::Instance->LoadData("playerBalance", gSaveContext.playerBalance);
SaveManager::Instance->LoadData("hasWarpTransfer", gSaveContext.hasWarpTransfer);
SaveManager::Instance->LoadData("hasFee", gSaveContext.hasFee);
SaveManager::Instance->LoadData("hasPieceOfHeart", gSaveContext.hasPieceOfHeart);
SaveManager::Instance->LoadData("rupeesFee", gSaveContext.rupeesFee);
}
void SaveManager::LoadBaseVersion2() {
@ -1529,6 +1540,12 @@ void SaveManager::LoadBaseVersion2() {
});
});
}
SaveManager::Instance->LoadData("playerBalance", gSaveContext.playerBalance);
SaveManager::Instance->LoadData("hasWarpTransfer", gSaveContext.hasWarpTransfer);
SaveManager::Instance->LoadData("hasFee", gSaveContext.hasFee);
SaveManager::Instance->LoadData("hasPieceOfHeart", gSaveContext.hasPieceOfHeart);
SaveManager::Instance->LoadData("excessRupees", gSaveContext.excessRupees);
SaveManager::Instance->LoadData("rupeesFee", gSaveContext.rupeesFee);
}
}
@ -1751,6 +1768,12 @@ void SaveManager::LoadBaseVersion3() {
SaveManager::Instance->LoadData("tempCollectFlags", gSaveContext.backupFW.tempCollectFlags);
});
SaveManager::Instance->LoadData("dogParams", gSaveContext.dogParams);
SaveManager::Instance->LoadData("playerBalance", gSaveContext.playerBalance);
SaveManager::Instance->LoadData("hasWarpTransfer", gSaveContext.hasWarpTransfer);
SaveManager::Instance->LoadData("hasFee", gSaveContext.hasFee);
SaveManager::Instance->LoadData("hasPieceOfHeart", gSaveContext.hasPieceOfHeart);
SaveManager::Instance->LoadData("excessRupees", gSaveContext.excessRupees);
SaveManager::Instance->LoadData("rupeesFee", gSaveContext.rupeesFee);
}
void SaveManager::LoadBaseVersion4() {
@ -1932,6 +1955,12 @@ void SaveManager::LoadBaseVersion4() {
SaveManager::Instance->LoadData("tempCollectFlags", gSaveContext.backupFW.tempCollectFlags);
});
SaveManager::Instance->LoadData("dogParams", gSaveContext.dogParams);
SaveManager::Instance->LoadData("playerBalance", gSaveContext.playerBalance);
SaveManager::Instance->LoadData("hasWarpTransfer", gSaveContext.hasWarpTransfer);
SaveManager::Instance->LoadData("hasFee", gSaveContext.hasFee);
SaveManager::Instance->LoadData("hasPieceOfHeart", gSaveContext.hasPieceOfHeart);
SaveManager::Instance->LoadData("excessRupees", gSaveContext.excessRupees);
SaveManager::Instance->LoadData("rupeesFee", gSaveContext.rupeesFee);
}
void SaveManager::SaveBase(SaveContext* saveContext, int sectionID, bool fullSave) {
@ -2101,6 +2130,12 @@ void SaveManager::SaveBase(SaveContext* saveContext, int sectionID, bool fullSav
SaveManager::Instance->SaveData("tempCollectFlags", saveContext->backupFW.tempCollectFlags);
});
SaveManager::Instance->SaveData("dogParams", saveContext->dogParams);
SaveManager::Instance->SaveData("playerBalance", saveContext->playerBalance);
SaveManager::Instance->SaveData("hasWarpTransfer", saveContext->hasWarpTransfer);
SaveManager::Instance->SaveData("hasFee", saveContext->hasFee);
SaveManager::Instance->SaveData("hasPieceOfHeart", saveContext->hasPieceOfHeart);
SaveManager::Instance->SaveData("excessRupees", saveContext->excessRupees);
SaveManager::Instance->SaveData("rupeesFee", saveContext->rupeesFee);
}
// Load a string into a char array based on size and ensuring it is null terminated when overflowed

View File

@ -667,6 +667,11 @@ void DrawEnhancementsMenu() {
"- Not within range of Ocarina playing spots");
UIWidgets::PaddedEnhancementCheckbox("Pause Warp", "gPauseWarp", true, false);
UIWidgets::Tooltip("Selection of warp song in pause menu initiates warp. Disables song playback.");
UIWidgets::PaddedEnhancementCheckbox("Skip water take breath animation", "gSkipSwimDeepEndAnim", true, false);
UIWidgets::Tooltip("Skips Link's taking breath animation after coming up from water. This setting does not interfere with getting items from underwater.");
UIWidgets::PaddedEnhancementCheckbox("Open Bank Account", "gBanker", true, false);
UIWidgets::Tooltip("Allows the player to visit the beggar NPC to make a withdrawal."
"All excess rupees from checks will autoomatically warped to the bank.");
ImGui::EndTable();
ImGui::EndMenu();

View File

@ -13,7 +13,7 @@ extern "C" MessageTableEntry* sNesMessageEntryTablePtr;
extern "C" MessageTableEntry* sGerMessageEntryTablePtr;
extern "C" MessageTableEntry* sFraMessageEntryTablePtr;
extern "C" MessageTableEntry* sStaffMessageEntryTablePtr;
//extern "C" MessageTableEntry* _message_0xFFFC_nes;
//extern "C" MessageTableEntry* _message_0xFFFC_nes;
static void SetMessageEntry(MessageTableEntry& entry, const SOH::MessageEntry& msgEntry) {
entry.textId = msgEntry.id;
@ -187,4 +187,142 @@ extern "C" void OTRMessage_Init()
CustomMessage("Hey! Hey!&You can't take the rod out of here!&I'm serious!^Do you want to quit?&\x1B&%gYes&No%w",
"Hey! Hey!&Du kannst die Angel doch nicht&einfach mitnehmen!&Ganz im Ernst!^Möchtest du aufhören?&\x1B&%gJa&Nein%w", //TODO Used AI translation as placeholder
"Holà! Holà!&Les cannes ne sortent pas d'ici!&Je suis sérieux!^Voulez-vous arrêter?&\x1B&%gOui&Non%w")); //TODO Used AI translation as placeholder
}
CustomMessageManager::Instance->CreateMessage(
customMessageTableID, TEXT_BANKER_GREETING,
CustomMessage("Hey there, @! You&making a deposit? Or are you&here to make a withdrawal?",
"Hallo, @! Machen Sie&eine Einzahlung? Oder sind Sie&hier, um eine Auszahlung&vorzunehmen?",
"Salut, @! Vous&effectuez un dépôt ? Ou êtes-vous&ici pour effectuer un retrait?"));
CustomMessageManager::Instance->CreateMessage(
customMessageTableID, TEXT_BANKER_OPTIONS,
CustomMessage("What would you like to do?" "\x1C" "&%gDeposit Rupees&%gWithdrawal Rupees&%gNothing%w",
"Was würdest du gern tun?" "\x1C" "&%gRubine einzahlen&%gRubine abheben&%gNichts%w",
"Qu'est-ce que tu aimerais faire?" "\x1C" "&%gDéposer des rubis&%gRetirer des rubis&%gRien%w"));
CustomMessageManager::Instance->CreateMessage(
customMessageTableID, TEXT_BANKER_BALANCE,
CustomMessage("If I remember, as of your last &warp transfer your balance is&%y{{playerBalance}}%w rupees.",
"Wenn ich mich erinnere, betrug Ihr&Guthaben bei Ihrem letzten&Warp-Transfer %y{{playerBalance}}%w Rupien.",
"Si je me souviens bien, lors de&votre dernier transfert Warp,&votre solde était de %y{{playerBalance}}%w roupies."));
CustomMessageManager::Instance->CreateMessage(
customMessageTableID, TEXT_BANKER_WITHDRAWAL_AMOUNT,
CustomMessage("\x08Select Withdrawal Amount:& rupees.&Set the amount with \xAA and&press \x9F to decide.\x0A",
"\x08" "Auszahlungsbetrag:& Rubine.&Wählen Sie den Betrag mit \xAA.&Drücken Sie \x9F, um zu entscheiden.\x0A",
"\x08Sélectionnez le montant du retrait:& Roupies.&Réglez le montant avec \xAA et&appuyez sur \x9F pour décider.\x0A"));
CustomMessageManager::Instance->CreateMessage(
customMessageTableID, TEXT_BANKER_WITHDRAWAL_CONFIRM,
CustomMessage("Here are your rupees. Your new&balance is %y{{playerBalance}}%w rupees. See you&later!",
"Hier sind deine Rupien. Ihr neues&Guthaben beträgt %y{{playerBalance}}%w Rupien.&Bis später!",
"Voici vos roupies. Votre nouveau&solde est de %y{{playerBalance}}%w roupies. À plus&tard!"));
CustomMessageManager::Instance->CreateMessage(
customMessageTableID, TEXT_BANKER_DEPOSIT_AMOUNT,
CustomMessage("\x08Select Deposit Amount:& rupees.&Set the amount with \xAA and press&\x9F to decide.\x0A",
"\x08" "Einzahlungsbetrag:& Rubine.&Wählen Sie den Betrag mit \xAA.&Drücken Sie \x9F, um zu entscheiden.\x0A",
"\x08Sélectionnez le montant du dépôt:& Roupies.&Réglez le montant avec \xAA et&appuyez sur \x9F pour décider.\x0A"));
CustomMessageManager::Instance->CreateMessage(
customMessageTableID, TEXT_BANKER_DEPOSIT_CONFIRM,
CustomMessage("You've deposited your rupees. Your&new balance is %y{{playerBalance}}%w rupees. See&you later!",
"Sie haben Ihre Rupien eingezahlt.&Ihr neues Guthaben beträgt %y{{playexrBalance}}%w&Rupien. Bis später!",
"Vous avez déposé vos roupies.&Votre nouveau solde est de %y{{playerBalance}}%w&roupies. À plus tard!"));
CustomMessageManager::Instance->CreateMessage(
customMessageTableID, TEXT_BANKER_REWARD_WARP_TRANSFER_INTRO,
CustomMessage("Ho ho! Your savings have reached&%y200%w rupees! A fine achievement,&young spender!",
"Ho ho! Ihre Ersparnisse haben %y200%w&Rupien erreicht! Eine tolle Leistung,&junger Spender!",
"Ho ho! Vos économies ont atteint&%y200%w roupies! Une belle réussite,&jeune dépensier!"));
CustomMessageManager::Instance->CreateMessage(
customMessageTableID, TEXT_BANKER_REWARD_WARP_TRANSFER_ITEM,
CustomMessage("To reward your thriftiness, I've got&a special trinket for you...The&%rPirate's Charm%w!",
"Um deine Sparsamkeit zu belohnen,&habe ich ein besonderes&Schmuckstück für dich... den&%rPiratenzauber%w!",
"Pour récompenser votre économie,&j'ai un bijou spécial pour vous... Le&%rCharme du Pirate%w!"));
CustomMessageManager::Instance->CreateGetItemMessage(
//ITEM_RUPEE_BLUE is a placeholder for ITEM_PIRATE_CHARM which has not been implemented yet.
customMessageTableID, (GetItemID)TEXT_BANKER_REWARD_WARP_TRANSFER_LORE_1, ITEM_RUPEE_BLUE,
CustomMessage("This charm, infused with pirate&magic, can warp your treasures&directly to the bank! No more&heavy wallets for you!",
"Dieser mit Piratenmagie&durchdrungene Zauber kann Ihre&Schätze direkt an die Bank bringen!&Keine schweren Geldbörsen mehr!",
"Ce charme, imprégné de magie&pirate, peut transférer vos trésors&directement à la banque! Fini les&portefeuilles lourds pour vous!",
TEXTBOX_TYPE_BLUE));
CustomMessageManager::Instance->CreateMessage(
customMessageTableID, TEXT_BANKER_REWARD_WARP_TRANSFER_LORE_2,
CustomMessage("And that's not all! It also lets me&whisper your new balance to you&through the winds, once a %bwarp&transfer%w is complete.",
"Außerdem kann ich Ihnen Ihr neues&Gleichgewicht durch den Wind&zuflüstern, sobald ein %bWarp-Transfer%w&abgeschlossen ist.",
"Cela me permet également de vous&murmurer votre nouvel équilibre à&travers les vents, une fois le&%btransfert de distorsion%w terminé."));
CustomMessageManager::Instance->CreateMessage(
customMessageTableID, TEXT_BANKER_REWARD_WARP_TRANSFER_LORE_3,
CustomMessage("I've taken to calling it a %bwarp&transfer%w. A fitting name, don't you&think? It's quite the convenience!",
"Ich habe angefangen, es einen&%bWarp-Transfer%w zu nennen. Ein&passender Name, finden Sie nicht?&Das ist wirklich praktisch!",
"J'ai pris l'habitude de l'appeler&%btransfert de distorsion%w. Un nom&approprié, vous ne trouvez pas?&C'est tout à fait pratique!"));
CustomMessageManager::Instance->CreateMessage(
customMessageTableID, TEXT_BANKER_REWARD_FEE,
CustomMessage("Wow, over %y1000%w rupees saved! To&thank you, I'm dropping all&withdrawal and deposit fees!",
"Wow, über %y1000%w Rupien gespart!&Als Dankeschön verzichte ich auf&alle Abhebungs- und&Einzahlungsgebühren!",
"Wow, plus de %y1000%w roupies&économisées! Pour vous remercier,&je supprime tous les frais de&retrait et de dépôt!"));
CustomMessageManager::Instance->CreateMessage(
customMessageTableID, TEXT_BANKER_REWARD_PIECE_OF_HEART,
CustomMessage("Astounding! A whopping %y5000%w&rupees saved! For such a feat, a&%rPiece of Heart%w is yours!",
"Erstaunlich! Satte %y5000%w Rupien&gespart! Für eine solche Leistung&gehört Ihnen ein %rStück Herz%w!",
"Étonnant! Un énorme %y5000%w roupies&économisées! Pour un tel exploit,&un %rFragment de Coeur%w!"));
CustomMessageManager::Instance->CreateMessage(
customMessageTableID, TEXT_BANKER_ERROR_ZERO_AMOUNT,
CustomMessage(
"Eh, @? You can't&deposit the air in your pockets!&Come back when you've got some&real Rupees.",
"Äh, @? Sie können die&Luft nicht in Ihren Taschen&deponieren! Kommen Sie zurück,&wenn Sie echte Rupien haben.",
"Hein, @? Vous ne&pouvez pas déposer l'air dans vos&poches ! Revenez quand vous&aurez de vrais rubis."
));
CustomMessageManager::Instance->CreateMessage(
customMessageTableID, TEXT_BANKER_ERROR_INSUFFICIENT_BALANCE,
CustomMessage(
"Oh, @! It seems your&balance is running low. You need&more Rupees in the bank to make&this withdrawal.",
"Oh, @! Es scheint, dass&Ihr Guthaben zur Neige geht. Für&diese Auszahlung benötigen Sie&mehr Rupien auf der Bank.",
"Oh, @! Il semble que&votre solde soit faible. Vous avez&besoin de plus de roupies en&banque pour effectuer ce retrait."
));
CustomMessageManager::Instance->CreateMessage(
customMessageTableID, TEXT_BANKER_ERROR_WALLET_FULL,
CustomMessage(
"Whoa there, @! That&amount's too hefty for your wallet.&Trim it down a bit, eh?",
"Wow, @! Dieser Betrag&ist zu hoch für Ihren Geldbeutel.&Reduzieren Sie es ein wenig, oder?",
"Waouh, @! Ce montant&est trop lourd pour votre&portefeuille. Réduisez-le un peu,&hein?"
));
CustomMessageManager::Instance->CreateMessage(
customMessageTableID, TEXT_BANKER_ERROR_MAX_BALANCE,
CustomMessage(
"Woah, @! The bank's&max capacity is %y5000%w Rupees. I&don't have enough room for that&amount!",
"Boah, @! Die maximale&Kapazität der Bank beträgt %y5000%w&Rupien. Ich habe nicht genug Platz&für diese Menge!",
"Waouh, @! La capacité&maximale de la banque est de&%y5000%w roupies. Je n'ai pas assez de&place pour ce montant!"
));
CustomMessageManager::Instance->CreateMessage(
customMessageTableID, TEXT_BANKER_ERROR_DEPOSIT_NOT_WORTHWHILE,
CustomMessage(
"Hold up, @! There's a %y{{rupeesFee}}%w&Rupee handling fee. You'd lose&Rupees, not gain! Deposit more to&make it worthwhile.",
"Warte, @! Es fällt eine&Bearbeitungsgebühr von %y{{rupeesFee}}%w Rupien&an. Du würdest Rubine verlieren!&Zahlen Sie bitte mehr ein.",
"Tenir bon, @! Il y a des&frais de traitement de %y{{rupeesFee}}%w roupies.&Vous perdriez des rubis! Déposez&davantage s'il vous plaît."
));
CustomMessageManager::Instance->CreateMessage(
customMessageTableID, TEXT_BANKER_TRANSACTION_FEE,
CustomMessage(
"Ah, @! There's a %y{{rupeesFee}}%w&Rupee fee. Is that okay?\x1B&%gProceed&%gNevermind%w",
"Ach, @! Es fällt eine&Gebühr von %y{{rupeesFee}}%w Rupien an. Okay?\x1B&%gWeiter&%gNichts tun%w",
"Ah, @! Il y a des&frais de %y{{rupeesFee}}%w roupies. Est-ce OK?\x1B&%gProcéder&%gPas grave%w"
));
CustomMessageManager::Instance->CreateMessage(
customMessageTableID, TEXT_BANKER_EXCESS,
CustomMessage(
"Hey @! Banker here!&Your wallet is full. Warping over&%y{{excessRupees}}%w rupees!&Your new balance is %y{{playerBalance}}%w.",
"Hey @! Banker hier!&Ihr Geldbeutel ist voll. Warping&über %y{{excessRupees}}%w Rupien!&Ihr neues Guthaben beträgt %y{{playerBalance}}%w.",
"Hé @! Banquier ici!&Votre portefeuille est plein.&Déformation de plus de %y{{excessRupees}}%w roupies!&Votre nouveau solde est de %y{{playerBalance}}%w.",
TEXTBOX_TYPE_BLUE
));
CustomMessageManager::Instance->CreateMessage(
customMessageTableID, TEXT_BANKER_EXCESS_FULL,
CustomMessage(
"Hey @! Banker here!&I can't do a warp transfer when&your account is maxed out. Come&make a withdrawal!",
"Hey @! Banker hier!&Ich kann keine Warp-Überweisung&durchführen, wenn Ihr Konto voll&ist. Machen Sie eine Auszahlung!",
"Hé @! Banquier ici! Je&ne peux pas effectuer de transfert&Warp lorsque votre compte est au&maximum. Venez faire un retrait!",
TEXTBOX_TYPE_BLUE
));
CustomMessageManager::Instance->CreateMessage(
customMessageTableID, TEXT_BANKER_EXCESS_FEE,
CustomMessage(
"Hey @! Banker here!&There's a %y{{rupeesFee}}%w Rupee fee for warp&transfers. Your account doesn't&have enough to cover it.",
"Hey @! Banker hier! Es&gibt eine Gebühr von %y{{rupeesFee}}%w Rupien für&Warp-Überweisungen. Ihr Konto hat&nicht genug, um sie zu decken.",
"Hé @! Banquier ici! Il y&a des frais de %y{{rupeesFee}}%w roupies pour les&transferts Warp. Votre compte n'a&pas assez pour les couvrir.",
TEXTBOX_TYPE_BLUE
));
}

View File

@ -30,6 +30,10 @@
// So, when indexing into it with a item button index, we need to adjust
#define BUTTON_STATUS_INDEX(button) ((button) >= 4) ? ((button) + 1) : (button)
int balanceUpdated = 0;
int balanceMaxed = 0;
int balanceWasMaxed = 0;
s16 Top_HUD_Margin = 0;
s16 Left_HUD_Margin = 0;
s16 Right_HUD_Margin = 0;
@ -6550,34 +6554,49 @@ void Interface_Update(PlayState* play) {
(play->transitionMode == TRANS_MODE_OFF) && !Play_InCsMode(play)) {}
if (gSaveContext.rupeeAccumulator != 0) {
if (gSaveContext.rupeeAccumulator > 0) {
if (gSaveContext.rupeeAccumulator > 0) {
if (gSaveContext.rupees < CUR_CAPACITY(UPG_WALLET)) {
gSaveContext.rupeeAccumulator--;
gSaveContext.rupees++;
Audio_PlaySoundGeneral(NA_SE_SY_RUPY_COUNT, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8);
} else {
// "Rupee Amount MAX = %d"
osSyncPrintf("ルピー数MAX = %d\n", CUR_CAPACITY(UPG_WALLET));
gSaveContext.rupees = CUR_CAPACITY(UPG_WALLET);
gSaveContext.rupeeAccumulator--;
gSaveContext.rupees++;
Audio_PlaySoundGeneral(NA_SE_SY_RUPY_COUNT, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8);
} else {
balanceWasMaxed = (gSaveContext.playerBalance == 5000) ? 1 : 0;
if (CVarGetInteger("gBanker", 0) && gSaveContext.hasWarpTransfer) {
int rupeesToAdd = gSaveContext.rupeeAccumulator;
if (gSaveContext.playerBalance + rupeesToAdd > 5000) {
rupeesToAdd = 5000 - gSaveContext.playerBalance;
balanceMaxed = 1;
}
gSaveContext.playerBalance += rupeesToAdd;
osSyncPrintf("Added %d rupees to bank balance. New balance = %d\n", rupeesToAdd,
gSaveContext.playerBalance);
gSaveContext.excessRupees = rupeesToAdd;
gSaveContext.rupeeAccumulator = 0;
}
} else if (gSaveContext.rupees != 0) {
if (gSaveContext.rupeeAccumulator <= -50) {
gSaveContext.rupeeAccumulator += 10;
gSaveContext.rupees -= 10;
if (gSaveContext.rupees < 0) {
gSaveContext.rupees = 0;
balanceUpdated = 1;
} else {
// "Rupee Amount MAX = %d"
osSyncPrintf("ルピー数MAX = %d\n", CUR_CAPACITY(UPG_WALLET));
gSaveContext.rupees = CUR_CAPACITY(UPG_WALLET);
gSaveContext.rupeeAccumulator = 0;
}
}
} else if (gSaveContext.rupees != 0) {
if (gSaveContext.rupeeAccumulator <= -50) {
gSaveContext.rupeeAccumulator += 10;
gSaveContext.rupees -= 10;
Audio_PlaySoundGeneral(NA_SE_SY_RUPY_COUNT, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8);
if (gSaveContext.rupees < 0) {
gSaveContext.rupees = 0;
}
Audio_PlaySoundGeneral(NA_SE_SY_RUPY_COUNT, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8);
} else {
gSaveContext.rupeeAccumulator++;
gSaveContext.rupees--;
Audio_PlaySoundGeneral(NA_SE_SY_RUPY_COUNT, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8);
}
} else {
gSaveContext.rupeeAccumulator++;
gSaveContext.rupees--;
Audio_PlaySoundGeneral(NA_SE_SY_RUPY_COUNT, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8);
}
} else {
gSaveContext.rupeeAccumulator = 0;
gSaveContext.rupeeAccumulator = 0;
}
if (gSaveContext.rupeeAccumulator == 0 && gSaveContext.pendingSale != ITEM_NONE) {
u16 tempSaleItem = gSaveContext.pendingSale;

View File

@ -18,6 +18,10 @@
#include <time.h>
#include <assert.h>
//For Banker enhancement
#include "soh/Enhancements/custom-message/CustomMessageTypes.h"
void DrawBankerOverlay(PlayState* play, Gfx** gfx);
void* D_8012D1F0 = NULL;
//UNK_TYPE D_8012D1F4 = 0; // unused
Input* D_8012D1F8 = NULL;
@ -1470,6 +1474,20 @@ void Play_DrawOverlayElements(PlayState* play) {
Message_Draw(play);
//Banker code start
static s16 delayTimer = 15;
if (play->msgCtx.textId == TEXT_BANKER_WITHDRAWAL_AMOUNT || play->msgCtx.textId == TEXT_BANKER_DEPOSIT_AMOUNT) {
Gfx** gfx = &play->state.gfxCtx->overlay.p;
if (delayTimer > 0) {
delayTimer--;
return;
}
DrawBankerOverlay(play, gfx);
} else {
delayTimer = 15;
}
//Banker code end
if (play->gameOverCtx.state != GAMEOVER_INACTIVE) {
GameOver_FadeInLights(play);
}

View File

@ -32,6 +32,8 @@ void func_80A7127C(EnHy* this, PlayState* play);
void EnHy_DoNothing(EnHy* this, PlayState* play);
void func_80A714C4(EnHy* this, PlayState* play);
extern void BankerMain(PlayState* play, GraphicsContext* gfxCtx);
const ActorInit En_Hy_InitVars = {
ACTOR_EN_HY,
ACTORCAT_NPC,
@ -1105,6 +1107,13 @@ void func_80A71530(EnHy* this, PlayState* play) {
void EnHy_Update(Actor* thisx, PlayState* play) {
EnHy* this = (EnHy*)thisx;
//Banker Enhancement Hook Start
//(Might end up using the hook system, but this was a niche use case so I didn't bother.)
if (this->actor.id == 366 && this->actor.params == 1925 && CVarGetInteger("gBanker", 0)) {
BankerMain(play, play->state.gfxCtx);
}
//Banker Enhancement Hook End
if (this->actionFunc != EnHy_InitImpl) {
gSegments[6] = VIRTUAL_TO_PHYSICAL(play->objectCtx.status[this->objBankIndexOsAnime].segment);
SkelAnime_Update(&this->skelAnime);