HeavenStudio/Assets/Scripts/Games/SlotMonster/SlotMonster.cs
AstrlJelly fe6d213aac eye barelies, consecutive c&rs
we're so close!
2024-02-12 22:11:50 -05:00

298 lines
12 KiB
C#

using System;
using System.Collections.Generic;
using UnityEngine;
using HeavenStudio.Util;
using HeavenStudio.InputSystem;
using Jukebox;
namespace HeavenStudio.Games.Loaders
{
using static Minigames;
public static class NtrSlotMonsterLoader
{
public static Minigame AddGame(EventCaller eventCaller)
{
return new Minigame("slotMonster", "Slot Monster", "ffffff", false, false, new List<GameAction>()
{
new GameAction("startInterval", "Start Interval")
{
function = delegate {
if (eventCaller.gameManager.minigameObj.TryGetComponent(out SlotMonster instance)) {
var e = eventCaller.currentEntity;
instance.StartInterval(e.beat, e.length, e["auto"], e["eyeType"], 0);
}
},
defaultLength = 3f,
resizable = true,
preFunctionLength = 1,
priority = 2,
parameters = new List<Param>()
{
new Param("auto", true, "Auto Pass Turn", "Toggle if the turn should be passed automatically at the end of the start interval."),
new Param("eyeType", SlotMonster.EyeTypes.Random, "Eye Sprite", "Set the eye sprite to be used."),
},
},
new GameAction("slot", "Slot")
{
inactiveFunction = delegate {
// SoundByte.PlayOneShotGame("slotMonster/start_touch", eventCaller.currentEntity.beat, forcePlay: true);
SoundByte.PlayOneShotGame("slotMonster/start_touch", forcePlay: true);
},
defaultLength = 0.5f,
priority = 1,
parameters = new List<Param>()
{
new Param("drum", SlotMonster.DrumTypes.Default, "Drum SFX", "Set the drum SFX to be used. Default is Bass on the beat, and Snare off the beat.")
},
},
new GameAction("passTurn", "Pass Turn")
{
function = delegate {
if (eventCaller.gameManager.minigameObj.TryGetComponent(out SlotMonster instance)) {
var e = eventCaller.currentEntity;
instance.PassTurn(e.beat, e.length);
}
},
defaultLength = 1f,
priority = 1,
},
new GameAction("buttonColor", "Button Color")
{
function = delegate {
if (eventCaller.gameManager.minigameObj.TryGetComponent(out SlotMonster instance)) {
var e = eventCaller.currentEntity;
instance.ButtonColor(new Color[] { e["button1"], e["button2"], e["button3"] }, e["flash"]);
}
},
defaultLength = 1f,
priority = 1,
parameters = new List<Param>()
{
new Param("button1", new Color(0.38f, 0.98f, 0.25f), "Button 1 Color", "Set the color of the first button."),
new Param("button2", new Color(0.8f, 0.28f, 0.95f), "Button 2 Color", "Set the color of the second button."),
new Param("button3", new Color(0.87f, 0f, 0f), "Button 3 Color", "Set the color of the third button."),
new Param("flash", new Color(1f, 1f, 0.68f), "Button Flash Color", "Set the color of the flash of the buttons."),
},
},
}
);
}
}
}
namespace HeavenStudio.Games
{
using Scripts_SlotMonster;
public class SlotMonster : Minigame
{
public enum DrumTypes
{
Default,
Bass,
Snare,
}
public enum EyeTypes
{
Random,
Note,
Ring,
Cake,
Flower,
Beverage,
Mushroom,
Key,
Ribbon,
Hat,
Barista,
}
[Header("Animators")]
[SerializeField] Animator smAnim;
[SerializeField] Animator[] eyeAnims;
[SerializeField] SlotButton[] buttons;
public Color buttonFlashColor;
private List<RiqEntity> gameEntities;
private Sound rollingSound;
private int currentEyeSprite = 1;
private int maxButtons;
private int currentButton;
private void Awake()
{
foreach (var button in buttons) {
button.Init(this);
}
}
private void Update()
{
if (PlayerInput.GetIsAction(InputAction_BasicPress) && !IsExpectingInputNow(InputAction_BasicPress)) {
_ = HitButton();
ScoreMiss();
}
}
public override void OnPlay(double beat)
{
OnGameSwitch(beat);
}
public override void OnGameSwitch(double beat)
{
gameEntities = GameManager.instance.Beatmap.Entities.FindAll(c => c.datamodel.Split('/')[0] == "slotMonster");
foreach (RiqEntity e in gameEntities.FindAll(e => e.datamodel == "slotMonster/startInterval" && e.beat < beat && e.beat + e.length > beat)) {
StartInterval(e.beat, e.length, e["auto"], e["eyeType"], beat);
}
}
// make sure the current button is always between 0 and 2 (buttons 1-3)
private int GetCurrentButton() => Array.FindIndex(buttons, button => !button.pressed);
private bool HitButton(bool isHit = false, int timing = 0) // returns true if it's the last one
{
int thisButton = GetCurrentButton();
if (thisButton == -1) return false;
bool isLast = thisButton == maxButtons - 1;
string hitSfx = "slotMonster/stop_" + (isLast && isHit ? "hit" : (thisButton + 1));
SoundByte.PlayOneShotGame(hitSfx, forcePlay: true);
for (int i = thisButton; i < (isLast ? 3 : thisButton + 1); i++)
{
buttons[thisButton].Press();
if (eyeAnims[thisButton].IsPlayingAnimationNames("Spin")) {
int eyeSprite = currentEyeSprite;
string anim = "EyeItem";
if (!isHit) {
do {
eyeSprite = UnityEngine.Random.Range(0, 9);
} while (eyeSprite == (currentEyeSprite - 1));
anim += eyeSprite + 1;
} else {
if (timing == 1) {
eyeSprite = (eyeSprite + 1) % 9;
}
anim += eyeSprite + 1;
if (timing != 0) {
// string += lol
anim += "Barely";
}
}
Debug.Log(anim);
eyeAnims[thisButton].Play(anim, 0, 0);
}
}
if (isLast) {
if (rollingSound != null) rollingSound.Stop();
}
currentButton++;
return isLast && isHit;
}
public void StartInterval(double beat, float length, bool autoPass, int eyeSprite, double gameSwitchBeat)
{
List<RiqEntity> slotActions = gameEntities.FindAll(e => e.datamodel == "slotMonster/slot" && e.beat >= beat && e.beat < beat + length);
SoundByte.PlayOneShotGame("slotMonster/start_touch", forcePlay: true);
smAnim.DoScaledAnimationFromBeatAsync("Prepare", 0.5f, beat);
foreach (var button in buttons) {
button.anim.Play("PopUp", 0, 1);
}
List<MultiSound.Sound> sounds = new();
List<BeatAction.Action> actions = new();
maxButtons = Mathf.Min(slotActions.Count, 3);
for (int i = 0; i < maxButtons; i++) // limit to 3 actions
{
buttons[i].anim.Play("PopUp", 0, 0);
buttons[i].pressed = false;
eyeAnims[i].Play("Idle", 0, 1);
int whichSlot = i;
RiqEntity slot = slotActions[whichSlot];
// buttons[i].timing = slot.beat;
if (slot.beat < gameSwitchBeat) continue;
string sfx = "";
if (slot["drum"] == (int)DrumTypes.Default) {
sfx = slot.beat % 1 == 0 ? "bass" : "snare";
} else {
sfx = Enum.GetName(typeof(DrumTypes), (int)slot["drum"]).ToLower();
}
// Debug.Log(sfx);
sounds.Add(new(sfx + "DrumNTR", slot.beat));
actions.Add(new(slot.beat, delegate {
buttons[whichSlot].TryFlash();
}));
}
MultiSound.Play(sounds.ToArray(), false);
BeatAction.New(this, actions);
if (autoPass) {
BeatAction.New(this, new() { new(beat + length, delegate {
currentEyeSprite = eyeSprite == 0 ? UnityEngine.Random.Range(1, 10) : eyeSprite;
PassTurn(beat + length, 1, beat, slotActions);
})});
}
}
public void PassTurn(double beat, float length, double startBeat = -1, List<RiqEntity> slotActions = null)
{
smAnim.DoScaledAnimationFromBeatAsync("Release", 0.5f, beat);
for (int i = 0; i < eyeAnims.Length; i++) {
eyeAnims[i].DoScaledAnimationAsync("Spin", 0.5f);
}
SoundByte.PlayOneShotGame("slotMonster/start_rolling", forcePlay: true);
rollingSound = SoundByte.PlayOneShotGame("slotMonster/rolling", looping: true, forcePlay: true);
if (startBeat < 0 || slotActions == null) {
var startInterval = gameEntities.FindLast(e => e.datamodel == "slotMonster/startInterval" && e.beat + e.length < beat);
startBeat = startInterval.beat;
slotActions ??= gameEntities.FindAll(e => e.datamodel == "slotMonster/slot" && e.beat >= startInterval.beat && e.beat < startInterval.beat + startInterval.length);
}
List<BeatAction.Action> actions = new();
for (int i = 0; i < Mathf.Min(slotActions.Count, 3); i++) // limit to 3 actions
{
int whichSlot = i;
double slotBeat = slotActions[i].beat;
actions.Add(new(beat + length + slotBeat - startBeat, delegate {
buttons[whichSlot].TryFlash();
}));
PlayerActionEvent input = ScheduleInput(beat, slotBeat - startBeat + length, InputAction_BasicPress, ButtonHit, null, null);
// input.IsHittable = () => { // ugh this breaks the input check
// int currentButton = GetCurrentButton();
// return currentButton == whichSlot && !buttonsPressed[whichSlot];
// };
}
BeatAction.New(this, actions);
}
private void ButtonHit(PlayerActionEvent caller, float state)
{
int timing = state switch {
>= 1f => -1,
<= -1f => 1,
_ => 0,
};
bool isWin = HitButton(true, timing);
if (isWin) {
if (rollingSound != null) rollingSound.Stop();
smAnim.DoScaledAnimationAsync("Win", 0.5f);
}
if (state is >= 1f or <= -1f) SoundByte.PlayOneShot("nearMiss");
}
public void ButtonColor(Color[] colors, Color flashColor)
{
for (int i = 0; i < buttons.Length; i++) {
buttons[i].color = colors[i];
}
buttonFlashColor = flashColor;
}
}
}