HeavenStudioPlus/Assets/Scripts/Games/Tunnel/Tunnel.cs

327 lines
12 KiB
C#
Raw Normal View History

using DG.Tweening;
using NaughtyBezierCurves;
using HeavenStudio.Util;
using System;
using System.Collections.Generic;
using UnityEngine;
namespace HeavenStudio.Games.Loaders
{
using static Minigames;
public static class NtrTunnelLoader
{
public static Minigame AddGame(EventCaller eventCaller)
{
2024-01-15 19:22:26 +00:00
return new Minigame("tunnel", "Tunnel", "c00000", false, false, new List<GameAction>()
{
new GameAction("cowbell", "Start Cowbell")
{
preFunction = delegate { Tunnel.PreStartCowbell(eventCaller.currentEntity.beat, eventCaller.currentEntity.length); },
defaultLength = 1f,
resizable = false,
},
new GameAction("tunnel", "Tunnel")
{
function = delegate { if (Tunnel.instance != null) {
var e = eventCaller.currentEntity;
Tunnel.instance.StartTunnel(e.beat, e.length, e["volume"] / 100f, e["duration"]);
} },
defaultLength = 4f,
resizable = true,
parameters = new List<Param>()
{
Mass Text Update (#615) * Air Rally Text Update * Blue Bear Text Update * Board Meeting Text Update * Built To Scale DS Text Update also changed Air Rally's assetbundle tag from "normal" to "keep" * Catchy Tune Text Update also changed some minor wording in Board Meeting and Built To Scale DS * Cheer Readers Text Update * The Clappy Trio Text Update * Coin Toss Text Update * Crop Stomp Text Update * DJ School Text Update * Dog Ninja Text Update * Double Date Text Update * Drumming Practice Text Update * Fan Club Text Update * Fireworks Text Update * Second Contact Text Update * Flipper-Flop Text Update also fix an error in Catchy Tune * Fork Lifter Text Update * Glee Club Text Update * Karate Man Text Update also minor updates to other games * Kitties! Text Update * Launch Party Text Update * Lockstep Text Update * Marching Orders Text Update * Meat Grinder Text Update also fixed an error in Second Contact * Mr. Upbeat Text Update * Munchy Monk Text Update * Octopus Machine Text Update * Pajama Party Text Update * Quiz Show Text Update also changed some wording in meat grinder * Rhythm Rally Text Update * Rhythm Somen Text Update that was easy * Rhythm Tweezers Text Update * Ringside Text Update * Rockers Text Update this sucked * Samurai Slice DS Text Update * See Saw Text Update * Sneaky Spirits Text Update * Spaceball Text Update * Space Dance Text Update * Space Soccer Text Update * Splashdown Text Update * Tambourine Text Update * Tap Trial Text Update * Tap Troupe Text Update * The Dazzles Text Update * Toss Boys Text Update * Tram & Pauline Text Update also added translation for Fireworks * Tunnel Text Update * Wizard's Waltz Text Update * Working Dough Text Update * fix compiler errors * fix editor offset bug(?) * fix missing param in second contact * Ball Redispense text * remove space soccer swing * Trick on the Class Text Update * Non-Game Text Update * fix pre-function sorting * camera shake ease * remove a bunch of prints * rhythm tweezers bug fix * Update Credits.txt * ssds nop samurai bop * swap order of shake properties * Update FirstContact.cs --------- Co-authored-by: minenice55 <star.elementa@gmail.com>
2024-01-15 02:04:10 +00:00
new Param("duration", new EntityTypes.Float(0, 8, 2), "Fade Duration", "Set how long it takes for the volume to fade."),
new Param("volume", new EntityTypes.Float(0, 200, 10), "Volume", "Set the volume to fade to while in the tunnel."),
}
},
new GameAction("countin", "Count In")
{
preFunction = delegate { Tunnel.CountIn(eventCaller.currentEntity.beat, eventCaller.currentEntity.length); },
defaultLength = 4f,
resizable = true,
},
new GameAction("bg", "Change Background")
{
function = delegate { Tunnel.instance?.SetBg(eventCaller.currentEntity["type"]); },
defaultLength = 1f,
resizable = false,
parameters = new List<Param>()
{
new Param("type", Tunnel.BgOption.Beach, "Background", "Set the background to change to."),
}
}
},
new List<string>() { "ntr", "keep" },
"ntrtunnel", "en",
new List<string>() { "en" },
chronologicalSortKey: 103
);
}
}
}
namespace HeavenStudio.Games
{
public class Tunnel : Minigame
{
const double PostTunnelScrnTime = 0.25;
public static Tunnel instance { get; set; }
[Header("Backgrounds")]
[SerializeField] GameObject[] bg;
[SerializeField] Material tunnelLightMaterial;
[SerializeField] Color tunnelTint;
[SerializeField] Color tunnelScreen;
[SerializeField] GameObject tunnelWall;
[SerializeField] SpriteRenderer tunnelWallRenderer;
[SerializeField] float tunnelChunksPerSec;
[SerializeField] float tunnelWallChunkSize;
Vector3 tunnelStartPos;
Sound tunnelSoundRight, tunnelSoundMiddle, tunnelSoundLeft;
2022-08-18 18:23:33 +00:00
[Header("References")]
[SerializeField] GameObject frontHand;
2022-08-18 18:23:33 +00:00
[Header("Animators")]
[SerializeField] Animator cowbellAnimator;
[SerializeField] Animator driverAnimator;
2022-08-18 18:23:33 +00:00
[Header("Curves")]
[SerializeField] BezierCurve3D handCurve;
2022-08-18 18:23:33 +00:00
public enum BgOption
{
Beach,
Desert,
Field,
City,
Night,
MoaiDooWop,
CropStomp,
QuizShow
}
2022-08-18 18:23:33 +00:00
float fadeDuration = 2f;
double tunnelStartTime = double.MinValue;
double tunnelEndTime = double.MinValue;
double lastCowbell = double.MaxValue;
2022-08-18 18:23:33 +00:00
float handStart;
float handProgress;
bool inTunnel;
public struct QueuedCowbell
{
public double beat;
public float length;
}
static List<QueuedCowbell> queuedInputs = new List<QueuedCowbell>();
2022-08-18 18:23:33 +00:00
private void Awake()
{
instance = this;
tunnelStartPos = new Vector3(tunnelWallChunkSize, 0, 0);
2022-08-18 03:33:05 +00:00
}
void OnDestroy()
{
if (queuedInputs.Count > 0) queuedInputs.Clear();
foreach (var evt in scheduledInputs)
{
evt.Disable();
}
if (conductor != null && !(conductor.isPlaying || conductor.isPaused))
{
conductor.FadeMinigameVolume(conductor.songPositionInBeatsAsDouble, 0, 1);
tunnelLightMaterial.SetColor("_Color", Color.white);
tunnelLightMaterial.SetColor("_AddColor", Color.black);
tunnelSoundRight?.KillLoop();
tunnelSoundMiddle?.KillLoop();
tunnelSoundLeft?.KillLoop();
}
}
2022-08-18 03:33:05 +00:00
2024-01-17 23:49:14 +00:00
public override void OnPlay(double beat)
{
queuedInputs.Clear();
}
2022-08-18 03:33:05 +00:00
private void Start()
{
2022-08-18 18:23:33 +00:00
handStart = -1f;
tunnelWall.SetActive(false);
}
private void Update()
{
//update hand position
handProgress = Math.Min(base.conductor.songPositionInBeats - handStart, 1);
2022-08-20 18:45:54 +00:00
frontHand.transform.position = handCurve.GetPoint(EasingFunction.EaseOutQuad(0, 1, handProgress));
if (!conductor.isPlaying || conductor.isPaused)
{
return;
}
if (PlayerInput.GetIsAction(InputAction_BasicPress) && !IsExpectingInputNow(InputAction_BasicPress))
2022-08-18 03:33:05 +00:00
{
HitCowbell();
//print("unexpected input");
driverAnimator.Play("Angry1", -1, 0);
2022-08-18 03:33:05 +00:00
}
if (queuedInputs.Count > 0)
{
foreach (var input in queuedInputs)
{
StartCowbell(input.beat, input.length);
}
queuedInputs.Clear();
}
2022-08-18 18:23:33 +00:00
if (lastCowbell + 1 <= conductor.songPositionInBeatsAsDouble)
{
lastCowbell++;
ScheduleInput(lastCowbell, 1, InputAction_BasicPress, CowbellSuccess, CowbellMiss, CowbellEmpty);
}
// bg.localPosition = new Vector3(bgStartX - (2 * bgStartX * (((float)Time.realtimeSinceStartupAsDouble % bgScrollTime) / bgScrollTime)), 0, 0);
if (tunnelWall.activeSelf)
{
tunnelWall.transform.localPosition = tunnelStartPos - new Vector3(tunnelChunksPerSec * tunnelWallChunkSize * (float)(conductor.songPositionAsDouble - tunnelStartTime), 0, 0);
}
if (inTunnel && conductor.songPositionAsDouble >= tunnelEndTime + PostTunnelScrnTime)
{
conductor.FadeMinigameVolume(conductor.GetBeatFromSongPos(tunnelEndTime + PostTunnelScrnTime), fadeDuration, 1);
tunnelLightMaterial.SetColor("_Color", Color.white);
tunnelLightMaterial.SetColor("_AddColor", Color.black);
inTunnel = false;
}
}
2022-08-18 03:33:05 +00:00
public void HitCowbell()
{
SoundByte.PlayOneShot("count-ins/cowbell");
2022-08-18 23:28:23 +00:00
handStart = conductor.songPositionInBeats;
cowbellAnimator.Play("Shake", -1, 0);
2022-08-18 03:33:05 +00:00
}
public static void PreStartCowbell(double beat, float length)
{
if (GameManager.instance.currentGame == "tunnel")
{
instance.StartCowbell(beat, length);
}
else
{
queuedInputs.Add(new QueuedCowbell { beat = beat, length = length });
}
}
public void StartCowbell(double beat, float length)
{
lastCowbell = beat - 1;
ScheduleInput(lastCowbell, 1, InputAction_BasicPress, CowbellSuccess, CowbellMiss, CowbellEmpty);
}
2022-08-18 03:33:05 +00:00
public void CowbellSuccess(PlayerActionEvent caller, float state)
{
2022-08-18 03:33:05 +00:00
HitCowbell();
if (Math.Abs(state) >= 1f)
{
driverAnimator.Play("Disturbed", -1, 0);
}
else
{
driverAnimator.Play("Idle", -1, 0);
}
}
2022-08-18 03:33:05 +00:00
public void CowbellMiss(PlayerActionEvent caller)
{
driverAnimator.Play("Angry1", -1, 0);
}
public void CowbellEmpty(PlayerActionEvent caller) { }
public static void CountIn(double beat, float length)
2022-08-19 04:19:08 +00:00
{
2022-08-20 19:48:56 +00:00
List<MultiSound.Sound> cuelist = new List<MultiSound.Sound>();
for (int i = 0; i < length; i++)
2022-08-19 04:19:08 +00:00
{
if (i % 2 == 0)
2022-08-19 04:19:08 +00:00
{
2022-08-20 19:48:56 +00:00
//Jukebox.PlayOneShotGame("tunnel/en/one", beat+i);
//print("cueing one at " + (beat + i));
cuelist.Add(new MultiSound.Sound("tunnel/en/one", beat + i));
2022-08-19 04:19:08 +00:00
}
else
{
2022-08-20 19:48:56 +00:00
//Jukebox.PlayOneShotGame("tunnel/en/two", beat+i);
//print("cueing two at " + (beat + i));
cuelist.Add(new MultiSound.Sound("tunnel/en/two", beat + i));
2022-08-19 04:19:08 +00:00
}
2022-08-19 04:19:08 +00:00
}
MultiSound.Play(cuelist.ToArray(), forcePlay: true);
2022-08-19 04:19:08 +00:00
}
public void StartTunnel(double beat, double length, float volume = 0.1f, float fadeDuration = 2f)
{
if (conductor.songPositionAsDouble < tunnelEndTime + PostTunnelScrnTime)
{
return;
}
double targetBeat = beat + length;
tunnelStartTime = conductor.GetSongPosFromBeat(beat);
tunnelEndTime = conductor.GetSongPosFromBeat(targetBeat);
// tunnel chunks can be divided into quarters
double durationSec = Math.Ceiling((tunnelEndTime - tunnelStartTime) * 4 * tunnelChunksPerSec) * 0.25 / tunnelChunksPerSec;
tunnelWallRenderer.size = new Vector2((float)durationSec * tunnelWallChunkSize * tunnelChunksPerSec, 13.7f);
tunnelWall.transform.localPosition = tunnelStartPos;
tunnelWall.SetActive(true);
this.fadeDuration = fadeDuration;
conductor.FadeMinigameVolume(beat, fadeDuration, volume);
tunnelSoundRight?.KillLoop();
tunnelSoundMiddle?.KillLoop();
tunnelSoundLeft?.KillLoop();
tunnelSoundRight = SoundByte.PlayOneShotGame("tunnel/tunnelRight", beat, looping: true);
tunnelSoundMiddle = SoundByte.PlayOneShotGame("tunnel/tunnelMiddle", beat + (6 / 48f), looping: true);
tunnelSoundLeft = SoundByte.PlayOneShotGame("tunnel/tunnelLeft", beat + (12 / 48f), looping: true);
double tunnelEnd = conductor.GetBeatFromSongPos(tunnelEndTime + PostTunnelScrnTime);
tunnelSoundRight.SetLoopParams(tunnelEnd, 0.1);
tunnelSoundMiddle.SetLoopParams(tunnelEnd + (6 / 48f), 0.1);
tunnelSoundLeft.SetLoopParams(tunnelEnd + (12 / 48f), 0.25);
BeatAction.New(this, new List<BeatAction.Action>()
{
new BeatAction.Action(conductor.GetBeatFromSongPos(tunnelStartTime + 0.25), delegate {
tunnelLightMaterial.SetColor("_Color", tunnelTint);
tunnelLightMaterial.SetColor("_AddColor", tunnelScreen);
}),
});
inTunnel = true;
}
public void SetBg(int type)
{
foreach (var b in bg)
{
b.SetActive(false);
}
bg[type].SetActive(true);
}
}
}