-
Notifications
You must be signed in to change notification settings - Fork 776
Added weighted extra ice trap selection and rework extra traps system #6682
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
00a2a85
83451d5
c052588
faf5157
297c4ae
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -29,11 +29,6 @@ typedef enum { | |
| ADD_TRAP_MAX | ||
| } AltTrapType; | ||
|
|
||
| static AltTrapType roll = ADD_TRAP_MAX; | ||
| static int statusTimer = -1; | ||
| static int eventTimer = -1; | ||
| static EntranceIndex teleportRoll = ENTR_MAX; | ||
|
|
||
| const char* altTrapTypeCvars[] = { | ||
| CVAR_ENHANCEMENT("ExtraTraps.Ice"), CVAR_ENHANCEMENT("ExtraTraps.Burn"), | ||
| CVAR_ENHANCEMENT("ExtraTraps.Shock"), CVAR_ENHANCEMENT("ExtraTraps.Knockback"), | ||
|
|
@@ -48,117 +43,154 @@ const std::array<EntranceIndex, 7> teleportDestinations = { | |
| ENTR_TEMPLE_OF_TIME_WARP_PAD, | ||
| }; | ||
|
|
||
| std::vector<AltTrapType> getEnabledAddTraps() { | ||
| std::vector<AltTrapType> enabledAddTraps; | ||
| typedef struct { | ||
| AltTrapType trap; | ||
| uint16_t ticks; | ||
| void (*execute)(Player*, uint32_t); | ||
| uint32_t state; | ||
| } EventTimer; | ||
|
|
||
| static std::vector<EventTimer> timers = std::vector<EventTimer>(); | ||
|
|
||
| static void queueTimer(AltTrapType trap, uint16_t ticks, void (*execute)(Player*, uint32_t), uint32_t state = 0) { | ||
|
|
||
| EventTimer m = { .trap = trap, .ticks = ticks, .execute = execute, .state = state }; | ||
| timers.push_back(m); | ||
| } | ||
|
|
||
| static AltTrapType selectWeightedTrap(uint64_t* state) { | ||
| float weights[ADD_TRAP_MAX] = { 0.0f }; | ||
| float totalWeight = 0.0f; | ||
|
|
||
| bool weighted = CVarGetInteger(CVAR_ENHANCEMENT("ExtraTraps.WeightedTraps"), 0); | ||
|
|
||
| for (int i = 0; i < ADD_TRAP_MAX; i++) { | ||
| if (CVarGetInteger(altTrapTypeCvars[i], 0)) { | ||
| if (gSaveContext.equips.buttonItems[0] == ITEM_FISHING_POLE && | ||
| (i == ADD_VOID_TRAP || i == ADD_TELEPORT_TRAP)) { | ||
| continue; // don't add void or teleport if you're holding the fishing pole, as this causes issues | ||
| } | ||
| enabledAddTraps.push_back(static_cast<AltTrapType>(i)); | ||
| float weight = weighted ? CVarGetInteger(altTrapTypeCvars[i], 0) : 1; | ||
| if (gSaveContext.equips.buttonItems[0] == ITEM_FISHING_POLE && (i == ADD_VOID_TRAP || i == ADD_TELEPORT_TRAP)) { | ||
| weight = 0; // don't add void or teleport if you're holding the fishing pole, as this causes issues | ||
| } | ||
|
|
||
| totalWeight += weight; | ||
| weights[i] = totalWeight; | ||
| SPDLOG_TRACE("TRAP trap:{0} weight:{1} position:{2}", altTrapTypeCvars[i], weight, totalWeight); | ||
| } | ||
| if (enabledAddTraps.size() == 0) { | ||
| enabledAddTraps.push_back(ADD_ICE_TRAP); | ||
|
|
||
| if (totalWeight == 0.0f) // No weights? Just return an invalid value. | ||
| return ADD_TRAP_MAX; | ||
|
|
||
| double target = ShipUtils::RandomDouble(state) * totalWeight; | ||
|
|
||
| for (int i = 0; i < ADD_TRAP_MAX; i++) { | ||
| if (weights[i] >= target) { | ||
| SPDLOG_TRACE("SELECTED {0} {1} {2}", target, i, altTrapTypeCvars[i]); | ||
| return (AltTrapType)i; | ||
| } | ||
| } | ||
| return enabledAddTraps; | ||
| }; | ||
|
|
||
| return ADD_TRAP_MAX; | ||
| } | ||
|
|
||
| static void RollRandomTrap(uint64_t seed) { | ||
| uint64_t finalSeed = seed + (IS_RANDO ? static_cast<uint64_t>(Rando::Context::GetInstance()->GetSeed()) | ||
| : gSaveContext.ship.stats.fileCreatedAt); | ||
| uint64_t state; | ||
| ShipUtils::RandInit(finalSeed, &state); | ||
| AltTrapType roll = selectWeightedTrap(&state); | ||
| if (roll == ADD_TRAP_MAX) // If it failed to pick a trap, fallback to a basic ice trap. | ||
| { | ||
| roll = ADD_ICE_TRAP; | ||
| } | ||
|
|
||
| roll = ShipUtils::RandomElement(getEnabledAddTraps(), &state); | ||
| switch (roll) { | ||
| case ADD_ICE_TRAP: | ||
| case ADD_ICE_TRAP: { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not a big deal, but why are we adding brackets here?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When I was originally writing this, the lambdas were in variables, and there were name collisions. I just never removed the braces. |
||
| GameInteractor::RawAction::FreezePlayer(); | ||
| break; | ||
| case ADD_BURN_TRAP: | ||
| } | ||
| case ADD_BURN_TRAP: { | ||
| GameInteractor::RawAction::BurnPlayer(); | ||
| break; | ||
| case ADD_SHOCK_TRAP: | ||
| } | ||
| case ADD_SHOCK_TRAP: { | ||
| GameInteractor::RawAction::ElectrocutePlayer(); | ||
| break; | ||
| case ADD_KNOCK_TRAP: | ||
| eventTimer = 3; | ||
| } | ||
| case ADD_KNOCK_TRAP: { | ||
| queueTimer(ADD_KNOCK_TRAP, 3, | ||
| [](Player* player, uint32_t state) { GameInteractor::RawAction::KnockbackPlayer(1); }); | ||
| break; | ||
| case ADD_SPEED_TRAP: | ||
| } | ||
| case ADD_SPEED_TRAP: { | ||
| Audio_PlaySoundGeneral(NA_SE_VO_KZ_MOVE, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, | ||
| &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); | ||
|
|
||
| for (int i = 0; i < timers.size(); i++) { | ||
| if (timers[i].trap == ADD_SPEED_TRAP) { | ||
| timers[i].ticks += 200; | ||
| return; | ||
| } | ||
| } | ||
| GameInteractor::State::MovementSpeedMultiplier = 0.5f; | ||
| statusTimer = 200; | ||
| Notification::Emit({ .message = "Speed Decreased!" }); | ||
| queueTimer(ADD_SPEED_TRAP, 200, [](Player* player, uint32_t state) { | ||
| GameInteractor::State::MovementSpeedMultiplier = 1.0f; | ||
| Notification::Emit({ .message = "Speed Restored!" }); | ||
| }); | ||
| break; | ||
| case ADD_BOMB_TRAP: | ||
| eventTimer = 3; | ||
| } | ||
| case ADD_BOMB_TRAP: { | ||
| queueTimer(ADD_BOMB_TRAP, 3, | ||
| [](Player* player, uint32_t state) { GameInteractor::RawAction::SpawnActor(ACTOR_EN_BOM, 1); }); | ||
| break; | ||
| case ADD_VOID_TRAP: | ||
| } | ||
| case ADD_VOID_TRAP: { | ||
| Audio_PlaySoundGeneral(NA_SE_EN_GANON_LAUGH, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, | ||
| &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); | ||
| eventTimer = 3; | ||
| queueTimer(ADD_VOID_TRAP, 3, [](Player* player, uint32_t state) { Play_TriggerRespawn(gPlayState); }); | ||
| break; | ||
| case ADD_AMMO_TRAP: | ||
| eventTimer = 3; | ||
| } | ||
| case ADD_AMMO_TRAP: { | ||
| Notification::Emit({ .message = "Ammo Halved!" }); | ||
| queueTimer(ADD_AMMO_TRAP, 3, [](Player* player, uint32_t state) { | ||
| AMMO(ITEM_STICK) = static_cast<int8_t>(floor(AMMO(ITEM_STICK) * 0.5f)); | ||
| AMMO(ITEM_NUT) = static_cast<int8_t>(floor(AMMO(ITEM_NUT) * 0.5f)); | ||
| AMMO(ITEM_SLINGSHOT) = static_cast<int8_t>(floor(AMMO(ITEM_SLINGSHOT) * 0.5f)); | ||
| AMMO(ITEM_BOW) = static_cast<int8_t>(floor(AMMO(ITEM_BOW) * 0.5f)); | ||
| AMMO(ITEM_BOMB) = static_cast<int8_t>(floor(AMMO(ITEM_BOMB) * 0.5f)); | ||
| AMMO(ITEM_BOMBCHU) = static_cast<int8_t>(floor(AMMO(ITEM_BOMBCHU) * 0.5f)); | ||
| Audio_PlaySoundGeneral(NA_SE_VO_FR_SMILE_0, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, | ||
| &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); | ||
| }); | ||
| break; | ||
| case ADD_KILL_TRAP: | ||
| } | ||
| case ADD_KILL_TRAP: { | ||
| GameInteractor::RawAction::SetPlayerHealth(0); | ||
| break; | ||
| case ADD_TELEPORT_TRAP: | ||
| eventTimer = 3; | ||
| teleportRoll = ShipUtils::RandomElement(teleportDestinations, &state); | ||
| } | ||
| case ADD_TELEPORT_TRAP: { | ||
| EntranceIndex teleportRoll = ShipUtils::RandomElement(teleportDestinations, &state); | ||
|
|
||
| queueTimer( | ||
| ADD_TELEPORT_TRAP, 3, | ||
| [](Player* player, uint32_t state) { GameInteractor::RawAction::TeleportPlayer(state); }, teleportRoll); | ||
| break; | ||
| } | ||
| default: | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| static void OnPlayerUpdate() { | ||
| Player* player = GET_PLAYER(gPlayState); | ||
| if (statusTimer == 0) { | ||
| GameInteractor::State::MovementSpeedMultiplier = 1.0f; | ||
| } | ||
| if (eventTimer == 0) { | ||
| switch (roll) { | ||
| case ADD_KNOCK_TRAP: | ||
| GameInteractor::RawAction::KnockbackPlayer(1); | ||
| break; | ||
| case ADD_BOMB_TRAP: | ||
| GameInteractor::RawAction::SpawnActor(ACTOR_EN_BOM, 1); | ||
| break; | ||
| case ADD_VOID_TRAP: | ||
| Play_TriggerRespawn(gPlayState); | ||
| break; | ||
| case ADD_AMMO_TRAP: | ||
| AMMO(ITEM_STICK) = static_cast<int8_t>(floor(AMMO(ITEM_STICK) * 0.5f)); | ||
| AMMO(ITEM_NUT) = static_cast<int8_t>(floor(AMMO(ITEM_NUT) * 0.5f)); | ||
| AMMO(ITEM_SLINGSHOT) = static_cast<int8_t>(floor(AMMO(ITEM_SLINGSHOT) * 0.5f)); | ||
| AMMO(ITEM_BOW) = static_cast<int8_t>(floor(AMMO(ITEM_BOW) * 0.5f)); | ||
| AMMO(ITEM_BOMB) = static_cast<int8_t>(floor(AMMO(ITEM_BOMB) * 0.5f)); | ||
| AMMO(ITEM_BOMBCHU) = static_cast<int8_t>(floor(AMMO(ITEM_BOMBCHU) * 0.5f)); | ||
| Audio_PlaySoundGeneral(NA_SE_VO_FR_SMILE_0, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, | ||
| &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); | ||
| break; | ||
| case ADD_TELEPORT_TRAP: { | ||
| GameInteractor::RawAction::TeleportPlayer(teleportRoll); | ||
| break; | ||
| } | ||
| default: | ||
| break; | ||
| for (int i = timers.size() - 1; i >= 0; i--) { | ||
| auto& n = timers[i]; | ||
| if (--n.ticks == 0) { | ||
| n.execute(player, n.state); | ||
| timers.erase(timers.begin() + i); | ||
| } | ||
| } | ||
| if (statusTimer >= 0) { | ||
| statusTimer--; | ||
| } | ||
| if (eventTimer >= 0) { | ||
| eventTimer--; | ||
| } | ||
| } | ||
|
|
||
| void RegisterExtraTraps() { | ||
| static void RegisterExtraTraps() { | ||
| COND_HOOK(OnPlayerUpdate, CVAR_EXTRA_TRAPS_VALUE, OnPlayerUpdate); | ||
|
|
||
| COND_VB_SHOULD(VB_SHORT_CIRCUIT_GIVE_ITEM_PROCESS, true, { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
might as well just return
ADD_ICE_TRAPinselectWeightedTrap