2024-03-08 05:11:52 +00:00
|
|
|
using System;
|
|
|
|
using System.Linq;
|
|
|
|
using System.Collections;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
|
|
using HeavenStudio.Util;
|
|
|
|
using HeavenStudio.InputSystem;
|
|
|
|
|
|
|
|
using Jukebox;
|
|
|
|
|
|
|
|
namespace HeavenStudio.Games.Loaders
|
|
|
|
{
|
|
|
|
using static Minigames;
|
|
|
|
public static class AgbPowerCalligraphy
|
|
|
|
{
|
|
|
|
public static Minigame AddGame(EventCaller eventCaller)
|
|
|
|
{
|
|
|
|
return new Minigame("powerCalligraphy", "Power Calligraphy", "ffffff", false, false, new List<GameAction>()
|
|
|
|
{
|
2024-03-18 02:40:24 +00:00
|
|
|
new GameAction("bop", "Bop")
|
|
|
|
{
|
|
|
|
function = delegate {var e = eventCaller.currentEntity; PowerCalligraphy.instance.ToggleBop(e.beat, e.length, e["bop"], e["bopAuto"]); },
|
|
|
|
resizable = true,
|
|
|
|
parameters = new List<Param>()
|
|
|
|
{
|
|
|
|
new Param("bop", true, "Bop", "Toggle if the paddlers should bop for the duration of this event."),
|
|
|
|
new Param("bopAuto", false, "Bop (Auto)", "Toggle if the paddlers should automatically bop until another Bop event is reached.")
|
|
|
|
}
|
|
|
|
},
|
2024-03-08 05:11:52 +00:00
|
|
|
new GameAction("re", "Re (レ)")
|
|
|
|
{
|
|
|
|
function = delegate {var e = eventCaller.currentEntity; PowerCalligraphy.instance.Write(e.beat, (int)PowerCalligraphy.CharacterType.re); },
|
|
|
|
defaultLength = 8f,
|
|
|
|
},
|
|
|
|
new GameAction("comma", "Comma (、)")
|
|
|
|
{
|
|
|
|
function = delegate {var e = eventCaller.currentEntity; PowerCalligraphy.instance.Write(e.beat, (int)PowerCalligraphy.CharacterType.comma); },
|
|
|
|
defaultLength = 8f,
|
|
|
|
},
|
|
|
|
new GameAction("chikara", "Chikara (力)")
|
|
|
|
{
|
|
|
|
function = delegate {var e = eventCaller.currentEntity; PowerCalligraphy.instance.Write(e.beat, (int)PowerCalligraphy.CharacterType.chikara); },
|
|
|
|
defaultLength = 8f,
|
|
|
|
},
|
|
|
|
new GameAction("onore", "Onore (己)")
|
|
|
|
{
|
|
|
|
function = delegate {var e = eventCaller.currentEntity; PowerCalligraphy.instance.Write(e.beat, (int)PowerCalligraphy.CharacterType.onore); },
|
|
|
|
defaultLength = 8f,
|
|
|
|
},
|
|
|
|
new GameAction("sun", "Sun (寸)")
|
|
|
|
{
|
|
|
|
function = delegate {var e = eventCaller.currentEntity; PowerCalligraphy.instance.Write(e.beat, (int)PowerCalligraphy.CharacterType.sun); },
|
|
|
|
defaultLength = 8f,
|
|
|
|
},
|
|
|
|
new GameAction("kokoro", "Kokoro (心)")
|
|
|
|
{
|
|
|
|
function = delegate {var e = eventCaller.currentEntity; PowerCalligraphy.instance.Write(e.beat, (int)PowerCalligraphy.CharacterType.kokoro); },
|
|
|
|
defaultLength = 8f,
|
|
|
|
},
|
|
|
|
new GameAction("face", "Face (つるニハ○○ムし)")
|
|
|
|
{
|
|
|
|
function = delegate {var e = eventCaller.currentEntity; PowerCalligraphy.instance.Write(e.beat,
|
|
|
|
e["korean"] ? (int)PowerCalligraphy.CharacterType.face_kr : (int)PowerCalligraphy.CharacterType.face); },
|
|
|
|
parameters = new List<Param>()
|
|
|
|
{
|
|
|
|
new Param("korean", false, "Korean Version", "Change the character to Korean version. (つ3ニハ○○ムし)"),
|
|
|
|
},
|
|
|
|
defaultLength = 12f,
|
|
|
|
},
|
|
|
|
new GameAction("changeScrollSpeed", "Change Scroll Speed")
|
|
|
|
{
|
|
|
|
function = delegate {var e = eventCaller.currentEntity;
|
|
|
|
PowerCalligraphy.instance.ChangeScrollSpeed(e["x"], e["y"]);},
|
|
|
|
parameters = new List<Param>()
|
|
|
|
{
|
|
|
|
new Param("x", new EntityTypes.Float(-20, 20, 0), "X"),
|
|
|
|
new Param("y", new EntityTypes.Float(-20, 20, 0), "Y"),
|
|
|
|
},
|
|
|
|
defaultLength = 0.5f,
|
|
|
|
},
|
2024-03-18 02:40:24 +00:00
|
|
|
new GameAction("chounin events", "Chounin Animations")
|
|
|
|
{
|
|
|
|
function = delegate { var e = eventCaller.currentEntity; PowerCalligraphy.instance.PlayChouninAnimation(e["type"], e["pos"]); },
|
|
|
|
parameters = new List<Param>()
|
|
|
|
{
|
|
|
|
new Param("type", PowerCalligraphy.ChouninType.Dance, "Animation", "Set the animation for Chounin to perform."),
|
|
|
|
new Param("pos", new EntityTypes.Float(0, 14, 0), "Position", "Set the position of Chounin."),
|
|
|
|
}
|
|
|
|
},
|
2024-03-08 05:11:52 +00:00
|
|
|
new GameAction("end", "The End")
|
|
|
|
{
|
|
|
|
function = delegate {PowerCalligraphy.instance.TheEnd();},
|
|
|
|
defaultLength = 0.5f,
|
|
|
|
},
|
|
|
|
},
|
2024-03-29 02:35:07 +00:00
|
|
|
new List<string>() { "agb", "normal" }, "agbCalligraphy", "en", new List<string>() { },
|
|
|
|
chronologicalSortKey: 21
|
2024-03-08 05:11:52 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace HeavenStudio.Games
|
|
|
|
{
|
|
|
|
using Scripts_PowerCalligraphy;
|
|
|
|
public class PowerCalligraphy : Minigame
|
|
|
|
{
|
2024-03-11 12:22:30 +00:00
|
|
|
[Header("References")]
|
2024-03-08 05:11:52 +00:00
|
|
|
[SerializeField] List<GameObject> basePapers = new List<GameObject>();
|
2024-03-11 12:22:30 +00:00
|
|
|
[SerializeField] List<RuntimeAnimatorController> fudePosCntls = new List<RuntimeAnimatorController>();
|
2024-03-18 02:40:24 +00:00
|
|
|
[SerializeField] List<RuntimeAnimatorController> shiftCntls = new List<RuntimeAnimatorController>();
|
|
|
|
public Transform shiftHolder;
|
2024-03-08 05:11:52 +00:00
|
|
|
public Transform paperHolder;
|
2024-03-11 12:22:30 +00:00
|
|
|
public Animator endPaper;
|
2024-03-18 02:40:24 +00:00
|
|
|
public GameObject[] Chounin;
|
2024-03-11 12:22:30 +00:00
|
|
|
|
|
|
|
public Animator fudePosAnim;
|
|
|
|
public Animator fudeAnim;
|
2024-03-18 02:40:24 +00:00
|
|
|
public Animator shiftAnim;
|
|
|
|
public Fude playerFude;
|
2024-03-08 05:11:52 +00:00
|
|
|
|
2024-03-11 12:22:30 +00:00
|
|
|
[Header("Variables")]
|
|
|
|
public Vector3 scrollSpeed = new Vector3();
|
2024-03-18 02:40:24 +00:00
|
|
|
public float chouninSpeed;
|
|
|
|
float chouninRate => chouninSpeed / (Conductor.instance.pitchedSecPerBeat * 2f);
|
2024-03-08 05:11:52 +00:00
|
|
|
|
|
|
|
public enum CharacterType
|
|
|
|
{
|
|
|
|
re,
|
|
|
|
comma,
|
|
|
|
chikara,
|
|
|
|
onore,
|
|
|
|
sun,
|
|
|
|
kokoro,
|
|
|
|
face,
|
|
|
|
face_kr,
|
|
|
|
NONE,
|
|
|
|
}
|
|
|
|
|
2024-03-11 12:22:30 +00:00
|
|
|
double gameStartBeat;
|
2024-03-08 05:11:52 +00:00
|
|
|
public static PowerCalligraphy instance = null;
|
|
|
|
|
|
|
|
// Start is called before the first frame update
|
|
|
|
void Awake()
|
|
|
|
{
|
|
|
|
instance = this;
|
2024-03-18 02:40:24 +00:00
|
|
|
SetupBopRegion("powerCalligraphy", "bop", "bopAuto");
|
2024-03-08 05:11:52 +00:00
|
|
|
}
|
2024-03-11 12:22:30 +00:00
|
|
|
public override void OnGameSwitch(double beat)
|
|
|
|
{
|
|
|
|
gameStartBeat = beat;
|
|
|
|
NextPrepare(beat);
|
|
|
|
}
|
|
|
|
public override void OnPlay(double beat)
|
|
|
|
{
|
|
|
|
OnGameSwitch(beat);
|
|
|
|
}
|
2024-03-08 05:11:52 +00:00
|
|
|
|
|
|
|
Writing nowPaper;
|
|
|
|
bool isPrepare = false;
|
|
|
|
void Update()
|
|
|
|
{
|
|
|
|
var cond = Conductor.instance;
|
2024-03-18 02:40:24 +00:00
|
|
|
if (!cond.isPlaying || cond.isPaused) return;
|
2024-03-08 05:11:52 +00:00
|
|
|
|
|
|
|
if (PlayerInput.GetIsAction(InputAction_BasicPress) && !IsExpectingInputNow(InputAction_BasicPress))
|
|
|
|
{
|
2024-03-11 12:22:30 +00:00
|
|
|
if (nowPaper.onGoing && nowPaper.Stroke == 1)
|
2024-03-08 05:11:52 +00:00
|
|
|
{
|
|
|
|
nowPaper.ProcessInput("fast");
|
2024-03-18 02:40:24 +00:00
|
|
|
ChouninMiss();
|
2024-03-08 05:11:52 +00:00
|
|
|
ScoreMiss();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (PlayerInput.GetIsAction(InputAction_FlickPress) && !IsExpectingInputNow(InputAction_FlickPress))
|
|
|
|
{
|
2024-03-11 12:22:30 +00:00
|
|
|
if (nowPaper.onGoing && nowPaper.Stroke != 1)
|
2024-03-08 05:11:52 +00:00
|
|
|
{
|
|
|
|
nowPaper.ProcessInput("fast");
|
2024-03-18 02:40:24 +00:00
|
|
|
ChouninMiss();
|
2024-03-08 05:11:52 +00:00
|
|
|
ScoreMiss();
|
|
|
|
}
|
|
|
|
}
|
2024-03-18 02:40:24 +00:00
|
|
|
|
|
|
|
if (isChouninMove) UpdateChouninPos(chouninRate * Time.deltaTime);
|
2024-03-08 05:11:52 +00:00
|
|
|
}
|
|
|
|
|
2024-03-11 12:22:30 +00:00
|
|
|
private void SpawnPaper(int type)
|
2024-03-08 05:11:52 +00:00
|
|
|
{
|
2024-03-18 02:40:24 +00:00
|
|
|
if (nowPaper is not null) nowPaper.transform.SetParent(paperHolder.transform, true);
|
2024-03-08 05:11:52 +00:00
|
|
|
nowPaper = Instantiate(basePapers[type], paperHolder).GetComponent<Writing>();
|
|
|
|
nowPaper.scrollSpeed = scrollSpeed;
|
|
|
|
nowPaper.gameObject.SetActive(true);
|
|
|
|
nowPaper.Init();
|
2024-03-11 12:22:30 +00:00
|
|
|
fudePosAnim.runtimeAnimatorController = fudePosCntls[type];
|
2024-03-18 02:40:24 +00:00
|
|
|
fudePosAnim.Play("0", 0, 0);
|
|
|
|
shiftAnim.runtimeAnimatorController = shiftCntls[type];
|
|
|
|
shiftHolder.transform.position = new Vector3(0, 0, 0);
|
2024-03-08 05:11:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public void Write(double beat, int type)
|
|
|
|
{
|
2024-03-11 12:22:30 +00:00
|
|
|
Prepare(type);
|
2024-03-18 02:40:24 +00:00
|
|
|
nowPaper.transform.SetParent(shiftHolder.transform, true);
|
2024-03-11 12:22:30 +00:00
|
|
|
nowPaper.startBeat = beat;
|
2024-03-08 05:11:52 +00:00
|
|
|
nowPaper.Play();
|
2024-03-11 12:22:30 +00:00
|
|
|
double nextBeat = beat + nowPaper.nextBeat;
|
|
|
|
BeatAction.New(instance, new List<BeatAction.Action>(){
|
2024-03-18 02:40:24 +00:00
|
|
|
new BeatAction.Action(beat, delegate{isPrepare = false;}),
|
|
|
|
new BeatAction.Action(nextBeat, delegate{NextPrepare(nextBeat);}),
|
2024-03-11 12:22:30 +00:00
|
|
|
});
|
2024-03-08 05:11:52 +00:00
|
|
|
}
|
|
|
|
|
2024-03-11 12:22:30 +00:00
|
|
|
public void Prepare(int type)
|
2024-03-08 05:11:52 +00:00
|
|
|
{
|
2024-03-11 12:22:30 +00:00
|
|
|
if (!isPrepare)
|
|
|
|
{
|
|
|
|
isPrepare = true;
|
2024-03-18 02:40:24 +00:00
|
|
|
SpawnPaper(type);
|
2024-03-11 12:22:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
public void NextPrepare(double beat) // Prepare next paper
|
|
|
|
{
|
|
|
|
double endBeat = double.MaxValue;
|
|
|
|
var entities = gameManager.Beatmap.Entities;
|
|
|
|
|
|
|
|
RiqEntity firstEnd = entities.Find(c => (c.datamodel.StartsWith("gameManager/switchGame") || c.datamodel.Equals("gameManager/end")) && c.beat > gameStartBeat);
|
|
|
|
endBeat = firstEnd?.beat ?? endBeat;
|
|
|
|
|
|
|
|
RiqEntity nextPaper = entities.Find(v =>
|
|
|
|
(v.datamodel is "powerCalligraphy/re" or "powerCalligraphy/comma" or "powerCalligraphy/chikara" or "powerCalligraphy/onore" or "powerCalligraphy/sun" or "powerCalligraphy/kokoro" or "powerCalligraphy/face")
|
|
|
|
&& v.beat >= beat && v.beat < endBeat);
|
|
|
|
|
|
|
|
if (nextPaper is not null)
|
|
|
|
{
|
|
|
|
int type = nextPaper.datamodel switch
|
|
|
|
{
|
|
|
|
"powerCalligraphy/re" => (int)CharacterType.re,
|
|
|
|
"powerCalligraphy/comma" => (int)CharacterType.comma,
|
|
|
|
"powerCalligraphy/chikara" => (int)CharacterType.chikara,
|
|
|
|
"powerCalligraphy/onore" => (int)CharacterType.onore,
|
|
|
|
"powerCalligraphy/sun" => (int)CharacterType.sun,
|
|
|
|
"powerCalligraphy/kokoro" => (int)CharacterType.kokoro,
|
|
|
|
"powerCalligraphy/face" => nextPaper["korean"] ? (int)PowerCalligraphy.CharacterType.face_kr : (int)PowerCalligraphy.CharacterType.face,
|
|
|
|
_ => throw new NotImplementedException()
|
|
|
|
};
|
|
|
|
|
|
|
|
Prepare(type);
|
|
|
|
}
|
2024-03-08 05:11:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public void ChangeScrollSpeed(float x, float y)
|
|
|
|
{
|
|
|
|
scrollSpeed = new Vector3(x, y, 0);
|
|
|
|
nowPaper.scrollSpeed = scrollSpeed;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void TheEnd()
|
|
|
|
{
|
2024-03-11 12:22:30 +00:00
|
|
|
fudePosAnim.runtimeAnimatorController = fudePosCntls[(int)CharacterType.NONE];
|
|
|
|
fudePosAnim.Play("fudePos-end");
|
|
|
|
endPaper.Play("paper-end");
|
2024-03-08 05:11:52 +00:00
|
|
|
}
|
2024-03-18 02:40:24 +00:00
|
|
|
|
|
|
|
public override void OnBeatPulse(double beat)
|
|
|
|
{
|
|
|
|
if (BeatIsInBopRegion(beat)) Bop();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void ToggleBop(double beat, float length, bool bopOrNah, bool autoBop)
|
|
|
|
{
|
|
|
|
if (bopOrNah)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < length; i++)
|
|
|
|
{
|
|
|
|
BeatAction.New(instance, new() {new BeatAction.Action(beat + i, delegate {Bop();}) });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void Bop()
|
|
|
|
{
|
|
|
|
if (chouninType != (int)ChouninType.Dance) return;
|
|
|
|
isChouninMove = true;
|
|
|
|
double beat = Conductor.instance.songPositionInBeats;
|
|
|
|
|
|
|
|
for (int i=0; i<2; i++) {
|
|
|
|
int j = 0;
|
|
|
|
foreach (Transform child in Chounin[i].transform) {
|
|
|
|
var animator = child.GetComponent<Animator>();
|
|
|
|
if (animator != null) {
|
|
|
|
if ((int)(beat%2) == j%2) {
|
|
|
|
animator.DoScaledAnimationAsync("dance1", 0.5f);
|
|
|
|
} else {
|
|
|
|
animator.DoScaledAnimationAsync("dance0", 0.5f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public enum ChouninType {
|
|
|
|
Dance,
|
|
|
|
Bow,
|
|
|
|
Idle,
|
|
|
|
}
|
|
|
|
bool isChouninMove = false;
|
|
|
|
int chouninType = -1;
|
|
|
|
public void PlayChouninAnimation(int type, float pos)
|
|
|
|
{
|
|
|
|
isChouninMove = false;
|
|
|
|
chouninType = type;
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case (int)ChouninType.Dance:
|
|
|
|
isChouninMove = true;
|
|
|
|
Bop();
|
|
|
|
break;
|
|
|
|
case (int)ChouninType.Bow:
|
|
|
|
ChouninAnim("bow");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ChouninAnim("idle");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (pos>0) UpdateChouninPos(pos);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void ChouninAnim(string type)
|
|
|
|
{
|
|
|
|
for (int i=0; i<2; i++) {
|
|
|
|
foreach (Transform child in Chounin[i].transform) {
|
|
|
|
var animator = child.GetComponent<Animator>();
|
|
|
|
if (animator != null) {
|
|
|
|
if (i%2 == 1) {
|
|
|
|
animator.DoScaledAnimationAsync($"{type}1", 0.5f);
|
|
|
|
} else {
|
|
|
|
animator.DoScaledAnimationAsync($"{type}0", 0.5f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void ChouninMiss()
|
|
|
|
{
|
|
|
|
isChouninMove = false;
|
|
|
|
double beat = Conductor.instance.songPositionInBeats;
|
|
|
|
var currentChouninType = chouninType;
|
|
|
|
BeatAction.New(instance, new() {new BeatAction.Action(beat + 1.5f, delegate {
|
|
|
|
if (chouninType == -1) chouninType = currentChouninType;
|
|
|
|
})});
|
|
|
|
chouninType = -1;
|
|
|
|
ChouninAnim("fall");
|
|
|
|
}
|
|
|
|
|
|
|
|
private void UpdateChouninPos(float pos)
|
|
|
|
{
|
|
|
|
foreach (Transform child in Chounin[0].transform) {
|
|
|
|
var childPos = child.localPosition;
|
|
|
|
var newChildY = childPos.y - pos;
|
|
|
|
newChildY = newChildY < -6 ? newChildY + 12 : newChildY;
|
|
|
|
child.localPosition = new Vector3(childPos.x, newChildY, childPos.z);
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach (Transform child in Chounin[1].transform) {
|
|
|
|
var childPos = child.localPosition;
|
|
|
|
var newChildY = childPos.y + pos;
|
|
|
|
newChildY = newChildY > 6 ? newChildY - 12 : newChildY;
|
|
|
|
child.localPosition = new Vector3(childPos.x, newChildY, childPos.z);
|
|
|
|
}
|
|
|
|
}
|
2024-03-08 05:11:52 +00:00
|
|
|
}
|
|
|
|
}
|