Merge branch 'megaminerjenny:master' into main

This commit is contained in:
Slaith12
2022-03-06 18:37:51 -08:00
committed by GitHub
151 changed files with 11332 additions and 84 deletions

View File

@ -12,9 +12,11 @@ namespace RhythmHeavenMania.Games.CropStomp
public class CropStomp : Minigame
{
const float stepDistance = 2.115f;
public static float[] moleSoundOffsets = new float[]{ 0.134f, 0.05f, 0.061f };
float scrollRate => stepDistance / (Conductor.instance.secPerBeat * 2f / Conductor.instance.musicSource.pitch);
float grassWidth;
float dotsWidth = 19.2f;
private float newBeat = -1f; // So that marching can happen on beat 0.
private float marchStartBeat = -1f;
@ -23,20 +25,23 @@ namespace RhythmHeavenMania.Games.CropStomp
private int stepCount;
private bool isStepping;
public bool isMarching => marchStartBeat != -1f && Conductor.instance.isPlaying;
public bool isMarching => marchStartBeat != -1f;
[NonSerialized] public bool isFlicking;
public GameObject baseVeggie;
public GameObject baseMole;
public Animator legsAnim;
public Animator bodyAnim;
public Transform farmerTrans;
public SpriteRenderer grass;
public Transform grassTrans;
public Transform dotsTrans;
public Transform scrollingHolder;
public Transform veggieHolder;
public Farmer farmer;
public BezierCurve3D pickCurve;
public BezierCurve3D moleCurve;
private Tween shakeTween;
@ -68,15 +73,18 @@ namespace RhythmHeavenMania.Games.CropStomp
for (int i = 0; i < marchStarts.Count; i++)
{
var sampleBeat = marchStarts[i].beat;
if (cond.songPositionInBeats < sampleBeat)
if (cond.songPositionInBeats <= sampleBeat + 0.25f) // 0.25-beat buffer in case the start marching event is directly next to the game switch event.
{
startBeat = sampleBeat;
break;
}
}
// Spawn veggies.
// Veggie and mole events.
var vegEvents = entities.FindAll(v => v.datamodel == "cropStomp/veggies");
var moleEvents = entities.FindAll(m => m.datamodel == "cropStomp/mole");
// Spawn veggies.
for (int i = 0; i < vegEvents.Count; i++)
{
var vegBeat = vegEvents[i].beat;
@ -92,19 +100,49 @@ namespace RhythmHeavenMania.Games.CropStomp
var targetVeggieBeat = vegBeat + 2f * b;
if (startBeat < targetVeggieBeat)
{
SpawnVeggie(targetVeggieBeat, startBeat);
SpawnVeggie(targetVeggieBeat, startBeat, false);
}
}
}
}
// Spawn moles.
for (int i = 0; i < moleEvents.Count; i++)
{
var moleBeat = moleEvents[i].beat;
if (startBeat < moleBeat)
{
SpawnVeggie(moleBeat, startBeat, true);
}
}
}
List<Beatmap.Entity> cuedMoleSounds = new List<Beatmap.Entity>();
private void Update()
{
if (!isMarching)
var cond = Conductor.instance;
if (!cond.isPlaying)
return;
var cond = Conductor.instance;
// Mole sounds.
var moleEvents = GameManager.instance.Beatmap.entities.FindAll(m => m.datamodel == "cropStomp/mole");
for (int i = 0; i < moleEvents.Count; i++)
{
var moleEvent = moleEvents[i];
var timeToEvent = moleEvent.beat - cond.songPositionInBeats;
if (timeToEvent <= 3f && timeToEvent > 0f && !cuedMoleSounds.Contains(moleEvent))
{
cuedMoleSounds.Add(moleEvent);
MultiSound.Play(new MultiSound.Sound[] { new MultiSound.Sound("cropStomp/moleNyeh", (moleEvent.beat - 2f) - moleSoundOffsets[0] * Conductor.instance.songBpm / 60f),
new MultiSound.Sound("cropStomp/moleHeh1", (moleEvent.beat - 1.5f) - moleSoundOffsets[1] * Conductor.instance.songBpm / 60f),
new MultiSound.Sound("cropStomp/moleHeh2", (moleEvent.beat - 1f) - moleSoundOffsets[2] * Conductor.instance.songBpm / 60f) });
}
}
if (!isMarching)
return;
if (cond.ReportBeat(ref newBeat, marchOffset, true))
{
@ -151,6 +189,14 @@ namespace RhythmHeavenMania.Games.CropStomp
newGrassX = (newGrassX % (grassWidth * 4.5f));
grassTrans.localPosition = new Vector3(newGrassX, grassPos.y, grassPos.z);
// Dots scroll
var dotsPos = dotsTrans.localPosition;
var newDotsX = dotsPos.x + (scrollRate * Time.deltaTime);
newDotsX = (newDotsX % dotsWidth);
dotsTrans.localPosition = new Vector3(newDotsX, dotsPos.y, dotsPos.z);
}
private void LateUpdate()
@ -200,9 +246,9 @@ namespace RhythmHeavenMania.Games.CropStomp
isStepping = true;
}
private void SpawnVeggie(float beat, float startBeat)
private void SpawnVeggie(float beat, float startBeat, bool isMole)
{
var newVeggie = GameObject.Instantiate(baseVeggie, veggieHolder).GetComponent<Veggie>();
var newVeggie = GameObject.Instantiate(isMole ? baseMole : baseVeggie, veggieHolder).GetComponent<Veggie>();
newVeggie.targetBeat = beat;

View File

@ -14,14 +14,16 @@ namespace RhythmHeavenMania.Games.CropStomp
public bool isMole;
public Sprite[] veggieSprites;
public Sprite[] moleSprites;
public Animator moleAnim;
public SpriteRenderer veggieSprite;
public Transform veggieTrans;
public BezierCurve3D curve;
private BezierCurve3D hitCurve;
public float targetBeat;
private float stompedBeat;
private float pickedBeat;
private float pickTime = 1f;
private int veggieState = 0;
private bool boinked; // Player got barely when trying to pick.
@ -39,6 +41,10 @@ namespace RhythmHeavenMania.Games.CropStomp
{
veggieSprite.sprite = veggieSprites[UnityEngine.Random.Range(0, veggieSprites.Length)];
}
else
{
pickTime = 1.5f;
}
}
private bool gotStomped; // Safeguard in case nested Update() call breaks.
@ -97,7 +103,8 @@ namespace RhythmHeavenMania.Games.CropStomp
{
veggieState = -1;
Jukebox.PlayOneShotGame("cropStomp/veggieMiss");
if (!isMole)
Jukebox.PlayOneShotGame("cropStomp/veggieMiss");
return;
}
@ -113,6 +120,18 @@ namespace RhythmHeavenMania.Games.CropStomp
veggieState = -1;
boinked = true;
curve.transform.localScale = Vector3.one; // Return curve to normal size in the case of mole curves.
var key1 = curve.KeyPoints[0];
var key1Pos = key1.Position;
key1.Position = new Vector3(key1Pos.x, veggieTrans.position.y, key1Pos.z);
var key2 = curve.KeyPoints[1];
var key2Pos = key2.Position;
key2.Position = new Vector3(key2Pos.x, veggieTrans.position.y + 2f, key2Pos.z);
pickedBeat = cond.songPositionInBeats;
Jukebox.PlayOneShot("miss");
MissedUpdate();
@ -124,28 +143,53 @@ namespace RhythmHeavenMania.Games.CropStomp
}
}
bool moleLaughing;
private void MissedUpdate()
{
if (boinked)
{
float fallPosition = Conductor.instance.GetPositionFromBeat(pickedBeat, 1f);
fallPosition = Mathf.Clamp(fallPosition, 0, 1);
veggieTrans.position = curve.GetPoint(fallPosition);
if (fallPosition < 1f)
{
var rotSpeed = isMole ? pickedRotationSpeed : -pickedRotationSpeed;
veggieTrans.rotation = Quaternion.Euler(0, 0, veggieTrans.rotation.eulerAngles.z + (rotSpeed * Time.deltaTime));
}
else
{
veggieTrans.rotation = Quaternion.Euler(0, 0, 180f);
}
}
else
{
if (isMole && !moleLaughing)
{
var distDiff = transform.position.x - game.farmerTrans.position.x;
if (distDiff > 1.5f)
{
moleAnim.Play("Chuckle", 0, 0);
moleLaughing = true;
}
}
}
}
private void PickedUpdate()
{
float pickPosition = Conductor.instance.GetPositionFromBeat(pickedBeat, 1f);
float pickPosition = Conductor.instance.GetPositionFromBeat(pickedBeat, pickTime);
pickPosition = Mathf.Clamp(pickPosition, 0, 1);
veggieTrans.position = game.pickCurve.GetPoint(pickPosition);
veggieTrans.position = hitCurve.GetPoint(pickPosition);
veggieTrans.rotation = Quaternion.Euler(0, 0, veggieTrans.rotation.eulerAngles.z + (pickedRotationSpeed * Time.deltaTime));
var rotSpeed = isMole ? -pickedRotationSpeed : pickedRotationSpeed;
veggieTrans.rotation = Quaternion.Euler(0, 0, veggieTrans.rotation.eulerAngles.z + (rotSpeed * Time.deltaTime));
var veggieScale = Mathf.Min(1.5f - pickPosition, 1f);
veggieTrans.localScale = Vector2.one * veggieScale;
if (!isMole)
{
var veggieScale = Mathf.Min(1.5f - pickPosition, 1f);
veggieTrans.localScale = Vector2.one * veggieScale;
}
}
private void StompVeggie(bool autoTriggered)
@ -180,6 +224,10 @@ namespace RhythmHeavenMania.Games.CropStomp
new BeatAction.Action(targetBeat - 0.5f, delegate { Jukebox.PlayOneShotGame("cropStomp/veggieOh"); })
});
}
else
{
moleAnim.Play("Idle", 0, 0);
}
var veggieScale = veggieTrans.localScale;
veggieTrans.localScale = new Vector3(veggieScale.x * 0.5f, veggieScale.y, veggieScale.z);
@ -211,10 +259,23 @@ namespace RhythmHeavenMania.Games.CropStomp
BeatAction.New(gameObject, new List<BeatAction.Action>()
{
new BeatAction.Action(pickedBeat + 0.5f, delegate { veggieSprite.sortingOrder = -1; }),
new BeatAction.Action(pickedBeat + 1f, delegate { GameObject.Destroy(gameObject); })
new BeatAction.Action(pickedBeat + pickTime, delegate { GameObject.Destroy(gameObject); })
});
Jukebox.PlayOneShotGame("cropStomp/veggieKay");
hitCurve = game.pickCurve;
}
else
{
BeatAction.New(gameObject, new List<BeatAction.Action>()
{
new BeatAction.Action(pickedBeat + pickTime, delegate { GameObject.Destroy(gameObject); })
});
Jukebox.PlayOneShotGame("cropStomp/GEUH");
hitCurve = game.moleCurve;
}
if (squashTween != null)

View File

@ -0,0 +1,53 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;
namespace RhythmHeavenMania.Games.KarateMan
{
// Physics in Rhythm Heaven Mania? nah im just fuckin lazy
public class CookingPotDestroyEffect : MonoBehaviour
{
public SpriteRenderer SpriteRenderer;
public int spriteIndex;
public int index;
private float rotationSpeed;
public GameObject pot;
private void Start()
{
SpriteRenderer sr = gameObject.AddComponent<SpriteRenderer>();
sr.sprite = KarateMan.instance.CookingPotSprites[1];
Rigidbody2D rb2d = gameObject.AddComponent<Rigidbody2D>();
rb2d.gravityScale = 5;
rb2d.collisionDetectionMode = CollisionDetectionMode2D.Continuous;
rb2d.AddForce(Vector3.up * Random.Range(875, 925));
rotationSpeed = Random.Range(100, 200);
PhysicsMaterial2D mat = new PhysicsMaterial2D();
mat.bounciness = 0;
StartCoroutine(FadeOut());
gameObject.name = "cookingpot_lid";
}
private void Update()
{
transform.eulerAngles -= new Vector3(0, 0, rotationSpeed * Time.deltaTime);
transform.position = new Vector3(pot.transform.position.x, transform.position.y, transform.position.z);
}
private IEnumerator FadeOut()
{
yield return new WaitForSeconds(Conductor.instance.secPerBeat * 3);
Destroy(gameObject);
}
}
}

View File

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

View File

@ -12,8 +12,6 @@ namespace RhythmHeavenMania.Games.KarateMan
[Header("Components")]
public Animator anim;
public GameObject HitEffect;
public ParticleSystem HitParticle;
public ParticleSystem RockParticle;
public GameObject BulbHit;
[SerializeField] private SpriteRenderer head;
[SerializeField] private Sprite[] heads;
@ -268,7 +266,7 @@ namespace RhythmHeavenMania.Games.KarateMan
}
else
{
if (p.type == 2 || p.type == 3 || p.type == 4 || p.type == 6)
if (p.type == 2 || p.type == 3 || p.type == 4 || p.type == 6 || p.type == 999)
{
punchLeft = false;
}

View File

@ -14,7 +14,18 @@ namespace RhythmHeavenMania.Games.KarateMan
Pot = 0,
Rock = 2,
Ball = 3,
TacoBell = 6
CookingPot = 6,
Alien = 7,
TacoBell = 999
}
public enum HitThree
{
HitTwo,
HitThree,
HitThreeAlt,
HitFour
}
public enum LightBulbType
@ -65,6 +76,8 @@ namespace RhythmHeavenMania.Games.KarateMan
public Sprite[] ObjectSprites;
public Sprite[] BarrelSprites;
public Sprite[] CookingPotSprites;
public Sprite[] OtherSprites;
public List<BGSpriteC> BGSprites;
public SpriteRenderer BGSprite;
@ -84,6 +97,8 @@ namespace RhythmHeavenMania.Games.KarateMan
private float bgBeat;
public ParticleSystem potHitEffect;
public GameObject comboRef;
public GameObject HIT3Ref;
@ -150,7 +165,9 @@ namespace RhythmHeavenMania.Games.KarateMan
p.createBeat = beat;
p.isThrown = true;
p.type = type;
p.Sprite.GetComponent<SpriteRenderer>().sprite = ObjectSprites[type];
if(type <= ObjectSprites.Length)
p.Sprite.GetComponent<SpriteRenderer>().sprite = ObjectSprites[type];
if (combo)
{
@ -210,7 +227,25 @@ namespace RhythmHeavenMania.Games.KarateMan
});
break;
case 6:
outSnd = "karateman/objectOut";
if (Starpelly.Mathp.GetDecimalFromFloat(beat) == 0f)
outSnd = "karateman/objectOut";
else
outSnd = "karateman/offbeatObjectOut";
p.hitSnd = "karateman/cookingPot";
break;
case 7:
if (Starpelly.Mathp.GetDecimalFromFloat(beat) == 0f)
outSnd = "karateman/objectOut";
else
outSnd = "karateman/offbeatObjectOut";
p.hitSnd = "karateman/alienHit";
break;
case 999:
p.Sprite.GetComponent<SpriteRenderer>().sprite = OtherSprites[0];
if (Starpelly.Mathp.GetDecimalFromFloat(beat) == 0f)
outSnd = "karateman/objectOut";
else
outSnd = "karateman/offbeatObjectOut";
p.hitSnd = "karateman/tacobell";
break;
}
@ -264,6 +299,9 @@ namespace RhythmHeavenMania.Games.KarateMan
}
}
if (!Conductor.instance.isPlaying)
return;
// Call "hit" voice slightly early to account for sound offset.
var hitVoiceEvents = GameManager.instance.Beatmap.entities.FindAll(c => c.datamodel == "karateman/hit3" || c.datamodel == "karateman/hit4");
for (int i = 0; i < hitVoiceEvents.Count; i++)
@ -273,7 +311,9 @@ namespace RhythmHeavenMania.Games.KarateMan
if (timeToEvent <= 1f && timeToEvent > 0f && !cuedVoices.Contains(hitEvent))
{
cuedVoices.Add(hitEvent);
MultiSound.Play(new MultiSound.Sound[] { new MultiSound.Sound("karateman/hit", hitEvent.beat - hitVoiceOffset * Conductor.instance.songBpm / 60f) });
var sound = "karateman/hit";
if (hitEvent.type == (int)KarateMan.HitThree.HitThreeAlt) sound += "Alt";
MultiSound.Play(new MultiSound.Sound[] { new MultiSound.Sound(sound, hitEvent.beat - hitVoiceOffset * Conductor.instance.songBpm / 60f) });
}
}
}
@ -308,9 +348,16 @@ namespace RhythmHeavenMania.Games.KarateMan
bop.startBeat = beat;
}
public void Hit3(float beat)
public void Hit2(float beat)
{
MultiSound.Play(new MultiSound.Sound[] { new MultiSound.Sound("karateman/three", beat + 0.5f) });
MultiSound.Play(new MultiSound.Sound[] { new MultiSound.Sound("karateman/two", beat + 0.5f) });
}
public void Hit3(float beat, bool alt = false)
{
var sound = "karateman/three";
if (alt) sound += "Alt";
MultiSound.Play(new MultiSound.Sound[] { new MultiSound.Sound(sound, beat + 0.5f) });
GameObject hit3 = Instantiate(HIT3Ref, this.transform);
hit3.transform.GetChild(0).GetChild(1).GetComponent<SpriteRenderer>().sprite = Numbers[2];
BeatAction.New(hit3, new List<BeatAction.Action>()

View File

@ -16,6 +16,7 @@ namespace RhythmHeavenMania.Games.KarateMan
private GameObject newHolder;
public GameObject Sprite;
public GameObject BulbLightSprite;
public GameObject CookingPotLid;
private SpriteRenderer spriteComp;
public GameObject Shadow;
private SpriteRenderer shadowSpriteComp;
@ -70,6 +71,9 @@ namespace RhythmHeavenMania.Games.KarateMan
else
hitLength = 14f;
if (type == 6)
CookingPotLid.SetActive(true);
/*if (combo)
{
if (comboIndex == 0)
@ -266,7 +270,7 @@ namespace RhythmHeavenMania.Games.KarateMan
switch (type)
{
case 0:
// HitParticle.Play();
if(!combo) KarateMan.instance.potHitEffect.Play();
break;
case 1:
GameObject bulbHit = Instantiate(KarateJoe.instance.BulbHit);
@ -275,11 +279,19 @@ namespace RhythmHeavenMania.Games.KarateMan
Destroy(bulbHit, 0.7f);
break;
case 2:
// RockParticle.Play();
// TODO: Rock destroy particle effect
break;
case 4:
BarrelDestroy(false);
break;
case 6:
// TODO: Rock destroy particle effect
CookingPotLid.SetActive(false);
CookingPotDestroy();
break;
case 999:
Jukebox.PlayOneShotGame("karateman/rockHit");
break;
}
if (!kick)
@ -327,6 +339,17 @@ namespace RhythmHeavenMania.Games.KarateMan
Holder.transform.parent = newHolder.transform;
}
public void CookingPotDestroy()
{
GameObject lid = new GameObject();
lid.transform.localPosition = Holder.transform.localPosition;
lid.transform.parent = transform.parent;
lid.transform.localScale = Holder.transform.localScale;
CookingPotDestroyEffect cpde = lid.AddComponent<CookingPotDestroyEffect>();
cpde.pot = Sprite;
}
public void BarrelDestroy(bool combo)
{
for (int i = 0; i < 8; i++)

View File

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

View File

@ -0,0 +1,89 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using Starpelly;
using RhythmHeavenMania.Util;
namespace RhythmHeavenMania.Games.MrUpbeat
{
public class MrUpbeat : Minigame
{
[Header("References")]
public GameObject metronome;
public UpbeatMan man;
public GameEvent beat = new GameEvent();
public GameEvent offbeat = new GameEvent();
public bool canGo = false;
private int beatCount = 0;
public static MrUpbeat instance;
private void Awake()
{
instance = this;
}
private void Update()
{
if (canGo)
metronome.transform.eulerAngles = new Vector3(0, 0, 270 - Mathf.Cos(Mathf.PI * Conductor.instance.songPositionInBeats) * 75);
//else
// metronome.transform.eulerAngles = new Vector3(0, 0, 200);
List<Beatmap.Entity> gos = GameManager.instance.Beatmap.entities.FindAll(c => c.datamodel == "mrUpbeat/go");
for(int i=0; i<gos.Count; i++)
{
if ((gos[i].beat - 0.15f) <= Conductor.instance.songPositionInBeats && (gos[i].beat + gos[i].length) - 0.15f > Conductor.instance.songPositionInBeats)
{
canGo = true;
break;
} else
{
canGo = false;
}
}
if (Conductor.instance.ReportBeat(ref beat.lastReportedBeat) && canGo)
{
if(beatCount % 2 == 0)
Jukebox.PlayOneShotGame("mrUpbeat/metronomeRight");
else
Jukebox.PlayOneShotGame("mrUpbeat/metronomeLeft");
beatCount++;
}
if (Conductor.instance.ReportBeat(ref offbeat.lastReportedBeat, 0.25f, true))
{
man.Blip();
if(canGo) man.targetBeat = offbeat.lastReportedBeat + 1f;
}
}
public override void OnGameSwitch()
{
base.OnGameSwitch();
canGo = false;
man.stepTimes = 0;
SetInterval(0);
}
public void SetInterval(float beat)
{
beatCount = 0;
offbeat.startBeat = beat;
man.targetBeat = beat + 320f;
man.Idle();
}
public void Go(float beat)
{
beatCount = 0;
}
}
}

View File

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

View File

@ -0,0 +1,102 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using Starpelly;
using RhythmHeavenMania.Util;
namespace RhythmHeavenMania.Games.MrUpbeat
{
public class UpbeatMan : PlayerActionObject
{
[Header("References")]
public MrUpbeat game;
public Animator animator;
public Animator blipAnimator;
public GameObject[] shadows;
public float targetBeat = 0.25f;
public int stepTimes = 0;
private bool stepped = false;
public GameEvent blip = new GameEvent();
private void Update()
{
float normalizedBeat = Conductor.instance.GetPositionFromMargin(targetBeat, 0.5f);
StateCheck(normalizedBeat);
if(game.canGo && normalizedBeat > Minigame.LateTime())
{
//Fall();
targetBeat += 100f;
return;
}
if (PlayerInput.Pressed())
{
if (state.perfect)
{
Step();
}
else if(state.notPerfect())
{
Fall();
}
else
{
Step();
}
}
}
public override void OnAce()
{
if (!game.canGo) return;
Step();
}
public void Idle()
{
stepTimes = 0;
transform.localScale = new Vector3(1, 1);
animator.Play("Idle", 0, 0);
}
public void Step()
{
stepTimes++;
animator.Play("Step", 0, 0);
Jukebox.PlayOneShotGame("mrUpbeat/step");
if (stepTimes % 2 == 1)
{
shadows[0].SetActive(false);
shadows[1].SetActive(true);
transform.localScale = new Vector3(-1, 1);
} else
{
shadows[0].SetActive(true);
shadows[1].SetActive(false);
transform.localScale = new Vector3(1, 1);
}
}
public void Fall()
{
animator.Play("Fall", 0, 0);
Jukebox.PlayOneShot("miss");
}
public void Blip()
{
Jukebox.PlayOneShotGame("mrUpbeat/blip");
blipAnimator.Play("Blip", 0, 0);
}
}
}

View File

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

View File

@ -27,7 +27,9 @@ namespace RhythmHeavenMania.Games.RhythmRally
{
if (!game.served || game.missed || !game.started) return;
float stateBeat = Conductor.instance.GetPositionFromMargin(game.targetBeat, 1f);
var cond = Conductor.instance;
float stateBeat = cond.GetPositionFromMargin(game.targetBeat, 1f);
StateCheck(stateBeat);
if (PlayerInput.Pressed())
@ -41,6 +43,10 @@ namespace RhythmHeavenMania.Games.RhythmRally
Miss();
Jukebox.PlayOneShot("miss");
playerAnim.Play("Swing", 0, 0);
game.missCurve.KeyPoints[0].Position = game.ball.transform.position;
game.missCurve.transform.localScale = new Vector3(state.early ? 1f : -1f, 1f, 1f);
game.missBeat = cond.songPositionInBeats;
}
else
{
@ -52,6 +58,7 @@ namespace RhythmHeavenMania.Games.RhythmRally
if (stateBeat > Minigame.EndTime())
{
Miss();
game.ball.SetActive(false);
}
}

View File

@ -23,6 +23,7 @@ namespace RhythmHeavenMania.Games.RhythmRally
public BezierCurve3D serveCurve;
public BezierCurve3D returnCurve;
public BezierCurve3D tossCurve;
public BezierCurve3D missCurve;
public GameObject ballHitFX;
@ -39,6 +40,7 @@ namespace RhythmHeavenMania.Games.RhythmRally
public float serveBeat;
public float targetBeat;
public float tossBeat;
public float missBeat;
public float tossLength;
private bool inPose;
@ -146,16 +148,20 @@ namespace RhythmHeavenMania.Games.RhythmRally
if (!missed)
{
float curveHeight = 1f;
if (rallySpeed == RallySpeed.Fast && served)
curveHeight = 0.5f;
float curveHeight = 1.25f;
if ((rallySpeed == RallySpeed.Fast && served) || rallySpeed == RallySpeed.SuperFast)
curveHeight = 0.75f;
else if (rallySpeed == RallySpeed.Fast && !served && hitPosition1 >= 1f)
curveHeight = 2f;
else if (rallySpeed == RallySpeed.Slow)
curveHeight = 3f;
curveToUse.transform.localScale = new Vector3(1f, curveHeight, 1f);
ball.transform.position = curveToUse.GetPoint(Mathf.Clamp(curvePosition, 0, 1));
ball.transform.position = curveToUse.GetPoint(Mathf.Max(0, curvePosition));
// Make ball inactive before it passes through the floor.
if (curvePosition > 1.05f)
ball.SetActive(false);
}
else
{
@ -163,6 +169,14 @@ namespace RhythmHeavenMania.Games.RhythmRally
{
TossUpdate(tossBeat, tossLength);
}
else
{
var missPosition = cond.GetPositionFromBeat(missBeat, 1f);
ball.transform.position = missCurve.GetPoint(Mathf.Max(0, missPosition));
if (missPosition > 1f)
ball.SetActive(false);
}
}
// TODO: Make conditional so ball shadow only appears when over table.
@ -189,10 +203,19 @@ namespace RhythmHeavenMania.Games.RhythmRally
// Check if paddler should do ready animation.
bool readyToPrep;
if (rallySpeed == RallySpeed.Slow || (!served && rallySpeed == RallySpeed.Fast))
readyToPrep = timeBeforeNextHit <= 2f;
else
readyToPrep = timeBeforeNextHit <= 1f;
switch (rallySpeed)
{
case RallySpeed.Slow:
case RallySpeed.Fast:
readyToPrep = timeBeforeNextHit <= 2f;
break;
case RallySpeed.SuperFast:
readyToPrep = timeBeforeNextHit <= 0.5f;
break;
default:
readyToPrep = timeBeforeNextHit <= 1f;
break;
}
// Paddler ready animation.
if (readyToPrep && !opponentServing && !inPose)
@ -261,6 +284,12 @@ namespace RhythmHeavenMania.Games.RhythmRally
public void Serve(float beat, RallySpeed speed)
{
if (!ball.activeSelf)
ball.SetActive(true);
if (!ballTrail.gameObject.activeSelf)
ballTrail.gameObject.SetActive(true);
served = true;
missed = false;
started = true;
@ -298,6 +327,9 @@ namespace RhythmHeavenMania.Games.RhythmRally
public void Toss(float beat, float length, float height, bool firstToss = false)
{
// Hide trail while tossing to prevent weirdness while teleporting ball.
ballTrail.gameObject.SetActive(false);
tossCurve.transform.localScale = new Vector3(1f, height, 1f);
tossBeat = beat;
tossLength = length;
@ -308,24 +340,17 @@ namespace RhythmHeavenMania.Games.RhythmRally
opponentAnim.Play("Ready1");
}
StartCoroutine(TossTrailCo());
}
// Hide the trail for one frame to avoid shenanigans when teleporting the ball.
IEnumerator TossTrailCo()
{
ballTrail.emitting = false;
TossUpdate(tossBeat, tossLength);
yield return null;
ballTrail.emitting = true;
if (!ball.activeSelf)
ball.SetActive(true);
}
private void TossUpdate(float beat, float duration)
{
var tossPosition = Conductor.instance.GetPositionFromBeat(beat, duration);
ball.transform.position = tossCurve.GetPoint(Mathf.Clamp(tossPosition, 0, 1));
if (tossPosition > 1.05f)
ball.SetActive(false);
}
public void PlayWhistle()
@ -337,7 +362,7 @@ namespace RhythmHeavenMania.Games.RhythmRally
{
playerAnim.Play("Pose", 0, 0);
opponentAnim.Play("Pose", 0, 0);
ball.gameObject.SetActive(false); // temporary solution, should realistically just fall down
ball.SetActive(false); // temporary solution, should realistically just fall down
inPose = true;
}

View File

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

View File

@ -0,0 +1,36 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace RhythmHeavenMania.Games.WizardsWaltz
{
public class Girl : MonoBehaviour
{
public Animator animator;
public GameObject[] flowers;
private int flowerCount = 0;
public void Happy()
{
animator.Play("Happy", 0, 0);
SetFlowers(1);
}
public void Sad()
{
animator.Play("Sad", 0, 0);
SetFlowers(-1);
}
public void SetFlowers(int add = 0)
{
flowerCount = Mathf.Clamp(flowerCount + add, 0, flowers.Length);
for (int i = 0; i < flowers.Length; i++)
{
flowers[i].SetActive(i < flowerCount);
}
}
}
}

View File

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

View File

@ -0,0 +1,33 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using RhythmHeavenMania.Util;
using System;
namespace RhythmHeavenMania.Games.WizardsWaltz
{
public class MagicFX : MonoBehaviour
{
public Animator animator;
public SpriteRenderer spriteRenderer;
public GameObject shimmer;
public void Start()
{
int order = (int)Math.Round((transform.position.z - 2) * 1000);
spriteRenderer.sortingOrder = order;
shimmer.GetComponent<SpriteRenderer>().sortingOrder = order;
animator.Play("Magic", 0, 0);
Rigidbody2D rb2d = gameObject.AddComponent<Rigidbody2D>();
rb2d.gravityScale = 2.5f;
}
public void Kill()
{
Destroy(shimmer);
Destroy(gameObject);
}
}
}

View File

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

View File

@ -0,0 +1,105 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
namespace RhythmHeavenMania.Games.WizardsWaltz
{
public class Plant : PlayerActionObject
{
public Animator animator;
public SpriteRenderer spriteRenderer;
public float createBeat;
private WizardsWaltz game;
private bool hit = false;
private bool passed = false;
public int order = 0;
private void Awake()
{
game = WizardsWaltz.instance;
}
private void Start()
{
spriteRenderer.sortingOrder = order;
animator.Play("Appear", 0, 0);
}
private void Update()
{
if (!passed && Conductor.instance.songPositionInBeats > createBeat + game.beatInterval)
{
StartCoroutine(FadeOut());
passed = true;
}
if (hit) return;
float stateBeat = Conductor.instance.GetPositionFromMargin(createBeat + game.beatInterval, 1f);
StateCheck(stateBeat);
if (PlayerInput.Pressed(true))
{
if (state.perfect)
{
Ace();
} else if (state.notPerfect())
{
Miss();
}
}
}
public void Bloom()
{
animator.Play("Hit", 0, 0);
}
public void IdlePlant()
{
animator.Play("IdlePlant", 0, 0);
}
public void IdleFlower()
{
animator.Play("IdleFlower", 0, 0);
}
public void Eat()
{
animator.Play("Eat", 0, 0);
}
public void EatLoop()
{
animator.Play("EatLoop", 0, 0);
}
public void Ace()
{
game.wizard.Magic(this, true);
hit = true;
}
public void Miss()
{
game.wizard.Magic(this, false);
hit = true;
}
public override void OnAce()
{
Ace();
}
public IEnumerator FadeOut()
{
yield return new WaitForSeconds(Conductor.instance.secPerBeat * game.beatInterval / 2f);
Destroy(gameObject);
}
}
}

View File

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

View File

@ -0,0 +1,79 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using RhythmHeavenMania.Util;
namespace RhythmHeavenMania.Games.WizardsWaltz
{
public class Wizard : MonoBehaviour
{
public Animator animator;
public GameObject shadow;
private float newBeat = 0;
private int beats = 0;
private WizardsWaltz game;
private float songPos;
private void Awake()
{
game = WizardsWaltz.instance;
}
void Update()
{
songPos = Conductor.instance.songPositionInBeats;
var am = game.beatInterval / 2f;
var x = Mathf.Sin(Mathf.PI * songPos / am) * 6;
var y = Mathf.Cos(Mathf.PI * songPos / am) * 1.5f;
var scale = 1 - Mathf.Cos(Mathf.PI * songPos / am) * 0.35f;
transform.position = new Vector3(x, 1.5f + y, 0);
shadow.transform.position = new Vector3(x, -3f + y, 0);
var xscale = scale;
if (y > 0) xscale *= -1;
transform.localScale = new Vector3(xscale, scale, 1);
shadow.transform.localScale = new Vector3(scale, scale, 1);
}
private void LateUpdate()
{
if (PlayerInput.Pressed(true))
{
animator.Play("Magic", 0, 0);
Jukebox.PlayOneShotGame("wizardsWaltz/wand");
}
}
public void Idle()
{
animator.Play("Idle", 0, 0);
}
public void Magic(Plant plant, bool hit)
{
animator.Play("Magic", 0, 0);
if(plant == null)
{
// TODO: Play empty A press sound
return;
}
if (hit)
{
Jukebox.PlayOneShotGame("wizardsWaltz/grow");
plant.Bloom();
game.girl.Happy();
}
else
{
Jukebox.PlayOneShot("miss");
plant.Eat();
game.girl.Sad();
}
}
}
}

View File

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

View File

@ -0,0 +1,105 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using Starpelly;
using RhythmHeavenMania.Util;
namespace RhythmHeavenMania.Games.WizardsWaltz
{
public class WizardsWaltz : Minigame
{
[Header("References")]
public Wizard wizard;
public Girl girl;
public GameObject plantHolder;
public GameObject plantBase;
public GameObject fxHolder;
public GameObject fxBase;
private int timer = 0;
public float beatInterval = 4f;
float intervalStartBeat;
bool intervalStarted;
public float wizardBeatOffset = 0f;
[NonSerialized] public int plantsLeft = 0;
public static WizardsWaltz instance;
private void Awake()
{
instance = this;
}
private void Update()
{
if (!Conductor.instance.isPlaying && !Conductor.instance.isPaused && intervalStarted)
{
intervalStarted = false;
}
}
private void FixedUpdate()
{
if (timer % 8 == 0 || UnityEngine.Random.Range(0,8) == 0)
{
var songPos = Conductor.instance.songPositionInBeats;
var am = beatInterval / 2f;
var x = Mathf.Sin(Mathf.PI * songPos / am) * 6 + UnityEngine.Random.Range(-0.5f, 0.5f);
var y = Mathf.Cos(Mathf.PI * songPos / am) * 2f + UnityEngine.Random.Range(-0.5f, 0.5f); ;
var scale = 1 - Mathf.Cos(Mathf.PI * songPos / am) * 0.35f + UnityEngine.Random.Range(-0.2f, 0.2f); ;
MagicFX magic = Instantiate(fxBase, fxHolder.transform).GetComponent<MagicFX>();
magic.transform.position = new Vector3(x, 0.5f + y, 0);
magic.transform.localScale = wizard.gameObject.transform.localScale;
magic.gameObject.SetActive(true);
}
timer++;
}
public void SetIntervalStart(float beat, float interval = 4f)
{
// Don't do these things if the interval was already started.
if (!intervalStarted)
{
plantsLeft = 0;
intervalStarted = true;
}
intervalStartBeat = beat;
beatInterval = interval;
}
public void SpawnFlower(float beat)
{
// If interval hasn't started, assume this is the first hair of the interval.
if (!intervalStarted)
SetIntervalStart(beat, beatInterval);
Jukebox.PlayOneShotGame("wizardsWaltz/plant", beat);
Plant plant = Instantiate(plantBase, plantHolder.transform).GetComponent<Plant>();
var songPos = Conductor.instance.songPositionInBeats;
var am = (beatInterval / 2f);
var x = Mathf.Sin(Mathf.PI * songPos / am) * 6;
var y = -3f + Mathf.Cos(Mathf.PI * songPos / am) * 1.5f;
var scale = 1 - Mathf.Cos(Mathf.PI * songPos / am) * 0.35f;
var xscale = scale;
if (y > -3.5f) xscale *= -1;
plant.transform.localPosition = new Vector3(x, y, 0);
plant.transform.localScale = new Vector3(xscale, scale, 1);
plant.order = (int)Math.Round((scale - 1) * 1000);
plant.gameObject.SetActive(true);
plant.createBeat = beat;
plantsLeft++;
}
}
}

View File

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

View File

@ -56,7 +56,7 @@ namespace RhythmHeavenMania.Editor
eventSelector.SetActive(true);
DestroyParams();
Editor.instance.SetGameEventTitle($"Select game event for {gridGameSelector.SelectedMinigame}");
Editor.instance.SetGameEventTitle($"Select game event for {gridGameSelector.SelectedMinigame.Replace("\n", "")}");
}
public void StartParams(Beatmap.Entity entity)

View File

@ -105,7 +105,7 @@ namespace RhythmHeavenMania.Editor
currentEventIndex = 0;
UpdateIndex(0, false);
Editor.instance.SetGameEventTitle($"Select game event for {gameName}");
Editor.instance.SetGameEventTitle($"Select game event for {gameName.Replace("\n", "")}");
}
private void AddEvents()

View File

@ -173,7 +173,7 @@ namespace RhythmHeavenMania.Editor.Track
Tooltip.AddTooltip(StopBTN.gameObject, "Stop <color=#adadad>[Space]</color>");
Tooltip.AddTooltip(MetronomeBTN.gameObject, "Metronome <color=#adadad>[M]</color>");
Tooltip.AddTooltip(AutoplayBTN.gameObject, "Autoplay <color=#adadad>[A]</color>");
Tooltip.AddTooltip(AutoplayBTN.gameObject, "Autoplay <color=#adadad>[P]</color>");
Tooltip.AddTooltip(SelectionsBTN.gameObject, "Tool: Selection <color=#adadad>[1]</color>");
Tooltip.AddTooltip(TempoChangeBTN.gameObject, "Tool: Tempo Change <color=#adadad>[2]</color>");
@ -258,7 +258,7 @@ namespace RhythmHeavenMania.Editor.Track
}
}
if (Input.GetKeyDown(KeyCode.A))
if (Input.GetKeyDown(KeyCode.P))
{
AutoPlayToggle();
}
@ -292,11 +292,11 @@ namespace RhythmHeavenMania.Editor.Track
float moveSpeed = 750;
if (Input.GetKey(KeyCode.LeftShift)) moveSpeed *= 2;
if (Input.GetKey(KeyCode.LeftArrow))
if (Input.GetKey(KeyCode.LeftArrow) || Input.GetKey(KeyCode.A))
{
TimelineContent.transform.localPosition += new Vector3(moveSpeed * Time.deltaTime, 0);
}
else if (Input.GetKey(KeyCode.RightArrow))
else if (Input.GetKey(KeyCode.RightArrow) || Input.GetKey(KeyCode.D))
{
TimelineContent.transform.localPosition += new Vector3(-moveSpeed * Time.deltaTime, 0);
}

View File

@ -16,6 +16,8 @@ using RhythmHeavenMania.Games.RhythmRally;
using RhythmHeavenMania.Games.BuiltToScaleDS;
using RhythmHeavenMania.Games.TapTrial;
using RhythmHeavenMania.Games.CropStomp;
using RhythmHeavenMania.Games.WizardsWaltz;
using RhythmHeavenMania.Games.MrUpbeat;
namespace RhythmHeavenMania
{
@ -247,13 +249,16 @@ namespace RhythmHeavenMania
new GameAction("hit3", delegate
{
var e = eventCaller.currentEntity;
if(e.toggle)
KarateMan.instance.Hit4(e.beat);
else
KarateMan.instance.Hit3(e.beat);
switch ((KarateMan.HitThree)e.type)
{
case KarateMan.HitThree.HitTwo: KarateMan.instance.Hit2(e.beat); break;
case KarateMan.HitThree.HitThreeAlt: KarateMan.instance.Hit3(e.beat, true); break;
case KarateMan.HitThree.HitFour: KarateMan.instance.Hit4(e.beat); break;
default: KarateMan.instance.Hit3(e.beat); break;
}
}, 1f, false, new List<Param>()
{
new Param("toggle", false, "Hit 4", "Whether or not the \"hit 4!\" sound should be played instead")
new Param("type", KarateMan.HitThree.HitThree, "Type", "What should be called out")
}),
new GameAction("prepare", delegate { KarateMan.instance.Prepare(eventCaller.currentEntity.beat, eventCaller.currentEntity.length); }, 1f, true),
new GameAction("set background color", delegate {
@ -280,7 +285,7 @@ namespace RhythmHeavenMania
new GameAction("pot", delegate { KarateMan.instance.Shoot(eventCaller.currentEntity.beat, 0); }, 2, hidden: true),
new GameAction("rock", delegate { KarateMan.instance.Shoot(eventCaller.currentEntity.beat, 2); }, 2, hidden: true),
new GameAction("ball", delegate { KarateMan.instance.Shoot(eventCaller.currentEntity.beat, 3); }, 2, hidden: true),
new GameAction("tacobell", delegate { KarateMan.instance.Shoot(eventCaller.currentEntity.beat, 6); }, 2, hidden: true),
new GameAction("tacobell", delegate { KarateMan.instance.Shoot(eventCaller.currentEntity.beat, 999); }, 2, hidden: true),
new GameAction("hit4", delegate { KarateMan.instance.Hit4(eventCaller.currentEntity.beat); }, hidden: true),
new GameAction("bgfxon", delegate { KarateMan.instance.SetBackgroundFX(KarateMan.BackgroundFXType.Sunburst); }, hidden: true),
new GameAction("bgfxoff", delegate { KarateMan.instance.SetBackgroundFX(KarateMan.BackgroundFXType.None); }, hidden: true),
@ -343,7 +348,7 @@ namespace RhythmHeavenMania
} ),
}),
new Minigame("rhythmRally", "Rhythm Rally \n<color=#eb5454>[WIP don't use]</color>", "FFFFFF", true, false, new List<GameAction>()
new Minigame("rhythmRally", "Rhythm Rally", "FFFFFF", true, false, new List<GameAction>()
{
new GameAction("bop", delegate { RhythmRally.instance.Bop(eventCaller.currentEntity.beat, eventCaller.currentEntity.length); }, 0.5f, true),
new GameAction("whistle", delegate { RhythmRally.instance.PlayWhistle(); }, 0.5f),
@ -376,10 +381,21 @@ namespace RhythmHeavenMania
new GameAction("jump tap", delegate { TapTrial.instance.JumpTap(eventCaller.currentEntity.beat); }, 2.0f, false),
new GameAction("final jump tap", delegate { TapTrial.instance.FinalJumpTap(eventCaller.currentEntity.beat); }, 2.0f, false),
}),
new Minigame("cropStomp", "Crop Stomp \n<color=#eb5454>[WIP don't use]</color>", "BFDEA6", false, false, new List<GameAction>()
new Minigame("cropStomp", "Crop Stomp", "BFDEA6", false, false, new List<GameAction>()
{
new GameAction("start marching", delegate { CropStomp.instance.StartMarching(eventCaller.currentEntity.beat); }, 2f, false),
new GameAction("veggies", delegate { }, 4f, true),
new GameAction("mole", delegate { }, 2f, false),
}),
new Minigame("wizardsWaltz", "Wizard's Waltz \n<color=#adadad>(Mahou Tsukai)</color>", "FFEF9C", false, false, new List<GameAction>()
{
new GameAction("start interval", delegate { WizardsWaltz.instance.SetIntervalStart(eventCaller.currentEntity.beat, eventCaller.currentEntity.length); }, 4f, true),
new GameAction("plant", delegate { WizardsWaltz.instance.SpawnFlower(eventCaller.currentEntity.beat); }, 0.5f, false),
}),
new Minigame("mrUpbeat", "Mr. Upbeat \n<color=#eb5454>[WIP don't use]</color>", "FFFFFF", false, false, new List<GameAction>()
{
new GameAction("prepare", delegate { MrUpbeat.instance.SetInterval(eventCaller.currentEntity.beat); }, 0.5f, true),
new GameAction("go", delegate { MrUpbeat.instance.Go(eventCaller.currentEntity.beat); }, 4f, true),
}),
/*new Minigame("spaceDance", "Space Dance", "B888F8", new List<GameAction>()
{