Merge branch 'master' into game-mobTrick

This commit is contained in:
minenice55
2022-06-19 21:47:42 -04:00
910 changed files with 394879 additions and 5059 deletions

View File

@ -41,6 +41,9 @@ namespace HeavenStudio
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public Color colorA;
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public Color colorB;
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public Color colorC;
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public string text1;
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public string text2;
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public string text3;
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public float swing;
public string datamodel;
[JsonIgnore] public Editor.Track.TimelineEventObj eventObj;

View File

@ -0,0 +1,36 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
namespace HeavenStudio.TextboxUtilities
{
public class TextboxObject : MonoBehaviour
{
[Header("Objects")]
public TMP_Text TextboxLabel;
public RectTransform TextboxLabelRect;
public SpriteRenderer UL;
public SpriteRenderer UR;
public SpriteRenderer DL;
public SpriteRenderer DR;
static Vector2 textboxSize = new Vector2(3f, 0.75f);
public void Resize(float scaleX, float scaleY)
{
Vector2 tScale = Vector2.Scale(textboxSize, new Vector2(scaleX, scaleY));
UL.size = tScale;
UR.size = tScale;
DL.size = tScale;
DR.size = tScale;
TextboxLabelRect.sizeDelta = new Vector2(11.2f * scaleX, 2.2f * scaleY);
}
public void SetText(string text)
{
TextboxLabel.text = text;
}
}
}

View File

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

View File

@ -85,6 +85,8 @@ namespace HeavenStudio
bool negativeOffset = firstBeatOffset < 0f;
bool negativeStartTime = false;
// Debug.Log("starting playback @ beat " + beat + ", offset is " + firstBeatOffset);
var startPos = GetSongPosFromBeat(beat);
if (negativeOffset)
{
@ -99,8 +101,10 @@ namespace HeavenStudio
else
time = startPos;
}
songPosBeat = time / secPerBeat;
//TODO: make this take into account past tempo changes
songPosBeat = GetBeatFromSongPos(time - firstBeatOffset);
// Debug.Log("corrected starting playback @ beat " + songPosBeat);
isPlaying = true;
isPaused = false;
@ -185,23 +189,24 @@ namespace HeavenStudio
{
Util.Jukebox.PlayOneShot("metronome");
}
else if (songPosition <= lastReportedBeat)
else if (songPositionInBeats < lastReportedBeat)
{
lastReportedBeat = (songPosition - (songPosition % secPerBeat));
lastReportedBeat = Mathf.Round(songPositionInBeats);
}
}
}
}
public bool ReportBeat(ref float lastReportedBeat, float offset = 0, bool shiftBeatToOffset = false)
public bool ReportBeat(ref float lastReportedBeat, float offset = 0, bool shiftBeatToOffset = true)
{
bool result = songPosition > (lastReportedBeat + offset) + secPerBeat;
if (result == true)
bool result = songPositionInBeats + (shiftBeatToOffset ? offset : 0f) >= (lastReportedBeat) + 1f;
if (result)
{
lastReportedBeat = (songPosition - (songPosition % secPerBeat));
if (!shiftBeatToOffset)
lastReportedBeat += offset;
lastReportedBeat += 1f;
if (lastReportedBeat < songPositionInBeats)
{
lastReportedBeat = Mathf.Round(songPositionInBeats);
}
}
return result;
}
@ -232,11 +237,93 @@ namespace HeavenStudio
return GetBeatFromPosition(position, targetBeat - margin, margin);
}
private List<Beatmap.TempoChange> GetSortedTempoChanges(Beatmap chart)
{
//iterate over all tempo changes, adding to counter
List<Beatmap.TempoChange> tempoChanges = chart.tempoChanges;
tempoChanges.Sort((x, y) => x.beat.CompareTo(y.beat)); //sorts all tempo changes by ascending time (GameManager already does this but juste en cas...)
return tempoChanges;
}
public float GetSongPosFromBeat(float beat)
{
return secPerBeat * beat;
Beatmap chart = GameManager.instance.Beatmap;
SetBpm(chart.bpm);
//initial counter
float counter = 0f;
//time of last tempo change, to know how much to add to counter
float lastTempoChangeBeat = 0f;
//iterate over all tempo changes, adding to counter
List<Beatmap.TempoChange> tempoChanges = GetSortedTempoChanges(chart);
foreach (var t in tempoChanges)
{
if (t.beat > beat)
{
// this tempo change is past our requested time, abort
break;
}
// Debug.Log("tempo change at " + t.beat);
counter += (t.beat - lastTempoChangeBeat) * secPerBeat;
// Debug.Log("counter is now " + counter);
// now update to new bpm
SetBpm(t.tempo);
lastTempoChangeBeat = t.beat;
}
//passed all past tempo changes, now extrapolate from last tempo change until requested position
counter += (beat - lastTempoChangeBeat) * secPerBeat;
// Debug.Log("GetSongPosFromBeat returning " + counter);
return counter;
}
//thank you @wooningcharithri#7419 for the psuedo-code
private float BeatsToSecs(float beats, float bpm)
{
// Debug.Log("BeatsToSecs returning " + beats / bpm * 60);
return beats / bpm * 60f;
}
private float SecsToBeats(float s, float bpm)
{
// Debug.Log("SecsToBeats returning " + s / 60f / bpm);
return s / 60f * bpm;
}
public float GetBeatFromSongPos(float seconds)
{
// Debug.Log("Getting beat of seconds " + seconds);
Beatmap chart = GameManager.instance.Beatmap;
float lastTempoChangeBeat = 0f;
float lastBpm = chart.bpm;
float counterSeconds = -firstBeatOffset;
List<Beatmap.TempoChange> tempoChanges = GetSortedTempoChanges(chart);
foreach (var t in tempoChanges)
{
float beatToNext = t.beat - lastTempoChangeBeat;
float secToNext = BeatsToSecs(beatToNext, lastBpm);
float nextSecs = counterSeconds + secToNext;
// Debug.Log("nextSecs is " + nextSecs + ", seconds " + seconds);
if (nextSecs >= seconds)
break;
lastTempoChangeBeat = t.beat;
lastBpm = t.tempo;
counterSeconds = nextSecs;
}
// Debug.Log("lastTempoChangeBeat is " + lastTempoChangeBeat + ", counterSeconds is " + counterSeconds);
return lastTempoChangeBeat + SecsToBeats(seconds - counterSeconds, lastBpm);
}
//
// convert real seconds to beats
public float GetRestFromRealTime(float seconds)
{
@ -257,7 +344,7 @@ namespace HeavenStudio
public float SongLengthInBeats()
{
if (!musicSource.clip) return 0;
return musicSource.clip.length / secPerBeat;
return GetBeatFromSongPos(musicSource.clip.length);
}
public bool SongPosLessThanClipLength(float t)

View File

@ -2,6 +2,9 @@ using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using HeavenStudio.Util;
using System.Linq;
namespace HeavenStudio
{
public class GameCamera : MonoBehaviour
@ -9,6 +12,42 @@ namespace HeavenStudio
public static GameCamera instance { get; private set; }
public new Camera camera;
private List<Beatmap.Entity> positionEvents = new List<Beatmap.Entity>();
private List<Beatmap.Entity> rotationEvents = new List<Beatmap.Entity>();
private List<Beatmap.Entity> scaleEvents = new List<Beatmap.Entity>();
/**
default cam position, for quick-resetting
**/
static Vector3 defaultPosition = new Vector3(0, 0, -10);
static Vector3 defaultRotEluer = new Vector3(0, 0, 0);
static Vector3 defaultScale = new Vector3(16, 9, 1);
/**
camera's current transformation
TODO: stretching (the scale param) not working, will need help with this cause I don't understand Unity's camera
**/
private static Vector3 position;
private static Vector3 rotEluer;
private static Vector3 scale;
/**
camera's last transformation
TODO: stretching (the scaleLast param) not working, will need help with this cause I don't understand Unity's camera
**/
private static Vector3 positionLast;
private static Vector3 rotEluerLast;
private static Vector3 scaleLast;
/**
transformations to apply *after* the global transform,
to use in minigame scripts (Spaceball, Rhythm Rally, Built to Scale, etc.)
and NOT in the editor
**/
public static Vector3 additionalPosition;
public static Vector3 additionalRotEluer;
public static Vector3 additionalScale;
[Header("Components")]
public Color baseColor;
@ -20,7 +59,111 @@ namespace HeavenStudio
private void Start()
{
GameManager.instance.onBeatChanged += OnBeatChanged;
camera.backgroundColor = baseColor;
ResetTransforms();
ResetAdditionalTransforms();
positionLast = defaultPosition;
rotEluerLast = defaultRotEluer;
scaleLast = defaultScale;
}
public void OnBeatChanged(float beat)
{
ResetTransforms();
ResetAdditionalTransforms();
positionLast = defaultPosition;
rotEluerLast = defaultRotEluer;
scaleLast = defaultScale;
// this entire thing is a mess redo it later
//pos
positionEvents = EventCaller.GetAllInGameManagerList("vfx", new string[] { "move camera" });
// legacy event
positionEvents.AddRange(EventCaller.GetAllInGameManagerList("gameManager", new string[] { "move camera" }));
//rot
rotationEvents = EventCaller.GetAllInGameManagerList("vfx", new string[] { "rotate camera" });
positionEvents.AddRange(EventCaller.GetAllInGameManagerList("gameManager", new string[] { "rotate camera" }));
//scale (TODO)
// scaleEvents = EventCaller.GetAllInGameManagerList("vfx", new string[] { "scale camera" });
UpdateCameraTranslate();
UpdateCameraRotate();
}
private void Update()
{
UpdateCameraTranslate();
UpdateCameraRotate();
Camera cam = GetCamera();
cam.transform.localPosition = position + additionalPosition;
cam.transform.eulerAngles = rotEluer + additionalRotEluer;
cam.transform.localScale = Vector3.Scale(scale, additionalScale);
}
private void UpdateCameraTranslate()
{
foreach (var e in positionEvents)
{
float prog = Conductor.instance.GetPositionFromBeat(e.beat, e.length);
if (prog >= 0f)
{
EasingFunction.Function func = EasingFunction.GetEasingFunction(e.ease);
float dx = func(positionLast.x, e.valA, Mathf.Min(prog, 1f));
float dy = func(positionLast.y, e.valB, Mathf.Min(prog, 1f));
float dz = func(positionLast.z, -e.valC, Mathf.Min(prog, 1f));
position = new Vector3(dx, dy, dz);
}
if (prog > 1f)
{
positionLast = new Vector3(e.valA, e.valB, -e.valC);
}
}
}
private void UpdateCameraRotate()
{
foreach (var e in rotationEvents)
{
float prog = Conductor.instance.GetPositionFromBeat(e.beat, e.length);
if (prog >= 0f)
{
EasingFunction.Function func = EasingFunction.GetEasingFunction(e.ease);
float dx = func(rotEluerLast.x, e.valA, Mathf.Min(prog, 1f));
float dy = func(rotEluerLast.y, e.valB, Mathf.Min(prog, 1f));
float dz = func(rotEluerLast.z, e.valC, Mathf.Min(prog, 1f));
rotEluer = new Vector3(dx, dy, dz);
}
if (prog > 1f)
{
rotEluerLast = new Vector3(e.valA, e.valB, -e.valC);
}
}
}
public static void ResetTransforms()
{
position = defaultPosition;
rotEluer = defaultRotEluer;
scale = defaultScale;
}
public static void ResetAdditionalTransforms()
{
additionalPosition = new Vector3(0, 0, 0);
additionalRotEluer = new Vector3(0, 0, 0);
additionalScale = new Vector3(1, 1, 1);
}
public static Camera GetCamera()
{
return instance.camera;
}
}
}

View File

@ -20,17 +20,18 @@ namespace HeavenStudio
[Header("Components")]
public TextAsset txt;
public Camera GameCamera, CursorCam;
public Camera GameCamera, CursorCam, OverlayCamera;
public CircleCursor CircleCursor;
[HideInInspector] public GameObject GamesHolder;
public Games.Global.Flash fade;
public GameObject textbox;
[Header("Games")]
public string currentGame;
Coroutine currentGameSwitchIE;
[Header("Properties")]
public int currentEvent, currentTempoEvent;
public int currentEvent, currentTempoEvent, currentPreEvent, currentPreSwitch;
public float startOffset;
public bool playOnStart;
public float startBeat;
@ -56,7 +57,11 @@ namespace HeavenStudio
public void Init()
{
currentPreEvent= 0;
currentPreSwitch = 0;
this.transform.localScale = new Vector3(30000000, 30000000);
SpriteRenderer sp = this.gameObject.AddComponent<SpriteRenderer>();
sp.enabled = false;
sp.color = Color.black;
@ -88,6 +93,9 @@ namespace HeavenStudio
Conductor.instance.SetVolume(Beatmap.musicVolume);
Conductor.instance.firstBeatOffset = Beatmap.firstBeatOffset;
GameObject textbox = Instantiate(Resources.Load<GameObject>("Prefabs/Common/Textbox"));
textbox.name = "Textbox";
if (playOnStart)
{
Play(startBeat);
@ -144,10 +152,53 @@ namespace HeavenStudio
}
}
public void SeekAheadAndPreload(float start, float seekTime = 8f)
{
//seek ahead to preload games that have assetbundles
//check game switches first
var gameSwitchs = Beatmap.entities.FindAll(c => c.datamodel.Split(1) == "switchGame");
if (currentPreSwitch < gameSwitchs.Count && currentPreSwitch >= 0)
{
if (start + seekTime >= gameSwitchs[currentPreSwitch].beat)
{
string gameName = gameSwitchs[currentPreSwitch].datamodel.Split(2);
var inf = GetGameInfo(gameName);
if (inf.usesAssetBundle && !inf.AssetsLoaded)
{
Debug.Log("ASYNC loading assetbundle for game " + gameName);
StartCoroutine(inf.LoadCommonAssetBundleAsync());
StartCoroutine(inf.LoadLocalizedAssetBundleAsync());
}
currentPreSwitch++;
}
}
//then check game entities
List<float> entities = Beatmap.entities.Select(c => c.beat).ToList();
if (currentPreEvent < Beatmap.entities.Count && currentPreEvent >= 0)
{
if (start + seekTime >= entities[currentPreEvent])
{
var entitiesAtSameBeat = Beatmap.entities.FindAll(c => c.beat == Beatmap.entities[currentPreEvent].beat && !EventCaller.FXOnlyGames().Contains(EventCaller.instance.GetMinigame(c.datamodel.Split('/')[0])));
for (int i = 0; i < entitiesAtSameBeat.Count; i++)
{
string gameName = entitiesAtSameBeat[i].datamodel.Split('/')[0];
var inf = GetGameInfo(gameName);
if (inf.usesAssetBundle && !inf.AssetsLoaded)
{
Debug.Log("ASYNC loading assetbundle for game " + gameName);
StartCoroutine(inf.LoadCommonAssetBundleAsync());
StartCoroutine(inf.LoadLocalizedAssetBundleAsync());
}
}
currentPreEvent++;
}
}
}
// LateUpdate works a bit better(?) but causes some bugs (like issues with bop animations).
private void Update()
{
if (Beatmap.entities.Count < 1)
if (BeatmapEntities() < 1) //bruh really you forgot to ckeck tempo changes
return;
if (!Conductor.instance.isPlaying)
return;
@ -155,6 +206,22 @@ namespace HeavenStudio
List<float> entities = Beatmap.entities.Select(c => c.beat).ToList();
List<float> tempoChanges = Beatmap.tempoChanges.Select(c => c.beat).ToList();
if (currentTempoEvent < Beatmap.tempoChanges.Count && currentTempoEvent >= 0)
{
// Debug.Log("Checking Tempo Change at " + tempoChanges[currentTempoEvent] + ", current beat " + Conductor.instance.songPositionInBeats);
if (Conductor.instance.songPositionInBeats >= tempoChanges[currentTempoEvent])
{
// Debug.Log("Tempo Change at " + Conductor.instance.songPositionInBeats + " of bpm " + Beatmap.tempoChanges[currentTempoEvent].tempo);
Conductor.instance.SetBpm(Beatmap.tempoChanges[currentTempoEvent].tempo);
Conductor.instance.timeSinceLastTempoChange = Time.time;
currentTempoEvent++;
}
}
float seekTime = 8f;
//seek ahead to preload games that have assetbundles
SeekAheadAndPreload(Conductor.instance.songPositionInBeats, seekTime);
if (currentEvent < Beatmap.entities.Count && currentEvent >= 0)
{
if (Conductor.instance.songPositionInBeats >= entities[currentEvent] /*&& SongPosLessThanClipLength(Conductor.instance.songPositionInBeats)*/)
@ -190,16 +257,6 @@ namespace HeavenStudio
// currentEvent += gameManagerEntities.Count;
}
}
if (currentTempoEvent < Beatmap.tempoChanges.Count && currentTempoEvent >= 0)
{
if (Conductor.instance.songPositionInBeats >= tempoChanges[currentTempoEvent])
{
Conductor.instance.songBpm = Beatmap.tempoChanges[currentTempoEvent].tempo;
Conductor.instance.timeSinceLastTempoChange = Time.time;
currentTempoEvent++;
}
}
}
public void ToggleInputs(bool inputs)
@ -275,6 +332,7 @@ namespace HeavenStudio
List<float> entities = Beatmap.entities.Select(c => c.beat).ToList();
currentEvent = entities.IndexOf(Mathp.GetClosestInList(entities, beat));
currentPreEvent = entities.IndexOf(Mathp.GetClosestInList(entities, beat));
var gameSwitchs = Beatmap.entities.FindAll(c => c.datamodel.Split(1) == "switchGame");
@ -283,6 +341,7 @@ namespace HeavenStudio
if (gameSwitchs.Count > 0)
{
int index = gameSwitchs.FindIndex(c => c.beat == Mathp.GetClosestInList(gameSwitchs.Select(c => c.beat).ToList(), beat));
currentPreSwitch = index;
var closestGameSwitch = gameSwitchs[index];
if (closestGameSwitch.beat <= beat)
{
@ -321,10 +380,23 @@ namespace HeavenStudio
if (Beatmap.tempoChanges.Count > 0)
{
currentTempoEvent = 0;
List<float> tempoChanges = Beatmap.tempoChanges.Select(c => c.beat).ToList();
currentTempoEvent = tempoChanges.IndexOf(Mathp.GetClosestInList(tempoChanges, beat));
//for tempo changes, just go over all of em until the last one we pass
for (int t = 0; t < tempoChanges.Count; t++)
{
// Debug.Log("checking tempo event " + t + " against beat " + beat + "( tc beat " + tempoChanges[t] + ")");
if (tempoChanges[t] > beat)
{
break;
}
currentTempoEvent = t;
}
// Debug.Log("currentTempoEvent is now " + currentTempoEvent);
}
SeekAheadAndPreload(beat);
}
#endregion
@ -417,6 +489,14 @@ namespace HeavenStudio
return !newGameInfo.fxOnly;
}).ToList()[0].datamodel.Split(0);
}
else
{
if (gameInfo.usesAssetBundle)
{
//game is packed in an assetbundle, load from that instead
return gameInfo.GetCommonAssetBundle().LoadAsset<GameObject>(name);
}
}
}
return Resources.Load<GameObject>($"Games/{name}");
}
@ -444,7 +524,7 @@ namespace HeavenStudio
public void ResetCamera()
{
GameCamera.transform.localPosition = new Vector3(0, 0, -10);
HeavenStudio.GameCamera.ResetAdditionalTransforms();
}
}
}

View File

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

View File

@ -0,0 +1,193 @@
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 NtrCoinLoader
{
public static Minigame AddGame(EventCaller eventCaller)
{
return new Minigame("coinToss", "Coin Toss \n [One coin at a time!]", "B4E6F6", false, false, new List<GameAction>()
{
new GameAction("toss", delegate { CoinToss.instance.TossCoin(eventCaller.currentEntity.beat, eventCaller.currentEntity.toggle); }, 7, false, parameters: new List<Param>()
{
new Param("toggle", false, "Audience Reaction", "Enable Audience Reaction"),
}),
new GameAction("set background color", delegate { var e = eventCaller.currentEntity; CoinToss.instance.ChangeBackgroundColor(e.colorA, 0f); }, 0.5f, false, new List<Param>()
{
new Param("colorA", CoinToss.defaultBgColor, "Background Color", "The background color to change to")
} ),
new GameAction("fade background color", delegate { var e = eventCaller.currentEntity; CoinToss.instance.FadeBackgroundColor(e.colorA, e.colorB, e.length); }, 1f, true, new List<Param>()
{
new Param("colorA", Color.white, "Start Color", "The starting color in the fade"),
new Param("colorB", CoinToss.defaultBgColor, "End Color", "The ending color in the fade")
} ),
new GameAction("set foreground color", delegate { var e = eventCaller.currentEntity; CoinToss.instance.ChangeBackgroundColor(e.colorA, 0f, true); }, 0.5f, false, new List<Param>()
{
new Param("colorA", CoinToss.defaultFgColor, "Background Color", "The background color to change to")
} ),
new GameAction("fade foreground color", delegate { var e = eventCaller.currentEntity; CoinToss.instance.FadeBackgroundColor(e.colorA, e.colorB, e.length, true); }, 1f, true, new List<Param>()
{
new Param("colorA", Color.white, "Start Color", "The starting color in the fade"),
new Param("colorB", CoinToss.defaultFgColor, "End Color", "The ending color in the fade")
} ),
},
new List<string>() {"ntr", "aim"},
"ntrcoin", "en",
new List<string>() {}
);
}
}
}
namespace HeavenStudio.Games
{
//using Scripts_CoinToss;
public class CoinToss : Minigame
{
//Right now, you can only throw one coin at a time.
//..Which makes sense, you only have one coin in the original game
//Though it would need a bit of code rewrite to make it work with multiple coins
public static CoinToss instance { get; set; }
private static Color _defaultBgColor;
public static Color defaultBgColor
{
get
{
ColorUtility.TryParseHtmlString("#F7F742", out _defaultBgColor);
return _defaultBgColor;
}
}
private static Color _defaultFgColor;
public static Color defaultFgColor
{
get
{
ColorUtility.TryParseHtmlString("#FFFF83", out _defaultFgColor);
return _defaultFgColor;
}
}
[Header("Backgrounds")]
public SpriteRenderer fg;
public SpriteRenderer bg;
Tween bgColorTween;
Tween fgColorTween;
[Header("Animators")]
public Animator handAnimator;
public Boolean isThrowing;
public bool audienceReacting;
public PlayerActionEvent coin;
private void Awake()
{
instance = this;
isThrowing = false;
coin = null;
}
private void Update()
{
//nothing
}
private void LateUpdate()
{
//nothing
}
public void TossCoin(float beat, bool audienceReacting)
{
if (coin != null) return;
//Play sound and animations
Jukebox.PlayOneShotGame("coinToss/throw");
handAnimator.Play("Throw", 0, 0);
//Game state says the hand is throwing the coin
isThrowing = true;
this.audienceReacting = audienceReacting;
coin = ScheduleInput(beat, 6f, InputType.STANDARD_DOWN, CatchSuccess, CatchMiss, CatchEmpty);
//coin.perfectOnly = true;
}
public void CatchSuccess(PlayerActionEvent caller, float state)
{
Jukebox.PlayOneShotGame("coinToss/catch");
if(this.audienceReacting) Jukebox.PlayOneShotGame("coinToss/applause");
handAnimator.Play("Catch_success", 0, 0);
isThrowing = false;
}
public void CatchMiss(PlayerActionEvent caller)
{
Jukebox.PlayOneShotGame("coinToss/miss");
if(this.audienceReacting) Jukebox.PlayOneShotGame("coinToss/disappointed");
handAnimator.Play("Pickup", 0, 0);
isThrowing = false;
}
public void CatchEmpty(PlayerActionEvent caller)
{
handAnimator.Play("Catch_empty", 0, 0);
isThrowing = false;
coin.CanHit(false);
}
public void ChangeBackgroundColor(Color color, float beats, bool isFg = false)
{
var seconds = Conductor.instance.secPerBeat * beats;
if(!isFg)
{
if (bgColorTween != null)
bgColorTween.Kill(true);
} else
{
if (fgColorTween != null)
fgColorTween.Kill(true);
}
if (seconds == 0)
{
if(!isFg) bg.color = color;
if (isFg) fg.color = color;
}
else
{
if(!isFg) bgColorTween = bg.DOColor(color, seconds);
if(isFg) fgColorTween = fg.DOColor(color, seconds);
}
}
public void FadeBackgroundColor(Color start, Color end, float beats, bool isFg = false)
{
ChangeBackgroundColor(start, 0f, isFg);
ChangeBackgroundColor(end, beats, isFg);
}
}
}

View File

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

View File

@ -270,7 +270,7 @@ namespace HeavenStudio.Games
public void StartMarching(float beat)
{
marchStartBeat = beat;
marchOffset = (marchStartBeat % 1) * Conductor.instance.secPerBeat / Conductor.instance.musicSource.pitch;
marchOffset = marchStartBeat % 1;
currentMarchBeat = 0;
stepCount = 0;
@ -291,10 +291,9 @@ namespace HeavenStudio.Games
if (shakeTween != null)
shakeTween.Kill(true);
var camTrans = GameCamera.instance.transform;
camTrans.localPosition = new Vector3(camTrans.localPosition.x, 0.75f, camTrans.localPosition.z);
camTrans.DOLocalMoveY(0f, 0.5f).SetEase(Ease.OutElastic, 1f);
DOTween.Punch(() => GameCamera.additionalPosition, x => GameCamera.additionalPosition = x, new Vector3(0, 0.75f, 0),
Conductor.instance.pitchedSecPerBeat*0.5f, 18, 1f);
isStepping = true;
}

View File

@ -25,7 +25,11 @@ namespace HeavenStudio.Games.Loaders
{
new Param("type", DJSchool.DJVoice.Standard, "Voice", "The voice line to play"),
}),
});
},
new List<string>() {"ntr", "normal"},
"ntrdj", "en",
new List<string>(){}
);
}
}
}

View File

@ -12,44 +12,55 @@ namespace HeavenStudio.Games.Loaders
{
public static Minigame AddGame(EventCaller eventCaller) {
return new Minigame("fanClub", "Fan Club", "FDFD00", false, false, new List<GameAction>()
{
new GameAction("bop", delegate { var e = eventCaller.currentEntity; FanClub.instance.Bop(e.beat, e.length, e.type); }, 0.5f, true, parameters: new List<Param>()
{
new Param("type", FanClub.IdolBopType.Both, "Bop target", "Who to make bop"),
}),
new GameAction("yeah, yeah, yeah", delegate { var e = eventCaller.currentEntity; FanClub.instance.CallHai(e.beat, e.toggle); }, 8, false, parameters: new List<Param>()
new GameAction("bop", delegate { var e = eventCaller.currentEntity; FanClub.instance.Bop(e.beat, e.length, e.type); }, 0.5f, true, parameters: new List<Param>()
{
new Param("toggle", false, "Disable call", "Disable the idol's call")
},
inactiveFunction: delegate { var e = eventCaller.currentEntity; FanClub.WarnHai(e.beat, e.toggle);}
),
new Param("type", FanClub.IdolBopType.Both, "Bop target", "Who to make bop"),
}),
new GameAction("I suppose", delegate { var e = eventCaller.currentEntity; FanClub.instance.CallKamone(e.beat, e.toggle, 0, e.type); }, 6, false, parameters: new List<Param>()
new GameAction("yeah, yeah, yeah", delegate { var e = eventCaller.currentEntity; FanClub.instance.CallHai(e.beat, e.toggle); }, 8, false, parameters: new List<Param>()
{
new Param("toggle", false, "Disable call", "Disable the idol's call")
},
inactiveFunction: delegate { var e = eventCaller.currentEntity; FanClub.WarnHai(e.beat, e.toggle);}
),
new GameAction("I suppose", delegate { var e = eventCaller.currentEntity; FanClub.instance.CallKamone(e.beat, e.toggle, 0, e.type); }, 6, false, parameters: new List<Param>()
{
new Param("type", FanClub.KamoneResponseType.Through, "Response type", "Type of response to use"),
new Param("toggle", false, "Disable call", "Disable the idol's call")
},
inactiveFunction: delegate { var e = eventCaller.currentEntity; FanClub.WarnKamone(e.beat, e.toggle, 0, e.type);}
),
new GameAction("double clap", delegate { var e = eventCaller.currentEntity; FanClub.instance.CallBigReady(e.beat, e.toggle); }, 4, false, parameters: new List<Param>()
{
new Param("toggle", false, "Disable call", "Disable the call")
},
inactiveFunction: delegate { var e = eventCaller.currentEntity; FanClub.WarnBigReady(e.beat, e.toggle); }
),
new GameAction("play idol animation", delegate { var e = eventCaller.currentEntity; FanClub.instance.PlayAnim(e.beat, e.length, e.type); }, 1, true, parameters: new List<Param>()
{
new Param("type", FanClub.KamoneResponseType.Through, "Response type", "Type of response to use"),
new Param("toggle", false, "Disable call", "Disable the idol's call")
},
inactiveFunction: delegate { var e = eventCaller.currentEntity; FanClub.WarnKamone(e.beat, e.toggle);}
),
new Param("type", FanClub.IdolAnimations.Bop, "Animation", "Animation to play")
}),
new GameAction("double clap", delegate { var e = eventCaller.currentEntity; FanClub.instance.CallBigReady(e.beat, e.toggle); }, 4, false, parameters: new List<Param>()
new GameAction("play stage animation", delegate { var e = eventCaller.currentEntity; FanClub.instance.PlayAnimStage(e.beat, e.type); }, 1, true, parameters: new List<Param>()
{
new Param("toggle", false, "Disable call", "Disable the call")
},
inactiveFunction: delegate { var e = eventCaller.currentEntity; FanClub.WarnBigReady(e.beat, e.toggle); }
),
new Param("type", FanClub.StageAnimations.Flash, "Animation", "Animation to play")
}),
new GameAction("play idol animation", delegate { var e = eventCaller.currentEntity; FanClub.instance.PlayAnim(e.beat, e.length, e.type); }, 1, true, parameters: new List<Param>()
{
new Param("type", FanClub.IdolAnimations.Bop, "Animation", "Animation to play")
}),
new GameAction("play stage animation", delegate { var e = eventCaller.currentEntity; FanClub.instance.PlayAnimStage(e.beat, e.type); }, 1, true, parameters: new List<Param>()
{
new Param("type", FanClub.StageAnimations.Reset, "Animation", "Animation to play")
}),
});
new GameAction("set performance type", delegate { var e = eventCaller.currentEntity; FanClub.SetPerformanceType(e.type);}, 0.5f, false, parameters: new List<Param>()
{
new Param("type", FanClub.IdolPerformanceType.Normal, "Performance Type", "Set of animations for the idol to use")
},
inactiveFunction: delegate { var e = eventCaller.currentEntity; FanClub.SetPerformanceType(e.type); }
),
},
new List<string>() {"ntr", "normal"},
"ntridol", "jp",
new List<string>() {"jp"}
);
}
}
}
@ -73,19 +84,27 @@ namespace HeavenStudio.Games
Call,
Response,
Jump,
//TODO: BigCall
BigCall,
Squat,
Wink,
Dab
Dab,
None
}
public enum KamoneResponseType {
Through,
Jump,
ThroughFast,
JumpFast,
}
public enum StageAnimations {
Reset,
Flash,
//TODO: spotlight
Spot
}
public enum IdolPerformanceType {
Normal,
Arrange,
// Tour(this one is fan made so ?)
}
// userdata here
@ -100,6 +119,9 @@ namespace HeavenStudio.Games
public GameObject spectator;
public GameObject spectatorAnchor;
[Header("References")]
public Material spectatorMat;
// end userdata
//arisa's animation controller
@ -113,8 +135,10 @@ namespace HeavenStudio.Games
public GameEvent specBop = new GameEvent();
public GameEvent noBop = new GameEvent();
public GameEvent noResponse = new GameEvent();
public GameEvent noCall = new GameEvent();
public GameEvent noSpecBop = new GameEvent();
private static int performanceType = (int) IdolPerformanceType.Normal;
private bool responseToggle = false;
private static float wantHais = Single.MinValue;
private static float wantKamone = Single.MinValue;
@ -159,7 +183,6 @@ namespace HeavenStudio.Games
Player.player = true;
}
Spectators.Add(mobj);
fan.Init();
//prepare spawn point of next spectator
spawnPos.x += RADIUS * 2;
@ -175,6 +198,33 @@ namespace HeavenStudio.Games
// spawnPos.z -= RADIUS/4;
}
}
if (performanceType != (int) IdolPerformanceType.Normal)
{
idolAnimator.Play("NoPose" + GetPerformanceSuffix(), -1, 0);
}
ToSpot();
}
public static string GetPerformanceSuffix()
{
switch (performanceType)
{
case (int) IdolPerformanceType.Arrange:
return "Arrange";
default:
return "";
}
}
public static void SetPerformanceType(int type = (int) IdolPerformanceType.Normal)
{
performanceType = type;
if (GameManager.instance.currentGame == "fanClub")
{
FanClub.instance.idolAnimator.Play("NoPose" + GetPerformanceSuffix(), -1, 0);
}
}
public override void OnGameSwitch(float beat)
@ -204,7 +254,7 @@ namespace HeavenStudio.Games
if (cond.songPositionInBeats >= bop.startBeat && cond.songPositionInBeats < bop.startBeat + bop.length)
{
if (!(cond.songPositionInBeats >= noBop.startBeat && cond.songPositionInBeats < noBop.startBeat + noBop.length))
idolAnimator.Play("IdolBeat", 0, 0);
idolAnimator.Play("IdolBeat" + GetPerformanceSuffix(), 0, 0);
}
}
@ -226,7 +276,7 @@ namespace HeavenStudio.Games
float yMul = jumpPos * 2f - 1f;
float yWeight = -(yMul*yMul) + 1f;
//TODO: idol start position
ArisaRootMotion.transform.localPosition = new Vector3(0, 2f * yWeight);
ArisaRootMotion.transform.localPosition = new Vector3(0, 2f * yWeight + 0.25f);
ArisaShadow.transform.localScale = new Vector3((1f-yWeight*0.8f) * IDOL_SHADOW_SCALE, (1f-yWeight*0.8f) * IDOL_SHADOW_SCALE, 1f);
}
else
@ -273,6 +323,12 @@ namespace HeavenStudio.Games
noResponse.startBeat = beat;
}
private void DisableCall(float beat, float length)
{
noCall.length = length;
noCall.startBeat = beat;
}
private void DisableSpecBop(float beat, float length)
{
float bt = Conductor.instance.songPositionInBeats;
@ -293,54 +349,63 @@ namespace HeavenStudio.Games
public void PlayAnim(float beat, float length, int type)
{
idolJumpStartTime = Single.MinValue;
DisableResponse(beat, length);
DisableBop(beat, length);
DisableResponse(beat, length + 0.5f);
DisableBop(beat, length + 0.5f);
DisableCall(beat, length + 0.5f);
switch (type)
{
case (int) IdolAnimations.Bop:
idolAnimator.Play("IdolBeat", -1, 0);
idolAnimator.Play("IdolBeat" + GetPerformanceSuffix(), -1, 0);
break;
case (int) IdolAnimations.PeaceVocal:
idolAnimator.Play("IdolPeace", -1, 0);
idolAnimator.Play("IdolPeace" + GetPerformanceSuffix(), -1, 0);
break;
case (int) IdolAnimations.Peace:
idolAnimator.Play("IdolPeaceNoSync", -1, 0);
idolAnimator.Play("IdolPeaceNoSync" + GetPerformanceSuffix(), -1, 0);
break;
case (int) IdolAnimations.Clap:
idolAnimator.Play("IdolCrap", -1, 0);
idolAnimator.Play("IdolCrap" + GetPerformanceSuffix(), -1, 0);
break;
case (int) IdolAnimations.Call:
BeatAction.New(Arisa, new List<BeatAction.Action>()
{
new BeatAction.Action(beat, delegate { Arisa.GetComponent<Animator>().Play("IdolCall0", -1, 0); }),
new BeatAction.Action(beat + 0.75f, delegate { Arisa.GetComponent<Animator>().Play("IdolCall1", -1, 0); }),
new BeatAction.Action(beat, delegate { Arisa.GetComponent<Animator>().Play("IdolCall0" + GetPerformanceSuffix(), -1, 0); }),
new BeatAction.Action(beat + 0.75f, delegate { Arisa.GetComponent<Animator>().Play("IdolCall1" + GetPerformanceSuffix(), -1, 0); }),
});
break;
case (int) IdolAnimations.Response:
idolAnimator.Play("IdolResponse", -1, 0);
idolAnimator.Play("IdolResponse" + GetPerformanceSuffix(), -1, 0);
break;
case (int) IdolAnimations.Jump:
DoIdolJump(beat, length);
break;
case (int) IdolAnimations.BigCall:
BeatAction.New(Arisa, new List<BeatAction.Action>()
{
new BeatAction.Action(beat, delegate { Arisa.GetComponent<Animator>().Play("IdolBigCall0" + GetPerformanceSuffix(), -1, 0); }),
new BeatAction.Action(beat + length, delegate { Arisa.GetComponent<Animator>().Play("IdolBigCall1" + GetPerformanceSuffix(), -1, 0); }),
});
break;
case (int) IdolAnimations.Squat:
BeatAction.New(Arisa, new List<BeatAction.Action>()
{
new BeatAction.Action(beat, delegate { Arisa.GetComponent<Animator>().Play("IdolSquat0", -1, 0); }),
new BeatAction.Action(beat + 1f, delegate { Arisa.GetComponent<Animator>().Play("IdolSquat1", -1, 0); }),
new BeatAction.Action(beat, delegate { Arisa.GetComponent<Animator>().Play("IdolSquat0" + GetPerformanceSuffix(), -1, 0); }),
new BeatAction.Action(beat + length, delegate { Arisa.GetComponent<Animator>().Play("IdolSquat1" + GetPerformanceSuffix(), -1, 0); }),
});
break;
case (int) IdolAnimations.Wink:
BeatAction.New(Arisa, new List<BeatAction.Action>()
{
new BeatAction.Action(beat, delegate { Arisa.GetComponent<Animator>().Play("IdolWink0", -1, 0); }),
new BeatAction.Action(beat + length, delegate { Arisa.GetComponent<Animator>().Play("IdolWink1", -1, 0); }),
new BeatAction.Action(beat, delegate { Arisa.GetComponent<Animator>().Play("IdolWink0" + GetPerformanceSuffix(), -1, 0); }),
new BeatAction.Action(beat + length, delegate { Arisa.GetComponent<Animator>().Play("IdolWink1" + GetPerformanceSuffix(), -1, 0); }),
});
break;
case (int) IdolAnimations.Dab:
idolAnimator.Play("IdolDab", -1, 0);
idolAnimator.Play("IdolDab" + GetPerformanceSuffix(), -1, 0);
Jukebox.PlayOneShotGame("fanClub/arisa_dab");
break;
default: break;
}
}
@ -350,13 +415,28 @@ namespace HeavenStudio.Games
{
case (int) StageAnimations.Reset:
StageAnimator.Play("Bg", -1, 0);
ToSpot();
break;
case (int) StageAnimations.Flash:
StageAnimator.Play("Bg_Light", -1, 0);
ToSpot();
break;
case (int) StageAnimations.Spot:
StageAnimator.Play("Bg_Spot", -1, 0);
ToSpot(false);
break;
}
}
public void ToSpot(bool unspot = true)
{
Arisa.GetComponent<NtrIdolAri>().ToSpot(unspot);
if (unspot)
spectatorMat.SetColor("_Color", new Color(1, 1, 1, 1));
else
spectatorMat.SetColor("_Color", new Color(117/255f, 177/255f, 209/255f, 1));
}
private void DoIdolJump(float beat, float length = 3f)
{
DisableBop(beat, length);
@ -366,8 +446,8 @@ namespace HeavenStudio.Games
//play anim
BeatAction.New(Arisa, new List<BeatAction.Action>()
{
new BeatAction.Action(beat, delegate { Arisa.GetComponent<Animator>().Play("IdolJump", -1, 0); }),
new BeatAction.Action(beat + 1f, delegate { Arisa.GetComponent<Animator>().Play("IdolLand", -1, 0); }),
new BeatAction.Action(beat, delegate { Arisa.GetComponent<Animator>().Play("IdolJump" + GetPerformanceSuffix(), -1, 0); }),
new BeatAction.Action(beat + 1f, delegate { Arisa.GetComponent<Animator>().Play("IdolLand" + GetPerformanceSuffix(), -1, 0); }),
});
}
@ -377,17 +457,43 @@ namespace HeavenStudio.Games
{
if (!(Conductor.instance.songPositionInBeats >= noResponse.startBeat && Conductor.instance.songPositionInBeats < noResponse.startBeat + noResponse.length))
{
idolAnimator.Play("IdolCrap", -1, 0);
idolAnimator.Play("IdolCrap" + GetPerformanceSuffix(), -1, 0);
}
}
}
private void DoIdolPeace(bool sync = true)
{
if (!(Conductor.instance.songPositionInBeats >= noCall.startBeat && Conductor.instance.songPositionInBeats < noCall.startBeat + noCall.length))
{
if (sync)
idolAnimator.Play("IdolPeace" + GetPerformanceSuffix(), -1, 0);
else
idolAnimator.Play("IdolPeaceNoSync" + GetPerformanceSuffix(), -1, 0);
}
}
private void DoIdolResponse()
{
if (responseToggle)
{
if (!(Conductor.instance.songPositionInBeats >= noResponse.startBeat && Conductor.instance.songPositionInBeats < noResponse.startBeat + noResponse.length))
idolAnimator.Play("IdolResponse", -1, 0);
idolAnimator.Play("IdolResponse" + GetPerformanceSuffix(), -1, 0);
}
}
private void DoIdolCall(int part = 0, bool big = false)
{
if (!(Conductor.instance.songPositionInBeats >= noCall.startBeat && Conductor.instance.songPositionInBeats < noCall.startBeat + noCall.length))
{
if (big)
{
idolAnimator.Play("IdolBigCall" + part + GetPerformanceSuffix(), -1, 0);
}
else
{
idolAnimator.Play("IdolCall" + part + GetPerformanceSuffix(), -1, 0);
}
}
}
@ -401,21 +507,21 @@ namespace HeavenStudio.Games
new MultiSound.Sound("fanClub/arisa_hai_3_jp", beat + 2f),
});
Prepare(beat + 3f);
responseToggle = false;
DisableBop(beat, 8f);
Prepare(beat + 3f);
Prepare(beat + 4f);
Prepare(beat + 5f);
Prepare(beat + 6f);
BeatAction.New(Arisa, new List<BeatAction.Action>()
{
new BeatAction.Action(beat, delegate { Arisa.GetComponent<Animator>().Play("IdolPeace", -1, 0);}),
new BeatAction.Action(beat + 1f, delegate { Arisa.GetComponent<Animator>().Play("IdolPeace", -1, 0);}),
new BeatAction.Action(beat + 2f, delegate { Arisa.GetComponent<Animator>().Play("IdolPeace", -1, 0);}),
new BeatAction.Action(beat, delegate { DoIdolPeace();}),
new BeatAction.Action(beat + 1f, delegate { DoIdolPeace();}),
new BeatAction.Action(beat + 2f, delegate { DoIdolPeace();}),
new BeatAction.Action(beat + 2.5f, delegate { DisableSpecBop(beat + 2.5f, 5f);}),
new BeatAction.Action(beat + 3f, delegate { Arisa.GetComponent<Animator>().Play("IdolPeaceNoSync"); PlayPrepare(); }),
new BeatAction.Action(beat + 3f, delegate { DoIdolPeace(false); PlayPrepare(); }),
new BeatAction.Action(beat + 4f, delegate { PlayOneClap(beat + 4f); DoIdolClaps();}),
new BeatAction.Action(beat + 5f, delegate { PlayOneClap(beat + 5f); DoIdolClaps();}),
@ -450,26 +556,45 @@ namespace HeavenStudio.Games
const float CALL_LENGTH = 2.5f;
public void CallKamone(float beat, bool noSound = false, int type = 0, int responseType = (int) KamoneResponseType.Through)
{
if (!noSound)
MultiSound.Play(new MultiSound.Sound[] {
new MultiSound.Sound("fanClub/arisa_ka_jp", beat),
new MultiSound.Sound("fanClub/arisa_mo_jp", beat + 0.5f, offset: 0.07407407f),
new MultiSound.Sound("fanClub/arisa_ne_jp", beat + 1f, offset: 0.07407407f),
});
bool doJump = (responseType == (int) KamoneResponseType.Jump || responseType == (int) KamoneResponseType.JumpFast);
bool isBig = (responseType == (int) KamoneResponseType.ThroughFast || responseType == (int) KamoneResponseType.JumpFast);
DisableResponse(beat, 2f);
if (isBig)
{
if (!noSound)
{
MultiSound.Play(new MultiSound.Sound[] {
new MultiSound.Sound("fanClub/arisa_ka_fast_jp", beat),
new MultiSound.Sound("fanClub/arisa_mo_fast_jp", beat + 0.25f),
new MultiSound.Sound("fanClub/arisa_ne_fast_jp", beat + 0.5f),
});
}
}
else
{
if (!noSound)
{
MultiSound.Play(new MultiSound.Sound[] {
new MultiSound.Sound("fanClub/arisa_ka_jp", beat),
new MultiSound.Sound("fanClub/arisa_mo_jp", beat + 0.5f, offset: 0.07407407f),
new MultiSound.Sound("fanClub/arisa_ne_jp", beat + 1f, offset: 0.07407407f),
});
}
}
responseToggle = true;
DisableBop(beat, (responseType == (int) KamoneResponseType.Jump) ? 6.25f : 5.25f);
DisableBop(beat, (doJump) ? 6.25f : 5.25f);
DisableSpecBop(beat + 0.5f, 6f);
Prepare(beat + 1f);
Prepare(beat + 1f, 3);
Prepare(beat + 2.5f);
Prepare(beat + 3f, 2);
Prepare(beat + 4f, 1);
BeatAction.New(Arisa, new List<BeatAction.Action>()
{
new BeatAction.Action(beat, delegate { Arisa.GetComponent<Animator>().Play("IdolCall0", -1, 0); }),
new BeatAction.Action(beat + 0.75f, delegate { Arisa.GetComponent<Animator>().Play("IdolCall1", -1, 0); }),
new BeatAction.Action(beat, delegate { DoIdolCall(0, isBig); }),
new BeatAction.Action(beat + (isBig ? 1f : 0.75f), delegate { DoIdolCall(1, isBig); }),
new BeatAction.Action(beat + 1f, delegate { PlayPrepare(); }),
new BeatAction.Action(beat + 2f, delegate { PlayLongClap(beat + 2f); DoIdolResponse(); }),
@ -477,7 +602,7 @@ namespace HeavenStudio.Games
new BeatAction.Action(beat + 3.5f, delegate { PlayOneClap(beat + 3.5f); }),
new BeatAction.Action(beat + 4f, delegate { PlayChargeClap(beat + 4f); DoIdolResponse(); }),
new BeatAction.Action(beat + 5f, delegate { PlayJump(beat + 5f);
if (responseType == (int) KamoneResponseType.Jump)
if (doJump)
{
DoIdolJump(beat + 5f);
}
@ -501,11 +626,22 @@ namespace HeavenStudio.Games
wantKamone = beat;
wantKamoneType = responseType;
if (noSound) return;
MultiSound.Play(new MultiSound.Sound[] {
new MultiSound.Sound("fanClub/arisa_ka_jp", beat),
new MultiSound.Sound("fanClub/arisa_mo_jp", beat + 0.5f, offset: 0.07407407f),
new MultiSound.Sound("fanClub/arisa_ne_jp", beat + 1f, offset: 0.07407407f),
}, forcePlay:true);
if (responseType == (int) KamoneResponseType.ThroughFast || responseType == (int) KamoneResponseType.JumpFast)
{
MultiSound.Play(new MultiSound.Sound[] {
new MultiSound.Sound("fanClub/arisa_ka_fast_jp", beat),
new MultiSound.Sound("fanClub/arisa_mo_fast_jp", beat + 0.25f),
new MultiSound.Sound("fanClub/arisa_ne_fast_jp", beat + 0.5f),
}, forcePlay:true);
}
else
{
MultiSound.Play(new MultiSound.Sound[] {
new MultiSound.Sound("fanClub/arisa_ka_jp", beat),
new MultiSound.Sound("fanClub/arisa_mo_jp", beat + 0.5f, offset: 0.07407407f),
new MultiSound.Sound("fanClub/arisa_ne_jp", beat + 1f, offset: 0.07407407f),
}, forcePlay:true);
}
}
public void ContinueKamone(float beat, int type = 0, int responseType = (int) KamoneResponseType.Through)
@ -516,12 +652,13 @@ namespace HeavenStudio.Games
const float BIGCALL_LENGTH = 2.75f;
public void CallBigReady(float beat, bool noSound = false)
{
Prepare(beat + 1.5f);
Prepare(beat + 2f);
if (!noSound)
Jukebox.PlayOneShotGame("fanClub/crowd_big_ready");
DisableSpecBop(beat, 3.75f);
Prepare(beat + 1.5f);
Prepare(beat + 2f);
PlayAnimationAll("FanBigReady", onlyOverrideBop: true);
BeatAction.New(this.gameObject, new List<BeatAction.Action>()
@ -563,11 +700,11 @@ namespace HeavenStudio.Games
{
string clipName = Spectators[i].GetComponent<Animator>().GetCurrentAnimatorClipInfo(0)[0].clip.name;
if (clipName == "FanBeat" || clipName == "NoPose")
Spectators[i].GetComponent<Animator>().Play(anim);
Spectators[i].GetComponent<Animator>().Play(anim, -1, 0);
}
continue;
}
Spectators[i].GetComponent<Animator>().Play(anim);
Spectators[i].GetComponent<Animator>().Play(anim, -1, 0);
}
}

View File

@ -7,6 +7,11 @@ public class NtrIdolAri : MonoBehaviour
[Header("Objects")]
public ParticleSystem idolClapEffect;
public ParticleSystem idolWinkEffect;
public ParticleSystem idolKissEffect;
public ParticleSystem idolWinkArrEffect;
[Header("References")]
public Material coreMat;
public void ClapParticle()
{
@ -17,4 +22,22 @@ public class NtrIdolAri : MonoBehaviour
{
idolWinkEffect.Play();
}
public void KissParticle()
{
idolKissEffect.Play();
}
public void WinkArrangeParticle()
{
idolWinkArrEffect.Play();
}
public void ToSpot(bool unspot = true)
{
if (unspot)
coreMat.SetColor("_AddColor", new Color(0, 0, 0, 0));
else
coreMat.SetColor("_AddColor", new Color(0, 100/255f, 200/255f, 0));
}
}

View File

@ -21,138 +21,92 @@ namespace HeavenStudio.Games.Scripts_FanClub
[Header("Properties")]
[NonSerialized] public bool player = false;
[NonSerialized] public bool hitValid = false;
public float jumpStartTime = Single.MinValue;
bool stopBeat = false;
bool stopCharge = false;
bool hasJumped = false;
float clappingStartTime = 0f;
float clappingStartTime = Single.MinValue;
public Queue<KeyValuePair<float, int>> upcomingHits;
public float startBeat;
public int type;
public bool doCharge = false;
private bool inputHit = false;
private bool hasHit = false;
public void Init()
public void AddHit(float beat, int type = 0)
{
if (player)
upcomingHits = new Queue<KeyValuePair<float, int>>(); // beat, type
inputHit = true;
hasHit = true;
}
public override void OnAce()
{
Hit(true, type, true);
}
public void AddHit(float beat, int type)
{
inputHit = false;
upcomingHits.Enqueue(new KeyValuePair<float, int>(beat, type));
}
public void Hit(bool _hit, int type = 0, bool fromAutoplay = false)
{
if (player && !hasHit)
{
if (type == 0)
ClapStart(_hit, true, doCharge, fromAutoplay);
else if (type == 1)
JumpStart(_hit, true, fromAutoplay);
switch (type)
{
case 0:
FanClub.instance.ScheduleInput(beat, 1f, InputType.STANDARD_DOWN, ClapJust, ClapThrough, Out);
break;
case 1:
FanClub.instance.ScheduleInput(beat, 1f, InputType.STANDARD_UP, JumpJust, JumpThrough, JumpOut);
break;
case 2:
FanClub.instance.ScheduleInput(beat, 1f, InputType.STANDARD_DOWN, ChargeClapJust, ClapThrough, Out);
break;
default:
FanClub.instance.ScheduleInput(beat, 1f, InputType.STANDARD_DOWN, LongClapJust, ClapThrough, Out);
break;
}
}
}
hasHit = true;
public void ClapJust(PlayerActionEvent caller, float state)
{
bool auto = GameManager.instance.autoplay;
ClapStart(true, false, auto ? 0.25f : 0f);
}
public void ChargeClapJust(PlayerActionEvent caller, float state)
{
bool auto = GameManager.instance.autoplay;
ClapStart(true, true, auto ? 1f : 0f);
}
public void LongClapJust(PlayerActionEvent caller, float state)
{
bool auto = GameManager.instance.autoplay;
ClapStart(true, false, auto ? 1f : 0f);
}
public void JumpJust(PlayerActionEvent caller, float state)
{
JumpStart(true);
}
public void ClapThrough(PlayerActionEvent caller) {
FanClub.instance.AngerOnMiss();
}
public void JumpThrough(PlayerActionEvent caller) {
FanClub.instance.AngerOnMiss();
}
public void Out(PlayerActionEvent caller) {}
public void JumpOut(PlayerActionEvent caller) {
var cond = Conductor.instance;
if (stopCharge)
{
caller.CanHit(false);
}
}
private void Update()
{
var cond = Conductor.instance;
// read cue queue and pop when needed
if (hasHit)
{
if (upcomingHits?.Count > 0)
{
var next = upcomingHits.Dequeue();
startBeat = next.Key;
type = next.Value == 2 ? 0 : next.Value;
doCharge = (next.Value == 2);
// reset our shit to prepare for next hit
hasHit = false;
ResetState();
}
else if (Conductor.instance.GetPositionFromBeat(startBeat, 1) >= Minigame.EndTime())
{
startBeat = Single.MinValue;
type = 0;
doCharge = false;
// DO NOT RESET, wait for future cues
}
}
// no input?
if (!hasHit && Conductor.instance.GetPositionFromBeat(startBeat, 1f) >= Minigame.EndTime())
{
FanClub.instance.AngerOnMiss();
hasHit = true;
}
// dunno what this is for
if (!inputHit && Conductor.instance.GetPositionFromBeat(startBeat, 1) >= Minigame.EndTime())
{
inputHit = true;
}
if (!hasHit)
{
float normalizedBeat = Conductor.instance.GetPositionFromBeat(startBeat, 1);
StateCheck(normalizedBeat);
}
if (player)
{
if (PlayerInput.Pressed() && type == 0)
{
if (state.perfect)
{
Hit(true);
} else if (state.notPerfect())
{
Hit(false);
}
}
if (PlayerInput.PressedUp() && type == 1)
{
if (state.perfect)
{
Hit(true, type);
} else if (state.notPerfect())
{
Hit(false, type);
}
}
if (PlayerInput.Pressed())
{
if (!hasHit || (upcomingHits?.Count == 0 && startBeat == Single.MinValue))
FanClub.instance.AngerOnMiss();
hasJumped = false;
stopBeat = true;
jumpStartTime = -99f;
animator.Play("FanClap", -1, 0);
Jukebox.PlayOneShotGame("fanClub/play_clap");
Jukebox.PlayOneShotGame("fanClub/crap_impact");
clappingStartTime = cond.songPositionInBeats;
if (!FanClub.instance.IsExpectingInputNow())
{
ClapStart(false);
}
}
if (PlayerInput.Pressing())
{
if (cond.songPositionInBeats > clappingStartTime + 1.5f && !stopCharge)
if (clappingStartTime != Single.MinValue && cond.songPositionInBeats > clappingStartTime + 2f && !stopCharge)
{
animator.Play("FanClapCharge", -1, 0);
stopCharge = true;
@ -160,15 +114,9 @@ namespace HeavenStudio.Games.Scripts_FanClub
}
if (PlayerInput.PressedUp())
{
if (stopCharge)
if (clappingStartTime != Single.MinValue && cond.songPositionInBeats > clappingStartTime + 2f && stopCharge && !FanClub.instance.IsExpectingInputNow())
{
if (!hasHit || (upcomingHits?.Count == 0 && startBeat == Single.MinValue))
FanClub.instance.AngerOnMiss();
animator.Play("FanJump", -1, 0);
Jukebox.PlayOneShotGame("fanClub/play_jump");
jumpStartTime = cond.songPositionInBeats;
stopCharge = false;
JumpStart(false);
}
else
{
@ -204,41 +152,39 @@ namespace HeavenStudio.Games.Scripts_FanClub
}
}
public void ClapStart(bool hit, bool force = false, bool doCharge = false, bool fromAutoplay = false)
public void ClapStart(bool hit, bool doCharge = false, float autoplayRelease = 0f)
{
var cond = Conductor.instance;
if (hit)
{
if (doCharge)
BeatAction.New(this.gameObject, new List<BeatAction.Action>()
{
new BeatAction.Action(cond.songPositionInBeats + 0.1f, delegate {
if (PlayerInput.Pressing() || fromAutoplay)
{
animator.Play("FanClapCharge", -1, 0);
stopCharge = true;
}
}),
});
}
else
if (!hit)
{
FanClub.instance.AngerOnMiss();
}
if (fromAutoplay || !force)
{
stopBeat = true;
jumpStartTime = -99f;
animator.Play("FanClap", -1, 0);
Jukebox.PlayOneShotGame("fanClub/play_clap");
Jukebox.PlayOneShotGame("fanClub/crap_impact");
clappingStartTime = cond.songPositionInBeats;
}
if (fromAutoplay && !doCharge)
{
var cond = Conductor.instance;
hasJumped = false;
stopBeat = true;
jumpStartTime = -99f;
animator.Play("FanClap", -1, 0);
Jukebox.PlayOneShotGame("fanClub/play_clap");
Jukebox.PlayOneShotGame("fanClub/crap_impact");
clappingStartTime = cond.songPositionInBeats;
if (doCharge)
BeatAction.New(this.gameObject, new List<BeatAction.Action>()
{
new BeatAction.Action(cond.songPositionInBeats + 0.1f, delegate {
if (PlayerInput.Pressing() || autoplayRelease > 0f)
{
animator.Play("FanClapCharge", -1, 0);
stopCharge = true;
}
}),
});
if (autoplayRelease > 0f && !doCharge)
{
BeatAction.New(this.gameObject, new List<BeatAction.Action>()
{
new BeatAction.Action(cond.songPositionInBeats + autoplayRelease, delegate {
animator.Play("FanFree", -1, 0);
stopBeat = false;
}),
@ -247,22 +193,18 @@ namespace HeavenStudio.Games.Scripts_FanClub
}
}
public void JumpStart(bool hit, bool force = false, bool fromAutoplay = false)
public void JumpStart(bool hit)
{
var cond = Conductor.instance;
if (hit)
{}
else
if (!hit)
{
FanClub.instance.AngerOnMiss();
}
if (fromAutoplay || !force)
{
animator.Play("FanJump", -1, 0);
Jukebox.PlayOneShotGame("fanClub/play_jump");
jumpStartTime = cond.songPositionInBeats;
stopCharge = false;
}
var cond = Conductor.instance;
animator.Play("FanJump", -1, 0);
Jukebox.PlayOneShotGame("fanClub/play_jump");
jumpStartTime = cond.songPositionInBeats;
stopCharge = false;
}
public bool IsJumping()

View File

@ -0,0 +1,291 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using HeavenStudio.TextboxUtilities;
namespace HeavenStudio.Games.Global
{
public class Textbox : MonoBehaviour
{
public enum TextboxAnchor {
TopLeft,
TopMiddle,
TopRight,
Left,
Middle,
Right,
BottomLeft,
BottomMiddle,
BottomRight
}
public enum ClosedCaptionsAnchor {
Top,
Bottom,
}
private List<Beatmap.Entity> textboxEvents = new List<Beatmap.Entity>();
private List<Beatmap.Entity> openCaptionsEvents = new List<Beatmap.Entity>();
private List<Beatmap.Entity> idolEvents = new List<Beatmap.Entity>();
private List<Beatmap.Entity> closedCaptionsEvents = new List<Beatmap.Entity>();
Textbox instance;
[Header("Objects")]
public GameObject TextboxEnabler;
public TextboxObject TextboxObject;
public GameObject OpenCaptionsEnabler;
public TMP_Text OpenCaptionsLabel;
public RectTransform OpenCaptionsLabelRect;
public GameObject IdolEnabler;
public Animator IdolAnimator;
public TMP_Text IdolSongLabel;
public TMP_Text IdolArtistLabel;
public GameObject ClosedCaptionsEnabler;
public TMP_Text ClosedCaptionsLabel;
public RectTransform ClosedCaptionsLabelRect;
public RectTransform ClosedCaptionsBgRect;
float XAnchor = 1.5f;
float YAnchor = 1.75f;
Vector2 textboxSize = new Vector2(3f, 0.75f);
bool idolShown = false;
public void Awake()
{
instance = this;
}
public void Start()
{
GameManager.instance.onBeatChanged += OnBeatChanged;
TextboxEnabler.SetActive(false);
OpenCaptionsEnabler.SetActive(false);
ClosedCaptionsEnabler.SetActive(false);
UpdateTextboxDisplay();
UpdateOpenCaptionsDisplay();
UpdateClosedCaptionsDisplay();
}
public void Update()
{
UpdateTextboxDisplay();
UpdateOpenCaptionsDisplay();
UpdateIdolDisplay();
UpdateClosedCaptionsDisplay();
}
public void OnBeatChanged(float beat)
{
TextboxEnabler.SetActive(false);
OpenCaptionsEnabler.SetActive(false);
ClosedCaptionsEnabler.SetActive(false);
textboxEvents = EventCaller.GetAllInGameManagerList("vfx", new string[] { "display textbox" });
openCaptionsEvents = EventCaller.GetAllInGameManagerList("vfx", new string[] { "display open captions" });
idolEvents = EventCaller.GetAllInGameManagerList("vfx", new string[] { "display song artist" });
closedCaptionsEvents = EventCaller.GetAllInGameManagerList("vfx", new string[] { "display closed captions" });
UpdateTextboxDisplay();
UpdateOpenCaptionsDisplay();
UpdateClosedCaptionsDisplay();
UpdateIdolDisplay();
if (!idolShown)
{
IdolAnimator.Play("NoPose", -1, 0);
IdolAnimator.speed = 1;
}
}
private void UpdateTextboxDisplay()
{
foreach (var e in textboxEvents)
{
float prog = Conductor.instance.GetPositionFromBeat(e.beat, e.length);
if (prog >= 0f && prog <= 1f)
{
TextboxEnabler.SetActive(true);
TextboxObject.SetText(e.text1);
TextboxObject.Resize(e.valA, e.valB);
// ouch
switch (e.type)
{
case (int) TextboxAnchor.TopLeft:
TextboxEnabler.transform.localPosition = new Vector3(-XAnchor, YAnchor);
break;
case (int) TextboxAnchor.TopMiddle:
TextboxEnabler.transform.localPosition = new Vector3(0, YAnchor);
break;
case (int) TextboxAnchor.TopRight:
TextboxEnabler.transform.localPosition = new Vector3(XAnchor, YAnchor);
break;
case (int) TextboxAnchor.Left:
TextboxEnabler.transform.localPosition = new Vector3(-XAnchor, 0);
break;
case (int) TextboxAnchor.Middle:
TextboxEnabler.transform.localPosition = new Vector3(0, 0);
break;
case (int) TextboxAnchor.Right:
TextboxEnabler.transform.localPosition = new Vector3(XAnchor, 0);
break;
case (int) TextboxAnchor.BottomLeft:
TextboxEnabler.transform.localPosition = new Vector3(-XAnchor, -YAnchor);
break;
case (int) TextboxAnchor.BottomMiddle:
TextboxEnabler.transform.localPosition = new Vector3(0, -YAnchor);
break;
case (int) TextboxAnchor.BottomRight:
TextboxEnabler.transform.localPosition = new Vector3(XAnchor, -YAnchor);
break;
default:
TextboxEnabler.transform.localPosition = new Vector3(0, 0);
break;
}
return;
}
if (prog > 1f || prog < 0f)
{
TextboxEnabler.transform.localPosition = new Vector3(0, 0);
TextboxEnabler.SetActive(false);
}
}
}
private void UpdateOpenCaptionsDisplay()
{
foreach (var e in openCaptionsEvents)
{
float prog = Conductor.instance.GetPositionFromBeat(e.beat, e.length);
if (prog >= 0f && prog <= 1f)
{
OpenCaptionsEnabler.SetActive(true);
OpenCaptionsLabel.text = e.text1;
OpenCaptionsLabelRect.sizeDelta = new Vector2(18f * e.valA, 2.5f * e.valB);
// ouch
switch (e.type)
{
case (int) TextboxAnchor.TopLeft:
OpenCaptionsEnabler.transform.localPosition = new Vector3(-XAnchor, YAnchor);
break;
case (int) TextboxAnchor.TopMiddle:
OpenCaptionsEnabler.transform.localPosition = new Vector3(0, YAnchor);
break;
case (int) TextboxAnchor.TopRight:
OpenCaptionsEnabler.transform.localPosition = new Vector3(XAnchor, YAnchor);
break;
case (int) TextboxAnchor.Left:
OpenCaptionsEnabler.transform.localPosition = new Vector3(-XAnchor, 0);
break;
case (int) TextboxAnchor.Middle:
OpenCaptionsEnabler.transform.localPosition = new Vector3(0, 0);
break;
case (int) TextboxAnchor.Right:
OpenCaptionsEnabler.transform.localPosition = new Vector3(XAnchor, 0);
break;
case (int) TextboxAnchor.BottomLeft:
OpenCaptionsEnabler.transform.localPosition = new Vector3(-XAnchor, -YAnchor);
break;
case (int) TextboxAnchor.BottomMiddle:
OpenCaptionsEnabler.transform.localPosition = new Vector3(0, -YAnchor);
break;
case (int) TextboxAnchor.BottomRight:
OpenCaptionsEnabler.transform.localPosition = new Vector3(XAnchor, -YAnchor);
break;
default:
OpenCaptionsEnabler.transform.localPosition = new Vector3(0, 0);
break;
}
return;
}
if (prog > 1f || prog < 0f)
{
OpenCaptionsEnabler.transform.localPosition = new Vector3(0, 0);
OpenCaptionsEnabler.SetActive(false);
}
}
}
private void UpdateIdolDisplay()
{
var cond = Conductor.instance;
foreach (var e in idolEvents)
{
float prog = cond.GetPositionFromBeat(e.beat, e.length);
if (prog >= 0f && prog <= 1f)
{
float inp = cond.GetPositionFromBeat(e.beat, 1);
IdolSongLabel.text = e.text1;
IdolArtistLabel.text = e.text2;
IdolAnimator.Play("IdolShow", -1, Mathf.Min(inp, 1));
IdolAnimator.speed = 0;
idolShown = true;
return;
}
else if (idolShown)
{
if (prog < 1f)
{
IdolAnimator.Play("NoPose", -1, 0);
IdolAnimator.speed = 1;
idolShown = false;
}
else
{
IdolAnimator.Play("IdolHide", -1, 0);
IdolAnimator.speed = (1f / cond.pitchedSecPerBeat) * 0.5f;
idolShown = false;
}
}
}
}
private void UpdateClosedCaptionsDisplay()
{
foreach (var e in closedCaptionsEvents)
{
float prog = Conductor.instance.GetPositionFromBeat(e.beat, e.length);
if (prog >= 0f && prog <= 1f)
{
ClosedCaptionsEnabler.SetActive(true);
ClosedCaptionsLabel.text = e.text1;
ClosedCaptionsLabelRect.sizeDelta = new Vector2(9f, e.valA);
ClosedCaptionsBgRect.sizeDelta = new Vector2(9f, e.valA);
switch (e.type)
{
case (int) ClosedCaptionsAnchor.Bottom:
ClosedCaptionsEnabler.transform.localPosition = new Vector3(0, -2.5f + e.valA/2);
break;
default:
ClosedCaptionsEnabler.transform.localPosition = new Vector3(0, 2.5f - e.valA/2);
break;
}
return;
}
if (prog > 1f || prog < 0f)
{
ClosedCaptionsEnabler.SetActive(false);
}
}
}
}
}

View File

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

View File

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

View File

@ -0,0 +1,37 @@
using HeavenStudio.Util;
using System;
using System.Collections.Generic;
using UnityEngine;
namespace HeavenStudio.Games.Loaders
{
using static Minigames;
public static class RvlRocketLoader
{
public static Minigame AddGame(EventCaller eventCaller) {
return new Minigame("launch party", "Launch Party \n<color=#eb5454>[WIP don't use]</color>", "000000", false, false, new List<GameAction>()
{
});
}
}
}
namespace HeavenStudio.Games
{
// using Scripts_LaunchParty;
public class LaunchParty : Minigame
{
// Start is called before the first frame update
void Awake()
{
}
// Update is called once per frame
void Update()
{
}
}
}

View File

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

View File

@ -6,7 +6,7 @@ namespace HeavenStudio.Games
{
public class Minigame : MonoBehaviour
{
public static float earlyTime = 0.84f, perfectTime = 0.91f, lateTime = 1.09f, endTime = 1.15f;
public static float earlyTime = 0.1f, perfectTime = 0.06f, lateTime = 0.06f, endTime = 0.1f;
public List<Minigame.Eligible> EligibleHits = new List<Minigame.Eligible>();
[System.Serializable]
@ -21,25 +21,149 @@ namespace HeavenStudio.Games
public float createBeat;
}
// hopefully these will fix the lowbpm problem
public List<PlayerActionEvent> scheduledInputs = new List<PlayerActionEvent>();
/**
* Schedule an Input for a later time in the minigame. Executes the methods put in parameters
*
* float startBeat : When the scheduling started (In beats)
* float timer : How many beats later should the input be expected
* InputType inputType : The type of the input that's expected (Press, release, A, B, Directions..) (Check InputType class for a list)
* ActionEventCallbackState OnHit : Method to run if the Input has been Hit
* ActionEventCallback OnMiss : Method to run if the Input has been Missed
* ActionEventCallback OnBlank : Method to run whenever there's an Input while this is Scheduled (Shouldn't be used too much)
*/
public PlayerActionEvent ScheduleInput(float startBeat,
float timer,
InputType inputType,
PlayerActionEvent.ActionEventCallbackState OnHit,
PlayerActionEvent.ActionEventCallback OnMiss,
PlayerActionEvent.ActionEventCallback OnBlank)
{
GameObject evtObj = new GameObject("ActionEvent" + (startBeat+timer));
evtObj.AddComponent<PlayerActionEvent>();
PlayerActionEvent evt = evtObj.GetComponent<PlayerActionEvent>();
evt.startBeat = startBeat;
evt.timer = timer;
evt.inputType = inputType;
evt.OnHit = OnHit;
evt.OnMiss = OnMiss;
evt.OnBlank = OnBlank;
evt.OnDestroy = RemoveScheduledInput;
evt.canHit = true;
evt.enabled = true;
evt.transform.parent = this.transform.parent;
evtObj.SetActive(true);
scheduledInputs.Add(evt);
return evt;
}
public PlayerActionEvent ScheduleAutoplayInput(float startBeat,
float timer,
InputType inputType,
PlayerActionEvent.ActionEventCallbackState OnHit,
PlayerActionEvent.ActionEventCallback OnMiss,
PlayerActionEvent.ActionEventCallback OnBlank)
{
PlayerActionEvent evt = ScheduleInput(startBeat, timer, inputType, OnHit, OnMiss, OnBlank);
evt.autoplayOnly = true;
return evt;
}
public PlayerActionEvent ScheduleUserInput(float startBeat,
float timer,
InputType inputType,
PlayerActionEvent.ActionEventCallbackState OnHit,
PlayerActionEvent.ActionEventCallback OnMiss,
PlayerActionEvent.ActionEventCallback OnBlank)
{
PlayerActionEvent evt = ScheduleInput(startBeat, timer, inputType, OnHit, OnMiss, OnBlank);
evt.noAutoplay = true;
return evt;
}
//Clean up method used whenever a PlayerActionEvent has finished
public void RemoveScheduledInput(PlayerActionEvent evt)
{
scheduledInputs.Remove(evt);
}
//Get the scheduled input that should happen the **Soonest**
//Can return null if there's no scheduled inputs
public PlayerActionEvent GetClosestScheduledInput()
{
PlayerActionEvent closest = null;
foreach(PlayerActionEvent toCompare in scheduledInputs)
{
if(closest == null)
{
closest = toCompare;
} else
{
float t1 = closest.startBeat + closest.timer;
float t2 = toCompare.startBeat + toCompare.timer;
// Debug.Log("t1=" + t1 + " -- t2=" + t2);
if (t2 < t1) closest = toCompare;
}
}
return closest;
}
//Hasn't been tested yet. *Should* work.
//Can be used to detect if the user is expected to input something now or not
//Useful for strict call and responses games like Tambourine
public bool IsExpectingInputNow()
{
PlayerActionEvent input = GetClosestScheduledInput();
if (input == null) return false;
return input.IsExpectingInputNow();
}
// now should fix the fast bpm problem
public static float EarlyTime()
{
return earlyTime;
return 1f - ScaleTimingMargin(earlyTime);
}
public static float PerfectTime()
{
return perfectTime;
return 1f - ScaleTimingMargin(perfectTime);
}
public static float LateTime()
{
return lateTime;
return 1f + ScaleTimingMargin(lateTime);
}
public static float EndTime()
{
return endTime;
return 1f + ScaleTimingMargin(endTime);
}
//scales timing windows to the BPM in an ""intelligent"" manner
static float ScaleTimingMargin(float f)
{
float bpm = Conductor.instance.songBpm * Conductor.instance.musicSource.pitch;
float a = bpm / 120f;
float b = (Mathf.Log(a) + 2f) * 0.5f;
float r = Mathf.Lerp(a, b, 0.25f);
return r * f;
}
public int firstEnable = 0;

View File

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

View File

@ -0,0 +1,171 @@
using HeavenStudio.Util;
using System.Collections;
using System.Collections.Generic;
using System;
using UnityEngine;
namespace HeavenStudio.Games.Scripts_PajamaParty
{
public class CtrPillowMonkey : MonoBehaviour
{
[Header("Objects")]
public GameObject Monkey;
public GameObject Shadow;
public GameObject Projectile;
public Animator anim;
public int row;
public int col;
float startJumpTime = Single.MinValue;
float jumpLength = 1f;
float jumpHeight = 4f;
int jumpAlt;
private bool hasJumped = false;
float startThrowTime = Single.MinValue;
float throwLength = 4f;
float throwHeight = 12f;
private bool hasThrown = false;
void Awake()
{
anim = Monkey.GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
var cond = Conductor.instance;
//jumping logic
float jumpPos = cond.GetPositionFromBeat(startJumpTime, jumpLength);
if (jumpPos >= 0 && jumpPos <= 1f)
{
hasJumped = true;
float yMul = jumpPos * 2f - 1f;
float yWeight = -(yMul*yMul) + 1f;
Monkey.transform.localPosition = new Vector3(0, jumpHeight * yWeight);
Shadow.transform.localScale = new Vector3((1f-yWeight*0.2f) * 1.2f, (1f-yWeight*0.2f) * 0.8f, 1f);
if (jumpAlt > 1)
{
float t;
if (jumpAlt == 3)
t = 1f - jumpPos;
else
t = jumpPos;
Monkey.transform.rotation = Quaternion.Euler(0, 0, Mathf.Lerp(22.5f, -22.5f, t));
anim.DoScaledAnimation("MonkeyJump0" + jumpAlt, startJumpTime, jumpLength);
}
else
anim.DoScaledAnimation("MonkeyJump", startJumpTime, jumpLength);
}
else
{
if (hasJumped)
{
hasJumped = false;
PajamaParty.instance.DoBedImpact();
anim.DoScaledAnimationAsync("MonkeyLand");
Monkey.transform.rotation = Quaternion.Euler(0, 0, 0);
jumpAlt = 0;
}
startJumpTime = Single.MinValue;
Monkey.transform.localPosition = new Vector3(0, 0);
Shadow.transform.localScale = new Vector3(1.2f, 0.8f, 1f);
}
//throwing logic
jumpPos = cond.GetPositionFromBeat(startThrowTime, throwLength);
if (jumpPos >= 0 && jumpPos <= 1f)
{
hasThrown = true;
float yMul = jumpPos * 2f - 1f;
float yWeight = -(yMul*yMul) + 1f;
Projectile.transform.localPosition = new Vector3(0, throwHeight * yWeight + 1.5f);
Projectile.transform.rotation = Quaternion.Euler(0, 0, Projectile.transform.rotation.eulerAngles.z - (360f * Time.deltaTime));
}
else
{
startThrowTime = Single.MinValue;
if (hasThrown)
{
Projectile.transform.localPosition = new Vector3(0, 0);
Projectile.transform.rotation = Quaternion.Euler(0, 0, 0);
anim.DoUnscaledAnimation("MonkeyBeat");
Projectile.SetActive(false);
hasThrown = false;
}
}
}
public void Jump(float beat, int alt = 1)
{
startJumpTime = beat;
jumpAlt = 0;
if (alt > 1)
{
jumpAlt = alt;
}
}
public void Charge(float beat)
{
anim.DoUnscaledAnimation("MonkeyReady");
}
public void Throw(float beat)
{
anim.DoUnscaledAnimation("MonkeyThrow");
startThrowTime = beat;
Projectile.SetActive(true);
}
public void ReadySleep(float beat, int action)
{
var cond = Conductor.instance;
startThrowTime = Single.MinValue;
Projectile.transform.localPosition = new Vector3(0, 0);
Projectile.transform.rotation = Quaternion.Euler(0, 0, 0);
if (hasThrown)
{
Projectile.SetActive(false);
hasThrown = false;
}
startJumpTime = Single.MinValue;
Monkey.transform.localPosition = new Vector3(0, 0);
Shadow.transform.localScale = new Vector3(1.2f, 0.8f, 1f);
List<BeatAction.Action> seq =
new List<BeatAction.Action>()
{
new BeatAction.Action( beat, delegate { anim.DoScaledAnimationAsync("MonkeySleep00"); }),
new BeatAction.Action( beat + 0.5f, delegate { anim.DoUnscaledAnimation("MonkeySleep01"); }),
};
if (col == 0 || col == 4)
{
seq.Add(new BeatAction.Action( beat + 1f, delegate { anim.DoScaledAnimationAsync("MonkeySleep02"); }));
}
else if (col == 1 || col == 3)
{
seq.Add(new BeatAction.Action( beat + 1.5f, delegate { anim.DoScaledAnimationAsync("MonkeyReadySleep"); }));
seq.Add(new BeatAction.Action( beat + 2.5f, delegate { anim.DoScaledAnimationAsync("MonkeySleep02"); }));
}
else
{
seq.Add(new BeatAction.Action( beat + 3f, delegate { anim.DoScaledAnimationAsync("MonkeyReadySleep"); }));
seq.Add(new BeatAction.Action( beat + 4f, delegate { anim.DoScaledAnimationAsync("MonkeySleep02"); }));
}
if (action != (int) PajamaParty.SleepType.NoAwake)
seq.Add(new BeatAction.Action( beat + 7f, delegate { anim.DoScaledAnimationAsync("MonkeyAwake"); }));
BeatAction.New(Monkey, seq);
}
}
}

View File

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

View File

@ -0,0 +1,446 @@
using HeavenStudio.Util;
using System.Collections;
using System.Collections.Generic;
using System;
using UnityEngine;
namespace HeavenStudio.Games.Scripts_PajamaParty
{
public class CtrPillowPlayer : MonoBehaviour
{
[Header("Objects")]
public GameObject Player;
public GameObject Shadow;
public GameObject Projectile;
public GameObject Projectile_Root;
public Animator anim;
float startJumpTime = Single.MinValue;
float jumpLength = 0;
float jumpHeight = 0;
bool jumpNg = false;
private bool hasJumped = false;
private bool canJump = true;
private bool charging = false;
private bool canCharge = true;
float startThrowTime = Single.MinValue;
float throwLength = 0;
float throwHeight = 0;
// true = throw, false = dropped ("Out")
bool throwType = true;
bool hasThrown = false;
bool throwNg = false;
bool longSleep = false;
public bool canSleep = false;
void Awake()
{
anim = Player.GetComponent<Animator>();
longSleep = false;
}
// Update is called once per frame
void Update()
{
var cond = Conductor.instance;
if (PlayerInput.Pressed() && canJump && !PajamaParty.instance.IsExpectingInputNow())
{
Jukebox.PlayOneShot("miss");
PlayerJump(cond.songPositionInBeats, true, false);
}
if (PlayerInput.AltPressed() && canCharge)
{
StartCharge();
}
if (PlayerInput.AltPressedUp() && charging && !PajamaParty.instance.IsExpectingInputNow())
{
Jukebox.PlayOneShot("miss");
EndCharge(cond.songPositionInBeats, false, false);
}
// mako jumping logic
float jumpPos = cond.GetPositionFromBeat(startJumpTime, jumpLength);
if (jumpPos >= 0 && jumpPos <= 1f)
{
hasJumped = true;
float yMul = jumpPos * 2f - 1f;
float yWeight = -(yMul*yMul) + 1f;
Player.transform.localPosition = new Vector3(0, jumpHeight * yWeight);
Shadow.transform.localScale = new Vector3((1f-yWeight*0.2f) * 1.65f, (1f-yWeight*0.2f), 1f);
// handles the shirt lifting
anim.DoScaledAnimation("MakoJump", startJumpTime, jumpLength);
}
else
{
if (hasJumped)
{
canJump = true;
canCharge = true;
hasJumped = false;
PajamaParty.instance.DoBedImpact();
if (jumpNg)
anim.DoScaledAnimationAsync("MakoCatchNg");
else if (jumpHeight != 4f)
anim.DoScaledAnimationAsync("MakoCatch");
else
anim.DoScaledAnimationAsync("MakoLand");
jumpNg = false;
}
startJumpTime = Single.MinValue;
Player.transform.localPosition = new Vector3(0, 0);
Shadow.transform.localScale = new Vector3(1.65f, 1f, 1f);
}
//thrown pillow logic
jumpPos = cond.GetPositionFromBeat(startThrowTime, throwLength);
if (jumpPos >= 0 && jumpPos <= 1f)
{
if (throwType)
{
hasThrown = true;
float yMul = jumpPos * 2f - 1f;
float yWeight = -(yMul*yMul) + 1f;
Projectile_Root.transform.localPosition = new Vector3(0, throwHeight * yWeight + 0.5f);
}
else
{
Projectile.GetComponent<Animator>().DoScaledAnimation("ThrowOut", startThrowTime, throwLength);
}
Projectile.transform.rotation = Quaternion.Euler(0, 0, Projectile.transform.rotation.eulerAngles.z - (360f * Time.deltaTime));
}
else
{
startThrowTime = Single.MinValue;
Projectile_Root.transform.localPosition = new Vector3(0, 0);
if (hasThrown)
{
Projectile.GetComponent<Animator>().Play("NoPose", -1, 0);
Projectile.transform.rotation = Quaternion.Euler(0, 0, 0);
if (throwNg)
{
anim.DoUnscaledAnimation("MakoCatchNg");
}
else
{
anim.DoUnscaledAnimation("MakoCatch");
}
//TODO: change when locales are a thing
Jukebox.PlayOneShotGame("pajamaParty/catch" + UnityEngine.Random.Range(0, 2)); //bruh
Projectile.SetActive(false);
hasThrown = false;
throwNg = false;
canCharge = true;
canJump = true;
}
}
}
public void ProjectileThrow(float beat, bool drop = false, bool ng = false)
{
throwNg = ng;
Projectile.SetActive(true);
startThrowTime = beat;
if (drop)
{
throwType = false;
throwLength = 0.5f;
Projectile.GetComponent<Animator>().DoScaledAnimation("ThrowOut", startThrowTime, throwLength);
Projectile.transform.rotation = Quaternion.Euler(0, 0, 360f * UnityEngine.Random.Range(0f, 1f));
}
else
{
throwType = true;
throwHeight = ng ? 1.5f : 12f;
throwLength = ng ? 1f : 4f;
}
}
public void PlayerJump(float beat, bool pressout = false, bool ng = false)
{
startJumpTime = beat;
canCharge = false;
canJump = false;
//temp
jumpLength = (ng || pressout) ? 0.5f : 1f;
jumpHeight = (ng || pressout) ? 2f : 4f;
jumpNg = ng;
}
public void StartCharge()
{
canJump = false;
anim.DoUnscaledAnimation("MakoReady");
charging = true;
}
public void EndCharge(float beat, bool hit = true, bool ng = false)
{
ProjectileThrow(beat, !hit, ng);
var cond = Conductor.instance;
charging = false;
canCharge = false;
if (hit)
anim.DoUnscaledAnimation("MakoThrow");
else
{
anim.DoScaledAnimationAsync("MakoThrowOut", 0.5f);
BeatAction.New(Player, new List<BeatAction.Action>()
{
new BeatAction.Action(
beat + 0.5f,
delegate {
anim.DoScaledAnimationAsync("MakoPickUp");
Jukebox.PlayOneShotGame("pajamaParty/catch" + UnityEngine.Random.Range(0, 2)); //bruh
Projectile.SetActive(false);
canCharge = true;
canJump = true;
}
)
});
}
}
public void PlayerThrough(float beat)
{
var cond = Conductor.instance;
anim.DoScaledAnimationAsync("MakoThrough", 0.5f);
charging = false;
canCharge = false;
canJump = false;
BeatAction.New(Player, new List<BeatAction.Action>()
{
new BeatAction.Action(
beat + 0.5f,
delegate {
canCharge = true;
canJump = true;
}
)
});
}
// jumping cues (timings for both are the same)
public void ScheduleJump(float beat)
{
PajamaParty.instance.ScheduleInput(beat, 2f, InputType.STANDARD_DOWN, JumpJustOrNg, JumpThrough, JumpOut);
}
public void JumpJustOrNg(PlayerActionEvent caller, float state)
{
if (canJump)
{
var cond = Conductor.instance;
if (state <= -1f || state >= 1f)
{
Jukebox.PlayOneShot("miss");
PlayerJump(cond.songPositionInBeats, false, true);
}
else
{
Jukebox.PlayOneShotGame("pajamaParty/jumpJust");
PlayerJump(cond.songPositionInBeats, false, false);
}
caller.CanHit(false);
}
}
public void JumpOut(PlayerActionEvent caller) {}
public void JumpThrough(PlayerActionEvent caller)
{
if (canJump)
{
var cond = Conductor.instance;
PlayerThrough(cond.songPositionInBeats);
}
}
//////
// throw cue
public void ScheduleThrow(float beat)
{
PajamaParty.instance.ScheduleInput(beat, 2f, InputType.STANDARD_ALT_DOWN, ChargeJustOrNg, ThrowThrough, JumpOut);
PajamaParty.instance.ScheduleInput(beat, 3f, InputType.STANDARD_ALT_UP, ThrowJustOrNg, ThrowThrough, JumpOut);
}
public void ChargeJustOrNg(PlayerActionEvent caller, float state) {
StartCharge();
throwNg = (state <= -1f || state >= 1f);
Jukebox.PlayOneShotGame("pajamaParty/throw4");
}
public void ThrowJustOrNg(PlayerActionEvent caller, float state)
{
if (charging)
{
var cond = Conductor.instance;
if (state <= -1f || state >= 1f)
{
Jukebox.PlayOneShot("miss");
EndCharge(cond.songPositionInBeats, true, true);
}
else
{
Jukebox.PlayOneShotGame("pajamaParty/throw5");
EndCharge(cond.songPositionInBeats, true, (throwNg || false));
}
caller.CanHit(false);
}
}
public void ThrowThrough(PlayerActionEvent caller)
{
if (canCharge)
{
var cond = Conductor.instance;
PlayerThrough(cond.songPositionInBeats);
}
}
//
// sleep cue
public void StartSleepSequence(float beat, bool alt, int action)
{
if (hasJumped)
{
hasJumped = false;
PajamaParty.instance.DoBedImpact();
jumpNg = false;
}
startJumpTime = Single.MinValue;
Player.transform.localPosition = new Vector3(0, 0);
Shadow.transform.localScale = new Vector3(1.65f, 1f, 1f);
Projectile.GetComponent<Animator>().Play("NoPose", -1, 0);
startThrowTime = Single.MinValue;
Projectile_Root.transform.localPosition = new Vector3(0, 0);
Projectile.transform.rotation = Quaternion.Euler(0, 0, 0);
if (hasThrown)
{
Projectile.SetActive(false);
hasThrown = false;
}
PajamaParty.instance.ScheduleInput(beat, 4f, InputType.STANDARD_DOWN, SleepJustOrNg, SleepThrough, SleepOut);
var cond = Conductor.instance;
charging = false;
canCharge = false;
canJump = false;
if (hasJumped)
{
canJump = true;
canCharge = true;
hasJumped = false;
PajamaParty.instance.DoBedImpact();
anim.DoScaledAnimationAsync("MakoLand");
}
startJumpTime = Single.MinValue;
Player.transform.localPosition = new Vector3(0, 0);
Shadow.transform.localScale = new Vector3(1.65f, 1f, 1f);
if (action == (int) PajamaParty.SleepType.NoAwake)
{
longSleep = true;
}
BeatAction.New(Player, new List<BeatAction.Action>()
{
new BeatAction.Action(
beat,
delegate { anim.DoScaledAnimationAsync("MakoSleep00"); }
),
new BeatAction.Action(
beat + 0.5f,
delegate { anim.DoUnscaledAnimation("MakoSleep01"); }
),
new BeatAction.Action(
beat + 1f,
delegate {
canSleep = true;
}
),
new BeatAction.Action(
beat + 3f,
delegate {
if (canSleep)
anim.DoScaledAnimationAsync(alt ? "MakoReadySleep01" : "MakoReadySleep");
}
),
new BeatAction.Action(
beat + 8f,
delegate {
canCharge = true;
canJump = true;
}
),
});
}
public void SleepJustOrNg(PlayerActionEvent caller, float state)
{
var cond = Conductor.instance;
if (canSleep)
{
caller.CanHit(false);
canSleep = false;
if (state <= -1f || state >= 1f)
anim.DoUnscaledAnimation("MakoSleepNg");
else
{
Jukebox.PlayOneShotGame("pajamaParty/siesta4");
anim.DoScaledAnimationAsync("MakoSleepJust");
if (!longSleep)
{
BeatAction.New(Player, new List<BeatAction.Action>()
{
new BeatAction.Action(
caller.startBeat + 7f,
delegate {
anim.DoScaledAnimationAsync("MakoAwake");
Jukebox.PlayOneShotGame("pajamaParty/siestaDone");
}
),
});
}
longSleep = false;
}
}
}
public void SleepThrough(PlayerActionEvent caller)
{
var cond = Conductor.instance;
if (canSleep)
{
anim.DoScaledAnimationAsync("MakoSleepThrough", -1, 0);
caller.CanHit(false);
canSleep = false;
}
}
public void SleepOut(PlayerActionEvent caller)
{
var cond = Conductor.instance;
if (canSleep)
{
anim.DoScaledAnimationAsync("MakoSleepOut", 0.5f);
Jukebox.PlayOneShotGame("pajamaParty/siestaBad");
caller.CanHit(false);
canSleep = false;
}
}
//////
}
}

View File

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

View File

@ -0,0 +1,351 @@
using HeavenStudio.Util;
using System.Collections;
using System.Collections.Generic;
using System;
using UnityEngine;
using UnityEngine.Rendering;
namespace HeavenStudio.Games.Loaders
{
using static Minigames;
public static class CtrPillowLoader
{
public static Minigame AddGame(EventCaller eventCaller) {
return new Minigame("pajamaParty", "Pajama Party", "965076", false, false, new List<GameAction>()
{
// both same timing
new GameAction("jump (side to middle)", delegate {PajamaParty.instance.DoThreeJump(eventCaller.currentEntity.beat);}, 4f, false,
inactiveFunction: delegate {PajamaParty.WarnThreeJump(eventCaller.currentEntity.beat);}
),
new GameAction("jump (back to front)", delegate {PajamaParty.instance.DoFiveJump(eventCaller.currentEntity.beat);}, 4f, false,
inactiveFunction: delegate {PajamaParty.WarnFiveJump(eventCaller.currentEntity.beat);}
),
//idem
new GameAction("slumber", delegate {var e = eventCaller.currentEntity; PajamaParty.instance.DoSleepSequence(e.beat, e.toggle, e.type);}, 8f, false, parameters: new List<Param>()
{
new Param("type", PajamaParty.SleepType.Normal, "Sleep Type", "Type of sleep action to use"),
new Param("toggle", false, "Alt. Animation", "Use an alternate animation for Mako")
},
inactiveFunction: delegate {var e = eventCaller.currentEntity; PajamaParty.WarnSleepSequence(e.beat, e.toggle);}
),
new GameAction("throw", delegate {PajamaParty.instance.DoThrowSequence(eventCaller.currentEntity.beat);}, 8f, false,
inactiveFunction: delegate {PajamaParty.WarnThrowSequence(eventCaller.currentEntity.beat);}
),
//cosmetic
// new GameAction("open / close background", delegate { }, 2f, true),
// do shit with mako's face? (talking?)
},
new List<string>() {"ctr", "normal"},
"ctrpillow", "jp",
new List<string>() {"en", "jp", "ko"}
);
}
}
}
namespace HeavenStudio.Games
{
using Scripts_PajamaParty;
public class PajamaParty : Minigame
{
[Header("Objects")]
public CtrPillowPlayer Mako;
public GameObject Bed;
public GameObject MonkeyPrefab;
[Header("Positions")]
public Transform SpawnRoot;
//game scene
public static PajamaParty instance;
CtrPillowMonkey[,] monkeys;
//cues while unoaded
static float WantThreeJump = Single.MinValue;
static float WantFiveJump = Single.MinValue;
static float WantThrowSequence = Single.MinValue;
static float WantSleepSequence = Single.MinValue;
static bool WantSleepType = false;
static int WantSleepAction = (int) PajamaParty.SleepType.Normal;
public enum SleepType {
Normal,
NoAwake,
}
void Awake()
{
instance = this;
//spawn monkeys
// is 5x5 grid with row 0, col 2 being empty (the player)
// m m m m m
// m m m m m
// m m m m m
// m m m m m
// m m P m m
monkeys = new CtrPillowMonkey[5,5];
float RADIUS = 2.75f;
float scale = 1.0f;
int sorting = 10;
//set our start position (at Mako + 2*radius to the right)
Vector3 spawnPos = SpawnRoot.position + new Vector3(-RADIUS*3, 0);
for (int y = 0; y < 5; y++)
{
for (int x = 0; x < 5; x++)
{
//on x-axis we go left to right
spawnPos += new Vector3(RADIUS*scale, 0);
if (!(y == 0 && x == 2)) //don't spawn at the player's position
{
GameObject mobj = Instantiate(MonkeyPrefab, SpawnRoot.parent);
CtrPillowMonkey monkey = mobj.GetComponent<CtrPillowMonkey>();
mobj.GetComponent<SortingGroup>().sortingOrder = sorting;
mobj.transform.localPosition = new Vector3(spawnPos.x, spawnPos.y, spawnPos.z);
mobj.transform.localScale = new Vector3(scale, scale);
monkey.row = y;
monkey.col = x;
monkeys[x, y] = monkey;
}
}
// on the y-axis we go front to back (player to the rear)
scale -= 0.1f;
spawnPos = SpawnRoot.position - new Vector3(RADIUS*3*scale, -RADIUS/3.75f*(y+1), -RADIUS/5f*(y+1));
sorting--;
}
}
public override void OnGameSwitch(float beat)
{
if (WantThreeJump != Single.MinValue)
{
DoThreeJump(WantThreeJump, false);
WantThreeJump = Single.MinValue;
}
if (WantFiveJump != Single.MinValue)
{
DoFiveJump(WantFiveJump, false);
WantFiveJump = Single.MinValue;
}
if (WantThrowSequence != Single.MinValue)
{
DoThrowSequence(WantThrowSequence, false);
WantThrowSequence = Single.MinValue;
}
if (WantSleepSequence != Single.MinValue)
{
DoSleepSequence(WantSleepSequence, WantSleepType, WantSleepAction, false);
WantSleepSequence = Single.MinValue;
}
}
public void DoThreeJump(float beat, bool doSound = true)
{
Mako.ScheduleJump(beat);
if (doSound)
MultiSound.Play(new MultiSound.Sound[] {
new MultiSound.Sound("pajamaParty/three1", beat),
new MultiSound.Sound("pajamaParty/three2", beat + 1f),
new MultiSound.Sound("pajamaParty/three3", beat + 2f),
});
BeatAction.New(Bed, new List<BeatAction.Action>()
{
new BeatAction.Action(
beat,
delegate {
JumpCol(0, beat);
JumpCol(4, beat);
}
),
new BeatAction.Action(
beat + 1,
delegate {
JumpCol(1, beat + 1, 3);
JumpCol(3, beat + 1, 3);
}
),
new BeatAction.Action(
beat + 2,
delegate {
JumpCol(2, beat + 2);
}
),
});
}
public static void WarnThreeJump(float beat)
{
MultiSound.Play(new MultiSound.Sound[] {
new MultiSound.Sound("pajamaParty/three1", beat),
new MultiSound.Sound("pajamaParty/three2", beat + 1f),
new MultiSound.Sound("pajamaParty/three3", beat + 2f),
}, forcePlay:true);
WantThreeJump = beat;
}
public void DoFiveJump(float beat, bool doSound = true)
{
Mako.ScheduleJump(beat);
if (doSound)
MultiSound.Play(new MultiSound.Sound[] {
new MultiSound.Sound("pajamaParty/five1", beat),
new MultiSound.Sound("pajamaParty/five2", beat + 0.5f),
new MultiSound.Sound("pajamaParty/five3", beat + 1f),
new MultiSound.Sound("pajamaParty/five4", beat + 1.5f),
new MultiSound.Sound("pajamaParty/five5", beat + 2f)
});
BeatAction.New(Bed, new List<BeatAction.Action>()
{
new BeatAction.Action( beat, delegate { JumpRow(4, beat); }),
new BeatAction.Action( beat + 0.5f, delegate { JumpRow(3, beat + 0.5f, 2); }),
new BeatAction.Action( beat + 1f, delegate { JumpRow(2, beat + 1f); }),
new BeatAction.Action( beat + 1.5f, delegate { JumpRow(1, beat + 1.5f, 2); }),
new BeatAction.Action( beat + 2f, delegate { JumpRow(0, beat + 2f); }),
});
}
public static void WarnFiveJump(float beat)
{
MultiSound.Play(new MultiSound.Sound[] {
new MultiSound.Sound("pajamaParty/five1", beat),
new MultiSound.Sound("pajamaParty/five2", beat + 0.5f),
new MultiSound.Sound("pajamaParty/five3", beat + 1f),
new MultiSound.Sound("pajamaParty/five4", beat + 1.5f),
new MultiSound.Sound("pajamaParty/five5", beat + 2f)
}, forcePlay:true);
WantFiveJump = beat;
}
public void DoThrowSequence(float beat, bool doSound = true)
{
Mako.ScheduleThrow(beat);
if (doSound)
PlayThrowSequenceSound(beat);
BeatAction.New(Mako.Player, new List<BeatAction.Action>()
{
new BeatAction.Action( beat + 2f, delegate { MonkeyCharge(beat + 2f); } ),
new BeatAction.Action( beat + 3f, delegate { MonkeyThrow(beat + 3f); } ),
});
}
public static void WarnThrowSequence(float beat)
{
PlayThrowSequenceSound(beat, true);
WantThrowSequence = beat;
}
public static void PlayThrowSequenceSound(float beat, bool force = false)
{
MultiSound.Play(new MultiSound.Sound[] {
new MultiSound.Sound("pajamaParty/throw1", beat),
new MultiSound.Sound("pajamaParty/throw2", beat + 0.5f),
new MultiSound.Sound("pajamaParty/throw3", beat + 1f),
//TODO: change when locales are a thing
new MultiSound.Sound("pajamaParty/throw4a", beat + 1.5f),
new MultiSound.Sound("pajamaParty/charge", beat + 2f),
}, forcePlay: force);
}
public void DoSleepSequence(float beat, bool alt = false, int action = (int) PajamaParty.SleepType.Normal, bool doSound = true)
{
var cond = Conductor.instance;
Mako.StartSleepSequence(beat, alt, action);
MonkeySleep(beat, action);
if (doSound)
MultiSound.Play(new MultiSound.Sound[] {
new MultiSound.Sound("pajamaParty/siesta1", beat),
new MultiSound.Sound("pajamaParty/siesta2", beat + 0.5f),
new MultiSound.Sound("pajamaParty/siesta3", beat + 1f),
new MultiSound.Sound("pajamaParty/siesta3", beat + 2.5f),
new MultiSound.Sound("pajamaParty/siesta3", beat + 4f)
});
}
public static void WarnSleepSequence(float beat, bool alt = false)
{
MultiSound.Play(new MultiSound.Sound[] {
new MultiSound.Sound("pajamaParty/siesta1", beat),
new MultiSound.Sound("pajamaParty/siesta2", beat + 0.5f),
new MultiSound.Sound("pajamaParty/siesta3", beat + 1f),
new MultiSound.Sound("pajamaParty/siesta3", beat + 2.5f),
new MultiSound.Sound("pajamaParty/siesta3", beat + 4f)
}, forcePlay: true);
WantSleepSequence = beat;
WantSleepType = alt;
}
public void DoBedImpact()
{
Bed.GetComponent<Animator>().Play("BedImpact", -1, 0);
}
public void JumpRow(int row, float beat, int alt = 1)
{
if (row > 4 || row < 0)
{
return;
}
for (int i = 0; i < 5; i++)
{
if (!(i == 2 && row == 0))
{
monkeys[i, row].Jump(beat, alt);
}
}
}
public void JumpCol(int col, float beat, int alt = 1)
{
if (col > 4 || col < 0)
{
return;
}
for (int i = 0; i < 5; i++)
{
if (!(col == 2 && i == 0))
{
monkeys[col, i].Jump(beat, alt);
}
}
}
public void MonkeyCharge(float beat)
{
foreach (CtrPillowMonkey monkey in monkeys)
{
if (monkey != null)
{
monkey.Charge(beat);
}
}
}
public void MonkeyThrow(float beat)
{
foreach (CtrPillowMonkey monkey in monkeys)
{
if (monkey != null)
{
monkey.Throw(beat);
}
}
}
public void MonkeySleep(float beat, int action)
{
foreach (CtrPillowMonkey monkey in monkeys)
{
if (monkey != null)
{
monkey.ReadySleep(beat, action);
}
}
}
}
}

View File

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

View File

@ -0,0 +1,175 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;
using HeavenStudio.Util;
using Starpelly;
namespace HeavenStudio.Games
{
public class PlayerActionEvent : PlayerActionObject
{
public delegate void ActionEventCallback(PlayerActionEvent caller);
public delegate void ActionEventCallbackState(PlayerActionEvent caller, float state);
public ActionEventCallbackState OnHit; //Function to trigger when an input has been done perfectly
public ActionEventCallback OnMiss; //Function to trigger when an input has been missed
public ActionEventCallback OnBlank; //Function to trigger when an input has been recorded while this is pending
public ActionEventCallback OnDestroy; //Function to trigger whenever this event gets destroyed. /!\ Shouldn't be used for a minigame! Use OnMiss instead /!\
public float startBeat;
public float timer;
public bool canHit = true; //Indicates if you can still hit the cue or not. If set to false, it'll guarantee a miss
public bool enabled = true; //Indicates if the PlayerActionEvent is enabled. If set to false, it'll not trigger any events and destroy itself AFTER it's not relevant anymore
public bool autoplayOnly = false; //Indicates if the input event only triggers when it's autoplay. If set to true, NO Miss or Blank events will be triggered when you're not autoplaying.
public bool noAutoplay = false; //Indicates if this PlayerActionEvent is recognized by the autoplay. /!\ Overrides autoPlayOnly /!\
public InputType inputType; //The type of input. Check the InputType class to see a list of all of them
public bool perfectOnly = false; //Indicates that the input only recognize perfect inputs.
public void setHitCallback(ActionEventCallbackState OnHit)
{
this.OnHit = OnHit;
}
public void setMissCallback(ActionEventCallback OnMiss)
{
this.OnMiss = OnMiss;
}
public void Enable() { enabled = true; }
public void Disable() { enabled = false; }
public void CanHit(bool canHit)
{
this.canHit = canHit;
}
public void Update()
{
if(!Conductor.instance.NotStopped()){CleanUp();} // If the song is stopped entirely in the editor, destroy itself as we don't want duplicates
if (noAutoplay && autoplayOnly) autoplayOnly = false;
if (noAutoplay && triggersAutoplay){ triggersAutoplay = false; }
float normalizedBeat = Conductor.instance.GetPositionFromBeat(startBeat,timer);
// allows ace detection with this new system
float stateProg = ((normalizedBeat - Minigame.PerfectTime()) / (Minigame.LateTime() - Minigame.PerfectTime()) - 0.5f) * 2;
StateCheck(normalizedBeat);
//BUGFIX: ActionEvents destroyed too early
if (normalizedBeat > Minigame.EndTime()) Miss();
if (IsCorrectInput() && !autoplayOnly)
{
if (state.perfect)
{
Hit(stateProg);
}
else if (state.early && !perfectOnly)
{
Hit(-1f);
}
else if (state.late && !perfectOnly)
{
Hit(1f);
}
else
{
Blank();
}
}
}
public bool IsExpectingInputNow()
{
float normalizedBeat = Conductor.instance.GetPositionFromBeat(startBeat, timer);
return normalizedBeat > Minigame.EarlyTime() && normalizedBeat < Minigame.EndTime();
}
public bool IsCorrectInput()
{
// This one is a mouthful but it's an evil good to detect the correct input
// Forgive me for those input type names
return (
//General inputs, both down and up
(PlayerInput.Pressed() && inputType == InputType.STANDARD_DOWN) ||
(PlayerInput.AltPressed() && inputType == InputType.STANDARD_ALT_DOWN) ||
(PlayerInput.GetAnyDirectionDown() && inputType == InputType.DIRECTION_DOWN) ||
(PlayerInput.PressedUp() && inputType == InputType.STANDARD_UP) ||
(PlayerInput.AltPressedUp() && inputType == InputType.STANDARD_ALT_UP) ||
(PlayerInput.GetAnyDirectionUp() && inputType == InputType.DIRECTION_UP) ||
//Specific directional inputs
(PlayerInput.GetSpecificDirectionDown(PlayerInput.DOWN) && inputType == InputType.DIRECTION_DOWN_DOWN) ||
(PlayerInput.GetSpecificDirectionDown(PlayerInput.UP) && inputType == InputType.DIRECTION_UP_DOWN) ||
(PlayerInput.GetSpecificDirectionDown(PlayerInput.LEFT) && inputType == InputType.DIRECTION_LEFT_DOWN) ||
(PlayerInput.GetSpecificDirectionDown(PlayerInput.RIGHT) && inputType == InputType.DIRECTION_RIGHT_DOWN) ||
(PlayerInput.GetSpecificDirectionUp(PlayerInput.DOWN) && inputType == InputType.DIRECTION_DOWN_UP) ||
(PlayerInput.GetSpecificDirectionUp(PlayerInput.UP) && inputType == InputType.DIRECTION_UP_UP) ||
(PlayerInput.GetSpecificDirectionUp(PlayerInput.LEFT) && inputType == InputType.DIRECTION_LEFT_UP) ||
(PlayerInput.GetSpecificDirectionUp(PlayerInput.RIGHT) && inputType == InputType.DIRECTION_RIGHT_UP)
);
}
//For the Autoplay
public override void OnAce()
{
float normalizedBeat = Conductor.instance.GetPositionFromBeat(startBeat,timer);
// allows ace detection with this new system
float stateProg = ((normalizedBeat - Minigame.PerfectTime()) / (Minigame.LateTime() - Minigame.PerfectTime()) - 0.5f) * 2;
Hit(stateProg);
}
//The state parameter is either -1 -> Early, 0 -> Perfect, 1 -> Late
public void Hit(float state)
{
if (OnHit != null && enabled)
{
if(canHit)
{
OnHit(this, state);
CleanUp();
} else
{
Blank();
}
}
}
public void Miss()
{
if (OnMiss != null && enabled && !autoplayOnly)
{
OnMiss(this);
}
CleanUp();
}
public void Blank()
{
if(OnBlank != null && enabled && !autoplayOnly)
{
OnBlank(this);
}
}
public void CleanUp()
{
OnDestroy(this);
Destroy(this.gameObject);
}
}
}

View File

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

View File

@ -33,7 +33,7 @@ namespace HeavenStudio.Games
{
if (aceTimes == 0)
{
if (triggersAutoplay && (GameManager.instance.autoplay || autoPlay) && GameManager.instance.canInput && normalizedBeat > 0.99f)
if (triggersAutoplay && (GameManager.instance.autoplay || autoPlay) && GameManager.instance.canInput && normalizedBeat > 0.995f)
{
OnAce();
if (!autoPlay)

View File

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

View File

@ -0,0 +1,59 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace HeavenStudio.Games.Scripts_NtrSamurai
{
public class NtrSamurai : MonoBehaviour
{
[Header("References")]
public Animator animator;
[Header("Properties")]
public bool stepping;
public void Init()
{
stepping = false;
}
// Update is called once per frame
void Update()
{
}
public void Bop()
{
if (!stepping && !(animator.GetCurrentAnimatorClipInfo(0)[0].clip.name == "Slash"))
animator.Play("Beat", -1, 0);
}
public void Step(bool off)
{
stepping = !off;
if (off)
{
animator.Play("Beat", -1, 0);
}
else
{
if (animator.GetCurrentAnimatorClipInfo(0)[0].clip.name == "Slash")
animator.Play("StepSeathe", -1, 0);
else
animator.Play("Step", -1, 0);
}
}
public void Slash()
{
stepping = false;
animator.Play("Slash", -1, 0);
}
public bool isStepping()
{
return stepping;
}
}
}

View File

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

View File

@ -0,0 +1,56 @@
using DG.Tweening;
using NaughtyBezierCurves;
using HeavenStudio.Util;
using System;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;
using NaughtyBezierCurves;
namespace HeavenStudio.Games.Scripts_NtrSamurai
{
public class NtrSamuraiChild : MonoBehaviour
{
[Header("Transforms")]
public Transform DebrisPosL;
public Transform DebrisPosR;
public Transform WalkPos0;
public Transform WalkPos1;
[Header("Objects")]
public Animator anim;
public float startBeat = Single.MinValue;
public bool isMain = true;
// Update is called once per frame
void Update()
{
if (!isMain)
{
var cond = Conductor.instance;
float prog = Conductor.instance.GetPositionFromBeat(startBeat + 1f, 2f);
if (prog >= 0)
{
Walk();
transform.position = Vector3.Lerp(WalkPos0.position, WalkPos1.position, prog);
if (prog >= 1f)
{
GameObject.Destroy(gameObject);
}
}
}
}
public void Bop()
{
anim.Play("ChildBeat", -1, 0);
}
public void Walk()
{
anim.Play("ChildWalk");
}
}
}

View File

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

View File

@ -0,0 +1,302 @@
using DG.Tweening;
using NaughtyBezierCurves;
using HeavenStudio.Util;
using System;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;
using NaughtyBezierCurves;
namespace HeavenStudio.Games.Scripts_NtrSamurai
{
public class NtrSamuraiObject : MonoBehaviour
{
[Header("Objects")]
public ParticleSystem moneyBurst;
public Animator anim;
public NtrSamuraiObject secondHalf;
[Header("Transforms")]
public Transform doubleLaunchPos;
public Transform heldPos;
public float startBeat;
public int type;
public bool isDebris = false;
public int holdingCash = 1;
BezierCurve3D currentCurve;
int flyProg = 0;
bool flying = true;
bool missedLaunch = false;
bool missedHit = false;
PlayerActionEvent launchProg;
PlayerActionEvent hitProg;
void Awake()
{
if (isDebris)
{
switch (type)
{
case (int) SamuraiSliceNtr.ObjectType.Fish:
anim.Play("ObjFishDebris");
break;
case (int) SamuraiSliceNtr.ObjectType.Demon:
anim.Play("ObjDemonDebris02");
break;
default:
anim.Play("ObjMelonDebris");
break;
}
currentCurve = SamuraiSliceNtr.instance.DebrisLeftCurve;
var cond = Conductor.instance;
float flyPos = cond.GetPositionFromBeat(startBeat, 1f);
transform.position = currentCurve.GetPoint(flyPos);
}
else
{
switch (type)
{
case (int) SamuraiSliceNtr.ObjectType.Fish:
anim.Play("ObjFish");
break;
case (int) SamuraiSliceNtr.ObjectType.Demon:
anim.Play("ObjDemon");
MultiSound.Play(new MultiSound.Sound[] {
new MultiSound.Sound("samuraiSliceNtr/ntrSamurai_in01", startBeat + 1f, 1.5f),
new MultiSound.Sound("samuraiSliceNtr/ntrSamurai_in01", startBeat + 1.5f, 1.25f),
new MultiSound.Sound("samuraiSliceNtr/ntrSamurai_in01", startBeat + 2f),
});
break;
default:
anim.Play("ObjMelon");
break;
}
launchProg = SamuraiSliceNtr.instance.ScheduleInput(startBeat, 2f, InputType.STANDARD_ALT_DOWN, LaunchSuccess, LaunchMiss, LaunchThrough);
//autoplay: launch anim
SamuraiSliceNtr.instance.ScheduleAutoplayInput(startBeat, 2f, InputType.STANDARD_ALT_DOWN, DoLaunchAutoplay, LaunchThrough, LaunchThrough);
//autoplay: unstep
SamuraiSliceNtr.instance.ScheduleAutoplayInput(startBeat, 1.75f, InputType.STANDARD_ALT_UP, DoUnStepAutoplay, LaunchThrough, LaunchThrough);
currentCurve = SamuraiSliceNtr.instance.InCurve;
transform.rotation = Quaternion.Euler(0, 0, transform.rotation.eulerAngles.z + (360f * startBeat));
var cond = Conductor.instance;
float flyPos = cond.GetPositionFromBeat(launchProg.startBeat, 3f);
transform.position = currentCurve.GetPoint(flyPos);
transform.rotation = Quaternion.Euler(0, 0, transform.rotation.eulerAngles.z + (-360f * Time.deltaTime) + UnityEngine.Random.Range(0f, 180f));
}
}
void Update()
{
var cond = Conductor.instance;
float flyPos;
if (flying)
{
switch (flyProg)
{
case -2: // being carried by a child
flyPos = cond.GetPositionFromBeat(startBeat + 2f, 2f);
if (heldPos == null || flyPos > 1f)
{
GameObject.Destroy(gameObject);
return;
}
transform.position = heldPos.position;
break;
case -1: // sliced by samurai, falling towards child
flyPos = cond.GetPositionFromBeat(startBeat, 1f);
transform.position = currentCurve.GetPoint(flyPos);
transform.rotation = Quaternion.Euler(0, 0, transform.rotation.eulerAngles.z + ((isDebris? 360f : -360f) * Time.deltaTime));
if (flyPos > 1f)
{
Jukebox.PlayOneShotGame("samuraiSliceNtr/ntrSamurai_catch");
if (!isDebris)
{
NtrSamuraiChild child = SamuraiSliceNtr.instance.CreateChild(startBeat + 1f);
heldPos = child.DebrisPosR;
secondHalf.heldPos = child.DebrisPosL;
}
flyProg = -2;
return;
}
break;
case 2: // fish first bounce
float jumpPos = cond.GetPositionFromBeat(launchProg.startBeat, 2f);
float yMul = jumpPos * 2f - 1f;
float yWeight = -(yMul*yMul) + 1f;
transform.position = doubleLaunchPos.position + new Vector3(0, 4.5f * yWeight);
transform.rotation = Quaternion.Euler(0, 0, transform.rotation.eulerAngles.z + (-2 * 360f * Time.deltaTime));
if (jumpPos > 2f)
{
// missed...
GameObject.Destroy(gameObject);
return;
}
break;
case 1: // launched from board to samurai
float flyDur = 3f;
switch (type)
{
case (int) SamuraiSliceNtr.ObjectType.Demon:
flyDur = 5f;
break;
default:
flyDur = 3f;
break;
}
flyPos = cond.GetPositionFromBeat(hitProg.startBeat, flyDur);
transform.position = currentCurve.GetPoint(flyPos);
transform.rotation = Quaternion.Euler(0, 0, transform.rotation.eulerAngles.z + (3 * 360f * Time.deltaTime));
if (flyPos > 1f)
{
// missed...
GameObject.Destroy(gameObject);
return;
}
break;
default: // object initial spawn, flying towards board
flyPos = cond.GetPositionFromBeat(launchProg.startBeat, 3f);
transform.position = currentCurve.GetPoint(flyPos);
transform.rotation = Quaternion.Euler(0, 0, transform.rotation.eulerAngles.z + (-360f * Time.deltaTime));
if (flyPos > 1f)
{
// missed...
GameObject.Destroy(gameObject);
return;
}
break;
}
}
}
void DoLaunch()
{
switch (type)
{
case (int) SamuraiSliceNtr.ObjectType.Fish:
if (flyProg == 2)
{
flyProg = 1;
hitProg = SamuraiSliceNtr.instance.ScheduleInput(startBeat + 4f, 2f, InputType.STANDARD_DOWN, HitSuccess, HitMiss, LaunchThrough);
SamuraiSliceNtr.instance.ScheduleAutoplayInput(startBeat + 4f, 2f, InputType.STANDARD_DOWN, DoSliceAutoplay, LaunchThrough, LaunchThrough);
currentCurve = SamuraiSliceNtr.instance.LaunchCurve;
Jukebox.PlayOneShotGame("samuraiSliceNtr/holy_mackerel" + UnityEngine.Random.Range(1, 4), pitch: UnityEngine.Random.Range(0.95f, 1.05f), volume: 1f/4);
}
else
{
flyProg = 2;
launchProg = SamuraiSliceNtr.instance.ScheduleInput(startBeat + 2f, 2f, InputType.STANDARD_ALT_DOWN, LaunchSuccess, LaunchMiss, LaunchThrough);
SamuraiSliceNtr.instance.ScheduleAutoplayInput(startBeat + 2f, 2f, InputType.STANDARD_ALT_DOWN, DoLaunchAutoplay, LaunchThrough, LaunchThrough);
//autoplay: unstep
SamuraiSliceNtr.instance.ScheduleAutoplayInput(startBeat + 2f, 1.75f, InputType.STANDARD_ALT_UP, DoUnStepAutoplay, LaunchThrough, LaunchThrough);
currentCurve = null;
Jukebox.PlayOneShotGame("samuraiSliceNtr/holy_mackerel" + UnityEngine.Random.Range(1, 4), pitch: UnityEngine.Random.Range(0.95f, 1.05f), volume: 0.8f);
}
break;
case (int) SamuraiSliceNtr.ObjectType.Demon:
flyProg = 1;
hitProg = SamuraiSliceNtr.instance.ScheduleInput(startBeat + 2f, 4f, InputType.STANDARD_DOWN, HitSuccess, HitMiss, LaunchThrough);
SamuraiSliceNtr.instance.ScheduleAutoplayInput(startBeat + 2f, 4f, InputType.STANDARD_DOWN, DoSliceAutoplay, LaunchThrough, LaunchThrough);
currentCurve = SamuraiSliceNtr.instance.LaunchHighCurve;
break;
default:
flyProg = 1;
hitProg = SamuraiSliceNtr.instance.ScheduleInput(startBeat + 2f, 2f, InputType.STANDARD_DOWN, HitSuccess, HitMiss, LaunchThrough);
SamuraiSliceNtr.instance.ScheduleAutoplayInput(startBeat + 2f, 2f, InputType.STANDARD_DOWN, DoSliceAutoplay, LaunchThrough, LaunchThrough);
currentCurve = SamuraiSliceNtr.instance.LaunchCurve;
break;
}
}
void DoLaunchAutoplay(PlayerActionEvent caller, float state)
{
SamuraiSliceNtr.instance.DoStep();
}
void DoSliceAutoplay(PlayerActionEvent caller, float state)
{
SamuraiSliceNtr.instance.DoSlice();
}
void DoUnStepAutoplay(PlayerActionEvent caller, float state)
{
if (SamuraiSliceNtr.instance.player.stepping)
{
SamuraiSliceNtr.instance.DoUnStep();
}
}
public void LaunchSuccess(PlayerActionEvent caller, float state)
{
launchProg.Disable();
DoLaunch();
Jukebox.PlayOneShotGame("samuraiSliceNtr/ntrSamurai_launchImpact", pitch: UnityEngine.Random.Range(0.85f, 1.05f));
}
public void LaunchMiss(PlayerActionEvent caller)
{
missedLaunch = true;
}
public void LaunchThrough(PlayerActionEvent caller) {}
public void HitSuccess(PlayerActionEvent caller, float state)
{
flyProg = -1;
hitProg.Disable();
if (UnityEngine.Random.Range(0f, 1f) >= 0.5f)
Jukebox.PlayOneShotGame("samuraiSliceNtr/ntrSamurai_just00", pitch: UnityEngine.Random.Range(0.95f, 1.05f));
else
Jukebox.PlayOneShotGame("samuraiSliceNtr/ntrSamurai_just01", pitch: UnityEngine.Random.Range(0.95f, 1.05f));
currentCurve = SamuraiSliceNtr.instance.DebrisRightCurve;
var mobj = GameObject.Instantiate(SamuraiSliceNtr.instance.objectPrefab, SamuraiSliceNtr.instance.objectHolder);
var mobjDat = mobj.GetComponent<NtrSamuraiObject>();
mobjDat.startBeat = caller.startBeat + caller.timer;
mobjDat.type = type;
mobjDat.isDebris = true;
mobjDat.flyProg = -1;
mobj.transform.position = transform.position;
mobj.transform.rotation = transform.rotation;
mobj.GetComponent<SpriteRenderer>().sortingOrder = 4;
mobj.SetActive(true);
secondHalf = mobjDat;
this.startBeat = caller.startBeat + caller.timer;
if (type == (int) SamuraiSliceNtr.ObjectType.Demon)
{
anim.Play("ObjDemonDebris01");
}
if (holdingCash > 0)
{
moneyBurst.Emit(holdingCash);
Jukebox.PlayOneShotGame((holdingCash > 2) ? "samuraiSliceNtr/ntrSamurai_scoreMany" : "samuraiSliceNtr/ntrSamurai_ng", pitch: UnityEngine.Random.Range(0.95f, 1.05f));
}
}
public void HitMiss(PlayerActionEvent caller)
{
missedHit = true;
}
}
}

View File

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

View File

@ -0,0 +1,146 @@
using HeavenStudio.Util;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;
using NaughtyBezierCurves;
namespace HeavenStudio.Games.Loaders
{
using static Minigames;
public static class NtrSamuraiLoader
{
public static Minigame AddGame(EventCaller eventCaller) {
return new Minigame("samuraiSliceNtr", "Samurai Slice (DS) \n<color=#eb5454>[WIP]</color>", "00165D", false, false, new List<GameAction>()
{
new GameAction("spawn object", delegate
{
SamuraiSliceNtr.instance.ObjectIn(eventCaller.currentEntity.beat, eventCaller.currentEntity.type, (int) eventCaller.currentEntity.valA);
}, 8, false, new List<Param>()
{
new Param("type", SamuraiSliceNtr.ObjectType.Melon, "Object", "The object to spawn"),
new Param("valA", new EntityTypes.Integer(0, 30, 1), "Money", "The amount of coins the object spills out when sliced"),
}),
//new GameAction("start bopping", delegate { SamuraiSliceNtr.instance.Bop(eventCaller.currentEntity.beat, eventCaller.currentEntity.length); }, 1),
},
new List<string>() {"ntr", "normal"},
"ntrsamurai", "en",
new List<string>() {"en"}
);
}
}
}
namespace HeavenStudio.Games
{
using Scripts_NtrSamurai;
public class SamuraiSliceNtr : Minigame
{
public enum ObjectType {
Melon,
Fish,
Demon
}
[Header("References")]
public NtrSamurai player;
public GameObject launcher;
public GameObject objectPrefab;
public GameObject childParent;
public Transform objectHolder;
public BezierCurve3D InCurve;
public BezierCurve3D LaunchCurve;
public BezierCurve3D LaunchHighCurve;
public BezierCurve3D NgLaunchCurve;
public BezierCurve3D DebrisLeftCurve;
public BezierCurve3D DebrisRightCurve;
//game scene
public static SamuraiSliceNtr instance;
public GameEvent bop = new GameEvent();
private void Awake()
{
instance = this;
}
// Update is called once per frame
void Update()
{
var cond = Conductor.instance;
if (cond.ReportBeat(ref bop.lastReportedBeat, bop.startBeat % 1))
{
player.Bop();
childParent.GetComponent<NtrSamuraiChild>().Bop();
}
if (PlayerInput.AltPressed())
DoStep();
if (PlayerInput.AltPressedUp() && player.isStepping())
DoUnStep();
if (PlayerInput.Pressed())
DoSlice();
}
public void DoStep()
{
Jukebox.PlayOneShotGame("samuraiSliceNtr/ntrSamurai_launchThrough");
player.Step(false);
launcher.GetComponent<Animator>().Play("Launch", -1, 0);
}
public void DoUnStep()
{
player.Step(true);
launcher.GetComponent<Animator>().Play("UnStep", -1, 0);
}
public void DoSlice()
{
if (player.isStepping())
{
launcher.GetComponent<Animator>().Play("UnStep", -1, 0);
}
Jukebox.PlayOneShotGame("samuraiSliceNtr/ntrSamurai_through");
player.Slash();
}
public void Bop(float beat, float length)
{
bop.length = length;
bop.startBeat = beat;
}
public void ObjectIn(float beat, int type = (int) ObjectType.Melon, int value = 1)
{
var mobj = GameObject.Instantiate(objectPrefab, objectHolder);
var mobjDat = mobj.GetComponent<NtrSamuraiObject>();
mobjDat.startBeat = beat;
mobjDat.type = type;
mobjDat.holdingCash = value;
mobj.SetActive(true);
Jukebox.PlayOneShotGame("samuraiSliceNtr/ntrSamurai_in00");
}
public NtrSamuraiChild CreateChild(float beat)
{
var mobj = GameObject.Instantiate(childParent, objectHolder);
var mobjDat = mobj.GetComponent<NtrSamuraiChild>();
mobjDat.startBeat = beat;
mobjDat.isMain = false;
mobjDat.Bop();
mobj.SetActive(true);
return mobjDat;
}
}
}

View File

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

View File

@ -12,8 +12,12 @@ namespace HeavenStudio.Games.Loaders
public static Minigame AddGame(EventCaller eventCaller) {
return new Minigame("spaceSoccer", "Space Soccer", "B888F8", false, false, new List<GameAction>()
{
new GameAction("ball dispense", delegate { SpaceSoccer.instance.Dispense(eventCaller.currentEntity.beat); }, 2f,
inactiveFunction: delegate { SpaceSoccer.DispenseSound(eventCaller.currentEntity.beat); }),
new GameAction("ball dispense", delegate { SpaceSoccer.instance.Dispense(eventCaller.currentEntity.beat, !eventCaller.currentEntity.toggle); }, 2f,
parameters: new List<Param>()
{
new Param("toggle", false, "Disable Sound", "Disables the dispense sound")
},
inactiveFunction: delegate { if (!eventCaller.currentEntity.toggle) { SpaceSoccer.DispenseSound(eventCaller.currentEntity.beat); } }),
new GameAction("keep-up", delegate { }, 4f, true),
new GameAction("high kick-toe!", delegate { }, 3f, false, new List<Param>()
{

View File

@ -117,27 +117,27 @@ namespace HeavenStudio.Games
{
if (normalizedBeat > 1)
{
GameCamera.instance.camera.transform.localPosition = new Vector3(0, 0, currentZoomCamDistance);
GameCamera.additionalPosition = new Vector3(0, 0, currentZoomCamDistance + 10);
}
else
{
if (currentZoomCamLength < 0)
{
GameCamera.instance.camera.transform.localPosition = new Vector3(0, 0, currentZoomCamDistance);
GameCamera.additionalPosition = new Vector3(0, 0, currentZoomCamDistance + 10);
}
else
{
EasingFunction.Function func = EasingFunction.GetEasingFunction(lastEase);
float newPosZ = func(lastCamDistance, currentZoomCamDistance, normalizedBeat);
GameCamera.instance.camera.transform.localPosition = new Vector3(0, 0, newPosZ);
float newPosZ = func(lastCamDistance + 10, currentZoomCamDistance + 10, normalizedBeat);
GameCamera.additionalPosition = new Vector3(0, 0, newPosZ);
}
}
}
else
{
// ?
GameCamera.instance.camera.transform.localPosition = new Vector3(0, 0, -10f);
GameCamera.additionalPosition = new Vector3(0, 0, 0);
}
}
}

View File

@ -54,6 +54,12 @@ namespace HeavenStudio.Games.Scripts_Spaceball
hitRot = Holder.transform.eulerAngles.z;
Jukebox.PlayOneShotGame("spaceball/hit");
// jank fix for a bug with autoplay - freeform
if (GameManager.instance.autoplay && Conductor.instance.isPlaying && GameManager.instance.canInput)
{
Jukebox.PlayOneShotGame("spaceball/swing");
}
randomEndPosX = Random.Range(40f, 55f);
@ -134,4 +140,4 @@ namespace HeavenStudio.Games.Scripts_Spaceball
}
}
}
}

View File

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

View File

@ -0,0 +1,22 @@
using HeavenStudio.Util;
using System;
using System.Collections.Generic;
using UnityEngine;
namespace HeavenStudio.Games
{
public class TramAndPauline : Minigame
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}
}

View File

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

View File

@ -19,6 +19,7 @@ namespace HeavenStudio
GameObject Cameras = Instantiate(Resources.Load<GameObject>("Prefabs/Cameras")); Cameras.name = "Cameras";
GameObject MainCamera = Cameras.transform.GetChild(0).gameObject;
GameObject CursorCamera = Cameras.transform.GetChild(1).gameObject;
GameObject OverlayCamera = Cameras.transform.GetChild(2).gameObject;
GameObject Cursor = Instantiate(Resources.Load<GameObject>("Prefabs/Cursor"));
Cursor.name = "Cursor";
@ -36,6 +37,7 @@ namespace HeavenStudio
gameManager.CircleCursor = Cursor.transform.GetChild(0).GetComponent<CircleCursor>();
gameManager.GameCamera = MainCamera.GetComponent<Camera>();
gameManager.CursorCam = CursorCamera.GetComponent<Camera>();
gameManager.OverlayCamera = OverlayCamera.GetComponent<Camera>();
GameObject Profiler = Instantiate(Resources.Load<GameObject>("Prefabs/GameProfiler"));
Profiler.name = "GameProfiler";

View File

@ -0,0 +1,34 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace HeavenStudio
{
public enum InputType : int {
//General
//-------
//Down
STANDARD_DOWN = 0,
STANDARD_ALT_DOWN = 1,
DIRECTION_DOWN = 2,
//Up
STANDARD_UP = 3,
STANDARD_ALT_UP = 4,
DIRECTION_UP = 5,
//Specific
//--------
//Down
DIRECTION_DOWN_DOWN = 6,
DIRECTION_UP_DOWN = 7,
DIRECTION_LEFT_DOWN = 8,
DIRECTION_RIGHT_DOWN = 9,
//Up
DIRECTION_DOWN_UP = 10,
DIRECTION_UP_UP = 11,
DIRECTION_LEFT_UP = 12,
DIRECTION_RIGHT_UP = 13
}
}

View File

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

View File

@ -28,6 +28,9 @@ namespace HeavenStudio.Editor
[SerializeField] private Canvas MainCanvas;
[SerializeField] public Camera EditorCamera;
[SerializeField] public GameObject EditorLetterbox;
[SerializeField] public GameObject GameLetterbox;
[Header("Rect")]
[SerializeField] private RenderTexture ScreenRenderTexture;
[SerializeField] private RawImage Screen;
@ -61,6 +64,7 @@ namespace HeavenStudio.Editor
private bool fullscreen;
public bool discordDuringTesting = false;
public bool canSelect = true;
public bool editingInputField = false;
public static Editor instance { get; private set; }
@ -75,6 +79,7 @@ namespace HeavenStudio.Editor
{
GameCamera.instance.camera.targetTexture = ScreenRenderTexture;
GameManager.instance.CursorCam.targetTexture = ScreenRenderTexture;
GameManager.instance.OverlayCamera.targetTexture = ScreenRenderTexture;
Screen.texture = ScreenRenderTexture;
GameManager.instance.Init();
@ -84,6 +89,8 @@ namespace HeavenStudio.Editor
{
GameObject GameIcon_ = Instantiate(GridGameSelector.GetChild(0).gameObject, GridGameSelector);
GameIcon_.GetComponent<Image>().sprite = GameIcon(EventCaller.instance.minigames[i].name);
GameIcon_.GetComponent<GridGameSelectorGame>().MaskTex = GameIconMask(EventCaller.instance.minigames[i].name);
GameIcon_.GetComponent<GridGameSelectorGame>().UnClickIcon();
GameIcon_.gameObject.SetActive(true);
GameIcon_.name = EventCaller.instance.minigames[i].displayName;
}
@ -106,14 +113,18 @@ namespace HeavenStudio.Editor
{
if (Input.GetKeyDown(KeyCode.Tab))
{
Fullscreen();
if (!Editor.instance.editingInputField)
Fullscreen();
}
if (Input.GetKeyDown(KeyCode.Delete))
{
List<TimelineEventObj> ev = new List<TimelineEventObj>();
for (int i = 0; i < Selections.instance.eventsSelected.Count; i++) ev.Add(Selections.instance.eventsSelected[i]);
CommandManager.instance.Execute(new Commands.Deletion(ev));
if (!Editor.instance.editingInputField)
{
List<TimelineEventObj> ev = new List<TimelineEventObj>();
for (int i = 0; i < Selections.instance.eventsSelected.Count; i++) ev.Add(Selections.instance.eventsSelected[i]);
CommandManager.instance.Execute(new Commands.Deletion(ev));
}
}
if (CommandManager.instance.canUndo())
@ -209,6 +220,11 @@ namespace HeavenStudio.Editor
return Resources.Load<Sprite>($"Sprites/Editor/GameIcons/{name}");
}
public static Texture GameIconMask(string name)
{
return Resources.Load<Texture>($"Sprites/Editor/GameIcons/{name}_mask");
}
#region Dialogs
public void SelectMusic()
@ -218,6 +234,7 @@ namespace HeavenStudio.Editor
new ExtensionFilter("Music Files", "mp3", "ogg", "wav")
};
#if UNITY_STANDALONE_WINDOWS
StandaloneFileBrowser.OpenFilePanelAsync("Open File", "", extensions, false, async (string[] paths) =>
{
if (paths.Length > 0)
@ -229,6 +246,19 @@ namespace HeavenStudio.Editor
}
}
);
#else
StandaloneFileBrowser.OpenFilePanelAsync("Open File", "", extensions, false, async (string[] paths) =>
{
if (paths.Length > 0)
{
Conductor.instance.musicSource.clip = await LoadClip("file://" + Path.Combine(paths));
changedMusic = true;
Timeline.FitToSong();
}
}
);
#endif
}
private async Task<AudioClip> LoadClip(string path)
@ -294,7 +324,7 @@ namespace HeavenStudio.Editor
{
new ExtensionFilter("Heaven Studio Remix File", "tengoku")
};
StandaloneFileBrowser.SaveFilePanelAsync("Save Remix As", "", "remix_level", extensions, (string path) =>
{
if (path != String.Empty)
@ -312,7 +342,7 @@ namespace HeavenStudio.Editor
{
var levelFile = archive.CreateEntry("remix.json", System.IO.Compression.CompressionLevel.NoCompression);
using (var zipStream = levelFile.Open())
zipStream.Write(Encoding.ASCII.GetBytes(GetJson()), 0, Encoding.ASCII.GetBytes(GetJson()).Length);
zipStream.Write(Encoding.UTF8.GetBytes(GetJson()), 0, Encoding.UTF8.GetBytes(GetJson()).Length);
if (changedMusic || currentRemixPath != path)
{
@ -337,6 +367,7 @@ namespace HeavenStudio.Editor
Timeline.instance.TempoInfo.UpdateStartingBPMText();
Timeline.instance.VolumeInfo.UpdateStartingVolumeText();
Timeline.instance.TempoInfo.UpdateOffsetText();
Timeline.FitToSong();
}
public void OpenRemix()
@ -369,7 +400,7 @@ namespace HeavenStudio.Editor
{
stream.CopyTo(ms);
bytes = ms.ToArray();
string json = Encoding.Default.GetString(bytes);
string json = Encoding.UTF8.GetString(bytes);
LoadRemix(json);
}
}
@ -410,19 +441,31 @@ namespace HeavenStudio.Editor
{
if (fullscreen == false)
{
EditorLetterbox.SetActive(false);
GameLetterbox.SetActive(true);
MainCanvas.enabled = false;
EditorCamera.enabled = false;
GameCamera.instance.camera.targetTexture = null;
GameCamera.instance.camera.transform.parent.GetChild(1).GetComponent<Camera>().enabled = false;
GameManager.instance.CursorCam.enabled = false;
GameManager.instance.OverlayCamera.targetTexture = null;
fullscreen = true;
}
else
{
EditorLetterbox.SetActive(true);
GameLetterbox.SetActive(false);
MainCanvas.enabled = true;
EditorCamera.enabled = true;
GameCamera.instance.camera.targetTexture = ScreenRenderTexture;
GameCamera.instance.camera.transform.parent.GetChild(1).GetComponent<Camera>().enabled = true;
GameManager.instance.CursorCam.enabled = true;
GameManager.instance.OverlayCamera.targetTexture = ScreenRenderTexture;
fullscreen = false;
GameCamera.instance.camera.rect = new Rect(0, 0, 1, 1);
GameManager.instance.CursorCam.rect = new Rect(0, 0, 1, 1);
GameManager.instance.OverlayCamera.rect = new Rect(0, 0, 1, 1);
}
}
@ -462,4 +505,4 @@ namespace HeavenStudio.Editor
}
}
}
}
}

View File

@ -18,6 +18,7 @@ namespace HeavenStudio.Editor
[SerializeField] private GameObject BooleanP;
[SerializeField] private GameObject DropdownP;
[SerializeField] private GameObject ColorP;
[SerializeField] private GameObject StringP;
public Beatmap.Entity entity;
@ -120,6 +121,10 @@ namespace HeavenStudio.Editor
{
prefab = ColorP;
}
else if(objType == typeof(string))
{
prefab = StringP;
}
GameObject input = Instantiate(prefab);
input.transform.SetParent(this.gameObject.transform);
@ -137,6 +142,7 @@ namespace HeavenStudio.Editor
private void DestroyParams()
{
Editor.instance.editingInputField = false;
active = false;
for (int i = childCountAtStart; i < transform.childCount; i++)
{

View File

@ -36,6 +36,10 @@ namespace HeavenStudio.Editor
public bool colorTableActive;
public ColorPreview colorPreview;
[Header("String")] //why wasn't this a thing before
[Space(10)]
public TMP_InputField inputFieldString;
private string propertyName;
public void SetProperties(string propertyName, object type, string caption)
@ -61,10 +65,16 @@ namespace HeavenStudio.Editor
parameterManager.entity[propertyName] = (int)slider.value;
});
inputField.onSelect.AddListener(delegate
{
Editor.instance.editingInputField = true;
});
inputField.onEndEdit.AddListener(delegate
{
slider.value = Mathf.RoundToInt(System.Convert.ToSingle(System.Convert.ToSingle(inputField.text)));
parameterManager.entity[propertyName] = (int)slider.value;
Editor.instance.editingInputField = false;
});
}
else if (objType == typeof(EntityTypes.Float))
@ -84,15 +94,21 @@ namespace HeavenStudio.Editor
parameterManager.entity[propertyName] = newValue;
});
inputField.onSelect.AddListener(delegate
{
Editor.instance.editingInputField = true;
});
inputField.onEndEdit.AddListener(delegate
{
slider.value = (float)System.Math.Round(System.Convert.ToSingle(inputField.text), 4);
parameterManager.entity[propertyName] = slider.value;
Editor.instance.editingInputField = false;
});
}
else if(type is bool)
{
toggle.isOn = (bool)type;
toggle.isOn = System.Convert.ToBoolean(parameterManager.entity[propertyName]); // ' (bool)type ' always results in false
toggle.onValueChanged.AddListener(delegate
{
@ -143,6 +159,24 @@ namespace HeavenStudio.Editor
colorPreview.ChangeColor(paramCol);
ColorTable.gameObject.SetActive(false);
}
//why the FUCK wasn't this a thing before lmao
else if(objType == typeof(string))
{
// Debug.Log("entity " + propertyName + " is: " + (string)(parameterManager.entity[propertyName]));
inputFieldString.text = (string)(parameterManager.entity[propertyName]);
inputFieldString.onSelect.AddListener(delegate
{
Editor.instance.editingInputField = true;
});
inputFieldString.onEndEdit.AddListener(delegate
{
// Debug.Log("setting " + propertyName + " to: " + inputFieldString.text);
parameterManager.entity[propertyName] = inputFieldString.text;
Editor.instance.editingInputField = false;
});
}
}
private void Update()

View File

@ -16,6 +16,7 @@ namespace HeavenStudio.Editor
public string SelectedMinigame;
[Header("Components")]
public GameObject SelectedGameIcon;
public GameObject GameEventSelector;
public GameObject EventRef;
public GameObject CurrentSelected;
@ -39,21 +40,24 @@ namespace HeavenStudio.Editor
private void Update()
{
if (gameOpen)
if(!Conductor.instance.NotStopped())
{
if (Input.GetKeyDown(KeyCode.DownArrow))
if (gameOpen)
{
UpdateIndex(currentEventIndex + 1);
if (Input.GetKeyDown(KeyCode.DownArrow))
{
UpdateIndex(currentEventIndex + 1);
}
else if (Input.GetKeyDown(KeyCode.UpArrow))
{
UpdateIndex(currentEventIndex - 1);
}
}
else if (Input.GetKeyDown(KeyCode.UpArrow))
{
UpdateIndex(currentEventIndex - 1);
}
}
if (Input.mouseScrollDelta.y != 0)
{
UpdateIndex(currentEventIndex - Mathf.RoundToInt(Input.mouseScrollDelta.y));
if (Input.mouseScrollDelta.y != 0)
{
UpdateIndex(currentEventIndex - Mathf.RoundToInt(Input.mouseScrollDelta.y));
}
}
}
@ -93,6 +97,10 @@ namespace HeavenStudio.Editor
public void SelectGame(string gameName, int index)
{
if (SelectedGameIcon != null)
{
SelectedGameIcon.GetComponent<GridGameSelectorGame>().UnClickIcon();
}
mg = EventCaller.instance.minigames.Find(c => c.displayName == gameName);
SelectedMinigame = gameName;
gameOpen = true;
@ -100,7 +108,9 @@ namespace HeavenStudio.Editor
DestroyEvents();
AddEvents();
transform.GetChild(index).GetChild(0).gameObject.SetActive(true);
// transform.GetChild(index).GetChild(0).gameObject.SetActive(true);
SelectedGameIcon = transform.GetChild(index).gameObject;
SelectedGameIcon.GetComponent<GridGameSelectorGame>().ClickIcon();
currentEventIndex = 0;
UpdateIndex(0, false);

View File

@ -1,6 +1,9 @@
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.UI;
using DG.Tweening;
namespace HeavenStudio.Editor
{
public class GridGameSelectorGame : MonoBehaviour
@ -9,14 +12,44 @@ namespace HeavenStudio.Editor
public GridGameSelector GridGameSelector;
public Texture MaskTex;
public Texture BgTex;
private Material m_Material;
private void Start()
{
Tooltip.AddTooltip(this.gameObject, this.gameObject.name);
}
public void SetupTextures()
{
if (m_Material == null)
{
m_Material = Instantiate(GetComponent<Image>().material);
GetComponent<Image>().material = m_Material;
}
m_Material.SetTexture("_MaskTex", MaskTex);
m_Material.SetTexture("_BgTex", BgTex);
}
public void OnClick()
{
GridGameSelector.SelectGame(this.gameObject.name, this.transform.GetSiblingIndex());
}
//TODO: animate between shapes
public void ClickIcon()
{
transform.DOScale(new Vector3(1.15f, 1.15f, 1f), 0.1f);
BgTex = Resources.Load<Texture>($"Sprites/GeneralPurpose/Circle");
SetupTextures();
}
public void UnClickIcon()
{
transform.DOScale(new Vector3(1f, 1f, 1f), 0.1f);
BgTex = Resources.Load<Texture>($"Sprites/GeneralPurpose/Square");
SetupTextures();
}
}
}

View File

@ -129,11 +129,7 @@ namespace HeavenStudio.Editor.Track
}
private void AddTempoChange(bool create, Beatmap.TempoChange tempoChange_ = null)
{
// TEMP: DISABLED UNTIL CRITICAL FIXES
if (create)
return;
{
GameObject tempoChange = Instantiate(RefTempoChange.gameObject, this.transform);
tempoChange.transform.GetChild(0).GetComponent<Image>().color = EditorTheme.theme.properties.TempoLayerCol.Hex2RGB();

View File

@ -258,24 +258,29 @@ namespace HeavenStudio.Editor.Track
if (Input.GetKeyDown(KeyCode.Space))
{
if (Input.GetKey(KeyCode.LeftShift))
if (!Editor.instance.editingInputField)
{
PlayCheck(false);
}
else
{
PlayCheck(true);
if (Input.GetKey(KeyCode.LeftShift))
{
PlayCheck(false);
}
else
{
PlayCheck(true);
}
}
}
if (Input.GetKeyDown(KeyCode.P))
{
AutoPlayToggle();
if (!Editor.instance.editingInputField)
AutoPlayToggle();
}
if (Input.GetKeyDown(KeyCode.M))
{
MetronomeToggle();
if (!Editor.instance.editingInputField)
MetronomeToggle();
}
@ -291,7 +296,7 @@ namespace HeavenStudio.Editor.Track
if (movingPlayback)
{
RectTransformUtility.ScreenPointToLocalPointInRectangle(TimelineContent, Input.mousePosition, Editor.instance.EditorCamera, out lastMousePos);
TimelineSlider.localPosition = new Vector3(Mathf.Clamp(Mathp.Round2Nearest(lastMousePos.x + 0.12f, Timeline.SnapInterval()), 0, Mathf.Infinity), TimelineSlider.transform.localPosition.y);
TimelineSlider.localPosition = new Vector3(Mathf.Max(Mathp.Round2Nearest(lastMousePos.x + 0.12f, Timeline.SnapInterval()), 0), TimelineSlider.transform.localPosition.y);
if (TimelineSlider.localPosition.x != lastBeatPos)
Conductor.instance.SetBeat(TimelineSlider.transform.localPosition.x);
@ -302,13 +307,16 @@ namespace HeavenStudio.Editor.Track
float moveSpeed = 750;
if (Input.GetKey(KeyCode.LeftShift)) moveSpeed *= 2;
if (Input.GetKey(KeyCode.LeftArrow) || Input.GetKey(KeyCode.A))
if (!Editor.instance.editingInputField)
{
TimelineContent.transform.localPosition += new Vector3(moveSpeed * Time.deltaTime, 0);
}
else if (Input.GetKey(KeyCode.RightArrow) || Input.GetKey(KeyCode.D))
{
TimelineContent.transform.localPosition += new Vector3(-moveSpeed * Time.deltaTime, 0);
if (Input.GetKey(KeyCode.LeftArrow) || Input.GetKey(KeyCode.A))
{
TimelineContent.transform.localPosition += new Vector3(moveSpeed * Time.deltaTime, 0);
}
else if (Input.GetKey(KeyCode.RightArrow) || Input.GetKey(KeyCode.D))
{
TimelineContent.transform.localPosition += new Vector3(-moveSpeed * Time.deltaTime, 0);
}
}
if (Conductor.instance.isPlaying)

View File

@ -1,18 +1,21 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;
using HeavenStudio.Util;
using HeavenStudio.Editor.Track;
using HeavenStudio.Games;
using System;
using System.Linq;
using System.Reflection;
using System.IO;
namespace HeavenStudio
{
public class Minigames
{
public class Minigame
@ -25,7 +28,24 @@ namespace HeavenStudio
public bool fxOnly;
public List<GameAction> actions = new List<GameAction>();
public Minigame(string name, string displayName, string color, bool threeD, bool fxOnly, List<GameAction> actions)
public List<string> tags;
public string defaultLocale = "en";
public string wantAssetBundle = "";
public List<string> supportedLocales;
public bool usesAssetBundle => (wantAssetBundle != "");
public bool hasLocales => (supportedLocales.Count > 0);
public bool AssetsLoaded => (((hasLocales && localeLoaded && currentLoadedLocale == defaultLocale) || (!hasLocales)) && commonLoaded);
private AssetBundle bundleCommon = null;
private bool commonLoaded = false;
private bool commonPreloaded = false;
private string currentLoadedLocale = "";
private AssetBundle bundleLocalized = null;
private bool localeLoaded = false;
private bool localePreloaded = false;
public Minigame(string name, string displayName, string color, bool threeD, bool fxOnly, List<GameAction> actions, List<string> tags = null, string assetBundle = "", string defaultLocale = "en", List<string> supportedLocales = null)
{
this.name = name;
this.displayName = displayName;
@ -33,6 +53,83 @@ namespace HeavenStudio
this.actions = actions;
this.threeD = threeD;
this.fxOnly = fxOnly;
this.tags = tags ?? new List<string>();
this.wantAssetBundle = assetBundle;
this.defaultLocale = defaultLocale;
this.supportedLocales = supportedLocales ?? new List<string>();
}
public AssetBundle GetLocalizedAssetBundle()
{
if (!hasLocales) return null;
if (!usesAssetBundle) return null;
if (bundleLocalized == null || currentLoadedLocale != defaultLocale) //TEMPORARY: use the game's default locale until we add localization support
{
if (localeLoaded) return bundleLocalized;
// TODO: try/catch for missing assetbundles
currentLoadedLocale = defaultLocale;
bundleLocalized = AssetBundle.LoadFromFile(Path.Combine(Application.streamingAssetsPath, wantAssetBundle + "/locale." + defaultLocale));
localeLoaded = true;
}
return bundleLocalized;
}
public AssetBundle GetCommonAssetBundle()
{
if (commonLoaded) return bundleCommon;
if (!usesAssetBundle) return null;
if (bundleCommon == null)
{
// TODO: try/catch for missing assetbundles
bundleCommon = AssetBundle.LoadFromFile(Path.Combine(Application.streamingAssetsPath, wantAssetBundle + "/common"));
commonLoaded = true;
}
return bundleCommon;
}
public IEnumerator LoadCommonAssetBundleAsync()
{
if (commonPreloaded || commonLoaded) yield break;
commonPreloaded = true;
if (!usesAssetBundle) yield break;
if (bundleCommon != null) yield break;
AssetBundleCreateRequest asyncBundleRequest = AssetBundle.LoadFromFileAsync(Path.Combine(Application.streamingAssetsPath, wantAssetBundle + "/common"));
if (bundleCommon != null) yield break;
yield return asyncBundleRequest;
AssetBundle localAssetBundle = asyncBundleRequest.assetBundle;
if (bundleCommon != null) yield break;
yield return localAssetBundle;
if (localAssetBundle == null) yield break;
bundleCommon = localAssetBundle;
commonLoaded = true;
}
public IEnumerator LoadLocalizedAssetBundleAsync()
{
if (localePreloaded) yield break;
localePreloaded = true;
if (!hasLocales) yield break;
if (!usesAssetBundle) yield break;
if (localeLoaded && bundleLocalized != null && currentLoadedLocale == defaultLocale) yield break;
AssetBundleCreateRequest asyncBundleRequest = AssetBundle.LoadFromFileAsync(Path.Combine(Application.streamingAssetsPath, wantAssetBundle + "/locale." + defaultLocale));
if (localeLoaded && bundleLocalized != null && currentLoadedLocale == defaultLocale) yield break;
yield return asyncBundleRequest;
AssetBundle localAssetBundle = asyncBundleRequest.assetBundle;
if (localeLoaded && bundleLocalized != null && currentLoadedLocale == defaultLocale) yield break;
yield return localAssetBundle;
if (localAssetBundle == null) yield break;
bundleLocalized = localAssetBundle;
currentLoadedLocale = defaultLocale;
localeLoaded = true;
}
}
@ -120,7 +217,7 @@ namespace HeavenStudio
new Minigame("gameManager", "Game Manager", "", false, true, new List<GameAction>()
{
new GameAction("switchGame", delegate { GameManager.instance.SwitchGame(eventCaller.currentSwitchGame, eventCaller.currentEntity.beat); }, 0.5f, inactiveFunction: delegate { GameManager.instance.SwitchGame(eventCaller.currentSwitchGame, eventCaller.currentEntity.beat); }),
new GameAction("end", delegate { Debug.Log("end"); }),
new GameAction("end", delegate { Debug.Log("end"); GameManager.instance.Stop(0); Timeline.instance?.SetTimeButtonColors(true, false, false);}),
new GameAction("skill star", delegate { }, 1f, true),
new GameAction("flash", delegate
{
@ -148,6 +245,29 @@ namespace HeavenStudio
{
new Param("toggle", true, "Enable Inputs")
}),
// DEPRECATED! Now in VFX
new GameAction("move camera", delegate
{
}, 1f, true, new List<Param>()
{
new Param("valA", new EntityTypes.Float(-50, 50, 0), "Right / Left"),
new Param("valB", new EntityTypes.Float(-50, 50, 0), "Up / Down"),
new Param("valC", new EntityTypes.Float(-0, 250, 10), "In / Out"),
new Param("ease", EasingFunction.Ease.Linear, "Ease Type")
},
hidden: true ),
new GameAction("rotate camera", delegate
{
}, 1f, true, new List<Param>()
{
new Param("valA", new EntityTypes.Integer(-360, 360, 0), "Pitch"),
new Param("valB", new EntityTypes.Integer(-360, 360, 0), "Yaw"),
new Param("valC", new EntityTypes.Integer(-360, 360, 0), "Roll"),
new Param("ease", EasingFunction.Ease.Linear, "Ease Type")
},
hidden: true ),
}),
new Minigame("countIn", "Count-Ins", "", false, true, new List<GameAction>()
{
@ -186,8 +306,66 @@ namespace HeavenStudio
new GameAction("four (alt)", delegate { SoundEffects.Count(3, true); }, 1f, hidden: true),
new GameAction("go! (alt)", delegate { SoundEffects.Go(true); }, 1f, hidden: true),
}),
new Minigame("vfx", "Visual Effects", "", false, true, new List<GameAction>()
{
new GameAction("move camera", delegate
{
//TODO: move cam
}, 1f, true, new List<Param>()
{
new Param("valA", new EntityTypes.Float(-50, 50, 0), "Right / Left"),
new Param("valB", new EntityTypes.Float(-50, 50, 0), "Up / Down"),
new Param("valC", new EntityTypes.Float(-0, 250, 10), "In / Out"),
new Param("ease", EasingFunction.Ease.Linear, "Ease Type")
} ),
new GameAction("rotate camera", delegate
{
//TODO: rot cam
}, 1f, true, new List<Param>()
{
new Param("valA", new EntityTypes.Integer(-360, 360, 0), "Pitch"),
new Param("valB", new EntityTypes.Integer(-360, 360, 0), "Yaw"),
new Param("valC", new EntityTypes.Integer(-360, 360, 0), "Roll"),
new Param("ease", EasingFunction.Ease.Linear, "Ease Type")
} ),
new GameAction("display textbox", delegate
{
}, 1f, true, new List<Param>()
{
new Param("text1", "", "Text", "The text to display in the textbox (Rich Text is supported!)"),
new Param("type", Games.Global.Textbox.TextboxAnchor.TopMiddle, "Anchor", "Where to anchor the textbox"),
new Param("valA", new EntityTypes.Float(0.25f, 4, 1), "Textbox Width", "Textbox width multiplier"),
new Param("valB", new EntityTypes.Float(0.5f, 8, 1), "Textbox Height", "Textbox height multiplier")
} ),
new GameAction("display open captions", delegate
{
}, 1f, true, new List<Param>()
{
new Param("text1", "", "Text", "The text to display in the captions (Rich Text is supported!)"),
new Param("type", Games.Global.Textbox.TextboxAnchor.BottomMiddle, "Anchor", "Where to anchor the captions"),
new Param("valA", new EntityTypes.Float(0.25f, 4, 1), "Captions Width", "Captions width multiplier"),
new Param("valB", new EntityTypes.Float(0.5f, 8, 1), "Captions Height", "Captions height multiplier")
} ),
new GameAction("display closed captions", delegate
{
}, 1f, true, new List<Param>()
{
new Param("text1", "", "Text", "The text to display in the captions (Rich Text is supported!)"),
new Param("type", Games.Global.Textbox.ClosedCaptionsAnchor.Top, "Anchor", "Where to anchor the captions"),
new Param("valA", new EntityTypes.Float(0.5f, 4, 1), "Captions Height", "Captions height multiplier")
} ),
new GameAction("display song artist", delegate
{
}, 1f, true, new List<Param>()
{
new Param("text1", "", "Title", "Text to display in the upper label (Rich Text is supported!)"),
new Param("text2", "", "Artist", "Text to display in the lower label (Rich Text is supported!)"),
} ),
}),
};
BuildLoadRunnerList();
foreach(var load in loadRunners)
{

View File

@ -7,6 +7,26 @@ namespace HeavenStudio
public class PlayerInput
{
//Clockwise
public const int UP = 0;
public const int RIGHT = 1;
public const int DOWN = 2;
public const int LEFT = 3;
// The autoplay isn't activated AND
// The song is actually playing AND
// The GameManager allows you to Input
public static bool playerHasControl()
{
return !GameManager.instance.autoplay && Conductor.instance.isPlaying && GameManager.instance.canInput;
}
/*--------------------*/
/* MAIN INPUT METHODS */
/*--------------------*/
// BUTTONS
public static bool Pressed(bool includeDPad = false)
{
bool keyDown = Input.GetKeyDown(KeyCode.Z) || (includeDPad && GetAnyDirectionDown());
@ -28,44 +48,80 @@ namespace HeavenStudio
public static bool AltPressed()
{
return Input.GetKeyDown(KeyCode.X) && !GameManager.instance.autoplay && Conductor.instance.isPlaying && GameManager.instance.canInput;
return Input.GetKeyDown(KeyCode.X) && playerHasControl();
}
public static bool AltPressedUp()
{
return Input.GetKeyUp(KeyCode.X) && !GameManager.instance.autoplay && Conductor.instance.isPlaying && GameManager.instance.canInput;
return Input.GetKeyUp(KeyCode.X) && playerHasControl();
}
public static bool AltPressing()
{
return Input.GetKey(KeyCode.X) && !GameManager.instance.autoplay && Conductor.instance.isPlaying && GameManager.instance.canInput;
return Input.GetKey(KeyCode.X) && playerHasControl();
}
//Directions
public static bool GetAnyDirectionDown()
{
return Input.GetKeyDown(KeyCode.UpArrow)
return (Input.GetKeyDown(KeyCode.UpArrow)
|| Input.GetKeyDown(KeyCode.DownArrow)
|| Input.GetKeyDown(KeyCode.LeftArrow)
|| Input.GetKeyDown(KeyCode.RightArrow);
|| Input.GetKeyDown(KeyCode.RightArrow)) && playerHasControl();
}
public static bool GetAnyDirectionUp()
{
return Input.GetKeyUp(KeyCode.UpArrow)
return (Input.GetKeyUp(KeyCode.UpArrow)
|| Input.GetKeyUp(KeyCode.DownArrow)
|| Input.GetKeyUp(KeyCode.LeftArrow)
|| Input.GetKeyUp(KeyCode.RightArrow);
|| Input.GetKeyUp(KeyCode.RightArrow)) && playerHasControl();
}
public static bool GetAnyDirection()
{
return Input.GetKey(KeyCode.UpArrow)
return (Input.GetKey(KeyCode.UpArrow)
|| Input.GetKey(KeyCode.DownArrow)
|| Input.GetKey(KeyCode.LeftArrow)
|| Input.GetKey(KeyCode.RightArrow);
|| Input.GetKey(KeyCode.RightArrow)) && playerHasControl();
}
public static bool GetSpecificDirectionDown(int direction)
{
KeyCode targetCode = getKeyCode(direction);
if (targetCode == KeyCode.None) return false;
return Input.GetKeyDown(targetCode) && playerHasControl();
}
public static bool GetSpecificDirectionUp(int direction)
{
KeyCode targetCode = getKeyCode(direction);
if (targetCode == KeyCode.None) return false;
return Input.GetKeyUp(targetCode) && playerHasControl();
}
private static KeyCode getKeyCode(int direction)
{
KeyCode targetKeyCode;
switch (direction)
{
case PlayerInput.UP: targetKeyCode = KeyCode.UpArrow; break;
case PlayerInput.DOWN: targetKeyCode = KeyCode.DownArrow; break;
case PlayerInput.LEFT: targetKeyCode = KeyCode.LeftArrow; break;
case PlayerInput.RIGHT: targetKeyCode = KeyCode.RightArrow; break;
default: targetKeyCode = KeyCode.None; break;
}
return targetKeyCode;
}
}
}

View File

@ -9,5 +9,64 @@ namespace HeavenStudio.Util
float compare = anim.GetCurrentAnimatorStateInfo(0).speed;
return anim.GetCurrentAnimatorStateInfo(0).normalizedTime >= compare && !anim.IsInTransition(0);
}
/// <summary>
/// Sets animator's progress on an animation based on current song beat between startTime and length
/// function must be called in actor's Update loop to update properly
/// </summary>
/// <param name="anim">Animator to update</param>
/// <param name="animName">name of animation to play</param>
/// <param name="startTime">reference start time of animation (progress 0.0)</param>
/// <param name="length">duration of animation (progress 1.0)</param>
/// <param name="timeScale">multiplier for animation progress (smaller values make animation slower)</param>
/// <param name="animLayer">animator layer to play animation on</param>
public static void DoScaledAnimation(this Animator anim, string animName, float startTime, float length = 1f, float timeScale = 1f, int animLayer = -1)
{
float pos = Conductor.instance.GetPositionFromBeat(startTime, length) * timeScale;
anim.Play(animName, animLayer, pos);
anim.speed = 0;
}
/// <summary>
/// Sets animator progress on an animation according to pos
/// </summary>
/// <param name="anim">Animator to update</param>
/// <param name="animName">name of animation to play</param>
/// <param name="pos">position to set animation progress to (0.0 - 1.0)</param>
/// <param name="animLayer">animator layer to play animation on</param>
public static void DoNormalizedAnimation(this Animator anim, string animName, float pos = 0f, int animLayer = -1)
{
anim.Play(animName, animLayer, pos);
anim.speed = 0;
}
/// <summary>
/// Plays animation on animator, scaling speed to song BPM
/// call this funtion once, when playing an animation
/// </summary>
/// <param name="anim">Animator to play animation on</param>
/// <param name="animName">name of animation to play</param>
/// <param name="timeScale">multiplier for animation speed</param>
/// <param name="startPos">starting progress of animation</param>
/// <param name="animLayer">animator layer to play animation on</param>
public static void DoScaledAnimationAsync(this Animator anim, string animName, float timeScale = 1f, float startPos = 0f, int animLayer = -1)
{
anim.Play(animName, animLayer, startPos);
anim.speed = (1f / Conductor.instance.pitchedSecPerBeat) * timeScale;
}
/// <summary>
/// Plays animation on animator, at default speed
/// this is the least nessecary function here lol
/// </summary>
/// <param name="anim">Animator to play animation on</param>
/// <param name="animName">name of animation to play</param>
/// <param name="startPos">starting progress of animation</param>
/// <param name="animLayer">animator layer to play animation on</param>
public static void DoUnscaledAnimation(this Animator anim, string animName, float startPos = 0f, int animLayer = -1)
{
anim.Play(animName, animLayer, startPos);
anim.speed = 1f;
}
}
}

View File

@ -40,7 +40,7 @@ namespace HeavenStudio.Util
FindJukebox().GetComponent<AudioSource>().volume = volume;
}
public static Sound PlayOneShot(string name, float beat = -1, float pitch = 1f, float volume = 1f, bool looping = false)
public static Sound PlayOneShot(string name, float beat = -1, float pitch = 1f, float volume = 1f, bool looping = false, string game = null)
{
GameObject oneShot = new GameObject("oneShot");
@ -49,7 +49,29 @@ namespace HeavenStudio.Util
audioSource.playOnAwake = false;
Sound snd = oneShot.AddComponent<Sound>();
AudioClip clip = Resources.Load<AudioClip>($"Sfx/{name}");
AudioClip clip = null;
if (game != null)
{
string soundName = name.Split('/')[2];
var inf = GameManager.instance.GetGameInfo(game);
//first try the game's common assetbundle
// Debug.Log("Jukebox loading sound " + soundName + " from common");
clip = inf.GetCommonAssetBundle()?.LoadAsset<AudioClip>(soundName);
//then the localized one
if (clip == null)
{
// Debug.Log("Jukebox loading sound " + soundName + " from locale");
clip = inf.GetLocalizedAssetBundle()?.LoadAsset<AudioClip>(soundName);
}
}
//can't load from assetbundle, load from resources
if (clip == null)
{
// Debug.Log("Jukebox loading sound " + name + " from resources");
clip = Resources.Load<AudioClip>($"Sfx/{name}");
}
snd.clip = clip;
snd.beat = beat;
snd.pitch = pitch;
@ -62,7 +84,7 @@ namespace HeavenStudio.Util
return snd;
}
public static Sound PlayOneShotScheduled(string name, double targetTime, float pitch = 1f, float volume = 1f, bool looping = false)
public static Sound PlayOneShotScheduled(string name, double targetTime, float pitch = 1f, float volume = 1f, bool looping = false, string game = null)
{
GameObject oneShot = new GameObject("oneShotScheduled");
@ -70,8 +92,26 @@ namespace HeavenStudio.Util
audioSource.playOnAwake = false;
var snd = oneShot.AddComponent<Sound>();
AudioClip clip = null;
if (game != null)
{
string soundName = name.Split('/')[2];
var inf = GameManager.instance.GetGameInfo(game);
//first try the game's common assetbundle
// Debug.Log("Jukebox loading sound " + soundName + " from common");
clip = inf.GetCommonAssetBundle()?.LoadAsset<AudioClip>(soundName);
//then the localized one
if (clip == null)
{
// Debug.Log("Jukebox loading sound " + soundName + " from locale");
clip = inf.GetLocalizedAssetBundle()?.LoadAsset<AudioClip>(soundName);
}
}
//can't load from assetbundle, load from resources
if (clip == null)
clip = Resources.Load<AudioClip>($"Sfx/{name}");
var clip = Resources.Load<AudioClip>($"Sfx/{name}");
audioSource.clip = clip;
snd.clip = clip;
snd.pitch = pitch;
@ -89,9 +129,11 @@ namespace HeavenStudio.Util
public static Sound PlayOneShotGame(string name, float beat = -1, float pitch = 1f, float volume = 1f, bool looping = false, bool forcePlay = false)
{
if (GameManager.instance.currentGame == name.Split('/')[0] || forcePlay)
string gameName = name.Split('/')[0];
var inf = GameManager.instance.GetGameInfo(gameName);
if (GameManager.instance.currentGame == gameName || forcePlay)
{
return PlayOneShot($"games/{name}", beat, pitch, volume, looping);
return PlayOneShot($"games/{name}", beat, pitch, volume, looping, inf.usesAssetBundle ? gameName : null);
}
return null;
@ -99,14 +141,18 @@ namespace HeavenStudio.Util
public static Sound PlayOneShotScheduledGame(string name, double targetTime, float pitch = 1f, float volume = 1f, bool looping = false, bool forcePlay = false)
{
if (GameManager.instance.currentGame == name.Split('/')[0] || forcePlay)
string gameName = name.Split('/')[0];
var inf = GameManager.instance.GetGameInfo(gameName);
if (GameManager.instance.currentGame == gameName || forcePlay)
{
return PlayOneShotScheduled($"games/{name}", targetTime, pitch, volume, looping);
return PlayOneShotScheduled($"games/{name}", targetTime, pitch, volume, looping, inf.usesAssetBundle ? gameName : null);
}
return null;
}
//TODO: playing sounds from assetbundles
public static void KillLoop(Sound source, float fadeTime)
{
// Safeguard against previously-destroyed sounds.