2022-02-15 23:28:08 +00:00
using System.Collections ;
using System.Collections.Generic ;
using UnityEngine ;
using NaughtyBezierCurves ;
using DG.Tweening ;
2022-02-16 17:04:28 +00:00
using System ;
2022-02-15 23:28:08 +00:00
2022-03-14 14:21:05 +00:00
using HeavenStudio.Util ;
2022-04-12 16:14:46 +00:00
namespace HeavenStudio.Games.Loaders
{
using static Minigames ;
public static class NtrFlickLoader
{
public static Minigame AddGame ( EventCaller eventCaller ) {
2023-04-02 02:28:23 +00:00
return new Minigame ( "builtToScaleDS" , "Built To Scale (DS)" , "1ad21a" , true , false , new List < GameAction > ( )
2022-04-12 16:14:46 +00:00
{
2023-02-14 16:31:51 +00:00
new GameAction ( "spawn blocks" , "Widget" )
2022-04-12 16:14:46 +00:00
{
2023-02-14 16:31:51 +00:00
function = delegate { var e = eventCaller . currentEntity ; BuiltToScaleDS . instance . MultiplePiano ( e . beat , e . length , e [ "silent" ] , e [ "note1" ] , e [ "note2" ] , e [ "note3" ] , e [ "note4" ] , e [ "note5" ] , e [ "note6" ] ) ; } ,
resizable = true ,
parameters = new List < Param > ( )
{
new Param ( "silent" , false , "Mute Audio" , "Whether the piano notes should be muted or not." ) ,
new Param ( "note1" , new EntityTypes . Integer ( - 24 , 24 , 0 ) , "1st note" , "The number of semitones up or down this note should be pitched" ) ,
new Param ( "note2" , new EntityTypes . Integer ( - 24 , 24 , 2 ) , "2nd note" , "The number of semitones up or down this note should be pitched" ) ,
new Param ( "note3" , new EntityTypes . Integer ( - 24 , 24 , 4 ) , "3rd note" , "The number of semitones up or down this note should be pitched" ) ,
new Param ( "note4" , new EntityTypes . Integer ( - 24 , 24 , 5 ) , "4th note" , "The number of semitones up or down this note should be pitched" ) ,
new Param ( "note5" , new EntityTypes . Integer ( - 24 , 24 , 7 ) , "5th note" , "The number of semitones up or down this note should be pitched" ) ,
new Param ( "note6" , new EntityTypes . Integer ( - 24 , 24 , 12 ) , "6th note" , "The number of semitones up or down this note should be pitched (This plays together with the 5th note)" ) ,
}
2022-08-21 03:13:52 +00:00
} ,
new GameAction ( "play piano" , "Play Note" )
{
2022-08-21 23:46:45 +00:00
function = delegate { BuiltToScaleDS . instance . PlayPiano ( eventCaller . currentEntity . beat , eventCaller . currentEntity . length , eventCaller . currentEntity [ "type" ] ) ; } ,
2022-08-21 03:13:52 +00:00
resizable = true ,
parameters = new List < Param > ( )
{
new Param ( "type" , new EntityTypes . Integer ( - 24 , 24 , 0 ) , "Semitones" , "The number of semitones up or down this note should be pitched" )
2023-02-14 16:31:51 +00:00
} ,
2022-08-21 03:13:52 +00:00
} ,
2022-04-12 16:14:46 +00:00
} ) ;
}
}
}
2022-03-14 14:21:05 +00:00
namespace HeavenStudio.Games
2022-02-15 23:28:08 +00:00
{
2022-03-12 04:10:13 +00:00
using Scripts_BuiltToScaleDS ;
2022-02-15 23:28:08 +00:00
public class BuiltToScaleDS : Minigame
{
2022-02-16 17:04:28 +00:00
public enum BTSObject { HitPieces , MissPieces , FlyingRod }
2022-02-15 23:28:08 +00:00
[Header("Camera")]
2023-04-23 19:27:23 +00:00
[SerializeField] Transform camPos ;
[SerializeField] float cameraFoV ;
2022-02-15 23:28:08 +00:00
[Header("References")]
2023-04-23 19:27:23 +00:00
[SerializeField] SkinnedMeshRenderer environmentRenderer ;
2022-02-16 17:04:28 +00:00
public GameObject flyingRodBase ;
public GameObject movingBlocksBase ;
public GameObject hitPartsBase ;
public GameObject missPartsBase ;
public Transform partsHolder ;
public Transform blocksHolder ;
public Animator shooterAnim ;
public Animator elevatorAnim ;
2022-02-15 23:28:08 +00:00
[Header("Properties")]
2023-04-23 19:27:23 +00:00
[SerializeField] float beltSpeed = 1f ;
2022-02-15 23:28:08 +00:00
private Material beltMaterial ;
private Material [ ] environmentMaterials ;
private float currentBeltOffset ;
2022-02-16 17:04:28 +00:00
[NonSerialized] public bool shootingThisFrame ;
2023-01-15 04:33:37 +00:00
[NonSerialized] public bool lastShotOut = false ;
2022-02-15 23:28:08 +00:00
public static BuiltToScaleDS instance ;
private void Awake ( )
{
instance = this ;
environmentMaterials = environmentRenderer . materials ;
beltMaterial = Instantiate ( environmentMaterials [ 8 ] ) ;
environmentMaterials [ 8 ] = beltMaterial ;
2022-03-10 12:45:21 +00:00
2022-02-16 17:04:28 +00:00
elevatorAnim . Play ( "MakeRod" , 0 , 1f ) ;
2022-02-15 23:28:08 +00:00
}
2023-04-23 19:27:23 +00:00
private void Start ( )
{
GameCamera . additionalPosition = camPos . position + ( Quaternion . Euler ( camPos . eulerAngles ) * Vector3 . forward * 10f ) ;
GameCamera . additionalRotEluer = camPos . eulerAngles ;
GameCamera . additionalFoV = cameraFoV ;
}
2022-08-21 23:46:45 +00:00
List < DynamicBeatmap . DynamicEntity > spawnedBlockEvents = new List < DynamicBeatmap . DynamicEntity > ( ) ;
2022-02-15 23:28:08 +00:00
void Update ( )
{
2022-02-16 17:04:28 +00:00
if ( ! Conductor . instance . isPlaying & & ! Conductor . instance . isPaused )
return ;
var currentBeat = Conductor . instance . songPositionInBeats ;
var blockEvents = GameManager . instance . Beatmap . entities . FindAll ( c = > c . datamodel = = "builtToScaleDS/spawn blocks" ) ;
for ( int i = 0 ; i < blockEvents . Count ; i + + )
{
var ev = blockEvents [ i ] ;
if ( spawnedBlockEvents . Contains ( ev ) ) continue ; // Don't spawn the same blocks multiple times.
2022-02-18 14:32:38 +00:00
var spawnBeat = ev . beat - ev . length ;
2022-02-16 17:04:28 +00:00
if ( currentBeat > spawnBeat & & currentBeat < ev . beat + ev . length )
{
SpawnBlocks ( spawnBeat , ev . length ) ;
spawnedBlockEvents . Add ( ev ) ;
break ;
}
}
2022-02-15 23:28:08 +00:00
currentBeltOffset = ( currentBeltOffset + Time . deltaTime * - beltSpeed ) % 1f ;
beltMaterial . mainTextureOffset = new Vector2 ( 0f , currentBeltOffset ) ;
environmentRenderer . materials = environmentMaterials ;
}
2022-02-16 17:04:28 +00:00
void LateUpdate ( )
{
var shooterState = shooterAnim . GetCurrentAnimatorStateInfo ( 0 ) ;
2023-01-15 04:33:37 +00:00
bool canShoot = ( ! shooterState . IsName ( "Shoot" ) | | shooterAnim . IsAnimationNotPlaying ( ) ) & & ! shootingThisFrame ;
2022-02-16 17:04:28 +00:00
2023-01-15 04:33:37 +00:00
if ( canShoot & & lastShotOut )
lastShotOut = false ;
if ( canShoot & & ! lastShotOut & & PlayerInput . Pressed ( ) & & ! IsExpectingInputNow ( InputType . STANDARD_DOWN ) )
2022-02-16 17:04:28 +00:00
{
2023-01-15 04:33:37 +00:00
lastShotOut = true ;
2022-02-16 17:04:28 +00:00
shootingThisFrame = true ;
Shoot ( ) ;
SpawnObject ( BTSObject . FlyingRod ) ;
2022-02-17 02:19:40 +00:00
Jukebox . PlayOneShotGame ( "builtToScaleDS/Boing" ) ;
2022-02-16 17:04:28 +00:00
}
if ( ! shootingThisFrame )
{
if ( blocksHolder . childCount = = 0 & & shooterState . IsName ( "Windup" ) & & shooterAnim . IsAnimationNotPlaying ( ) )
{
shooterAnim . Play ( "WindDown" , 0 , 0 ) ;
}
}
shootingThisFrame = false ;
}
public void SpawnBlocks ( float beat , float length )
{
var newBlocks = GameObject . Instantiate ( movingBlocksBase , blocksHolder ) . GetComponent < Blocks > ( ) ;
newBlocks . createBeat = beat ;
newBlocks . createLength = length ;
newBlocks . gameObject . SetActive ( true ) ;
SetBlockTime ( newBlocks , beat , length ) ;
}
const int blockFramesPerSecond = 24 ;
const int blockHitFrame = 39 ;
const int blockTotalFrames = 80 ;
2022-02-18 14:32:38 +00:00
const int spawnFrameOffset = - 3 ;
2022-02-16 17:04:28 +00:00
List < int > criticalFrames = new List < int > { 7 , 15 , 23 , 31 , 39 , 47 } ;
public void SetBlockTime ( Blocks blocks , float spawnBeat , float length )
{
2022-02-18 14:32:38 +00:00
float spawnTimeOffset = ( float ) spawnFrameOffset / ( float ) blockFramesPerSecond ;
2022-02-16 17:04:28 +00:00
float secondsPerFrame = 1f / blockFramesPerSecond ;
float secondsToHitFrame = secondsPerFrame * blockHitFrame ;
float secondsPerBeat = Conductor . instance . secPerBeat ;
2022-02-18 14:32:38 +00:00
float secondsToHitBeat = secondsPerBeat * 5f * length + spawnTimeOffset ;
2022-02-16 17:04:28 +00:00
float speedMult = secondsToHitFrame / secondsToHitBeat ;
2022-02-18 14:32:38 +00:00
float secondsPastSpawnTime = secondsPerBeat * ( Conductor . instance . songPositionInBeats - spawnBeat ) + spawnTimeOffset ;
2022-02-16 17:04:28 +00:00
float framesPastSpawnTime = blockFramesPerSecond * speedMult * secondsPastSpawnTime ;
// The only way I could deal with Unity's interpolation shenanigans without having a stroke.
if ( criticalFrames . Contains ( Mathf . FloorToInt ( framesPastSpawnTime ) ) )
framesPastSpawnTime = Mathf . CeilToInt ( framesPastSpawnTime ) ;
blocks . anim . Play ( "Move" , 0 , framesPastSpawnTime / blockTotalFrames ) ;
blocks . anim . speed = speedMult ;
}
public void SpawnObject ( BTSObject btsObject )
{
GameObject prefabToUse = null ;
string animNameToUse = "" ;
switch ( btsObject )
{
case BTSObject . HitPieces :
prefabToUse = hitPartsBase ;
animNameToUse = "PartsHit" ;
break ;
case BTSObject . MissPieces :
prefabToUse = missPartsBase ;
animNameToUse = "PartsMiss" ;
break ;
case BTSObject . FlyingRod :
prefabToUse = flyingRodBase ;
animNameToUse = "Fly" ;
break ;
}
if ( prefabToUse ! = null )
{
var newPiece = GameObject . Instantiate ( prefabToUse , partsHolder ) . GetComponent < BTSPiece > ( ) ;
newPiece . gameObject . SetActive ( true ) ;
newPiece . anim . Play ( animNameToUse , 0 , 0 ) ;
}
}
public void Shoot ( )
{
shooterAnim . Play ( "Shoot" , 0 , 0 ) ;
elevatorAnim . Play ( "MakeRod" , 0 , 0 ) ;
}
2022-03-07 09:16:31 +00:00
public void PlayPiano ( float beat , float length , int semiTones )
{
2023-03-27 03:09:55 +00:00
var pianoPitch = Jukebox . GetPitchFromSemiTones ( semiTones , true ) ;
2022-03-07 09:34:38 +00:00
var pianoSource = Jukebox . PlayOneShotGame ( "builtToScaleDS/Piano" , - 1 , pianoPitch , 0.8f , true ) ;
2022-03-07 09:16:31 +00:00
2022-03-10 03:59:48 +00:00
pianoSource . SetLoopParams ( beat + length , 0.1f ) ;
2022-03-07 09:16:31 +00:00
}
2023-02-14 16:31:51 +00:00
public void MultiplePiano ( float beat , float length , bool silent , int note1 , int note2 , int note3 , int note4 , int note5 , int note6 )
{
if ( silent ) return ;
BeatAction . New ( instance . gameObject , new List < BeatAction . Action > ( )
{
new BeatAction . Action ( beat , delegate { PlayPiano ( beat , length , note1 ) ; } ) ,
new BeatAction . Action ( beat + length , delegate { PlayPiano ( beat + length , length , note2 ) ; } ) ,
new BeatAction . Action ( beat + length * 2 , delegate { PlayPiano ( beat + length * 2 , length , note3 ) ; } ) ,
new BeatAction . Action ( beat + length * 3 , delegate { PlayPiano ( beat + length * 3 , length , note4 ) ; } ) ,
new BeatAction . Action ( beat + length * 4 , delegate { PlayPiano ( beat + length * 4 , 1f , note5 ) ; } ) ,
new BeatAction . Action ( beat + length * 4 , delegate { PlayPiano ( beat + length * 4 , 1f , note6 ) ; } ) ,
} ) ;
}
2022-02-15 23:28:08 +00:00
}
}