Mannequin Factory (#499)

* everything

yeah. everything..?
just needs an icon

* ass buns

* clean up + split up the blocks

* quick refresh

just so this doesn't get stale and fall behind in the codebase

* NOT DONE YET! gonna finish tomorrow

* it's done!!

* oh oops gotta actually load the game
This commit is contained in:
AstrlJelly
2024-01-29 21:41:35 -05:00
committed by GitHub
parent 3b7c0dc96a
commit f938ab84f5
81 changed files with 15755 additions and 0 deletions

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8fc314cb83e13a24a894d3465ad40476
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,233 @@
using System.Collections.Generic;
using HeavenStudio.Util;
using HeavenStudio.InputSystem;
using UnityEngine;
using TMPro;
using DG.Tweening;
namespace HeavenStudio.Games.Loaders
{
using static Minigames;
public static class AgbMannequinFactoryLoader
{
public static Minigame AddGame(EventCaller eventCaller) {
return new Minigame("mannequinFactory", "Mannequin Factory", "554899", false, false, new List<GameAction>()
{
new GameAction("headOut", "Send Head Out")
{
inactiveFunction = delegate {
MannequinFactory.HeadOutSFX(eventCaller.currentEntity.beat, 0);
},
function = delegate {
MannequinFactory.HeadOutSFX(eventCaller.currentEntity.beat, 0);
if (eventCaller.gameManager.minigameObj.TryGetComponent(out MannequinFactory instance)) {
instance.HeadOut(eventCaller.currentEntity.beat, 0);
}
},
defaultLength = 7,
},
new GameAction("misalignedHeadOut", "Send Misaligned Head Out")
{
inactiveFunction = delegate {
MannequinFactory.HeadOutSFX(eventCaller.currentEntity.beat, 1);
},
function = delegate {
MannequinFactory.HeadOutSFX(eventCaller.currentEntity.beat, 1);
if (eventCaller.gameManager.minigameObj.TryGetComponent(out MannequinFactory instance)) {
instance.HeadOut(eventCaller.currentEntity.beat, 1);
}
},
defaultLength = 7,
},
new GameAction("randomHeadOut", "Send Random Head Out")
{
// inactiveFunction = delegate {
// int random = Random.Range(0, 2);
// MannequinFactory.HeadOutSFX(eventCaller.currentEntity.beat, random);
// },
function = delegate {
int random = Random.Range(0, 2);
MannequinFactory.HeadOutSFX(eventCaller.currentEntity.beat, random);
if (eventCaller.gameManager.minigameObj.TryGetComponent(out MannequinFactory instance)) {
instance.HeadOut(eventCaller.currentEntity.beat, random);
}
},
defaultLength = 7,
},
new GameAction("changeText", "Change Text")
{
function = delegate {
if (eventCaller.gameManager.minigameObj.TryGetComponent(out MannequinFactory instance)) {
instance.SignText.text = eventCaller.currentEntity["text"];
}
},
defaultLength = 0.5f,
parameters = new List<Param>()
{
new Param("text", "Mannequin Factory", "Text", "The text to be displayed on the sign"),
}
},
new GameAction("bgColor", "Change Background Color")
{
function = delegate {
if (eventCaller.gameManager.minigameObj.TryGetComponent(out MannequinFactory instance)) {
var e = eventCaller.currentEntity;
instance.BackgroundColor(e.beat, e.length, e["colorStart"], e["colorEnd"], e["ease"]);
}
},
parameters = new List<Param>()
{
new Param("colorStart", new Color(0.97f, 0.94f, 0.51f, 1f), "Start Color", "The color to start fading from."),
new Param("colorEnd", new Color(0.97f, 0.94f, 0.51f, 1f), "End Color", "The color to end the fade."),
new Param("ease", Util.EasingFunction.Ease.Linear, "Ease", "The ease to use for color fade", new() {
new Param.CollapseParam((x, _) => (int)x != (int)Util.EasingFunction.Ease.Instant, new[] { "colorStart" }),
}),
},
resizable = true
},
},
new List<string>() {"agb", "normal"},
"agbmannequin", "en",
new List<string>() {}
);
}
}
}
namespace HeavenStudio.Games
{
using Scripts_MannequinFactory;
public class MannequinFactory : Minigame
{
[Header("Animators")]
public Animator HandAnim;
public Animator StampAnim;
[Header("References")]
[SerializeField] SpriteRenderer bg;
public TMP_Text SignText;
public GameObject MannequinHeadObject;
public double slapScheduledBeat = double.MinValue;
private double colorStartBeat = -1;
private float colorLength = 0f;
private Color colorStart, colorEnd = new Color(0.97f, 0.94f, 0.51f, 1f); // default bg color
private Util.EasingFunction.Ease colorEase;
protected static bool IA_PadLeft(out double dt)
{
return PlayerInput.GetPadDown(InputController.ActionsPad.Left, out dt);
}
public static PlayerInput.InputAction InputAction_First =
new("AgbMannequinFactoryTouchFirst", new int[] { IAPressCat, IAPressCat, IAPressCat },
IA_PadLeft, IA_TouchFlick, IA_Empty);
public static PlayerInput.InputAction InputAction_Second =
new("AgbMannequinFactoryTouchSecond", new int[] { IAPressCat, IAPressCat, IAPressCat },
IA_PadBasicPress, IA_TouchBasicPress, IA_Empty);
private void Update()
{
if (PlayerInput.GetIsAction(InputAction_First) && !IsExpectingInputNow(InputAction_First)
&& !HandAnim.IsPlayingAnimationNames("SlapEmpty", "SlapJust"))
{
HandAnim.DoScaledAnimationAsync("SlapEmpty", 0.3f);
}
bool canSlap = PlayerInput.CurrentControlStyle != InputController.ControlStyles.Touch || slapScheduledBeat < conductor.songPositionInBeatsAsDouble;
if (PlayerInput.GetIsAction(InputAction_Second) && !IsExpectingInputNow(InputAction_Second)
&& !StampAnim.IsPlayingAnimationNames("StampEmpty", "StampJust") && canSlap)
{
StampAnim.DoScaledAnimationAsync("StampEmpty", 0.3f);
}
float normalizedBeat = Mathf.Clamp01(Conductor.instance.GetPositionFromBeat(colorStartBeat, colorLength));
var func = Util.EasingFunction.GetEasingFunction(colorEase);
float newR = func(colorStart.r, colorEnd.r, normalizedBeat);
float newG = func(colorStart.g, colorEnd.g, normalizedBeat);
float newB = func(colorStart.b, colorEnd.b, normalizedBeat);
bg.color = new Color(newR, newG, newB);
}
public override void OnPlay(double beat) => StartGame(beat, true);
public override void OnGameSwitch(double beat) => StartGame(beat, false);
private void StartGame(double beat, bool isPlay)
{
var events = gameManager.Beatmap.Entities.FindAll(e => e.datamodel.Split('/')[0] == "mannequinFactory");
foreach (var e in events)
{
if (e.beat < beat && e.beat + 2.75 > beat && e.datamodel is "mannequinFactory/headOut" or "mannequinFactory/misalignedHeadOut" /* or "mannequinFactory/randomHeadOut" */) {
int cueType = e.datamodel switch {
"mannequinFactory/headOut" => 0,
"mannequinFactory/misalignedHeadOut" => 1,
"mannequinFactory/randomHeadOut" or _ => Random.Range(0, 2),
};
HeadOut(e.beat, cueType);
if (isPlay) {
HeadOutSFX(e.beat, cueType, beat);
}
}
}
var bg = events.FindLast(e => e.datamodel == "mannequinFactory/bgColor" && e.beat < beat);
if (bg != null) {
BackgroundColor(bg.beat, bg.length, bg["colorStart"], bg["colorEnd"], bg["ease"]);
} else {
Color color = new Color(0.97f, 0.94f, 0.51f, 1f);
BackgroundColor(0, 0, color, color, (int)EasingFunction.Ease.Instant);
}
}
public static void HeadOutSFX(double beat, int cueType, double fromBeat = 0)
{
var sfx = new List<MultiSound.Sound>() {
new("mannequinFactory/drum", beat ),
new("mannequinFactory/drum", beat + 0.5),
new("mannequinFactory/drum", beat + 1.5),
new("mannequinFactory/drum", beat + 2 ),
new("mannequinFactory/whoosh", beat + 5),
};
if (cueType == 0) {
for (int i = 0; i < 7; i++) {
sfx.Add(new($"mannequinFactory/drumroll{i + 1}", beat + 3 + (i * 0.1667)));
}
} else {
sfx.AddRange(new MultiSound.Sound[] {
new("mannequinFactory/drum", beat + 0.75),
new("mannequinFactory/drum", beat + 1 ),
new("mannequinFactory/whoosh", beat + 3),
});
}
sfx.Sort((x, y) => x.beat.CompareTo(y.beat));
sfx.RemoveAll(x => x.beat < fromBeat);
if (sfx.Count > 0) {
MultiSound.Play(sfx.ToArray(), forcePlay: true);
}
}
public void HeadOut(double beat, int cueType)
{
MannequinHead head = Instantiate(MannequinHeadObject, transform).GetComponent<MannequinHead>();
head.game = this;
head.startBeat = beat;
head.needSlap = cueType == 1;
}
public void BackgroundColor(double beat, float length, Color colorStartSet, Color colorEndSet, int ease)
{
colorStartBeat = beat;
colorLength = length;
colorStart = colorStartSet;
colorEnd = colorEndSet;
colorEase = (Util.EasingFunction.Ease)ease;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d0697b066afb3aa41a8bef8800523a8b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,136 @@
using System.Collections.Generic;
using UnityEngine;
using HeavenStudio.Util;
namespace HeavenStudio.Games.Scripts_MannequinFactory
{
public class MannequinHead : MonoBehaviour
{
public double startBeat;
public bool needSlap;
[Header("Animators")]
[SerializeField] SpriteRenderer headSr;
[SerializeField] Sprite[] heads;
[SerializeField] SpriteRenderer eyesSr;
[SerializeField] Sprite[] eyes;
[SerializeField] Animator headAnim;
int turnStatus;
public MannequinFactory game;
private void Start()
{
game.slapScheduledBeat = startBeat + 4;
turnStatus = needSlap ? 0 : 1;
headSr.sprite = heads[turnStatus];
BeatAction.New(game, new List<BeatAction.Action> {
new(startBeat + 1, delegate { headAnim.DoScaledAnimationAsync("Move1", 0.3f); }),
new(startBeat + 3, delegate { if (game.gameManager.autoplay) headAnim.DoScaledAnimationAsync("Move2", 0.3f); }),
new(startBeat + 4, delegate {
PlayerActionEvent input;
if (turnStatus == 1) {
input = game.ScheduleInput(startBeat, 5, MannequinFactory.InputAction_Second, StampJust, StampMiss, null);
} else {
input = game.ScheduleUserInput(startBeat, 5, MannequinFactory.InputAction_Second, StampUnJust, StampMiss, null);
}
input.IsHittable = () => !game.StampAnim.IsPlayingAnimationNames("StampEmpty", "StampJust");
}),
});
PlayerActionEvent input;
if (needSlap) {
input = game.ScheduleInput(startBeat, 3, MannequinFactory.InputAction_First, SlapJust, SlapMiss, null);
} else {
input = game.ScheduleUserInput(startBeat, 3, MannequinFactory.InputAction_First, SlapUnJust, SlapMiss, null);
}
input.IsHittable = () => !game.HandAnim.IsPlayingAnimationNames("SlapEmpty", "SlapJust");
}
private void SlapJust(PlayerActionEvent caller, float state)
{
SlapHit(state);
headSr.sprite = heads[turnStatus];
}
private void SlapUnJust(PlayerActionEvent caller, float state)
{
eyesSr.transform.localScale = new Vector2(-1, 1);
headSr.transform.localScale = new Vector2(-1, 1);
headSr.sprite = heads[0];
game.ScoreMiss();
SlapHit(state);
}
private void SlapHit(float state)
{
if (state >= 1f || state <= -1f) SoundByte.PlayOneShot("nearMiss");
turnStatus++;
SoundByte.PlayOneShotGame("mannequinFactory/slap");
game.HandAnim.DoScaledAnimationAsync("SlapJust", 0.3f);
headAnim.Play("Slapped", 0, 0);
}
private void SlapMiss(PlayerActionEvent caller)
{
headAnim.DoScaledAnimationAsync("Move2", 0.3f);
}
private void StampHit(float state)
{
if (state >= 1f || state <= -1f) SoundByte.PlayOneShot("nearMiss");
headAnim.DoScaledAnimationAsync("Stamp", 0.3f);
game.StampAnim.DoScaledAnimationAsync("StampJust", 0.3f);
SoundByte.PlayOneShotGame("mannequinFactory/eyes");
eyesSr.gameObject.SetActive(true);
}
private void StampJust(PlayerActionEvent caller, float state)
{
StampHit(state);
MultiSound.Play(new MultiSound.Sound[] {
new MultiSound.Sound("mannequinFactory/claw1", startBeat + 6),
new MultiSound.Sound("mannequinFactory/claw2", startBeat + 6.5),
});
BeatAction.New(game, new List<BeatAction.Action> {
new BeatAction.Action(startBeat + 5.75, delegate { headAnim.DoScaledAnimationAsync("Grabbed1", 0.3f); }),
new BeatAction.Action(startBeat + 6 , delegate { headAnim.DoScaledAnimationAsync("Grabbed2", 0.3f); }),
});
}
private void StampUnJust(PlayerActionEvent caller, float state)
{
StampHit(state);
eyesSr.sprite = eyes[1];
BeatAction.New(game, new List<BeatAction.Action> {
new BeatAction.Action(startBeat + 6, delegate {
SoundByte.PlayOneShotGame("mannequinFactory/miss");
headAnim.DoScaledAnimationAsync("StampMiss", 0.3f);
}),
});
}
private void StampMiss(PlayerActionEvent caller)
{
headAnim.DoScaledAnimationAsync("Move3", 0.3f);
BeatAction.New(game, new List<BeatAction.Action> {
new BeatAction.Action(startBeat + 6.5, delegate {
SoundByte.PlayOneShotGame("mannequinFactory/miss");
headAnim.DoScaledAnimationAsync("Miss", 0.3f);
}),
});
}
// animation event
public void DestroySelf()
{
Destroy(this);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e6b776b7f3531104982259e4ca09d7d5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -266,6 +266,17 @@ namespace HeavenStudio
Debug.LogWarning("Game loader NtrBackbeatLoader failed!");
}
Debug.Log("Running game loader AgbMannequinFactoryLoader");
game = AgbMannequinFactoryLoader.AddGame(eventCaller);
if (game != null)
{
eventCaller.minigames.Add(game.name, game);
}
else
{
Debug.LogWarning("Game loader AgbMannequinFactoryLoader failed!");
}
Debug.Log("Running game loader RvlManzaiLoader");
game = RvlManzaiLoader.AddGame(eventCaller);
if (game != null)

View File

@ -73,6 +73,10 @@ namespace HeavenStudio.Util
if (!double.IsNaN(startBeat)) {
var cond = Conductor.instance;
var animClip = Array.Find(anim.runtimeAnimatorController.animationClips, x => x.name == animName);
if (animClip == null) {
Debug.LogError("Animation clip " + animName + " not found!");
return;
}
double animLength = cond.SecsToBeats(animClip.length, cond.GetBpmAtBeat(startBeat));
pos = cond.GetPositionFromBeat(startBeat, animLength) * timeScale;
} else {