mirror of
https://github.com/HarbourMasters/Shipwright.git
synced 2025-08-20 13:23:45 -07:00
Various cleanup
This commit is contained in:
parent
70f353f6ec
commit
39609bdac9
25 changed files with 584 additions and 208 deletions
|
@ -67,6 +67,7 @@ static void DrawMenu() {
|
|||
if (UIWidgets::EnhancementCheckbox("Evil Gossip Stone", CVAR("EvilGossipStone"))) {
|
||||
OnConfigurationChanged();
|
||||
}
|
||||
UIWidgets::Tooltip("Don't you dare talk to them.");
|
||||
}
|
||||
|
||||
static void RegisterMod() {
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
#include "soh/Enhancements/game-interactor/GameInteractor.h"
|
||||
#include "soh/Enhancements/custom-message/CustomMessageManager.h"
|
||||
#include "soh/Enhancements/randomizer/randomizer.h"
|
||||
#include "soh/frame_interpolation.h"
|
||||
#include "soh_assets.h"
|
||||
|
||||
extern "C" {
|
||||
#include "macros.h"
|
||||
|
@ -80,9 +82,28 @@ void RandomizeBoulder(Actor* refActor) {
|
|||
Actor_Kill(actor);
|
||||
}
|
||||
|
||||
static void OnPresentChange() {
|
||||
isExchangeDisabled = !CVarGetInteger(CVAR("OrnExch.Enabled"), 0);
|
||||
COND_ID_HOOK(OnActorKill, ACTOR_EN_OE2, CVarGetInteger(CVAR("OrnExch.Enabled"), 0), [](void* actorRef) {
|
||||
bool spawningPresents = false;
|
||||
|
||||
struct Present {
|
||||
};
|
||||
|
||||
std::unordered_map<Actor*, Present> presents;
|
||||
|
||||
void Present_Init(Actor* actor, PlayState* play) {
|
||||
Present present;
|
||||
presents[actor] = present;
|
||||
|
||||
actor->gravity = -1;
|
||||
Actor_MoveXZGravity(actor);
|
||||
actor->shape.rot.y = Random(0, 0xFFFF);
|
||||
|
||||
Actor_UpdateBgCheckInfo(play, actor, 10.0f, 10.0f, 0.0f, 0xFF);
|
||||
}
|
||||
|
||||
void Present_Update(Actor* actor, PlayState* play) {
|
||||
Present* present = &presents[actor];
|
||||
|
||||
if (actor->xzDistToPlayer < 50.0f && actor->yDistToPlayer < 50.0f) {
|
||||
uint32_t giftsCollected = CVarGetInteger(CVAR("GiftsCollected"), 0);
|
||||
giftsCollected++;
|
||||
CVarSetInteger(CVAR("GiftsCollected"), giftsCollected);
|
||||
|
@ -91,9 +112,33 @@ static void OnPresentChange() {
|
|||
msg += " Gifts in Inventory.";
|
||||
Notification::Emit({
|
||||
.itemIcon = "RG_TRIFORCE_PIECE",
|
||||
.message = msg
|
||||
.message = msg,
|
||||
.messageColor = ImVec4(1.0f, 1.0f, 1.0f, 1.0f),
|
||||
});
|
||||
});
|
||||
Actor_Kill(actor);
|
||||
}
|
||||
}
|
||||
|
||||
void Present_Draw(Actor* actor, PlayState* play) {
|
||||
OPEN_DISPS(play->state.gfxCtx);
|
||||
|
||||
Gfx_SetupDL_25Opa(play->state.gfxCtx);
|
||||
|
||||
Matrix_Scale(30.0f, 30.0f, 30.0f, MTXMODE_APPLY);
|
||||
Matrix_Translate(49.20f, 0.0f, -106.60f, MTXMODE_APPLY);
|
||||
gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(play->state.gfxCtx, (char*)__FILE__, __LINE__), G_MTX_MODELVIEW | G_MTX_LOAD);
|
||||
gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 255, 255);
|
||||
gSPDisplayList(POLY_OPA_DISP++, (Gfx*)gXmasDecor100DL);
|
||||
|
||||
CLOSE_DISPS(play->state.gfxCtx);
|
||||
}
|
||||
|
||||
void Present_Destroy(Actor* actor, PlayState* play) {
|
||||
presents.erase(actor);
|
||||
}
|
||||
|
||||
static void OnPresentChange() {
|
||||
isExchangeDisabled = !CVarGetInteger(CVAR("OrnExch.Enabled"), 0);
|
||||
COND_ID_HOOK(OnOpenText, 0x204A, CVarGetInteger(CVAR("OrnExch.Enabled"), 0), [](u16 * textId, bool* loadFromMessageTable) {
|
||||
auto messageEntry = CustomMessage("");
|
||||
bool reduceGifts = false;
|
||||
|
@ -127,6 +172,48 @@ static void OnPresentChange() {
|
|||
});
|
||||
}
|
||||
});
|
||||
|
||||
COND_HOOK(OnSceneSpawnActors, CVarGetInteger(CVAR("OrnExch.Enabled"), 0), []() {
|
||||
presents.clear();
|
||||
Vec3f pos;
|
||||
static CollisionPoly presentPoly;
|
||||
static f32 raycastResult;
|
||||
pos.y = 9999.0f;
|
||||
int spawnAttempts = 0;
|
||||
while (spawnAttempts < 20) {
|
||||
if (GET_PLAYER(gPlayState) != nullptr) {
|
||||
pos.x = GET_PLAYER(gPlayState)->actor.world.pos.x;
|
||||
pos.z = GET_PLAYER(gPlayState)->actor.world.pos.z;
|
||||
} else {
|
||||
pos.x = 0;
|
||||
pos.z = 0;
|
||||
}
|
||||
// X/Z anywhere from -1000.0 to +1000.0 from player
|
||||
pos.x += (float)(Random(0, 20000)) - 10000.0f;
|
||||
pos.z += (float)(Random(0, 20000)) - 10000.0f;
|
||||
|
||||
raycastResult = BgCheck_AnyRaycastFloor1(&gPlayState->colCtx, &presentPoly, &pos);
|
||||
|
||||
if (raycastResult > BGCHECK_Y_MIN) {
|
||||
spawningPresents = true;
|
||||
Actor* actor = Actor_Spawn(&gPlayState->actorCtx, gPlayState, ACTOR_EN_OE2, pos.x, raycastResult, pos.z, 0, 0, 0, 0, false);
|
||||
spawningPresents = false;
|
||||
// break;
|
||||
}
|
||||
|
||||
spawnAttempts++;
|
||||
}
|
||||
});
|
||||
|
||||
COND_ID_HOOK(ShouldActorInit, ACTOR_EN_OE2, CVarGetInteger(CVAR("OrnExch.Enabled"), 0), [](void* actorRef, bool* should) {
|
||||
Actor* actor = (Actor*)actorRef;
|
||||
if (spawningPresents) {
|
||||
actor->init = Present_Init;
|
||||
actor->update = Present_Update;
|
||||
actor->draw = Present_Draw;
|
||||
actor->destroy = Present_Destroy;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void OnBlitzChange() {
|
||||
|
@ -194,32 +281,32 @@ static void DrawMenu() {
|
|||
}
|
||||
UIWidgets::Tooltip("Can you beat your objective before the Fever sets in?/n"
|
||||
"- Obtaining Ice Traps extends your timer.");
|
||||
if (UIWidgets::EnhancementSliderFloat("", "##FontScale", CVAR("FontScale"),
|
||||
1.0f, 5.0f, "Font: %.1fx", 1.0f, false, false, isFeverDisabled)) {
|
||||
OnFeverConfigurationChanged();
|
||||
if (CVarGetInteger(CVAR("Fever.Enabled"), 0)) {
|
||||
if (UIWidgets::EnhancementSliderFloat("", "##FontScale", CVAR("FontScale"),
|
||||
1.0f, 5.0f, "Font: %.1fx", 1.0f, false, false, isFeverDisabled)) {
|
||||
OnFeverConfigurationChanged();
|
||||
}
|
||||
UIWidgets::PaddedEnhancementSliderInt("Starting Timer: %d minutes", "##StartTime", CVAR("StartTimer"),
|
||||
5, 30, "", 15, true, true, false, isFeverDisabled);
|
||||
UIWidgets::PaddedEnhancementSliderInt("Time Extensions: %d minutes", "##ExtendTime", CVAR("ExtendTimer"),
|
||||
1, 10, "", 5, true, true, false, isFeverDisabled);
|
||||
}
|
||||
UIWidgets::PaddedEnhancementSliderInt("Starting Timer: %d minutes", "##StartTime", CVAR("StartTimer"),
|
||||
5, 30, "", 15, true, true, false, isFeverDisabled);
|
||||
UIWidgets::PaddedEnhancementSliderInt("Time Extensions: %d minutes", "##ExtendTime", CVAR("ExtendTimer"),
|
||||
1, 10, "", 5, true, true, false, isFeverDisabled);
|
||||
UIWidgets::PaddedSeparator();
|
||||
|
||||
if (UIWidgets::EnhancementCheckbox("Boulder Blitz", CVAR("Blitz.Enabled"))) {
|
||||
OnBlitzChange();
|
||||
}
|
||||
UIWidgets::Tooltip("Boulders will randomly be replaced with other boulder types.");
|
||||
UIWidgets::PaddedSeparator();
|
||||
|
||||
if (UIWidgets::EnhancementCheckbox("Ornament Exchange", CVAR("OrnExch.Enabled"))) {
|
||||
OnPresentChange();
|
||||
bool toggle = CVarGetInteger(CVAR("OrnExch.Enabled"), 0);
|
||||
CVarSetInteger("gHoliday.ItsHeckinPat.GiftsForNPCs", toggle);
|
||||
OnConfigChanged();
|
||||
}
|
||||
UIWidgets::Tooltip("See Malon as Young Link in Lon Lon Ranch to exchange Gifts for Ornaments!\n"
|
||||
"Note: Enabling this will set \"Gifts For NPCs\" to match.");
|
||||
UIWidgets::PaddedEnhancementSliderInt("Gifts Required: %d Gifts", "##GiftsReq", CVAR("OrnExch.Amount"),
|
||||
5, 30, "", 15, true, true, false, isExchangeDisabled);
|
||||
|
||||
UIWidgets::Tooltip("See Malon as Young Link in Lon Lon Ranch to exchange Gifts for Ornaments!");
|
||||
if (CVarGetInteger(CVAR("OrnExch.Enabled"), 0)) {
|
||||
UIWidgets::PaddedEnhancementSliderInt("Gifts Required: %d Gifts", "##GiftsReq", CVAR("OrnExch.Amount"),
|
||||
5, 30, "", 15, true, true, false, isExchangeDisabled);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -7,9 +7,15 @@
|
|||
#include "soh/Enhancements/randomizer/3drando/random.hpp"
|
||||
#include "soh/Enhancements/randomizer/3drando/location_access.hpp"
|
||||
#include "soh/Enhancements/randomizer/entrance.h"
|
||||
#include "soh/Enhancements/custom-collectible/CustomCollectible.h"
|
||||
#include "soh/Notification/Notification.h"
|
||||
#include "soh/Enhancements/nametag.h"
|
||||
|
||||
#include "objects/gameplay_field_keep/gameplay_field_keep.h"
|
||||
#include "objects/gameplay_keep/gameplay_keep.h"
|
||||
#include "objects/object_md/object_md.h"
|
||||
#include "objects/object_trap/object_trap.h"
|
||||
#include "objects/object_toryo/object_toryo.h"
|
||||
#include "src/overlays/actors/ovl_Door_Ana/z_door_ana.h"
|
||||
extern "C" {
|
||||
#include "macros.h"
|
||||
|
@ -20,6 +26,7 @@ extern PlayState* gPlayState;
|
|||
void DoorAna_SetupAction(DoorAna* doorAna, DoorAnaActionFunc actionFunc);
|
||||
void DoorAna_GrabPlayer(DoorAna* doorAna, PlayState* play);
|
||||
}
|
||||
extern GetItemEntry vanillaQueuedItemEntry;
|
||||
|
||||
#define AUTHOR "Fredomato"
|
||||
#define CVAR(v) "gHoliday." AUTHOR "." v
|
||||
|
@ -36,7 +43,7 @@ const s16 entrances[] = {
|
|||
0x00B7, 0x0201, 0x003B, 0x0463, 0x0588, 0x057C, 0x0578, 0x0340, 0x04C2, 0x03E8, 0x04BE, 0x0482, 0x0315, 0x045B, 0x0371, 0x0394,
|
||||
0x0272, 0x0211, 0x0053, 0x0472, 0x0453, 0x0351, 0x0384, 0x044B, 0x03EC, 0x04FF, 0x0700, 0x0800, 0x0701, 0x0801, 0x0702, 0x0802,
|
||||
0x0703, 0x0803, 0x0704, 0x0804, 0x0705, 0x0805, 0x0706, 0x0806, 0x0707, 0x0807, 0x0708, 0x0808, 0x0709, 0x0809, 0x070A, 0x080A,
|
||||
0x070B, 0x080B, 0x070C, 0x080C, 0x070D, 0x080D, 0x070E, 0x080E, 0x070F, 0x080F, 0x0710, 0x0711, 0x0811, 0x0712, 0x0812,
|
||||
0x070B, 0x080B, 0x080C, 0x070D, 0x080D, 0x070E, 0x080E, 0x070F, 0x080F, 0x0710, 0x0711, 0x0811, 0x0712, 0x0812,
|
||||
0x0713, 0x0813, 0x0714, 0x0814, 0x0715, 0x0815, 0x0716, 0x0816, 0x0717, 0x0817, 0x0718, 0x0818, 0x0719, 0x0819, 0x081A,
|
||||
0x071B, 0x081B, 0x071C, 0x081C, 0x071D, 0x081D, 0x071E, 0x081E, 0x071F, 0x081F, 0x0720, 0x0820, 0x004B, 0x035D, 0x031C, 0x0361,
|
||||
0x002D, 0x050B, 0x044F, 0x0359, 0x05E0, 0x020D, 0x011E, 0x0286, 0x04E2, 0x04D6, 0x01DD, 0x04DA, 0x00FC, 0x01A9, 0x0185, 0x04DE,
|
||||
|
@ -51,6 +58,15 @@ static bool midoGrottoInit = false;
|
|||
static SkelAnime midoSkelAnime;
|
||||
static Vec3s midoJointTable[17];
|
||||
static Vec3s midoMorphTable[17];
|
||||
int FredsQuestWoodCollected = 0;
|
||||
int FredsQuestWoodOnHand = 0;
|
||||
static int lastDisplayedCount = -1;
|
||||
static bool FredsQuestComplete = false;
|
||||
static SkelAnime collectionPointSkelAnime;
|
||||
static Vec3s collectionPointJointTable[17];
|
||||
static Vec3s collectionPointMorphTable[17];
|
||||
static std::string collectionPointNametag;
|
||||
|
||||
|
||||
static void RandomGrotto_WaitOpen(DoorAna* doorAna, PlayState* play) {
|
||||
if (!midoGrottoInit) {
|
||||
|
@ -61,9 +77,11 @@ static void RandomGrotto_WaitOpen(DoorAna* doorAna, PlayState* play) {
|
|||
|
||||
Actor* actor = &doorAna->actor;
|
||||
Player* player = GET_PLAYER(play);
|
||||
Math_SmoothStepToF(&actor->world.pos.x, player->actor.world.pos.x, 0.1f, 10.0f, 0.0f);
|
||||
Math_SmoothStepToF(&actor->world.pos.z, player->actor.world.pos.z, 0.1f, 10.0f, 0.0f);
|
||||
Math_SmoothStepToF(&actor->world.pos.y, player->actor.world.pos.y, 0.1f, 10.0f, 0.0f);
|
||||
if (!Player_InCsMode(play)) {
|
||||
Math_SmoothStepToF(&actor->world.pos.x, player->actor.world.pos.x, 0.1f, 10.0f, 0.0f);
|
||||
Math_SmoothStepToF(&actor->world.pos.z, player->actor.world.pos.z, 0.1f, 10.0f, 0.0f);
|
||||
Math_SmoothStepToF(&actor->world.pos.y, player->actor.world.pos.y, 0.1f, 10.0f, 0.0f);
|
||||
}
|
||||
|
||||
Math_ApproachS(&doorAna->actor.shape.rot.y, doorAna->actor.yawTowardsPlayer, 5, 0xBB8);
|
||||
|
||||
|
@ -103,11 +121,10 @@ static void RandomGrotto_Draw(Actor* actor, PlayState* play) {
|
|||
CLOSE_DISPS(play->state.gfxCtx);
|
||||
}
|
||||
|
||||
static void SpawnRandomGrotto() {
|
||||
static Vec3f FindValidPos(f32 distance) {
|
||||
Vec3f pos;
|
||||
pos.y = 9999.0f;
|
||||
int spawnAttempts = 0;
|
||||
while (spawnAttempts < 50) {
|
||||
while (true) {
|
||||
if (GET_PLAYER(gPlayState) != nullptr) {
|
||||
pos.x = GET_PLAYER(gPlayState)->actor.world.pos.x;
|
||||
pos.z = GET_PLAYER(gPlayState)->actor.world.pos.z;
|
||||
|
@ -115,34 +132,355 @@ static void SpawnRandomGrotto() {
|
|||
pos.x = 0;
|
||||
pos.z = 0;
|
||||
}
|
||||
// X/Z anywhere from -1000.0 to +1000.0 from player
|
||||
pos.x += (float)(Random(0, 2000)) - 1000.0f;
|
||||
pos.z += (float)(Random(0, 2000)) - 1000.0f;
|
||||
pos.x += (float)(Random(0, distance)) - distance / 2;
|
||||
pos.z += (float)(Random(0, distance)) - distance / 2;
|
||||
|
||||
raycastResult = BgCheck_AnyRaycastFloor1(&gPlayState->colCtx, &snowballPoly, &pos);
|
||||
|
||||
if (raycastResult > BGCHECK_Y_MIN) {
|
||||
Actor* grotto = Actor_Spawn(&gPlayState->actorCtx, gPlayState, ACTOR_DOOR_ANA, pos.x, raycastResult, pos.z, 0, 0, 0, 0, false);
|
||||
midoGrottoInit = false;
|
||||
DoorAna_SetupAction((DoorAna*)grotto, RandomGrotto_WaitOpen);
|
||||
grotto->draw = RandomGrotto_Draw;
|
||||
break;
|
||||
pos.y = raycastResult;
|
||||
return pos;
|
||||
}
|
||||
|
||||
spawnAttempts++;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: If in hyrule field and treeChopper is on, teleport somewhere else in hyrule field
|
||||
static void SpawnRandomGrotto() {
|
||||
if (
|
||||
gPlayState->sceneNum == SCENE_TEMPLE_OF_TIME_EXTERIOR_DAY ||
|
||||
gPlayState->sceneNum == SCENE_TEMPLE_OF_TIME_EXTERIOR_NIGHT ||
|
||||
gPlayState->sceneNum == SCENE_TEMPLE_OF_TIME_EXTERIOR_RUINS
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
Vec3f pos = FindValidPos(2000.0f);
|
||||
Actor* grotto = Actor_Spawn(&gPlayState->actorCtx, gPlayState, ACTOR_DOOR_ANA, pos.x, pos.y, pos.z, 0, 0, 0, 0, false);
|
||||
midoGrottoInit = false;
|
||||
DoorAna_SetupAction((DoorAna*)grotto, RandomGrotto_WaitOpen);
|
||||
grotto->draw = RandomGrotto_Draw;
|
||||
}
|
||||
|
||||
void SpawnStick(Vec3f pos) {
|
||||
CustomCollectible::Spawn(pos.x, pos.y + 150.0f, pos.z, 0, CustomCollectible::KILL_ON_TOUCH | CustomCollectible::TOSS_ON_SPAWN, 0, [](Actor* actor, PlayState* play) {
|
||||
FredsQuestWoodOnHand++;
|
||||
Audio_PlaySoundGeneral(NA_SE_SY_METRONOME, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
|
||||
}, [](Actor* actor, PlayState* play) {
|
||||
Matrix_Scale(40.0f, 40.0f, 40.0f, MTXMODE_APPLY);
|
||||
for (int i = 4; i < 7; i++) {
|
||||
Matrix_RotateZYX(800 * i, 0, 800 * i, MTXMODE_APPLY);
|
||||
GetItem_Draw(play, GID_STICK);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Actor* specialTree = nullptr;
|
||||
|
||||
void ChooseSpecialTree() {
|
||||
Actor* actor = gPlayState->actorCtx.actorLists[ACTORCAT_PROP].head;
|
||||
std::vector<Actor*> trees;
|
||||
|
||||
specialTree = nullptr;
|
||||
|
||||
while (actor != NULL) {
|
||||
if (ACTOR_EN_WOOD02 == actor->id && actor->params < 10) {
|
||||
trees.push_back(actor);
|
||||
}
|
||||
actor = actor->next;
|
||||
}
|
||||
|
||||
if (trees.size() <= 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
specialTree = trees[Random(0, trees.size() - 1)];
|
||||
}
|
||||
|
||||
extern "C" bool HandleTreeBonk(Actor* actor) {
|
||||
if (!CVarGetInteger(CVAR("FredsQuest.Enabled"), 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int damage = 2;
|
||||
// random chance of doing a crit
|
||||
if (Random(0, 100) < 30) {
|
||||
damage = 4;
|
||||
}
|
||||
|
||||
if (actor->colChkInfo.health - damage <= 0) {
|
||||
if (specialTree == actor) {
|
||||
ChooseSpecialTree();
|
||||
|
||||
for (int i = 0; i < CVarGetInteger(CVAR("FredsQuest.SpecialBreakDropRate"), 10); i++) {
|
||||
SpawnStick(actor->world.pos);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < CVarGetInteger(CVAR("FredsQuest.TreeBreakDropRate"), 3); i++) {
|
||||
SpawnStick(actor->world.pos);
|
||||
}
|
||||
}
|
||||
|
||||
// Move tree (instead of killing and spawning another)
|
||||
actor->colChkInfo.health = 8;
|
||||
Vec3f pos = FindValidPos(5000.0f);
|
||||
actor->world.pos.x = pos.x;
|
||||
actor->world.pos.y = pos.y;
|
||||
actor->world.pos.z = pos.z;
|
||||
} else {
|
||||
actor->colChkInfo.health -= damage;
|
||||
for (int i = 0; i < CVarGetInteger(CVAR("FredsQuest.TreeBonkDropRate"), 1); i++) {
|
||||
SpawnStick(actor->world.pos);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DrawCrazyTaxiArrow(Actor* actor, PlayState* play) {
|
||||
if (specialTree == nullptr || !CVarGetInteger(CVAR("FredsQuest.CrazyTaxiArrow"), 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
s16 yaw = Actor_WorldYawTowardActor(actor, specialTree);
|
||||
Math_ApproachS(&actor->shape.rot.y, yaw, 5, 10000);
|
||||
|
||||
OPEN_DISPS(gPlayState->state.gfxCtx);
|
||||
|
||||
Gfx_SetupDL_4Xlu(gPlayState->state.gfxCtx);
|
||||
|
||||
Matrix_Scale(50.0f, 50.0f, 50.0f, MTXMODE_APPLY);
|
||||
Matrix_Translate(0.0f, 70.0f, 0.0f, MTXMODE_APPLY);
|
||||
Matrix_RotateY(5.86f, MTXMODE_APPLY);
|
||||
|
||||
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(play->state.gfxCtx, (char*)__FILE__, __LINE__), G_MTX_MODELVIEW | G_MTX_LOAD);
|
||||
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 0, 255, 0, 255);
|
||||
gDPSetEnvColor(POLY_XLU_DISP++, 0, 255, 0, 255);
|
||||
gSPDisplayList(POLY_XLU_DISP++, (Gfx*)gDebugArrowDL);
|
||||
|
||||
CLOSE_DISPS(gPlayState->state.gfxCtx);
|
||||
}
|
||||
|
||||
void SpawnCrazyTaxiArrow() {
|
||||
EnItem00* arrow = CustomCollectible::Spawn(0, 0, 0, 0, CustomCollectible::KEEP_ON_PLAYER, 0, NULL, NULL);
|
||||
arrow->actor.draw = DrawCrazyTaxiArrow;
|
||||
}
|
||||
|
||||
void CollectionPoint_Update(Actor* actor, PlayState* play) {
|
||||
EnItem00* enItem00 = (EnItem00*)actor;
|
||||
|
||||
SkelAnime_Update(&collectionPointSkelAnime);
|
||||
|
||||
if (FredsQuestComplete) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (lastDisplayedCount != FredsQuestWoodCollected) {
|
||||
lastDisplayedCount = FredsQuestWoodCollected;
|
||||
collectionPointNametag = "Bring me wood!";
|
||||
if (FredsQuestWoodCollected > 0) {
|
||||
collectionPointNametag += std::string(" (") + std::to_string(FredsQuestWoodCollected) + "/" + std::to_string(CVarGetInteger(CVAR("FredsQuest.WoodNeeded"), 300)) + ")";
|
||||
}
|
||||
NameTag_RemoveAllForActor(actor);
|
||||
NameTag_RegisterForActorWithOptions(actor, collectionPointNametag.c_str(), { .yOffset = 100 });
|
||||
}
|
||||
|
||||
if ((actor->xzDistToPlayer <= 200.0f) && (fabsf(actor->yDistToPlayer) <= fabsf(50.0f))) {
|
||||
if (FredsQuestWoodOnHand) {
|
||||
FredsQuestWoodCollected++;
|
||||
FredsQuestWoodOnHand--;
|
||||
Audio_PlaySoundGeneral(NA_SE_SY_METRONOME, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
|
||||
|
||||
if (FredsQuestWoodCollected >= CVarGetInteger(CVAR("FredsQuest.WoodNeeded"), 300)) {
|
||||
FredsQuestComplete = true;
|
||||
collectionPointNametag = "You're a hero!";
|
||||
NameTag_RemoveAllForActor(actor);
|
||||
NameTag_RegisterForActorWithOptions(actor, collectionPointNametag.c_str(), { .yOffset = 100 });
|
||||
|
||||
if (IS_RANDO && Rando::Context::GetInstance()->GetOption(RSK_TRIFORCE_HUNT)) {
|
||||
vanillaQueuedItemEntry = Rando::StaticData::RetrieveItem(RG_TRIFORCE_PIECE).GetGIEntry_Copy();
|
||||
} else {
|
||||
vanillaQueuedItemEntry = Rando::StaticData::RetrieveItem(RG_HEART_CONTAINER).GetGIEntry_Copy();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CollectionPoint_Draw(Actor* actor, PlayState* play) {
|
||||
OPEN_DISPS(play->state.gfxCtx);
|
||||
|
||||
Gfx_SetupDL_25Opa(play->state.gfxCtx);
|
||||
SkelAnime_DrawSkeletonOpa(play, &collectionPointSkelAnime, NULL, NULL, actor);
|
||||
|
||||
// For every 2% of the goal, draw a stick at a different angle, building a tree
|
||||
Matrix_Scale(40.0f, 40.0f, 40.0f, MTXMODE_APPLY);
|
||||
Matrix_Translate(0, 0, -300.0f, MTXMODE_APPLY);
|
||||
for (int i = 0; i < FredsQuestWoodCollected / (CVarGetInteger(CVAR("FredsQuest.WoodNeeded"), 300) / 50); i++) {
|
||||
float angle = 10 * i;
|
||||
float radius = (50 - i) * 0.5f; // Radius decreases as it goes up
|
||||
float height = 10.0f; // Incremental height
|
||||
|
||||
Matrix_Translate(radius * cosf(angle), height, radius * sinf(angle), MTXMODE_APPLY);
|
||||
Matrix_RotateY(angle, MTXMODE_APPLY);
|
||||
GetItem_Draw(play, GID_STICK);
|
||||
}
|
||||
|
||||
CLOSE_DISPS(play->state.gfxCtx);
|
||||
}
|
||||
|
||||
void SpawnCollectionPoint() {
|
||||
EnItem00* collectionPoint = CustomCollectible::Spawn(859.0f, 347.0f, 5185.0f, 0xB000, 0, 0, NULL, NULL);
|
||||
collectionPoint->actor.update = CollectionPoint_Update;
|
||||
collectionPoint->actor.draw = CollectionPoint_Draw;
|
||||
collectionPoint->actor.flags |= ACTOR_FLAG_DRAW_WHILE_CULLED;
|
||||
SkelAnime_InitFlex(gPlayState, &collectionPointSkelAnime, (FlexSkeletonHeader*)&object_toryo_Skel_007150,
|
||||
(AnimationHeader*)&object_toryo_Anim_000E50, collectionPointJointTable, collectionPointMorphTable, 17);
|
||||
}
|
||||
|
||||
void RandomTrap_Update(Actor* actor, PlayState* play) {
|
||||
EnItem00* enItem00 = (EnItem00*)actor;
|
||||
|
||||
enItem00->unk_158--;
|
||||
if (enItem00->unk_158 == 0) {
|
||||
Actor_Kill(actor);
|
||||
return;
|
||||
}
|
||||
|
||||
Math_ApproachS(&actor->world.rot.y, actor->yawTowardsPlayer, 5, 0xBB8);
|
||||
actor->speedXZ = 3.0f;
|
||||
|
||||
// TODO: CVar for speed
|
||||
// Multiply speed by distance
|
||||
actor->speedXZ += actor->xzDistToPlayer * 0.01f;
|
||||
if (actor->xzDistToPlayer > 1000.0f && actor->velocity.y < -3.0f) {
|
||||
actor->velocity.y += ABS(actor->yDistToPlayer) * 0.01f;
|
||||
}
|
||||
|
||||
actor->shape.rot.y += 0x1000;
|
||||
|
||||
if ((actor->xzDistToPlayer <= 50.0f) && (fabsf(actor->yDistToPlayer) <= fabsf(20.0f))) {
|
||||
// TODO: Random crowd control effect
|
||||
GameInteractor::RawAction::KnockbackPlayer(5.0f);
|
||||
Actor_Kill(actor);
|
||||
}
|
||||
|
||||
if (actor->gravity != 0.0f) {
|
||||
Actor_MoveXZGravity(actor);
|
||||
Actor_UpdateBgCheckInfo(play, actor, 20.0f, 15.0f, 15.0f, 0x1D);
|
||||
}
|
||||
|
||||
if (actor->bgCheckFlags & 0x0003) {
|
||||
actor->speedXZ = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void RandomTrap_Draw(Actor* actor, PlayState* play) {
|
||||
OPEN_DISPS(play->state.gfxCtx);
|
||||
|
||||
Matrix_Scale(4.0f, 4.0f, 4.0f, MTXMODE_APPLY);
|
||||
Matrix_Translate(0, -200.0f, 0, MTXMODE_APPLY);
|
||||
func_8002EBCC(actor, play, 1);
|
||||
Gfx_DrawDListOpa(play, (Gfx*)gSlidingBladeTrapDL);
|
||||
|
||||
CLOSE_DISPS(play->state.gfxCtx);
|
||||
}
|
||||
|
||||
void SpawnRandomTrap() {
|
||||
Vec3f pos = FindValidPos(2000.0f);
|
||||
EnItem00* randomTrap = CustomCollectible::Spawn(pos.x, pos.y, pos.z, 0, CustomCollectible::TOSS_ON_SPAWN, 0, NULL, NULL);
|
||||
SoundSource_PlaySfxAtFixedWorldPos(gPlayState, &randomTrap->actor.world.pos, 20, NA_SE_EV_LIGHTNING);
|
||||
randomTrap->actor.update = RandomTrap_Update;
|
||||
randomTrap->actor.draw = RandomTrap_Draw;
|
||||
randomTrap->unk_158 = 20 * CVarGetInteger(CVAR("RandomTraps.Lifetime"), 30);
|
||||
}
|
||||
|
||||
void OnSceneInit() {
|
||||
// Reset wood collected
|
||||
FredsQuestWoodCollected = 0;
|
||||
FredsQuestWoodOnHand = 0;
|
||||
lastDisplayedCount = -1;
|
||||
FredsQuestComplete = false;
|
||||
|
||||
if (gPlayState->sceneNum != SCENE_HYRULE_FIELD) {
|
||||
return;
|
||||
}
|
||||
|
||||
ChooseSpecialTree();
|
||||
SpawnCrazyTaxiArrow();
|
||||
SpawnCollectionPoint();
|
||||
}
|
||||
|
||||
static void ConfigurationChanged() {
|
||||
COND_HOOK(OnSceneSpawnActors, CVarGetInteger(CVAR("KrampusHole"), 0), SpawnRandomGrotto);
|
||||
COND_HOOK(OnSceneSpawnActors, CVarGetInteger(CVAR("FredsQuest.Enabled"), 0), OnSceneInit);
|
||||
|
||||
COND_HOOK(OnPlayerUpdate, CVarGetInteger(CVAR("RandomTraps.Enabled"), 0), []() {
|
||||
if (rand() % CVarGetInteger(CVAR("RandomTraps.SpawnChance"), 400) == 0) {
|
||||
SpawnRandomTrap();
|
||||
}
|
||||
});
|
||||
|
||||
COND_HOOK(OnPlayerUpdate, CVarGetInteger(CVAR("FredsQuest.Enabled"), 0), []() {
|
||||
if (CVarGetInteger(CVAR("FredsQuest.EncumberedThreshold"), 60) == 0 || FredsQuestWoodOnHand <= CVarGetInteger(CVAR("FredsQuest.EncumberedThreshold"), 60)) {
|
||||
GameInteractor::State::RunSpeedModifier = 0;
|
||||
} else {
|
||||
GameInteractor::State::RunSpeedModifier = -2;
|
||||
}
|
||||
});
|
||||
|
||||
COND_VB_SHOULD(VB_PLAYER_ROLL, CVarGetInteger(CVAR("FredsQuest.Enabled"), 0), {
|
||||
if (FredsQuestWoodOnHand > CVarGetInteger(CVAR("FredsQuest.EncumberedThreshold"), 0)) {
|
||||
*should = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void DrawMenu() {
|
||||
ImGui::SeparatorText(AUTHOR);
|
||||
|
||||
if (UIWidgets::EnhancementCheckbox("The Krampus Hole", CVAR("KrampusHole"))) {
|
||||
// UIWidgets::EnhancementSliderFloat("Xfloat", "Xfloat", CVAR("tmpxf"), 0.0f, 10.0f, "%.2f", 1.0f, false);
|
||||
// UIWidgets::EnhancementSliderFloat("Yfloat", "Yfloat", CVAR("tmpyf"), 0.0f, 10.0f, "%.2f", 1.0f, false);
|
||||
// UIWidgets::EnhancementSliderFloat("Zfloat", "Zfloat", CVAR("tmpzf"), 0.0f, 10.0f, "%.2f", 1.0f, false);
|
||||
// UIWidgets::EnhancementSliderInt("Xs", "Xs", CVAR("tmpxs"), 0, UINT16_MAX, "%d", 1, false);
|
||||
// UIWidgets::EnhancementSliderInt("Ys", "Ys", CVAR("tmpys"), 0, UINT16_MAX, "%d", 1, false);
|
||||
// UIWidgets::EnhancementSliderInt("Zs", "Zs", CVAR("tmpzs"), 0, UINT16_MAX, "%d", 1, false);
|
||||
if (UIWidgets::EnhancementCheckbox("Fred's Quest", CVAR("FredsQuest.Enabled"))) {
|
||||
ConfigurationChanged();
|
||||
}
|
||||
UIWidgets::Tooltip("Collect wood and bring it to the collection point in Hyrule Field for a small reward.");
|
||||
if (CVarGetInteger(CVAR("FredsQuest.Enabled"), 0)) {
|
||||
if (UIWidgets::EnhancementCheckbox("Crazy Taxi Arrow", CVAR("FredsQuest.CrazyTaxiArrow"))) {
|
||||
ConfigurationChanged();
|
||||
}
|
||||
if (UIWidgets::EnhancementSliderInt("Wood Needed", "##FredsQuest.WoodNeeded", CVAR("FredsQuest.WoodNeeded"), 0, 1000, "%d", 300, false)) {
|
||||
ConfigurationChanged();
|
||||
}
|
||||
if (UIWidgets::EnhancementSliderInt("Tree Bonk Drop Rate", "##FredsQuest.TreeBonkDropRate", CVAR("FredsQuest.TreeBonkDropRate"), 0, 10, "%d", 1, false)) {
|
||||
ConfigurationChanged();
|
||||
}
|
||||
if (UIWidgets::EnhancementSliderInt("Tree Break Drop Rate", "##FredsQuest.TreeBreakDropRate", CVAR("FredsQuest.TreeBreakDropRate"), 0, 50, "%d", 3, false)) {
|
||||
ConfigurationChanged();
|
||||
}
|
||||
if (UIWidgets::EnhancementSliderInt("Special Break Drop Rate", "##FredsQuest.SpecialBreakDropRate", CVAR("FredsQuest.SpecialBreakDropRate"), 0, 50, "%d", 10, false)) {
|
||||
ConfigurationChanged();
|
||||
}
|
||||
if (UIWidgets::EnhancementSliderInt("Encumbered Threshold", "##FredsQuest.EncumberedThreshold", CVAR("FredsQuest.EncumberedThreshold"), 0, 200, "%d", 60, false)) {
|
||||
ConfigurationChanged();
|
||||
}
|
||||
UIWidgets::Tooltip("If you have more than this many sticks, you will be encumbered and run slower. 0 for disabled");
|
||||
}
|
||||
if (UIWidgets::EnhancementCheckbox("Random Traps", CVAR("RandomTraps.Enabled"))) {
|
||||
ConfigurationChanged();
|
||||
}
|
||||
UIWidgets::Tooltip("Random traps will spawn around you at a configurable rate. (Currently only knockback)");
|
||||
if (CVarGetInteger(CVAR("RandomTraps.Enabled"), 0)) {
|
||||
if (UIWidgets::EnhancementSliderInt("Trap Lifetime (Seconds)", "##RandomTraps.Lifetime", CVAR("RandomTraps.Lifetime"), 0, 60, "%d", 30, false)) {
|
||||
ConfigurationChanged();
|
||||
}
|
||||
if (UIWidgets::EnhancementSliderInt("Spawn Chance", "##RandomTraps.SpawnChance", CVAR("RandomTraps.SpawnChance"), 40, 2000, "%d", 1000, false)) {
|
||||
ConfigurationChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void RegisterMod() {
|
||||
|
|
18
soh/soh/Enhancements/Holiday/Fredomato.h
Normal file
18
soh/soh/Enhancements/Holiday/Fredomato.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
#ifndef FRED_H
|
||||
#define FRED_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern int FredsQuestWoodCollected;
|
||||
extern int FredsQuestWoodOnHand;
|
||||
|
||||
extern "C" {
|
||||
#include "z64actor.h"
|
||||
#endif
|
||||
|
||||
bool HandleTreeBonk(Actor* actor);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -102,13 +102,33 @@ void Penguin_Destroy(Actor* actor, PlayState* play) {
|
|||
|
||||
static void OnConfigurationChanged() {
|
||||
COND_HOOK(OnPlayerUpdate, CVarGetInteger(CVAR("Hailstorm"), 0), []() {
|
||||
// Every frame has a 1/300 chance of spawning hail
|
||||
if (rand() % 300 == 0) {
|
||||
// Every frame has a 1/500 chance of spawning close hail
|
||||
if (rand() % 500 == 0) {
|
||||
int spawned = 0;
|
||||
while (spawned < 1) {
|
||||
Vec3f pos = GET_PLAYER(gPlayState)->actor.world.pos;
|
||||
pos.x += (float)Random(0, 100) - 50.0f;
|
||||
pos.z += (float)Random(0, 100) - 50.0f;
|
||||
pos.x += (float)Random(0, 50) - 25.0f;
|
||||
pos.z += (float)Random(0, 50) - 25.0f;
|
||||
pos.y += 200.0f;
|
||||
|
||||
Actor* actor = Actor_Spawn(&gPlayState->actorCtx, gPlayState, ACTOR_EN_NUTSBALL, pos.x, pos.y, pos.z, 0, 0, 0, 0, false);
|
||||
EnNutsball* nut = (EnNutsball*)actor;
|
||||
nut->actor.draw = EnNutsball_Draw;
|
||||
nut->actor.shape.rot.y = 0;
|
||||
nut->timer = 0;
|
||||
nut->actionFunc = func_80ABBBA8;
|
||||
nut->actor.speedXZ = 0.0f;
|
||||
nut->actor.gravity = -2.0f;
|
||||
spawned++;
|
||||
}
|
||||
}
|
||||
// Every frame has a 1/50 chance of spawning far hail
|
||||
if (rand() % 50 == 0) {
|
||||
int spawned = 0;
|
||||
while (spawned < 1) {
|
||||
Vec3f pos = GET_PLAYER(gPlayState)->actor.world.pos;
|
||||
pos.x += (float)Random(0, 500) - 250.0f;
|
||||
pos.z += (float)Random(0, 500) - 250.0f;
|
||||
pos.y += 200.0f;
|
||||
|
||||
Actor* actor = Actor_Spawn(&gPlayState->actorCtx, gPlayState, ACTOR_EN_NUTSBALL, pos.x, pos.y, pos.z, 0, 0, 0, 0, false);
|
||||
|
@ -191,9 +211,11 @@ static void DrawMenu() {
|
|||
if (UIWidgets::EnhancementCheckbox("Penguins", CVAR("Penguins"))) {
|
||||
OnConfigurationChanged();
|
||||
}
|
||||
UIWidgets::Tooltip("Penguins will spawn in huddles throughout hyrule");
|
||||
if (UIWidgets::EnhancementCheckbox("Hailstorm", CVAR("Hailstorm"))) {
|
||||
OnConfigurationChanged();
|
||||
}
|
||||
UIWidgets::Tooltip("Ever persistent hailstorm throughout hyrule");
|
||||
}
|
||||
|
||||
static void RegisterMod() {
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
#include "soh/Enhancements/game-interactor/GameInteractor.h"
|
||||
#include "soh/Enhancements/cosmetics/CosmeticsEditor.h"
|
||||
|
||||
void OnConfigChanged();
|
||||
|
||||
inline std::vector<std::function<void()>> holidayDrawFuncs = {};
|
||||
inline std::vector<std::function<void()>> holidayRegisterFuncs = {};
|
||||
|
||||
|
|
|
@ -1,150 +0,0 @@
|
|||
#include "Holiday.hpp"
|
||||
#include "soh_assets.h"
|
||||
#include "soh/Enhancements/randomizer/3drando/random.hpp"
|
||||
#include "soh/frame_interpolation.h"
|
||||
#include "soh/Notification/Notification.h"
|
||||
#include "objects/gameplay_field_keep/gameplay_field_keep.h"
|
||||
#include "soh/Enhancements/custom-message/CustomMessageManager.h"
|
||||
#include "soh/util.h"
|
||||
#include "soh/Enhancements/randomizer/randomizer.h"
|
||||
|
||||
extern "C" {
|
||||
#include "macros.h"
|
||||
#include "functions.h"
|
||||
#include "variables.h"
|
||||
extern PlayState* gPlayState;
|
||||
}
|
||||
extern GetItemEntry vanillaQueuedItemEntry;
|
||||
|
||||
#define AUTHOR "ItsHeckinPat"
|
||||
#define CVAR(v) "gHoliday." AUTHOR "." v
|
||||
|
||||
bool spawningPresents = false;
|
||||
|
||||
int collectedPresent = 0;
|
||||
|
||||
struct Present {
|
||||
};
|
||||
|
||||
std::unordered_map<Actor*, Present> presents;
|
||||
|
||||
void Present_Init(Actor* actor, PlayState* play) {
|
||||
Present present;
|
||||
presents[actor] = present;
|
||||
|
||||
actor->gravity = -1;
|
||||
Actor_MoveXZGravity(actor);
|
||||
actor->shape.rot.y = Random(0, 0xFFFF);
|
||||
|
||||
Actor_UpdateBgCheckInfo(play, actor, 10.0f, 10.0f, 0.0f, 0xFF);
|
||||
}
|
||||
|
||||
void Present_Update(Actor* actor, PlayState* play) {
|
||||
Present* present = &presents[actor];
|
||||
|
||||
if (actor->xzDistToPlayer < 50.0f && actor->yDistToPlayer < 50.0f) {
|
||||
collectedPresent++;
|
||||
Notification::Emit({
|
||||
.itemIcon = "RG_TRIFORCE_PIECE",
|
||||
.message = "You collected a present!",
|
||||
.messageColor = ImVec4(1.0f, 1.0f, 1.0f, 1.0f),
|
||||
});
|
||||
Actor_Kill(actor);
|
||||
}
|
||||
}
|
||||
|
||||
void Present_Draw(Actor* actor, PlayState* play) {
|
||||
OPEN_DISPS(play->state.gfxCtx);
|
||||
|
||||
Gfx_SetupDL_25Opa(play->state.gfxCtx);
|
||||
|
||||
Matrix_Scale(30.0f, 30.0f, 30.0f, MTXMODE_APPLY);
|
||||
Matrix_Translate(49.20f, 0.0f, -106.60f, MTXMODE_APPLY);
|
||||
gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(play->state.gfxCtx, (char*)__FILE__, __LINE__), G_MTX_MODELVIEW | G_MTX_LOAD);
|
||||
gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 255, 255);
|
||||
gSPDisplayList(POLY_OPA_DISP++, (Gfx*)gXmasDecor100DL);
|
||||
|
||||
CLOSE_DISPS(play->state.gfxCtx);
|
||||
}
|
||||
|
||||
void Present_Destroy(Actor* actor, PlayState* play) {
|
||||
presents.erase(actor);
|
||||
}
|
||||
|
||||
static CollisionPoly presentPoly;
|
||||
static f32 raycastResult;
|
||||
|
||||
void OnConfigChanged() {
|
||||
COND_HOOK(OnSceneSpawnActors, CVarGetInteger(CVAR("GiftsForNPCs"), 0), []() {
|
||||
presents.clear();
|
||||
Vec3f pos;
|
||||
pos.y = 9999.0f;
|
||||
int spawnAttempts = 0;
|
||||
while (spawnAttempts < 50) {
|
||||
if (GET_PLAYER(gPlayState) != nullptr) {
|
||||
pos.x = GET_PLAYER(gPlayState)->actor.world.pos.x;
|
||||
pos.z = GET_PLAYER(gPlayState)->actor.world.pos.z;
|
||||
} else {
|
||||
pos.x = 0;
|
||||
pos.z = 0;
|
||||
}
|
||||
// X/Z anywhere from -1000.0 to +1000.0 from player
|
||||
pos.x += (float)(Random(0, 2000)) - 1000.0f;
|
||||
pos.z += (float)(Random(0, 2000)) - 1000.0f;
|
||||
|
||||
raycastResult = BgCheck_AnyRaycastFloor1(&gPlayState->colCtx, &presentPoly, &pos);
|
||||
|
||||
if (raycastResult > BGCHECK_Y_MIN) {
|
||||
spawningPresents = true;
|
||||
Actor* actor = Actor_Spawn(&gPlayState->actorCtx, gPlayState, ACTOR_EN_OE2, pos.x, raycastResult, pos.z, 0, 0, 0, 0, false);
|
||||
spawningPresents = false;
|
||||
// break;
|
||||
}
|
||||
|
||||
spawnAttempts++;
|
||||
}
|
||||
});
|
||||
|
||||
COND_ID_HOOK(ShouldActorInit, ACTOR_EN_OE2, CVarGetInteger(CVAR("GiftsForNPCs"), 0), [](void* actorRef, bool* should) {
|
||||
Actor* actor = (Actor*)actorRef;
|
||||
if (spawningPresents) {
|
||||
actor->init = Present_Init;
|
||||
actor->update = Present_Update;
|
||||
actor->draw = Present_Draw;
|
||||
actor->destroy = Present_Destroy;
|
||||
}
|
||||
});
|
||||
|
||||
COND_ID_HOOK(OnOpenText, 0x1019, CVarGetInteger(CVAR("GiftsForNPCs"), 0), [](u16 * textId, bool* loadFromMessageTable) {
|
||||
if (collectedPresent <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto messageEntry = CustomMessage("A present??? FOR ME???");
|
||||
messageEntry.Format();
|
||||
messageEntry.LoadIntoFont();
|
||||
*loadFromMessageTable = false;
|
||||
|
||||
vanillaQueuedItemEntry = Rando::StaticData::RetrieveItem(RG_PIECE_OF_HEART).GetGIEntry_Copy();
|
||||
|
||||
collectedPresent--;
|
||||
});
|
||||
}
|
||||
|
||||
static void DrawMenu() {
|
||||
ImGui::SeparatorText(AUTHOR);
|
||||
if (UIWidgets::EnhancementCheckbox("Gifts for NPCs", CVAR("GiftsForNPCs"))) {
|
||||
OnConfigChanged();
|
||||
}
|
||||
}
|
||||
|
||||
static void RegisterMod() {
|
||||
// #region Leave this alone unless you know what you are doing
|
||||
OnConfigChanged();
|
||||
// #endregion
|
||||
|
||||
// TODO: Anything you want to run once on startup
|
||||
}
|
||||
|
||||
// TODO: Uncomment this line to enable the mod
|
||||
static Holiday holiday(DrawMenu, RegisterMod);
|
|
@ -135,6 +135,7 @@ static void DrawMenu() {
|
|||
if (UIWidgets::EnhancementCheckbox("Ganon Dating Sim", CVAR("GanonDatingSim"))) {
|
||||
ConfigurationChanged();
|
||||
}
|
||||
UIWidgets::Tooltip("Prior to fighting him at the top of his Castle, you make an attempt to convince Ganon to join you instead.");
|
||||
}
|
||||
|
||||
static void RegisterMod() {
|
||||
|
|
|
@ -181,8 +181,10 @@ void ShinyDrawImGui() {
|
|||
UIWidgets::PaddedEnhancementCheckbox("Enable Shiny Enemies", CVAR("Shiny.Enabled"), true, false);
|
||||
UIWidgets::Tooltip("Allows enemies to be shiny.\nShiny enemies are 25% bigger and have 4 times the health but drop the equivalent of a gold rupee upon death");
|
||||
|
||||
UIWidgets::PaddedEnhancementSliderInt("Shiny Chance: %d", "##ShinyChance", CVAR("Shiny.Chance"), 1, 8192, "", 8192, true, true, false, false, "");
|
||||
UIWidgets::Tooltip("The chance for an enemy to be shiny is 1 / Shiny Chance");
|
||||
if (CVarGetInteger(CVAR("Shiny.Enabled"), 0)) {
|
||||
UIWidgets::PaddedEnhancementSliderInt("Shiny Chance: %d", "##ShinyChance", CVAR("Shiny.Chance"), 1, 8192, "", 8192, true, true, false, false, "");
|
||||
UIWidgets::Tooltip("The chance for an enemy to be shiny is 1 / Shiny Chance");
|
||||
}
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
|
|
@ -125,7 +125,7 @@ const s16 entrances[] = {
|
|||
0x00B7, 0x0201, 0x003B, 0x0463, 0x0588, 0x057C, 0x0578, 0x0340, 0x04C2, 0x03E8, 0x04BE, 0x0482, 0x0315, 0x045B, 0x0371, 0x0394,
|
||||
0x0272, 0x0211, 0x0053, 0x0472, 0x0453, 0x0351, 0x0384, 0x044B, 0x03EC, 0x04FF, 0x0700, 0x0800, 0x0701, 0x0801, 0x0702, 0x0802,
|
||||
0x0703, 0x0803, 0x0704, 0x0804, 0x0705, 0x0805, 0x0706, 0x0806, 0x0707, 0x0807, 0x0708, 0x0808, 0x0709, 0x0809, 0x070A, 0x080A,
|
||||
0x070B, 0x080B, 0x070C, 0x080C, 0x070D, 0x080D, 0x070E, 0x080E, 0x070F, 0x080F, 0x0710, 0x0711, 0x0811, 0x0712, 0x0812,
|
||||
0x070B, 0x080B, 0x080C, 0x070D, 0x080D, 0x070E, 0x080E, 0x070F, 0x080F, 0x0710, 0x0711, 0x0811, 0x0712, 0x0812,
|
||||
0x0713, 0x0813, 0x0714, 0x0814, 0x0715, 0x0815, 0x0716, 0x0816, 0x0717, 0x0817, 0x0718, 0x0818, 0x0719, 0x0819, 0x081A,
|
||||
0x071B, 0x081B, 0x071C, 0x081C, 0x071D, 0x081D, 0x071E, 0x081E, 0x071F, 0x081F, 0x0720, 0x0820, 0x004B, 0x035D, 0x031C, 0x0361,
|
||||
0x002D, 0x050B, 0x044F, 0x0359, 0x05E0, 0x020D, 0x011E, 0x0286, 0x04E2, 0x04D6, 0x01DD, 0x04DA, 0x00FC, 0x01A9, 0x0185, 0x04DE,
|
||||
|
@ -158,6 +158,14 @@ static void RandomGrotto_WaitOpen(DoorAna* doorAna, PlayState* play) {
|
|||
}
|
||||
|
||||
static void SpawnRandomGrotto() {
|
||||
if (
|
||||
gPlayState->sceneNum == SCENE_TEMPLE_OF_TIME_EXTERIOR_DAY ||
|
||||
gPlayState->sceneNum == SCENE_TEMPLE_OF_TIME_EXTERIOR_NIGHT ||
|
||||
gPlayState->sceneNum == SCENE_TEMPLE_OF_TIME_EXTERIOR_RUINS
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
Vec3f pos;
|
||||
pos.y = 9999.0f;
|
||||
int spawnAttempts = 0;
|
||||
|
@ -170,8 +178,8 @@ static void SpawnRandomGrotto() {
|
|||
pos.z = 0;
|
||||
}
|
||||
// X/Z anywhere from -1000.0 to +1000.0 from player
|
||||
pos.x += (float)(Random(0, 2000)) - 1000.0f;
|
||||
pos.z += (float)(Random(0, 2000)) - 1000.0f;
|
||||
pos.x += (float)(Random(0, 5000)) - 2500.0f;
|
||||
pos.z += (float)(Random(0, 5000)) - 2500.0f;
|
||||
|
||||
raycastResult = BgCheck_AnyRaycastFloor1(&gPlayState->colCtx, &snowballPoly, &pos);
|
||||
|
||||
|
@ -211,12 +219,15 @@ static void DrawMenu() {
|
|||
if (UIWidgets::EnhancementCheckbox("Snowballs", CVAR("Snowballs"))) {
|
||||
ConfigurationChanged();
|
||||
}
|
||||
UIWidgets::Tooltip("Rogue snowballs will spawn in Hyrule Field and Kakariko Village.");
|
||||
if (UIWidgets::EnhancementCheckbox("Lake Hylia Icebergs", CVAR("Icebergs"))) {
|
||||
ConfigurationChanged();
|
||||
}
|
||||
UIWidgets::Tooltip("Icebergs will spawn in Lake Hylia.");
|
||||
if (UIWidgets::EnhancementCheckbox("Down the Rabbit Hole", CVAR("DownTheRabbitHole"))) {
|
||||
ConfigurationChanged();
|
||||
}
|
||||
UIWidgets::Tooltip("Random grottos will spawn throughout Hyrule. Who knows where they will take you?");
|
||||
if (UIWidgets::EnhancementCheckbox("Super Bonk", CVAR("SuperBonk"))) {
|
||||
ConfigurationChanged();
|
||||
}
|
||||
|
|
|
@ -123,6 +123,7 @@ static void DrawMenu() {
|
|||
if (UIWidgets::EnhancementCheckbox("Bomb Arrows", CVAR("BombArrows.Enabled"))) {
|
||||
OnConfigurationChanged();
|
||||
}
|
||||
UIWidgets::Tooltip("Equip bombs over an already equipped Bow to shoot bomb arrows");
|
||||
}
|
||||
|
||||
static void RegisterMod() {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "TimeDisplay.h"
|
||||
#include "soh/Enhancements/gameplaystats.h"
|
||||
#include "soh/Enhancements/Holiday/Fredomato.h"
|
||||
#include <global.h>
|
||||
|
||||
#include "assets/textures/parameter_static/parameter_static.h"
|
||||
|
@ -40,7 +41,8 @@ const std::vector<TimeObject> timeDisplayList = {
|
|||
{ DISPLAY_IN_GAME_TIMER, "Display Gameplay Timer", CVAR_ENHANCEMENT("TimeDisplay.Timers.InGameTimer") },
|
||||
{ DISPLAY_TIME_OF_DAY, "Display Time of Day", CVAR_ENHANCEMENT("TimeDisplay.Timers.TimeofDay") },
|
||||
{ DISPLAY_CONDITIONAL_TIMER, "Display Conditional Timer", CVAR_ENHANCEMENT("TimeDisplay.Timers.HotWater") },
|
||||
{ DISPLAY_NAVI_TIMER, "Display Navi Timer", CVAR_ENHANCEMENT("TimeDisplay.Timers.NaviTimer") }
|
||||
{ DISPLAY_NAVI_TIMER, "Display Navi Timer", CVAR_ENHANCEMENT("TimeDisplay.Timers.NaviTimer") },
|
||||
{ DISPLAY_FRED_QUEST, "Display Fred's Quest", CVAR_ENHANCEMENT("TimeDisplay.Timers.FredsQuest") }
|
||||
};
|
||||
|
||||
static std::vector<TimeObject> activeTimers;
|
||||
|
@ -134,6 +136,10 @@ static void TimeDisplayGetTimer(uint32_t timeID) {
|
|||
}
|
||||
textureDisplay = Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName("NAVI_TIMER");
|
||||
break;
|
||||
case DISPLAY_FRED_QUEST:
|
||||
timeDisplayTime = std::to_string(FredsQuestWoodOnHand) + "/" + std::to_string(FredsQuestWoodCollected) + "/" +
|
||||
std::to_string(CVarGetInteger("gHoliday.Fredomato.FredsQuest.WoodNeeded", 300));
|
||||
textureDisplay = Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName("ITEM_STICK");
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -189,6 +195,12 @@ void TimeDisplayWindow::Draw() {
|
|||
ImGui::Image(textureDisplay, ImVec2(16.0f * fontScale, 16.0f * fontScale));
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
if (timers.timeID == DISPLAY_FRED_QUEST) {
|
||||
ImGui::Text("%s", timeDisplayTime.c_str());
|
||||
ImGui::PopID();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (timeDisplayTime != "-:--") {
|
||||
char* textToDecode = new char[timeDisplayTime.size() + 1];
|
||||
textToDecode = std::strcpy(textToDecode, timeDisplayTime.c_str());
|
||||
|
|
|
@ -17,7 +17,8 @@ typedef enum {
|
|||
DISPLAY_IN_GAME_TIMER,
|
||||
DISPLAY_TIME_OF_DAY,
|
||||
DISPLAY_CONDITIONAL_TIMER,
|
||||
DISPLAY_NAVI_TIMER
|
||||
DISPLAY_NAVI_TIMER,
|
||||
DISPLAY_FRED_QUEST,
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
|
|
|
@ -371,6 +371,7 @@ typedef enum {
|
|||
// Vanilla condition: !Flags_GetInfTable(INFTABLE_145)
|
||||
// Opt: *EnRu1
|
||||
VB_RUTO_BE_CONSIDERED_NOT_KIDNAPPED,
|
||||
VB_PLAYER_ROLL,
|
||||
|
||||
|
||||
/*** Give Items ***/
|
||||
|
|
|
@ -31,6 +31,7 @@ DEFINE_HOOK(OnEnemyDefeat, (void* actor));
|
|||
DEFINE_HOOK(OnBossDefeat, (void* actor));
|
||||
DEFINE_HOOK(OnTimestamp, (u8 item));
|
||||
DEFINE_HOOK(OnPlayerBonk, ());
|
||||
DEFINE_HOOK(OnPlayerRoll, ());
|
||||
DEFINE_HOOK(OnPlayerHealthChange, (int16_t amount));
|
||||
DEFINE_HOOK(OnPlayerBottleUpdate, (int16_t contents));
|
||||
DEFINE_HOOK(OnPlayDestroy, ());
|
||||
|
|
|
@ -139,6 +139,10 @@ void GameInteractor_ExecuteOnPlayerBonk() {
|
|||
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnPlayerBonk>();
|
||||
}
|
||||
|
||||
void GameInteractor_ExecuteOnPlayerRoll() {
|
||||
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnPlayerRoll>();
|
||||
}
|
||||
|
||||
void GameInteractor_ExecuteOnPlayerHealthChange(int16_t amount) {
|
||||
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnPlayerHealthChange>(amount);
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ void GameInteractor_ExecuteOnEnemyDefeat(void* actor);
|
|||
void GameInteractor_ExecuteOnBossDefeat(void* actor);
|
||||
void GameInteractor_ExecuteOnTimestamp (u8 item);
|
||||
void GameInteractor_ExecuteOnPlayerBonk();
|
||||
void GameInteractor_ExecuteOnPlayerRoll();
|
||||
void GameInteractor_ExecuteOnPlayerHealthChange(int16_t amount);
|
||||
void GameInteractor_ExecuteOnPlayerBottleUpdate(int16_t contents);
|
||||
void GameInteractor_ExecuteOnOcarinaSongAction();
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#include "soh/Enhancements/game-interactor/GameInteractor.h"
|
||||
#include "soh/OTRGlobals.h"
|
||||
|
||||
static bool isResultOfHandling = false;
|
||||
|
||||
/**
|
||||
* SET_CHECK_STATUS
|
||||
*
|
||||
|
@ -13,7 +15,7 @@
|
|||
*/
|
||||
|
||||
void Anchor::SendPacket_SetCheckStatus(RandomizerCheck rc) {
|
||||
if (!IsSaveLoaded()) {
|
||||
if (!IsSaveLoaded() || isResultOfHandling) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -42,12 +44,16 @@ void Anchor::HandlePacket_SetCheckStatus(nlohmann::json payload) {
|
|||
RandomizerCheckStatus status = payload["status"].get<RandomizerCheckStatus>();
|
||||
bool skipped = payload["skipped"].get<bool>();
|
||||
|
||||
isResultOfHandling = true;
|
||||
|
||||
if (randoContext->GetItemLocation(rc)->GetCheckStatus() != status) {
|
||||
randoContext->GetItemLocation(rc)->SetCheckStatus(status);
|
||||
}
|
||||
if (randoContext->GetItemLocation(rc)->GetIsSkipped() != skipped) {
|
||||
randoContext->GetItemLocation(rc)->SetIsSkipped(skipped);
|
||||
}
|
||||
|
||||
isResultOfHandling = false;
|
||||
}
|
||||
|
||||
#endif // ENABLE_REMOTE_CONTROL
|
||||
|
|
|
@ -151,7 +151,7 @@ void Anchor::HandlePacket_UpdateTeamState(nlohmann::json payload) {
|
|||
gSaveContext.infTable[i] = loadedData.infTable[i];
|
||||
}
|
||||
|
||||
for (int i = 0; i < 17; i++) {
|
||||
for (int i = 0; i < 52; i++) {
|
||||
gSaveContext.randomizerInf[i] = loadedData.randomizerInf[i];
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ void Window::Draw() {
|
|||
const float margin = 30.0f;
|
||||
const float padding = 10.0f;
|
||||
|
||||
int position = CVarGetInteger(CVAR_SETTING("Notifications.Position"), 0);
|
||||
int position = CVarGetInteger(CVAR_SETTING("Notifications.Position"), 3);
|
||||
|
||||
// Top Left
|
||||
ImVec2 basePosition;
|
||||
|
|
|
@ -586,7 +586,7 @@ void DrawSettingsMenu() {
|
|||
};
|
||||
|
||||
ImGui::Text("Position");
|
||||
UIWidgets::EnhancementCombobox(CVAR_SETTING("Notifications.Position"), notificationPosition, 0);
|
||||
UIWidgets::EnhancementCombobox(CVAR_SETTING("Notifications.Position"), notificationPosition, 3);
|
||||
UIWidgets::EnhancementSliderFloat("Duration: %.1f seconds", "##NotificationDuration", CVAR_SETTING("Notifications.Duration"), 3.0f, 30.0f, "", 10.0f, false, true, false);
|
||||
UIWidgets::EnhancementSliderFloat("BG Opacity: %.1f %%", "##NotificaitonBgOpacity", CVAR_SETTING("Notifications.BgOpacity"), 0.0f, 1.0f, "", 0.5f, true, true, false);
|
||||
UIWidgets::EnhancementSliderFloat("Size: %.1f", "##NotificaitonSize", CVAR_SETTING("Notifications.Size"), 1.0f, 20.0f, "", 1.8f, false, true, false);
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor.h"
|
||||
#include "soh/Enhancements/randomizer/draw.h"
|
||||
#include "soh/Enhancements/Holiday/Fredomato.h"
|
||||
#include "soh/ResourceManagerHelpers.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
|
|
@ -543,7 +543,9 @@ u16 func_80A6F810(PlayState* play, Actor* thisx) {
|
|||
return 0x5058;
|
||||
}
|
||||
case ENHY_TYPE_BOB_18:
|
||||
if (!LINK_IS_ADULT) {
|
||||
if (CVarGetInteger("gHoliday.Fredomato.TreeChopper", 0)) {
|
||||
return 0x505e;
|
||||
} else if (!LINK_IS_ADULT) {
|
||||
return (Flags_GetEventChkInf(EVENTCHKINF_ZELDA_FLED_HYRULE_CASTLE)) ? 0x505F : ((Flags_GetInfTable(INFTABLE_163)) ? 0x505E : 0x505D);
|
||||
} else {
|
||||
return (this->unk_330 & 0x800) ? 0x5062 : ((Flags_GetInfTable(INFTABLE_164)) ? 0x5061 : 0x5060);
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "z_en_wood02.h"
|
||||
#include "objects/object_wood02/object_wood02.h"
|
||||
#include "soh/Enhancements/Holiday/Fredomato.h"
|
||||
|
||||
#define FLAGS 0
|
||||
|
||||
|
@ -368,7 +369,9 @@ void EnWood02_Update(Actor* thisx, PlayState* play2) {
|
|||
dropsSpawnPt = this->actor.world.pos;
|
||||
dropsSpawnPt.y += 200.0f;
|
||||
|
||||
if ((this->unk_14C >= 0) && (this->unk_14C < 0x64) && (CVarGetInteger(CVAR_ENHANCEMENT("TreesDropSticks"), 0)) && !(INV_CONTENT(ITEM_STICK) == ITEM_NONE)) {
|
||||
if (HandleTreeBonk(&this->actor)) {
|
||||
// no-op
|
||||
} else if ((this->unk_14C >= 0) && (this->unk_14C < 0x64) && (CVarGetInteger(CVAR_ENHANCEMENT("TreesDropSticks"), 0)) && !(INV_CONTENT(ITEM_STICK) == ITEM_NONE)) {
|
||||
(numDrops = (Rand_ZeroOne() * 4));
|
||||
for (i = 0; i < numDrops; ++i) {
|
||||
Item_DropCollectible(play, &dropsSpawnPt, ITEM00_STICK);
|
||||
|
|
|
@ -6265,11 +6265,16 @@ s32 func_8083BBA0(Player* this, PlayState* play) {
|
|||
}
|
||||
|
||||
void Player_SetupRoll(Player* this, PlayState* play) {
|
||||
if (!GameInteractor_Should(VB_PLAYER_ROLL, true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player_SetupAction(play, this, Player_Action_Roll, 0);
|
||||
LinkAnimation_PlayOnceSetSpeed(play, &this->skelAnime,
|
||||
GET_PLAYER_ANIM(PLAYER_ANIMGROUP_landing_roll, this->modelAnimType),
|
||||
1.25f * sWaterSpeedFactor);
|
||||
gSaveContext.sohStats.count[COUNT_ROLLS]++;
|
||||
GameInteractor_ExecuteOnPlayerRoll();
|
||||
}
|
||||
|
||||
s32 Player_TryRoll(Player* this, PlayState* play) {
|
||||
|
@ -8554,6 +8559,16 @@ void Player_Action_808414F8(Player* this, PlayState* play) {
|
|||
}
|
||||
|
||||
Player_GetMovementSpeedAndYaw(this, &speedTarget, &yawTarget, SPEED_MODE_LINEAR, play);
|
||||
|
||||
int32_t giSpeedModifier = GameInteractor_RunSpeedModifier();
|
||||
if (giSpeedModifier != 0) {
|
||||
if (giSpeedModifier > 0) {
|
||||
speedTarget *= giSpeedModifier;
|
||||
} else {
|
||||
speedTarget /= abs(giSpeedModifier);
|
||||
}
|
||||
}
|
||||
|
||||
sp2C = func_8083FD78(this, &speedTarget, &yawTarget, play);
|
||||
|
||||
if (sp2C >= 0) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue