CrowdControl additions & improvements

This commit is contained in:
aMannus 2025-03-04 11:53:05 +01:00
commit d7fecf23c5
14 changed files with 92 additions and 387 deletions

View file

@ -84,7 +84,7 @@ static void RollRandomTrap(uint32_t seed) {
break; break;
case ADD_SPEED_TRAP: case ADD_SPEED_TRAP:
Audio_PlaySoundGeneral(NA_SE_VO_KZ_MOVE, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); Audio_PlaySoundGeneral(NA_SE_VO_KZ_MOVE, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
GameInteractor::State::RunSpeedModifier = -2; GameInteractor::State::MovementSpeedMultiplier = 0.5f;
statusTimer = 200; statusTimer = 200;
Notification::Emit({ .message = "Speed Decreased!" }); Notification::Emit({ .message = "Speed Decreased!" });
break; break;
@ -113,7 +113,7 @@ static void RollRandomTrap(uint32_t seed) {
static void OnPlayerUpdate() { static void OnPlayerUpdate() {
Player* player = GET_PLAYER(gPlayState); Player* player = GET_PLAYER(gPlayState);
if (statusTimer == 0) { if (statusTimer == 0) {
GameInteractor::State::RunSpeedModifier = 0; GameInteractor::State::MovementSpeedMultiplier = 1.0f;
} }
if (eventTimer == 0) { if (eventTimer == 0) {
switch (roll) { switch (roll) {

View file

@ -1089,7 +1089,7 @@ static bool SpeedModifierHandler(std::shared_ptr<Ship::Console> Console, const s
ERROR_MESSAGE("[SOH] Unexpected arguments passed"); ERROR_MESSAGE("[SOH] Unexpected arguments passed");
return 1; return 1;
} }
GameInteractionEffectBase* effect = new GameInteractionEffect::ModifyRunSpeedModifier(); GameInteractionEffectBase* effect = new GameInteractionEffect::ModifyMovementSpeedMultiplier();
try { try {
dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[0] = std::stoi(args[1], nullptr, 10); dynamic_cast<ParameterizedGameInteractionEffect*>(effect)->parameters[0] = std::stoi(args[1], nullptr, 10);

View file

@ -11,6 +11,7 @@ have functions to both enable and disable said effect.
#include "GameInteractionEffect.h" #include "GameInteractionEffect.h"
#include "GameInteractor.h" #include "GameInteractor.h"
#include <libultraship/bridge.h> #include <libultraship/bridge.h>
#include "soh/Enhancements/cosmetics/CosmeticsEditor.h"
extern "C" { extern "C" {
#include <z64.h> #include <z64.h>
@ -376,19 +377,23 @@ namespace GameInteractionEffect {
GameInteractor::RawAction::ForceEquipBoots(EQUIP_VALUE_BOOTS_KOKIRI); GameInteractor::RawAction::ForceEquipBoots(EQUIP_VALUE_BOOTS_KOKIRI);
} }
// MARK: - ModifyRunSpeedModifier // MARK: - ModifyMovementSpeedMultiplier
GameInteractionEffectQueryResult ModifyRunSpeedModifier::CanBeApplied() { GameInteractionEffectQueryResult ModifyMovementSpeedMultiplier::CanBeApplied() {
if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) { if (!GameInteractor::IsSaveLoaded() || GameInteractor::IsGameplayPaused()) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} else { } else {
return GameInteractionEffectQueryResult::Possible; return GameInteractionEffectQueryResult::Possible;
} }
} }
void ModifyRunSpeedModifier::_Apply() { void ModifyMovementSpeedMultiplier::_Apply() {
GameInteractor::State::RunSpeedModifier = parameters[0]; if (parameters[0] == -2) {
GameInteractor::State::MovementSpeedMultiplier = 0.5f;
} else if (parameters[0] == 2) {
GameInteractor::State::MovementSpeedMultiplier = 2.0f;
}
} }
void ModifyRunSpeedModifier::_Remove() { void ModifyMovementSpeedMultiplier::_Remove() {
GameInteractor::State::RunSpeedModifier = 0; GameInteractor::State::MovementSpeedMultiplier = 1.0f;
} }
// MARK: - OneHitKO // MARK: - OneHitKO
@ -489,18 +494,6 @@ namespace GameInteractionEffect {
GameInteractor::RawAction::SetCollisionViewer(false); GameInteractor::RawAction::SetCollisionViewer(false);
} }
// MARK: - SetCosmeticsColor
GameInteractionEffectQueryResult SetCosmeticsColor::CanBeApplied() {
if (!GameInteractor::IsSaveLoaded()) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} else {
return GameInteractionEffectQueryResult::Possible;
}
}
void SetCosmeticsColor::_Apply() {
GameInteractor::RawAction::SetCosmeticsColor(parameters[0], parameters[1]);
}
// MARK: - RandomizeCosmetics // MARK: - RandomizeCosmetics
GameInteractionEffectQueryResult RandomizeCosmetics::CanBeApplied() { GameInteractionEffectQueryResult RandomizeCosmetics::CanBeApplied() {
if (!GameInteractor::IsSaveLoaded()) { if (!GameInteractor::IsSaveLoaded()) {
@ -510,7 +503,7 @@ namespace GameInteractionEffect {
} }
} }
void RandomizeCosmetics::_Apply() { void RandomizeCosmetics::_Apply() {
GameInteractor::RawAction::RandomizeCosmeticsColors(true); CosmeticsEditor_RandomizeAll();
} }
// MARK: - PressButton // MARK: - PressButton

View file

@ -158,7 +158,7 @@ namespace GameInteractionEffect {
void _Remove() override; void _Remove() override;
}; };
class ModifyRunSpeedModifier: public RemovableGameInteractionEffect, public ParameterizedGameInteractionEffect { class ModifyMovementSpeedMultiplier: public RemovableGameInteractionEffect, public ParameterizedGameInteractionEffect {
GameInteractionEffectQueryResult CanBeApplied() override; GameInteractionEffectQueryResult CanBeApplied() override;
void _Apply() override; void _Apply() override;
void _Remove() override; void _Remove() override;
@ -202,11 +202,6 @@ namespace GameInteractionEffect {
void _Remove() override; void _Remove() override;
}; };
class SetCosmeticsColor: public GameInteractionEffectBase, public ParameterizedGameInteractionEffect {
GameInteractionEffectQueryResult CanBeApplied() override;
void _Apply() override;
};
class RandomizeCosmetics: public GameInteractionEffectBase { class RandomizeCosmetics: public GameInteractionEffectBase {
GameInteractionEffectQueryResult CanBeApplied() override; GameInteractionEffectQueryResult CanBeApplied() override;
void _Apply() override; void _Apply() override;

View file

@ -76,7 +76,7 @@ uint8_t GameInteractor_PacifistModeActive();
uint8_t GameInteractor_DisableZTargetingActive(); uint8_t GameInteractor_DisableZTargetingActive();
uint8_t GameInteractor_ReverseControlsActive(); uint8_t GameInteractor_ReverseControlsActive();
int32_t GameInteractor_DefenseModifier(); int32_t GameInteractor_DefenseModifier();
int32_t GameInteractor_RunSpeedModifier(); float GameInteractor_MovementSpeedMultiplier();
GIGravityLevel GameInteractor_GravityLevel(); GIGravityLevel GameInteractor_GravityLevel();
uint32_t GameInteractor_GetEmulatedButtons(); uint32_t GameInteractor_GetEmulatedButtons();
void GameInteractor_SetEmulatedButtons(uint32_t buttons); void GameInteractor_SetEmulatedButtons(uint32_t buttons);
@ -196,7 +196,7 @@ public:
static bool DisableZTargetingActive; static bool DisableZTargetingActive;
static bool ReverseControlsActive; static bool ReverseControlsActive;
static int32_t DefenseModifier; static int32_t DefenseModifier;
static int32_t RunSpeedModifier; static float MovementSpeedMultiplier;
static GIGravityLevel GravityLevel; static GIGravityLevel GravityLevel;
static uint32_t EmulatedButtons; static uint32_t EmulatedButtons;
static uint8_t RandomBombFuseTimerActive; static uint8_t RandomBombFuseTimerActive;
@ -454,8 +454,6 @@ public:
static void ClearAssignedButtons(uint8_t buttonSet); static void ClearAssignedButtons(uint8_t buttonSet);
static void SetTimeOfDay(uint32_t time); static void SetTimeOfDay(uint32_t time);
static void SetCollisionViewer(bool active); static void SetCollisionViewer(bool active);
static void SetCosmeticsColor(uint8_t cosmeticCategory, uint8_t colorValue);
static void RandomizeCosmeticsColors(bool excludeBiddingWarColors);
static void EmulateButtonPress(int32_t button); static void EmulateButtonPress(int32_t button);
static void AddOrTakeAmmo(int16_t amount, int16_t item); static void AddOrTakeAmmo(int16_t amount, int16_t item);
static void EmulateRandomButtonPress(uint32_t chancePercentage = 100); static void EmulateRandomButtonPress(uint32_t chancePercentage = 100);
@ -463,8 +461,10 @@ public:
static void SetPlayerInvincibility(bool active); static void SetPlayerInvincibility(bool active);
static void ClearCutscenePointer(); static void ClearCutscenePointer();
static GameInteractionEffectQueryResult SpawnEnemyWithOffset(uint32_t enemyId, int32_t enemyParams); static GameInteractionEffectQueryResult SpawnEnemyWithOffset(uint32_t enemyId, int32_t enemyParams,
static GameInteractionEffectQueryResult SpawnActor(uint32_t actorId, int32_t actorParams); std::string nameTag = "");
static GameInteractionEffectQueryResult SpawnActor(uint32_t actorId, int32_t actorParams,
std::string nameTag = "");
}; };
}; };

View file

@ -1,9 +1,9 @@
#include "GameInteractor.h" #include "GameInteractor.h"
#include <libultraship/bridge.h> #include <libultraship/bridge.h>
#include "soh/Enhancements/cosmetics/CosmeticsEditor.h"
#include "soh/Enhancements/randomizer/3drando/random.hpp" #include "soh/Enhancements/randomizer/3drando/random.hpp"
#include <math.h> #include <math.h>
#include "soh/Enhancements/debugger/colViewer.h" #include "soh/Enhancements/debugger/colViewer.h"
#include "soh/Enhancements/nametag.h"
extern "C" { extern "C" {
#include "variables.h" #include "variables.h"
@ -397,131 +397,6 @@ void GameInteractor::RawAction::SetCollisionViewer(bool active) {
} }
} }
void GameInteractor::RawAction::SetCosmeticsColor(uint8_t cosmeticCategory, uint8_t colorValue) {
Color_RGBA8 newColor;
newColor.r = 255;
newColor.g = 255;
newColor.b = 255;
newColor.a = 255;
switch (colorValue) {
case GI_COLOR_RED:
newColor.r = 200;
newColor.g = 30;
newColor.b = 30;
break;
case GI_COLOR_GREEN:
newColor.r = 50;
newColor.g = 200;
newColor.b = 50;
break;
case GI_COLOR_BLUE:
newColor.r = 50;
newColor.g = 50;
newColor.b = 200;
break;
case GI_COLOR_ORANGE:
newColor.r = 200;
newColor.g = 120;
newColor.b = 0;
break;
case GI_COLOR_YELLOW:
newColor.r = 234;
newColor.g = 240;
newColor.b = 33;
break;
case GI_COLOR_PURPLE:
newColor.r = 144;
newColor.g = 13;
newColor.b = 178;
break;
case GI_COLOR_PINK:
newColor.r = 215;
newColor.g = 93;
newColor.b = 246;
break;
case GI_COLOR_BROWN:
newColor.r = 108;
newColor.g = 72;
newColor.b = 15;
break;
case GI_COLOR_BLACK:
newColor.r = 0;
newColor.g = 0;
newColor.b = 0;
break;
default:
break;
}
switch (cosmeticCategory) {
case GI_COSMETICS_TUNICS:
CVarSetColor(CVAR_COSMETIC("Link.KokiriTunic.Value"), newColor);
CVarSetInteger(CVAR_COSMETIC("Link.KokiriTunic.Changed"), 1);
CVarSetColor(CVAR_COSMETIC("Link.GoronTunic.Value"), newColor);
CVarSetInteger(CVAR_COSMETIC("Link.GoronTunic.Changed"), 1);
CVarSetColor(CVAR_COSMETIC("Link.ZoraTunic.Value"), newColor);
CVarSetInteger(CVAR_COSMETIC("Link.ZoraTunic.Changed"), 1);
break;
case GI_COSMETICS_NAVI:
CVarSetColor(CVAR_COSMETIC("Navi.EnemyPrimary.Value"), newColor);
CVarSetInteger(CVAR_COSMETIC("Navi.EnemyPrimary.Changed"), 1);
CVarSetColor(CVAR_COSMETIC("Navi.EnemySecondary.Value"), newColor);
CVarSetInteger(CVAR_COSMETIC("Navi.EnemySecondary.Changed"), 1);
CVarSetColor(CVAR_COSMETIC("Navi.IdlePrimary.Value"), newColor);
CVarSetInteger(CVAR_COSMETIC("Navi.IdlePrimary.Changed"), 1);
CVarSetColor(CVAR_COSMETIC("Navi.IdleSecondary.Value"), newColor);
CVarSetInteger(CVAR_COSMETIC("Navi.IdleSecondary.Changed"), 1);
CVarSetColor(CVAR_COSMETIC("Navi.NPCPrimary.Value"), newColor);
CVarSetInteger(CVAR_COSMETIC("Navi.NPCPrimary.Changed"), 1);
CVarSetColor(CVAR_COSMETIC("Navi.NPCSecondary.Value"), newColor);
CVarSetInteger(CVAR_COSMETIC("Navi.NPCSecondary.Changed"), 1);
CVarSetColor(CVAR_COSMETIC("Navi.PropsPrimary.Value"), newColor);
CVarSetInteger(CVAR_COSMETIC("Navi.PropsPrimary.Changed"), 1);
CVarSetColor(CVAR_COSMETIC("Navi.PropsSecondary.Value"), newColor);
CVarSetInteger(CVAR_COSMETIC("Navi.PropsSecondary.Changed"), 1);
break;
case GI_COSMETICS_HAIR:
CVarSetColor(CVAR_COSMETIC("Link.Hair.Value"), newColor);
CVarSetInteger(CVAR_COSMETIC("Link.Hair.Changed"), 1);
break;
}
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
ApplyOrResetCustomGfxPatches();
}
void GameInteractor::RawAction::RandomizeCosmeticsColors(bool excludeBiddingWarColors) {
const char* cvarsToLock[12] = {
CVAR_COSMETIC("Link.KokiriTunic.Locked"),
CVAR_COSMETIC("Link.GoronTunic.Locked"),
CVAR_COSMETIC("Link.ZoraTunic.Locked"),
CVAR_COSMETIC("Navi.EnemyPrimary.Locked"),
CVAR_COSMETIC("Navi.EnemySecondary.Locked"),
CVAR_COSMETIC("Navi.IdlePrimary.Locked"),
CVAR_COSMETIC("Navi.IdleSecondary.Locked"),
CVAR_COSMETIC("Navi.NPCPrimary.Locked"),
CVAR_COSMETIC("Navi.NPCSecondary.Locked"),
CVAR_COSMETIC("Navi.PropsPrimary.Locked"),
CVAR_COSMETIC("Navi.PropsSecondary.Locked"),
CVAR_COSMETIC("Link.Hair.Locked")
};
if (excludeBiddingWarColors) {
for (uint8_t i = 0; i < 12; i++) {
CVarSetInteger(cvarsToLock[i], 1);
}
}
CosmeticsEditor_RandomizeAll();
if (excludeBiddingWarColors) {
for (uint8_t i = 0; i < 12; i++) {
CVarSetInteger(cvarsToLock[i], 0);
}
}
}
void GameInteractor::RawAction::EmulateButtonPress(int32_t button) { void GameInteractor::RawAction::EmulateButtonPress(int32_t button) {
GameInteractor::State::EmulatedButtons |= button; GameInteractor::State::EmulatedButtons |= button;
} }
@ -577,7 +452,8 @@ void GameInteractor::RawAction::ClearCutscenePointer() {
gPlayState->csCtx.segment = &null_cs; gPlayState->csCtx.segment = &null_cs;
} }
GameInteractionEffectQueryResult GameInteractor::RawAction::SpawnEnemyWithOffset(uint32_t enemyId, int32_t enemyParams) { GameInteractionEffectQueryResult GameInteractor::RawAction::SpawnEnemyWithOffset(uint32_t enemyId, int32_t enemyParams,
std::string nameTag) {
if (!GameInteractor::CanSpawnActor()) { if (!GameInteractor::CanSpawnActor()) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
@ -646,13 +522,29 @@ GameInteractionEffectQueryResult GameInteractor::RawAction::SpawnEnemyWithOffset
pos.x += 10; pos.x += 10;
pos.y += 10; pos.y += 10;
pos.z += 10; pos.z += 10;
if (Actor_Spawn(&gPlayState->actorCtx, gPlayState, enemyId, pos.x, pos.y, pos.z, 0, 0, 0, enemyParams, 0) == NULL) { Actor* actor =
Actor_Spawn(&gPlayState->actorCtx, gPlayState, enemyId, pos.x, pos.y, pos.z, 0, 0, 0, enemyParams, 0);
if (actor == NULL) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} }
if (nameTag != "" && CVarGetInteger(CVAR_ENHANCEMENT("CrowdControl.EnemyNameTags"), 0)) {
NameTag_RegisterForActor(actor, nameTag.c_str());
}
if (CVarGetInteger(CVAR_ENHANCEMENT("CrowdControl.SpawnedEnemiesIgnoredIngame"), 0)) {
Actor_ChangeCategory(gPlayState, &gPlayState->actorCtx, actor, ACTORCAT_NPC);
}
} }
return GameInteractionEffectQueryResult::Possible; return GameInteractionEffectQueryResult::Possible;
} else { } else {
if (Actor_Spawn(&gPlayState->actorCtx, gPlayState, enemyId, pos.x, pos.y, pos.z, 0, 0, 0, enemyParams, 0) != NULL) { Actor* actor =
Actor_Spawn(&gPlayState->actorCtx, gPlayState, enemyId, pos.x, pos.y, pos.z, 0, 0, 0, enemyParams, 0);
if (actor != NULL) {
if (nameTag != "" && CVarGetInteger(CVAR_ENHANCEMENT("CrowdControl.EnemyNameTags"), 0)) {
NameTag_RegisterForActor(actor, nameTag.c_str());
}
if (CVarGetInteger(CVAR_ENHANCEMENT("CrowdControl.SpawnedEnemiesIgnoredIngame"), 0)) {
Actor_ChangeCategory(gPlayState, &gPlayState->actorCtx, actor, ACTORCAT_NPC);
}
return GameInteractionEffectQueryResult::Possible; return GameInteractionEffectQueryResult::Possible;
} }
} }
@ -660,7 +552,8 @@ GameInteractionEffectQueryResult GameInteractor::RawAction::SpawnEnemyWithOffset
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} }
GameInteractionEffectQueryResult GameInteractor::RawAction::SpawnActor(uint32_t actorId, int32_t actorParams) { GameInteractionEffectQueryResult GameInteractor::RawAction::SpawnActor(uint32_t actorId, int32_t actorParams,
std::string nameTag) {
if (!GameInteractor::CanSpawnActor()) { if (!GameInteractor::CanSpawnActor()) {
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
@ -676,6 +569,9 @@ GameInteractionEffectQueryResult GameInteractor::RawAction::SpawnActor(uint32_t
return GameInteractionEffectQueryResult::TemporarilyNotPossible; return GameInteractionEffectQueryResult::TemporarilyNotPossible;
} }
if (nameTag != "" && CVarGetInteger(CVAR_ENHANCEMENT("CrowdControl.EnemyNameTags"), 0)) {
NameTag_RegisterForActor((Actor*)cucco, nameTag.c_str());
}
cucco->actionFunc = func_80AB70A0_nocutscene; cucco->actionFunc = func_80AB70A0_nocutscene;
return GameInteractionEffectQueryResult::Possible; return GameInteractionEffectQueryResult::Possible;
} else if (actorId == ACTOR_EN_BOM) { } else if (actorId == ACTOR_EN_BOM) {
@ -694,8 +590,15 @@ GameInteractionEffectQueryResult GameInteractor::RawAction::SpawnActor(uint32_t
return GameInteractionEffectQueryResult::Possible; return GameInteractionEffectQueryResult::Possible;
} else { } else {
// Generic spawn an actor at Link's position // Generic spawn an actor at Link's position
if (Actor_Spawn(&gPlayState->actorCtx, gPlayState, actorId, player->actor.world.pos.x, Actor* actor = Actor_Spawn(&gPlayState->actorCtx, gPlayState, actorId, player->actor.world.pos.x,
player->actor.world.pos.y, player->actor.world.pos.z, 0, 0, 0, actorParams, 0) != NULL) { player->actor.world.pos.y, player->actor.world.pos.z, 0, 0, 0, actorParams, 0);
if (actor != NULL) {
if (nameTag != "" && CVarGetInteger(CVAR_ENHANCEMENT("CrowdControl.EnemyNameTags"), 0)) {
NameTag_RegisterForActor((Actor*)actor, nameTag.c_str());
}
if (CVarGetInteger(CVAR_ENHANCEMENT("CrowdControl.SpawnedEnemiesIgnoredIngame"), 0)) {
Actor_ChangeCategory(gPlayState, &gPlayState->actorCtx, actor, ACTORCAT_NPC);
}
return GameInteractionEffectQueryResult::Possible; return GameInteractionEffectQueryResult::Possible;
} }
} }

View file

@ -10,7 +10,7 @@ bool GameInteractor::State::PacifistModeActive = 0;
bool GameInteractor::State::DisableZTargetingActive = 0; bool GameInteractor::State::DisableZTargetingActive = 0;
bool GameInteractor::State::ReverseControlsActive = 0; bool GameInteractor::State::ReverseControlsActive = 0;
int32_t GameInteractor::State::DefenseModifier = 0; int32_t GameInteractor::State::DefenseModifier = 0;
int32_t GameInteractor::State::RunSpeedModifier = 0; float GameInteractor::State::MovementSpeedMultiplier = 1.0f;
GIGravityLevel GameInteractor::State::GravityLevel = GI_GRAVITY_LEVEL_NORMAL; GIGravityLevel GameInteractor::State::GravityLevel = GI_GRAVITY_LEVEL_NORMAL;
uint32_t GameInteractor::State::EmulatedButtons = 0; uint32_t GameInteractor::State::EmulatedButtons = 0;
uint8_t GameInteractor::State::RandomBombFuseTimerActive = 0; uint8_t GameInteractor::State::RandomBombFuseTimerActive = 0;
@ -81,8 +81,8 @@ int32_t GameInteractor_DefenseModifier() {
} }
// MARK: - GameInteractor::State::DisableCameraRotationActive // MARK: - GameInteractor::State::DisableCameraRotationActive
int32_t GameInteractor_RunSpeedModifier() { float GameInteractor_MovementSpeedMultiplier() {
return GameInteractor::State::RunSpeedModifier; return GameInteractor::State::MovementSpeedMultiplier;
} }
// MARK: - GameInteractor::State::DisableCameraRotationActive // MARK: - GameInteractor::State::DisableCameraRotationActive

View file

@ -134,9 +134,11 @@ void CrowdControl::EmitMessage(uint32_t eventId, long timeRemaining, EffectResul
CrowdControl::EffectResult CrowdControl::ExecuteEffect(Effect* effect) { CrowdControl::EffectResult CrowdControl::ExecuteEffect(Effect* effect) {
GameInteractionEffectQueryResult giResult; GameInteractionEffectQueryResult giResult;
if (effect->category == kEffectCatSpawnEnemy) { if (effect->category == kEffectCatSpawnEnemy) {
giResult = GameInteractor::RawAction::SpawnEnemyWithOffset(effect->spawnParams[0], effect->spawnParams[1]); giResult = GameInteractor::RawAction::SpawnEnemyWithOffset(effect->spawnParams[0], effect->spawnParams[1],
effect->viewerName);
} else if (effect->category == kEffectCatSpawnActor) { } else if (effect->category == kEffectCatSpawnActor) {
giResult = GameInteractor::RawAction::SpawnActor(effect->spawnParams[0], effect->spawnParams[1]); giResult =
GameInteractor::RawAction::SpawnActor(effect->spawnParams[0], effect->spawnParams[1], effect->viewerName);
} else { } else {
giResult = GameInteractor::ApplyEffect(effect->giEffect); giResult = GameInteractor::ApplyEffect(effect->giEffect);
} }
@ -183,6 +185,7 @@ CrowdControl::Effect* CrowdControl::ParseMessage(nlohmann::json dataReceived) {
Effect* effect = new Effect(); Effect* effect = new Effect();
effect->lastExecutionResult = EffectResult::Initiate; effect->lastExecutionResult = EffectResult::Initiate;
effect->id = dataReceived["id"]; effect->id = dataReceived["id"];
effect->viewerName = dataReceived["viewer"];
auto parameters = dataReceived["parameters"]; auto parameters = dataReceived["parameters"];
uint32_t receivedParameter = 0; uint32_t receivedParameter = 0;
auto effectName = dataReceived["code"].get<std::string>(); auto effectName = dataReceived["code"].get<std::string>();
@ -299,13 +302,13 @@ CrowdControl::Effect* CrowdControl::ParseMessage(nlohmann::json dataReceived) {
case kEffectIncreaseSpeed: case kEffectIncreaseSpeed:
effect->category = kEffectCatSpeed; effect->category = kEffectCatSpeed;
effect->timeRemaining = 30000; effect->timeRemaining = 30000;
effect->giEffect = new GameInteractionEffect::ModifyRunSpeedModifier(); effect->giEffect = new GameInteractionEffect::ModifyMovementSpeedMultiplier();
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = 2; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = 2;
break; break;
case kEffectDecreaseSpeed: case kEffectDecreaseSpeed:
effect->category = kEffectCatSpeed; effect->category = kEffectCatSpeed;
effect->timeRemaining = 30000; effect->timeRemaining = 30000;
effect->giEffect = new GameInteractionEffect::ModifyRunSpeedModifier(); effect->giEffect = new GameInteractionEffect::ModifyMovementSpeedMultiplier();
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = -2; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = -2;
break; break;
case kEffectLowGravity: case kEffectLowGravity:
@ -617,147 +620,6 @@ CrowdControl::Effect* CrowdControl::ParseMessage(nlohmann::json dataReceived) {
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_TP_DEST_PRELUDE; dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_TP_DEST_PRELUDE;
break; break;
// Tunic Color (Bidding War)
case kEffectTunicRed:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS;
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_RED;
break;
case kEffectTunicGreen:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS;
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_GREEN;
break;
case kEffectTunicBlue:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS;
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_BLUE;
break;
case kEffectTunicOrange:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS;
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_ORANGE;
break;
case kEffectTunicYellow:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS;
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_YELLOW;
break;
case kEffectTunicPurple:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS;
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_PURPLE;
break;
case kEffectTunicPink:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS;
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_PINK;
break;
case kEffectTunicBrown:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS;
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_BROWN;
break;
case kEffectTunicBlack:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS;
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_BLACK;
break;
// Navi Color (Bidding War)
case kEffectNaviRed:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI;
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_RED;
break;
case kEffectNaviGreen:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI;
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_GREEN;
break;
case kEffectNaviBlue:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI;
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_BLUE;
break;
case kEffectNaviOrange:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI;
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_ORANGE;
break;
case kEffectNaviYellow:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI;
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_YELLOW;
break;
case kEffectNaviPurple:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI;
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_PURPLE;
break;
case kEffectNaviPink:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI;
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_PINK;
break;
case kEffectNaviBrown:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI;
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_BROWN;
break;
case kEffectNaviBlack:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI;
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_BLACK;
break;
// Link's Hair Color (Bidding War)
case kEffectHairRed:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR;
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_RED;
break;
case kEffectHairGreen:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR;
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_GREEN;
break;
case kEffectHairBlue:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR;
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_BLUE;
break;
case kEffectHairOrange:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR;
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_ORANGE;
break;
case kEffectHairYellow:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR;
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_YELLOW;
break;
case kEffectHairPurple:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR;
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_PURPLE;
break;
case kEffectHairPink:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR;
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_PINK;
break;
case kEffectHairBrown:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR;
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_BROWN;
break;
case kEffectHairBlack:
effect->giEffect = new GameInteractionEffect::SetCosmeticsColor();
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR;
dynamic_cast<ParameterizedGameInteractionEffect*>(effect->giEffect)->parameters[1] = GI_COLOR_BLACK;
break;
default: default:
break; break;
} }
@ -826,6 +688,13 @@ void CrowdControl::DrawMenu() {
} }
} }
UIWidgets::PaddedEnhancementCheckbox("Enemy Name Tags", CVAR_ENHANCEMENT("CrowdControl.EnemyNameTags"), true,
false);
UIWidgets::Tooltip("When viewers spawn enemies, the enemy will have a name tag above them with the viewer's name.");
UIWidgets::PaddedEnhancementCheckbox("Spawned Enemies Ignored Ingame", CVAR_ENHANCEMENT("CrowdControl.SpawnedEnemiesIgnoredIngame"), true,
false);
UIWidgets::Tooltip("Enemies spawned by CrowdControl won't be considered for \"clear enemy rooms\", so they don't need to be killed to complete these rooms.");
ImGui::PopID(); ImGui::PopID();
} }

View file

@ -58,6 +58,7 @@ class CrowdControl : public Network {
uint32_t category = 0; uint32_t category = 0;
long timeRemaining; long timeRemaining;
GameInteractionEffectBase *giEffect; GameInteractionEffectBase *giEffect;
std::string viewerName;
// Metadata used while executing (only for timed effects) // Metadata used while executing (only for timed effects)
bool isPaused; bool isPaused;

View file

@ -124,50 +124,5 @@ public class ShipOfHarkinian : SimpleTCPPack<SimpleTCPServerConnector>
new("Requiem Destination", "tp_requiem") { Category = "Teleport Player", Price = 100, Description = "Teleport the player to Desert Colossus." }, new("Requiem Destination", "tp_requiem") { Category = "Teleport Player", Price = 100, Description = "Teleport the player to Desert Colossus." },
new("Nocturne Destination", "tp_nocturne") { Category = "Teleport Player", Price = 100, Description = "Teleport the player to the Raveyard." }, new("Nocturne Destination", "tp_nocturne") { Category = "Teleport Player", Price = 100, Description = "Teleport the player to the Raveyard." },
new("Prelude Destination", "tp_prelude") { Category = "Teleport Player", Price = 100, Description = "Teleport the player to the Temple of Time." }, new("Prelude Destination", "tp_prelude") { Category = "Teleport Player", Price = 100, Description = "Teleport the player to the Temple of Time." },
// Tunic Color (Bidding War)
new("Tunic Color", "tunic", ItemKind.BidWar)
{
Parameters = new ParameterDef("Color", "color_tunic_param",
new Parameter("Red", "red"),
new Parameter("Green", "green"),
new Parameter("Blue", "blue"),
new Parameter("Orange", "orange"),
new Parameter("Yellow", "yellow"),
new Parameter("Purple", "purple"),
new Parameter("Pink", "pink"),
new Parameter("Brown", "brown"),
new Parameter("Black", "black"))
},
// Navi Color (Bidding War)
new("Navi Color", "navi", ItemKind.BidWar)
{
Parameters = new ParameterDef("Color", "color_navi_param",
new Parameter("Red", "red"),
new Parameter("Green", "green"),
new Parameter("Blue", "blue"),
new Parameter("Orange", "orange"),
new Parameter("Yellow", "yellow"),
new Parameter("Purple", "purple"),
new Parameter("Pink", "pink"),
new Parameter("Brown", "brown"),
new Parameter("Black", "black"))
},
// Link's Hair Color (Bidding War)
new("Link's Hair Color", "hair", ItemKind.BidWar)
{
Parameters = new ParameterDef("Color", "color_hair_param",
new Parameter("Red", "red"),
new Parameter("Green", "green"),
new Parameter("Blue", "blue"),
new Parameter("Orange", "orange"),
new Parameter("Yellow", "yellow"),
new Parameter("Purple", "purple"),
new Parameter("Pink", "pink"),
new Parameter("Brown", "brown"),
new Parameter("Black", "black"))
}
}; };
} }

View file

@ -240,8 +240,8 @@ GameInteractionEffectBase* Sail::EffectFromJson(nlohmann::json payload) {
effect->parameters[0] = payload["parameters"][0].get<int32_t>(); effect->parameters[0] = payload["parameters"][0].get<int32_t>();
} }
return effect; return effect;
} else if (name == "ModifyRunSpeedModifier") { } else if (name == "ModifyMovementSpeedMultiplier") {
auto effect = new GameInteractionEffect::ModifyRunSpeedModifier(); auto effect = new GameInteractionEffect::ModifyMovementSpeedMultiplier();
if (payload.contains("parameters")) { if (payload.contains("parameters")) {
effect->parameters[0] = payload["parameters"][0].get<int32_t>(); effect->parameters[0] = payload["parameters"][0].get<int32_t>();
} }
@ -280,13 +280,6 @@ GameInteractionEffectBase* Sail::EffectFromJson(nlohmann::json payload) {
return effect; return effect;
} else if (name == "SetCollisionViewer") { } else if (name == "SetCollisionViewer") {
return new GameInteractionEffect::SetCollisionViewer(); return new GameInteractionEffect::SetCollisionViewer();
} else if (name == "SetCosmeticsColor") {
auto effect = new GameInteractionEffect::SetCosmeticsColor();
if (payload.contains("parameters")) {
effect->parameters[0] = payload["parameters"][0].get<int32_t>();
effect->parameters[1] = payload["parameters"][1].get<int32_t>();
}
return effect;
} else if (name == "RandomizeCosmetics") { } else if (name == "RandomizeCosmetics") {
return new GameInteractionEffect::RandomizeCosmetics(); return new GameInteractionEffect::RandomizeCosmetics();
} else if (name == "PressButton") { } else if (name == "PressButton") {

View file

@ -1265,8 +1265,16 @@ void Actor_UpdatePos(Actor* actor) {
} }
void Actor_UpdateVelocityXZGravity(Actor* actor) { void Actor_UpdateVelocityXZGravity(Actor* actor) {
actor->velocity.x = Math_SinS(actor->world.rot.y) * actor->speedXZ; Player* player = GET_PLAYER(gPlayState);
actor->velocity.z = Math_CosS(actor->world.rot.y) * actor->speedXZ; uint8_t inCutscene = player->stateFlags1 & PLAYER_STATE1_CLIMBING_LADDER ||
player->stateFlags1 & PLAYER_STATE1_IN_CUTSCENE ||
player->stateFlags2 & PLAYER_STATE2_CRAWLING;
f32 speedModifier = 1.0f;
if (actor->id == ACTOR_PLAYER && !inCutscene) {
speedModifier = GameInteractor_MovementSpeedMultiplier();
}
actor->velocity.x = Math_SinS(actor->world.rot.y) * actor->speedXZ * speedModifier;
actor->velocity.z = Math_CosS(actor->world.rot.y) * actor->speedXZ * speedModifier;
actor->velocity.y += actor->gravity; actor->velocity.y += actor->gravity;
if (actor->velocity.y < actor->minVelocityY) { if (actor->velocity.y < actor->minVelocityY) {

View file

@ -58,6 +58,11 @@ void EnAttackNiw_Init(Actor* thisx, PlayState* play) {
this->actor.flags &= ~ACTOR_FLAG_ATTENTION_ENABLED; this->actor.flags &= ~ACTOR_FLAG_ATTENTION_ENABLED;
this->actor.shape.rot.y = this->actor.world.rot.y = (Rand_ZeroOne() - 0.5f) * 60000.0f; this->actor.shape.rot.y = this->actor.world.rot.y = (Rand_ZeroOne() - 0.5f) * 60000.0f;
this->actionFunc = func_809B5670; this->actionFunc = func_809B5670;
if (CVarGetInteger("gCrowdControl", 0) &&
CVarGetInteger(CVAR_ENHANCEMENT("CrowdControl.SpawnedEnemiesIgnoredIngame"), 0)) {
Actor_ChangeCategory(gPlayState, &gPlayState->actorCtx, this, ACTORCAT_NPC);
}
} }
void EnAttackNiw_Destroy(Actor* thisx, PlayState* play) { void EnAttackNiw_Destroy(Actor* thisx, PlayState* play) {

View file

@ -7078,15 +7078,6 @@ void func_8083DFE0(Player* this, f32* arg1, s16* arg2) {
if (this->meleeWeaponState == 0) { if (this->meleeWeaponState == 0) {
float maxSpeed = R_RUN_SPEED_LIMIT / 100.0f; float maxSpeed = R_RUN_SPEED_LIMIT / 100.0f;
int32_t giSpeedModifier = GameInteractor_RunSpeedModifier();
if (giSpeedModifier != 0) {
if (giSpeedModifier > 0) {
maxSpeed *= giSpeedModifier;
} else {
maxSpeed /= abs(giSpeedModifier);
}
}
if (CVarGetInteger(CVAR_ENHANCEMENT("MMBunnyHood"), BUNNY_HOOD_VANILLA) == BUNNY_HOOD_FAST_AND_JUMP && this->currentMask == PLAYER_MASK_BUNNY) { if (CVarGetInteger(CVAR_ENHANCEMENT("MMBunnyHood"), BUNNY_HOOD_VANILLA) == BUNNY_HOOD_FAST_AND_JUMP && this->currentMask == PLAYER_MASK_BUNNY) {
maxSpeed *= 1.5f; maxSpeed *= 1.5f;
} }
@ -8837,14 +8828,6 @@ void Player_Action_80842180(Player* this, PlayState* play) {
Player_GetMovementSpeedAndYaw(this, &sp2C, &sp2A, SPEED_MODE_CURVED, play); Player_GetMovementSpeedAndYaw(this, &sp2C, &sp2A, SPEED_MODE_CURVED, play);
if (!func_8083C484(this, &sp2C, &sp2A)) { if (!func_8083C484(this, &sp2C, &sp2A)) {
int32_t giSpeedModifier = GameInteractor_RunSpeedModifier();
if (giSpeedModifier != 0) {
if (giSpeedModifier > 0) {
sp2C *= giSpeedModifier;
} else {
sp2C /= abs(giSpeedModifier);
}
}
if (CVarGetInteger(CVAR_ENHANCEMENT("MMBunnyHood"), BUNNY_HOOD_VANILLA) != BUNNY_HOOD_VANILLA && this->currentMask == PLAYER_MASK_BUNNY) { if (CVarGetInteger(CVAR_ENHANCEMENT("MMBunnyHood"), BUNNY_HOOD_VANILLA) != BUNNY_HOOD_VANILLA && this->currentMask == PLAYER_MASK_BUNNY) {
sp2C *= 1.5f; sp2C *= 1.5f;