#ifdef ENABLE_REMOTE_CONTROL #include "CrowdControl.h" #include "CrowdControlTypes.h" #include #include #include #include #include #include extern "C" { #include #include "variables.h" #include "functions.h" #include "macros.h" extern PlayState* gPlayState; } void CrowdControl::Enable() { if (isEnabled) { return; } isEnabled = true; GameInteractor::Instance->EnableRemoteInteractor(); GameInteractor::Instance->RegisterRemoteJsonHandler([&](nlohmann::json payload) { HandleRemoteData(payload); }); ccThreadProcess = std::thread(&CrowdControl::ProcessActiveEffects, this); } void CrowdControl::Disable() { if (!isEnabled) { return; } isEnabled = false; ccThreadProcess.join(); GameInteractor::Instance->DisableRemoteInteractor(); } void CrowdControl::HandleRemoteData(nlohmann::json payload) { Effect* incomingEffect = ParseMessage(payload); if (!incomingEffect) { return; } // If effect is not a timed effect, execute and return result. if (!incomingEffect->timeRemaining) { EffectResult result = CrowdControl::ExecuteEffect(incomingEffect); EmitMessage(incomingEffect->id, incomingEffect->timeRemaining, result); } else { // If another timed effect is already active that conflicts with the incoming effect. bool isConflictingEffectActive = false; for (Effect* effect : activeEffects) { if (effect != incomingEffect && effect->category == incomingEffect->category && effect->id < incomingEffect->id) { isConflictingEffectActive = true; EmitMessage(incomingEffect->id, incomingEffect->timeRemaining, EffectResult::Retry); break; } } if (!isConflictingEffectActive) { // Check if effect can be applied, if it can't, let CC know. EffectResult result = CrowdControl::CanApplyEffect(incomingEffect); if (result == EffectResult::Retry || result == EffectResult::Failure) { EmitMessage(incomingEffect->id, incomingEffect->timeRemaining, result); return; } activeEffectsMutex.lock(); activeEffects.push_back(incomingEffect); activeEffectsMutex.unlock(); } } } void CrowdControl::ProcessActiveEffects() { while (isEnabled) { // We only want to send events when status changes, on start we send Success. // If it fails at some point, we send Pause, and when it starts to succeed again we send Success. // CC uses this to pause the timer on the overlay. activeEffectsMutex.lock(); auto it = activeEffects.begin(); while (it != activeEffects.end()) { Effect *effect = *it; EffectResult result = CrowdControl::ExecuteEffect(effect); if (result == EffectResult::Success) { // If time remaining has reached 0, we have finished the effect. if (effect->timeRemaining <= 0) { it = activeEffects.erase(std::remove(activeEffects.begin(), activeEffects.end(), effect), activeEffects.end()); GameInteractor::RemoveEffect(dynamic_cast(effect->giEffect)); delete effect; } else { // If we have a success after previously being paused, tell CC to resume timer. if (effect->isPaused) { effect->isPaused = false; EmitMessage(effect->id, effect->timeRemaining, EffectResult::Resumed); // If not paused before, subtract time from the timer and send a Success event if // the result is different from the last time this was ran. // Timed events are put on a thread that runs once per second. } else { effect->timeRemaining -= 1000; if (result != effect->lastExecutionResult) { effect->lastExecutionResult = result; EmitMessage(effect->id, effect->timeRemaining, EffectResult::Success); } } it++; } } else { // Timed effects only do Success or Retry if (!effect->isPaused && effect->timeRemaining > 0) { effect->isPaused = true; EmitMessage(effect->id, effect->timeRemaining, EffectResult::Paused); } it++; } } activeEffectsMutex.unlock(); std::this_thread::sleep_for(std::chrono::seconds(1)); } SPDLOG_TRACE("[CrowdControl] Ending Process thread..."); } void CrowdControl::EmitMessage(uint32_t eventId, long timeRemaining, EffectResult status) { nlohmann::json payload; payload["id"] = eventId; payload["type"] = 0; payload["timeRemaining"] = timeRemaining; payload["status"] = status; SPDLOG_INFO("[CrowdControl] Sending payload:\n{}", payload.dump()); GameInteractor::Instance->TransmitJsonToRemote(payload); } CrowdControl::EffectResult CrowdControl::ExecuteEffect(Effect* effect) { GameInteractionEffectQueryResult giResult; if (effect->category == kEffectCatSpawnEnemy) { giResult = GameInteractor::RawAction::SpawnEnemyWithOffset(effect->spawnParams[0], effect->spawnParams[1]); } else if (effect->category == kEffectCatSpawnActor) { giResult = GameInteractor::RawAction::SpawnActor(effect->spawnParams[0], effect->spawnParams[1]); } else { giResult = GameInteractor::ApplyEffect(effect->giEffect); } return TranslateGiEnum(giResult); } /// Checks if effect can be applied -- should not be used to check for spawn enemy effects. CrowdControl::EffectResult CrowdControl::CanApplyEffect(Effect* effect) { assert(effect->category != kEffectCatSpawnEnemy || effect->category != kEffectCatSpawnActor); GameInteractionEffectQueryResult giResult = GameInteractor::CanApplyEffect(effect->giEffect); return TranslateGiEnum(giResult); } CrowdControl::EffectResult CrowdControl::TranslateGiEnum(GameInteractionEffectQueryResult giResult) { // Translate GameInteractor result into CC's own enums. EffectResult result; if (giResult == GameInteractionEffectQueryResult::Possible) { result = EffectResult::Success; } else if (giResult == GameInteractionEffectQueryResult::TemporarilyNotPossible) { result = EffectResult::Retry; } else { result = EffectResult::Failure; } return result; } CrowdControl::Effect* CrowdControl::ParseMessage(nlohmann::json dataReceived) { if (!dataReceived.contains("id") || !dataReceived.contains("type")) { SPDLOG_ERROR("[CrowdControl] Invalid payload received:\n{}", dataReceived); return nullptr; } SPDLOG_INFO("[CrowdControl] Received payload:\n{}", dataReceived.dump()); Effect* effect = new Effect(); effect->lastExecutionResult = EffectResult::Initiate; effect->id = dataReceived["id"]; auto parameters = dataReceived["parameters"]; uint32_t receivedParameter = 0; auto effectName = dataReceived["code"].get(); if (parameters.size() > 0) { receivedParameter = dataReceived["parameters"][0]; } // Assign GameInteractionEffect + values to CC effect. // Categories are mostly used for checking for conflicting timed effects. switch (effectStringToEnum[effectName]) { // Spawn Enemies and Objects case kEffectSpawnCuccoStorm: effect->spawnParams[0] = ACTOR_EN_NIW; effect->category = kEffectCatSpawnActor; break; case kEffectSpawnLitBomb: effect->spawnParams[0] = ACTOR_EN_BOM; effect->category = kEffectCatSpawnActor; break; case kEffectSpawnExplosion: effect->spawnParams[0] = ACTOR_EN_BOM; effect->spawnParams[1] = 1; effect->category = kEffectCatSpawnActor; break; case kEffectSpawnArwing: effect->spawnParams[0] = ACTOR_EN_CLEAR_TAG; // Parameter for no cutscene Arwing effect->spawnParams[1] = 1; effect->category = kEffectCatSpawnEnemy; break; case kEffectSpawnDarklink: effect->spawnParams[0] = ACTOR_EN_TORCH2; effect->category = kEffectCatSpawnEnemy; break; case kEffectSpawnIronKnuckle: effect->spawnParams[0] = ACTOR_EN_IK; // Parameter for black standing Iron Knuckle effect->spawnParams[1] = 2; effect->category = kEffectCatSpawnEnemy; break; case kEffectSpawnStalfos: effect->spawnParams[0] = ACTOR_EN_TEST; // Parameter for gravity-obeying Stalfos effect->spawnParams[1] = 2; effect->category = kEffectCatSpawnEnemy; break; case kEffectSpawnFreezard: effect->spawnParams[0] = ACTOR_EN_FZ; effect->category = kEffectCatSpawnEnemy; break; case kEffectSpawnLikeLike: effect->spawnParams[0] = ACTOR_EN_RR; effect->category = kEffectCatSpawnEnemy; break; case kEffectSpawnGibdo: effect->spawnParams[0] = ACTOR_EN_RD; // Parameter for Gibdo effect->spawnParams[1] = 32766; effect->category = kEffectCatSpawnEnemy; break; case kEffectSpawnKeese: effect->spawnParams[0] = ACTOR_EN_FIREFLY; // Parameter for normal keese effect->spawnParams[1] = 2; effect->category = kEffectCatSpawnEnemy; break; case kEffectSpawnIceKeese: effect->spawnParams[0] = ACTOR_EN_FIREFLY; // Parameter for ice keese effect->spawnParams[1] = 4; effect->category = kEffectCatSpawnEnemy; break; case kEffectSpawnFireKeese: effect->spawnParams[0] = ACTOR_EN_FIREFLY; // Parameter for fire keese effect->spawnParams[1] = 1; effect->category = kEffectCatSpawnEnemy; break; case kEffectSpawnWolfos: effect->spawnParams[0] = ACTOR_EN_WF; effect->category = kEffectCatSpawnEnemy; break; case kEffectSpawnWallmaster: effect->spawnParams[0] = ACTOR_EN_WALLMAS; effect->category = kEffectCatSpawnEnemy; break; // Link Modifiers case kEffectTakeHalfDamage: effect->category = kEffectCatDamageTaken; effect->timeRemaining = 30000; effect->giEffect = new GameInteractionEffect::ModifyDefenseModifier(); dynamic_cast(effect->giEffect)->parameters[0] = 2; break; case kEffectTakeDoubleDamage: effect->category = kEffectCatDamageTaken; effect->timeRemaining = 30000; effect->giEffect = new GameInteractionEffect::ModifyDefenseModifier(); dynamic_cast(effect->giEffect)->parameters[0] = -2; break; case kEffectOneHitKo: effect->category = kEffectCatDamageTaken; effect->timeRemaining = 30000; effect->giEffect = new GameInteractionEffect::OneHitKO(); break; case kEffectInvincibility: effect->category = kEffectCatDamageTaken; effect->timeRemaining = 15000; effect->giEffect = new GameInteractionEffect::PlayerInvincibility(); break; break; case kEffectIncreaseSpeed: effect->category = kEffectCatSpeed; effect->timeRemaining = 30000; effect->giEffect = new GameInteractionEffect::ModifyRunSpeedModifier(); dynamic_cast(effect->giEffect)->parameters[0] = 2; break; case kEffectDecreaseSpeed: effect->category = kEffectCatSpeed; effect->timeRemaining = 30000; effect->giEffect = new GameInteractionEffect::ModifyRunSpeedModifier(); dynamic_cast(effect->giEffect)->parameters[0] = -2; break; case kEffectLowGravity: effect->category = kEffectCatGravity; effect->timeRemaining = 30000; effect->giEffect = new GameInteractionEffect::ModifyGravity(); dynamic_cast(effect->giEffect)->parameters[0] = GI_GRAVITY_LEVEL_LIGHT; break; case kEffectHighGravity: effect->category = kEffectCatGravity; effect->timeRemaining = 30000; effect->giEffect = new GameInteractionEffect::ModifyGravity(); dynamic_cast(effect->giEffect)->parameters[0] = GI_GRAVITY_LEVEL_HEAVY; break; case kEffectForceIronBoots: effect->category = kEffectCatBoots; effect->timeRemaining = 30000; effect->giEffect = new GameInteractionEffect::ForceEquipBoots(); dynamic_cast(effect->giEffect)->parameters[0] = EQUIP_VALUE_BOOTS_IRON; break; case kEffectForceHoverBoots: effect->category = kEffectCatBoots; effect->timeRemaining = 30000; effect->giEffect = new GameInteractionEffect::ForceEquipBoots(); dynamic_cast(effect->giEffect)->parameters[0] = EQUIP_VALUE_BOOTS_HOVER; break; case kEffectSlipperyFloor: effect->category = kEffectCatSlipperyFloor; effect->timeRemaining = 30000; effect->giEffect = new GameInteractionEffect::SlipperyFloor(); break; case kEffectNoLedgeGrabs: effect->category = kEffectCatNoLedgeGrabs; effect->timeRemaining = 30000; effect->giEffect = new GameInteractionEffect::DisableLedgeGrabs(); break; case kEffectRandomWind: effect->category = kEffectCatRandomWind; effect->timeRemaining = 30000; effect->giEffect = new GameInteractionEffect::RandomWind(); break; case kEffectRandomBonks: effect->category = kEffectCatRandomBonks; effect->timeRemaining = 60000; effect->giEffect = new GameInteractionEffect::RandomBonks(); break; // Hurt or Heal Link case kEffectEmptyHeart: effect->giEffect = new GameInteractionEffect::ModifyHealth(); dynamic_cast(effect->giEffect)->parameters[0] = receivedParameter * -1; break; case kEffectFillHeart: effect->giEffect = new GameInteractionEffect::ModifyHealth(); dynamic_cast(effect->giEffect)->parameters[0] = receivedParameter; break; case kEffectKnockbackLinkWeak: effect->giEffect = new GameInteractionEffect::KnockbackPlayer(); dynamic_cast(effect->giEffect)->parameters[0] = 1; break; case kEffectKnockbackLinkStrong: effect->giEffect = new GameInteractionEffect::KnockbackPlayer(); dynamic_cast(effect->giEffect)->parameters[0] = 3; break; case kEffectKnockbackLinkMega: effect->giEffect = new GameInteractionEffect::KnockbackPlayer(); dynamic_cast(effect->giEffect)->parameters[0] = 6; break; case kEffectBurnLink: effect->giEffect = new GameInteractionEffect::BurnPlayer(); break; case kEffectFreezeLink: effect->giEffect = new GameInteractionEffect::FreezePlayer(); break; case kEffectElectrocuteLink: effect->giEffect = new GameInteractionEffect::ElectrocutePlayer(); break; case kEffectKillLink: effect->giEffect = new GameInteractionEffect::SetPlayerHealth(); dynamic_cast(effect->giEffect)->parameters[0] = 0; break; // Give Items and Consumables case kEffectAddHeartContainer: effect->giEffect = new GameInteractionEffect::ModifyHeartContainers(); dynamic_cast(effect->giEffect)->parameters[0] = 1; break; case kEffectFillMagic: effect->giEffect = new GameInteractionEffect::FillMagic(); break; case kEffectAddRupees: effect->giEffect = new GameInteractionEffect::ModifyRupees(); dynamic_cast(effect->giEffect)->parameters[0] = receivedParameter; break; case kEffectGiveDekuShield: effect->giEffect = new GameInteractionEffect::GiveOrTakeShield(); dynamic_cast(effect->giEffect)->parameters[0] = ITEM_SHIELD_DEKU; break; case kEffectGiveHylianShield: effect->giEffect = new GameInteractionEffect::GiveOrTakeShield(); dynamic_cast(effect->giEffect)->parameters[0] = ITEM_SHIELD_HYLIAN; break; case kEffectRefillSticks: effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo(); dynamic_cast(effect->giEffect)->parameters[0] = receivedParameter; dynamic_cast(effect->giEffect)->parameters[1] = ITEM_STICK; break; case kEffectRefillNuts: effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo(); dynamic_cast(effect->giEffect)->parameters[0] = receivedParameter; dynamic_cast(effect->giEffect)->parameters[1] = ITEM_NUT; break; case kEffectRefillBombs: effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo(); dynamic_cast(effect->giEffect)->parameters[0] = receivedParameter; dynamic_cast(effect->giEffect)->parameters[1] = ITEM_BOMB; break; case kEffectRefillSeeds: effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo(); dynamic_cast(effect->giEffect)->parameters[0] = receivedParameter; dynamic_cast(effect->giEffect)->parameters[1] = ITEM_SLINGSHOT; break; case kEffectRefillArrows: effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo(); dynamic_cast(effect->giEffect)->parameters[0] = receivedParameter; dynamic_cast(effect->giEffect)->parameters[1] = ITEM_BOW; break; case kEffectRefillBombchus: effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo(); dynamic_cast(effect->giEffect)->parameters[0] = receivedParameter; dynamic_cast(effect->giEffect)->parameters[1] = ITEM_BOMBCHU; break; // Take Items and Consumables case kEffectRemoveHeartContainer: effect->giEffect = new GameInteractionEffect::ModifyHeartContainers(); dynamic_cast(effect->giEffect)->parameters[0] = -1; break; case kEffectEmptyMagic: effect->giEffect = new GameInteractionEffect::EmptyMagic(); break; case kEffectRemoveRupees: effect->giEffect = new GameInteractionEffect::ModifyRupees(); dynamic_cast(effect->giEffect)->parameters[0] = receivedParameter * -1; break; case kEffectTakeDekuShield: effect->giEffect = new GameInteractionEffect::GiveOrTakeShield(); dynamic_cast(effect->giEffect)->parameters[0] = -ITEM_SHIELD_DEKU; break; case kEffectTakeHylianShield: effect->giEffect = new GameInteractionEffect::GiveOrTakeShield(); dynamic_cast(effect->giEffect)->parameters[0] = -ITEM_SHIELD_HYLIAN; break; case kEffectTakeSticks: effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo(); dynamic_cast(effect->giEffect)->parameters[0] = receivedParameter * -1; dynamic_cast(effect->giEffect)->parameters[1] = ITEM_STICK; break; case kEffectTakeNuts: effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo(); dynamic_cast(effect->giEffect)->parameters[0] = receivedParameter * -1; dynamic_cast(effect->giEffect)->parameters[1] = ITEM_NUT; break; case kEffectTakeBombs: effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo(); dynamic_cast(effect->giEffect)->parameters[0] = receivedParameter * -1; dynamic_cast(effect->giEffect)->parameters[1] = ITEM_BOMB; break; case kEffectTakeSeeds: effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo(); dynamic_cast(effect->giEffect)->parameters[0] = receivedParameter * -1; dynamic_cast(effect->giEffect)->parameters[1] = ITEM_SLINGSHOT; break; case kEffectTakeArrows: effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo(); dynamic_cast(effect->giEffect)->parameters[0] = receivedParameter * -1; dynamic_cast(effect->giEffect)->parameters[1] = ITEM_BOW; break; case kEffectTakeBombchus: effect->giEffect = new GameInteractionEffect::AddOrTakeAmmo(); dynamic_cast(effect->giEffect)->parameters[0] = receivedParameter * -1; dynamic_cast(effect->giEffect)->parameters[1] = ITEM_BOMBCHU; break; // Link Size Modifiers case kEffectGiantLink: effect->category = kEffectCatLinkSize; effect->timeRemaining = 30000; effect->giEffect = new GameInteractionEffect::ModifyLinkSize(); dynamic_cast(effect->giEffect)->parameters[0] = GI_LINK_SIZE_GIANT; break; case kEffectMinishLink: effect->category = kEffectCatLinkSize; effect->timeRemaining = 30000; effect->giEffect = new GameInteractionEffect::ModifyLinkSize(); dynamic_cast(effect->giEffect)->parameters[0] = GI_LINK_SIZE_MINISH; break; case kEffectPaperLink: effect->category = kEffectCatLinkSize; effect->timeRemaining = 30000; effect->giEffect = new GameInteractionEffect::ModifyLinkSize(); dynamic_cast(effect->giEffect)->parameters[0] = GI_LINK_SIZE_PAPER; break; case kEffectSquishedLink: effect->category = kEffectCatLinkSize; effect->timeRemaining = 30000; effect->giEffect = new GameInteractionEffect::ModifyLinkSize(); dynamic_cast(effect->giEffect)->parameters[0] = GI_LINK_SIZE_SQUISHED; break; case kEffectInvisibleLink: effect->category = kEffectCatLinkSize; effect->timeRemaining = 30000; effect->giEffect = new GameInteractionEffect::InvisibleLink(); break; // Generic Effects case kEffectRandomBombTimer: effect->category = kEffectCatRandomBombFuseTimer; effect->timeRemaining = 60000; effect->giEffect = new GameInteractionEffect::RandomBombFuseTimer(); break; case kEffectSetTimeToDawn: effect->giEffect = new GameInteractionEffect::SetTimeOfDay(); dynamic_cast(effect->giEffect)->parameters[0] = GI_TIMEOFDAY_DAWN; break; case kEffectSetTimeToDusk: effect->giEffect = new GameInteractionEffect::SetTimeOfDay(); dynamic_cast(effect->giEffect)->parameters[0] = GI_TIMEOFDAY_DUSK; break; // Visual Effects case kEffectNoUi: effect->category = kEffectCatUi; effect->timeRemaining = 60000; effect->giEffect = new GameInteractionEffect::NoUI(); break; case kEffectRainstorm: effect->category = kEffectCatWeather; effect->timeRemaining = 30000; effect->giEffect = new GameInteractionEffect::WeatherRainstorm(); break; case kEffectDebugMode: effect->category = kEffectCatDebugMode; effect->timeRemaining = 30000; effect->giEffect = new GameInteractionEffect::SetCollisionViewer(); break; case kEffectRandomCosmetics: effect->giEffect = new GameInteractionEffect::RandomizeCosmetics(); break; // Controls case kEffectNoZButton: effect->category = kEffectCatNoZ; effect->timeRemaining = 30000; effect->giEffect = new GameInteractionEffect::DisableZTargeting(); break; case kEffectReverseControls: effect->category = kEffectCatReverseControls; effect->timeRemaining = 60000; effect->giEffect = new GameInteractionEffect::ReverseControls(); break; case kEffectPacifistMode: effect->category = kEffectCatPacifist; effect->timeRemaining = 15000; effect->giEffect = new GameInteractionEffect::PacifistMode(); break; case kEffectPressRandomButtons: effect->category = kEffectCatRandomButtons; effect->timeRemaining = 30000; effect->giEffect = new GameInteractionEffect::PressRandomButton(); dynamic_cast(effect->giEffect)->parameters[0] = 30; break; case kEffectClearCbuttons: effect->giEffect = new GameInteractionEffect::ClearAssignedButtons(); dynamic_cast(effect->giEffect)->parameters[0] = GI_BUTTONS_CBUTTONS; break; case kEffectClearDpad: effect->giEffect = new GameInteractionEffect::ClearAssignedButtons(); dynamic_cast(effect->giEffect)->parameters[0] = GI_BUTTONS_DPAD; break; // Teleport Player case kEffectTpLinksHouse: effect->giEffect = new GameInteractionEffect::TeleportPlayer(); dynamic_cast(effect->giEffect)->parameters[0] = GI_TP_DEST_LINKSHOUSE; break; case kEffectTpMinuet: effect->giEffect = new GameInteractionEffect::TeleportPlayer(); dynamic_cast(effect->giEffect)->parameters[0] = GI_TP_DEST_MINUET; break; case kEffectTpBolero: effect->giEffect = new GameInteractionEffect::TeleportPlayer(); dynamic_cast(effect->giEffect)->parameters[0] = GI_TP_DEST_BOLERO; break; case kEffectTpSerenade: effect->giEffect = new GameInteractionEffect::TeleportPlayer(); dynamic_cast(effect->giEffect)->parameters[0] = GI_TP_DEST_SERENADE; break; case kEffectTpRequiem: effect->giEffect = new GameInteractionEffect::TeleportPlayer(); dynamic_cast(effect->giEffect)->parameters[0] = GI_TP_DEST_REQUIEM; break; case kEffectTpNocturne: effect->giEffect = new GameInteractionEffect::TeleportPlayer(); dynamic_cast(effect->giEffect)->parameters[0] = GI_TP_DEST_NOCTURNE; break; case kEffectTpPrelude: effect->giEffect = new GameInteractionEffect::TeleportPlayer(); dynamic_cast(effect->giEffect)->parameters[0] = GI_TP_DEST_PRELUDE; break; // Tunic Color (Bidding War) case kEffectTunicRed: effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); dynamic_cast(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS; dynamic_cast(effect->giEffect)->parameters[1] = GI_COLOR_RED; break; case kEffectTunicGreen: effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); dynamic_cast(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS; dynamic_cast(effect->giEffect)->parameters[1] = GI_COLOR_GREEN; break; case kEffectTunicBlue: effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); dynamic_cast(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS; dynamic_cast(effect->giEffect)->parameters[1] = GI_COLOR_BLUE; break; case kEffectTunicOrange: effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); dynamic_cast(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS; dynamic_cast(effect->giEffect)->parameters[1] = GI_COLOR_ORANGE; break; case kEffectTunicYellow: effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); dynamic_cast(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS; dynamic_cast(effect->giEffect)->parameters[1] = GI_COLOR_YELLOW; break; case kEffectTunicPurple: effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); dynamic_cast(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS; dynamic_cast(effect->giEffect)->parameters[1] = GI_COLOR_PURPLE; break; case kEffectTunicPink: effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); dynamic_cast(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS; dynamic_cast(effect->giEffect)->parameters[1] = GI_COLOR_PINK; break; case kEffectTunicBrown: effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); dynamic_cast(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS; dynamic_cast(effect->giEffect)->parameters[1] = GI_COLOR_BROWN; break; case kEffectTunicBlack: effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); dynamic_cast(effect->giEffect)->parameters[0] = GI_COSMETICS_TUNICS; dynamic_cast(effect->giEffect)->parameters[1] = GI_COLOR_BLACK; break; // Navi Color (Bidding War) case kEffectNaviRed: effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); dynamic_cast(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI; dynamic_cast(effect->giEffect)->parameters[1] = GI_COLOR_RED; break; case kEffectNaviGreen: effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); dynamic_cast(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI; dynamic_cast(effect->giEffect)->parameters[1] = GI_COLOR_GREEN; break; case kEffectNaviBlue: effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); dynamic_cast(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI; dynamic_cast(effect->giEffect)->parameters[1] = GI_COLOR_BLUE; break; case kEffectNaviOrange: effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); dynamic_cast(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI; dynamic_cast(effect->giEffect)->parameters[1] = GI_COLOR_ORANGE; break; case kEffectNaviYellow: effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); dynamic_cast(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI; dynamic_cast(effect->giEffect)->parameters[1] = GI_COLOR_YELLOW; break; case kEffectNaviPurple: effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); dynamic_cast(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI; dynamic_cast(effect->giEffect)->parameters[1] = GI_COLOR_PURPLE; break; case kEffectNaviPink: effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); dynamic_cast(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI; dynamic_cast(effect->giEffect)->parameters[1] = GI_COLOR_PINK; break; case kEffectNaviBrown: effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); dynamic_cast(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI; dynamic_cast(effect->giEffect)->parameters[1] = GI_COLOR_BROWN; break; case kEffectNaviBlack: effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); dynamic_cast(effect->giEffect)->parameters[0] = GI_COSMETICS_NAVI; dynamic_cast(effect->giEffect)->parameters[1] = GI_COLOR_BLACK; break; // Link's Hair Color (Bidding War) case kEffectHairRed: effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); dynamic_cast(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR; dynamic_cast(effect->giEffect)->parameters[1] = GI_COLOR_RED; break; case kEffectHairGreen: effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); dynamic_cast(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR; dynamic_cast(effect->giEffect)->parameters[1] = GI_COLOR_GREEN; break; case kEffectHairBlue: effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); dynamic_cast(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR; dynamic_cast(effect->giEffect)->parameters[1] = GI_COLOR_BLUE; break; case kEffectHairOrange: effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); dynamic_cast(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR; dynamic_cast(effect->giEffect)->parameters[1] = GI_COLOR_ORANGE; break; case kEffectHairYellow: effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); dynamic_cast(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR; dynamic_cast(effect->giEffect)->parameters[1] = GI_COLOR_YELLOW; break; case kEffectHairPurple: effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); dynamic_cast(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR; dynamic_cast(effect->giEffect)->parameters[1] = GI_COLOR_PURPLE; break; case kEffectHairPink: effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); dynamic_cast(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR; dynamic_cast(effect->giEffect)->parameters[1] = GI_COLOR_PINK; break; case kEffectHairBrown: effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); dynamic_cast(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR; dynamic_cast(effect->giEffect)->parameters[1] = GI_COLOR_BROWN; break; case kEffectHairBlack: effect->giEffect = new GameInteractionEffect::SetCosmeticsColor(); dynamic_cast(effect->giEffect)->parameters[0] = GI_COSMETICS_HAIR; dynamic_cast(effect->giEffect)->parameters[1] = GI_COLOR_BLACK; break; default: break; } return effect; } #endif