From f4d001d843320e483907b43d710205a9ff1e7c31 Mon Sep 17 00:00:00 2001 From: Takkkom <76614532+Takkkom@users.noreply.github.com> Date: Fri, 18 Aug 2023 16:21:02 +0900 Subject: [PATCH] =?UTF-8?q?=E8=89=B2=E3=80=85=E6=94=B9=E5=96=8410=20(#483)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * TJAP3EXの機能に対応 * スキンの再読み込み機能を追加 * box.defを多言語対応 * 更にコマンドを追加 * Effects.jsonに対応 * レア度によってもらえるコインの数が変わるように * 譜面のエラーログを表示するように * BARLINEの修正 --- FDK19/コード/04.グラフィック/CTexture.cs | 164 +- TJAPlayer3/Common/Easing.cs | 105 +- TJAPlayer3/Common/TJAPlayer3.cs | 78 +- TJAPlayer3/Databases/DBCharacter.cs | 12 + TJAPlayer3/Databases/DBPuchichara.cs | 24 + TJAPlayer3/Songs/CBoxDef.cs | 38 +- TJAPlayer3/Songs/CDTX.cs | 2334 ++++++++++++++++- TJAPlayer3/Songs/Extended/CSongObject.cs | 112 + TJAPlayer3/Stages/01.StartUp/CCharacter.cs | 7 + TJAPlayer3/Stages/01.StartUp/CPuchichara.cs | 7 + TJAPlayer3/Stages/01.StartUp/TextureLoader.cs | 31 + .../Stages/06.SongLoading/CStage曲読み込み.cs | 9 + .../Stages/07.Game/CAct演奏ゲージ共通.cs | 68 +- .../Stages/07.Game/CStage演奏画面共通.cs | 703 ++++- .../07.Game/Taiko/CStage演奏ドラム画面.cs | 58 +- .../Stages/07.Game/Taiko/NotesManager.cs | 22 + TJAPlayer3/Stages/08.Result/CStage結果.cs | 62 +- TJAPlayer3/TJAPlayer3.csproj | 1 + Test/Global/Characters/Template/Effects.json | 3 + Test/Global/PuchiChara/Template/Effects.json | 6 + Test/Licenses/TJAPlayer3-Extended.txt | 21 + Test/Songs/01 OpenTaiko Chapter I/box.def | 4 + Test/Songs/02 OpenTaiko Chapter II/box.def | 1 + Test/Songs/L1 Collaborations/box.def | 4 + Test/Songs/L2 Custom Charts/box.def | 4 + Test/Songs/L3 Downloaded Songs/box.def | 4 + Test/Songs/S1 Dan-i Dojo/box.def | 4 + Test/Songs/S2 Taiko Towers/01 - Sweet/box.def | 5 +- Test/Songs/S2 Taiko Towers/02 - Spicy/box.def | 5 +- Test/Songs/S2 Taiko Towers/box.def | 4 + Test/Songs/X1 Favorite/box.def | 4 + Test/Songs/X2 Recent/box.def | 4 + Test/Songs/X3 Search By Difficulty/box.def | 3 + .../Graphics/5_Game/Adlib.png | Bin 0 -> 72337 bytes .../SimpleStyle/Graphics/5_Game/Adlib.png | Bin 0 -> 24781 bytes 35 files changed, 3770 insertions(+), 141 deletions(-) create mode 100644 TJAPlayer3/Songs/Extended/CSongObject.cs create mode 100644 Test/Global/Characters/Template/Effects.json create mode 100644 Test/Global/PuchiChara/Template/Effects.json create mode 100644 Test/Licenses/TJAPlayer3-Extended.txt create mode 100644 Test/System/SimpleStyle (1080p)/Graphics/5_Game/Adlib.png create mode 100644 Test/System/SimpleStyle/Graphics/5_Game/Adlib.png diff --git a/FDK19/コード/04.グラフィック/CTexture.cs b/FDK19/コード/04.グラフィック/CTexture.cs index d2d2f759..6152d66e 100644 --- a/FDK19/コード/04.グラフィック/CTexture.cs +++ b/FDK19/コード/04.グラフィック/CTexture.cs @@ -96,8 +96,8 @@ namespace FDK /// 論理画面を1とする場合の物理画面の倍率。 /// 論理値×画面比率=物理値。 /// - public static float f画面比率 = 1.0f; - + public static float f画面比率 = 1.0f; + // コンストラクタ public CTexture() @@ -111,6 +111,27 @@ namespace FDK this.fZ軸中心回転 = 0f; this.vc拡大縮小倍率 = new Vector3(1f, 1f, 1f); // this._txData = null; + } + + public CTexture(CTexture tx) + { + this.sz画像サイズ = tx.sz画像サイズ; + this.szテクスチャサイズ = tx.szテクスチャサイズ; + this._opacity = tx._opacity; + this.texture = tx.texture; + this.cvPositionColoredVertexies = tx.cvPositionColoredVertexies; + this.b加算合成 = tx.b加算合成; + this.fZ軸中心回転 = tx.fZ軸中心回転; + this.vc拡大縮小倍率 = tx.vc拡大縮小倍率; + // this._txData = null; + } + + public void UpdateTexture(Device device, Texture texture, int n幅, int n高さ) + { + this.texture = texture; + this.sz画像サイズ = new Size(n幅, n高さ); + this.szテクスチャサイズ = this.t指定されたサイズを超えない最適なテクスチャサイズを返す(device, this.sz画像サイズ); + this.rc全画像 = new Rectangle(0, 0, this.sz画像サイズ.Width, this.sz画像サイズ.Height); } /// @@ -1137,7 +1158,144 @@ namespace FDK device.SetTexture(0, this.texture); device.VertexFormat = PositionColoredTexturedVertex.Format; device.DrawUserPrimitives(PrimitiveType.TriangleStrip, 2, this.cvPositionColoredVertexies); - } + } + + + + + public void t2D描画SongObj(Device device, float x, float y, float xScale, float yScale) + { + if (this.texture == null) + return; + + float depth = 1f; + Rectangle rc画像内の描画領域 = this.rc全画像; + + if (this.fZ軸中心回転 == 0f) + { + #region [ (A) 回転なし ] + //----------------- + float fx = ((float)rc画像内の描画領域.Width) / 2f; + float fy = ((float)rc画像内の描画領域.Height) / 2f; + float f左U値 = ((float)rc画像内の描画領域.Left) / ((float)this.szテクスチャサイズ.Width); + float f右U値 = ((float)rc画像内の描画領域.Right) / ((float)this.szテクスチャサイズ.Width); + float f上V値 = ((float)rc画像内の描画領域.Top) / ((float)this.szテクスチャサイズ.Height); + float f下V値 = ((float)rc画像内の描画領域.Bottom) / ((float)this.szテクスチャサイズ.Height); + this.color4.Alpha = ((float)this._opacity) / 255f; + int color = ToArgb(this.color4); + + if (this.cvPositionColoredVertexies == null) + this.cvPositionColoredVertexies = new PositionColoredTexturedVertex[4]; + + // #27122 2012.1.13 from: 以下、マネージドオブジェクト(=ガベージ)の量産を抑えるため、new は使わず、メンバに値を1つずつ直接上書きする。 + + this.cvPositionColoredVertexies[0].Position.X = -fx; + this.cvPositionColoredVertexies[0].Position.Y = fy; + this.cvPositionColoredVertexies[0].Position.Z = depth; + this.cvPositionColoredVertexies[0].Color = color; + this.cvPositionColoredVertexies[0].TextureCoordinates.X = f左U値; + this.cvPositionColoredVertexies[0].TextureCoordinates.Y = f上V値; + + this.cvPositionColoredVertexies[1].Position.X = fx; + this.cvPositionColoredVertexies[1].Position.Y = fy; + this.cvPositionColoredVertexies[1].Position.Z = depth; + this.cvPositionColoredVertexies[1].Color = color; + this.cvPositionColoredVertexies[1].TextureCoordinates.X = f右U値; + this.cvPositionColoredVertexies[1].TextureCoordinates.Y = f上V値; + + this.cvPositionColoredVertexies[2].Position.X = -fx; + this.cvPositionColoredVertexies[2].Position.Y = -fy; + this.cvPositionColoredVertexies[2].Position.Z = depth; + this.cvPositionColoredVertexies[2].Color = color; + this.cvPositionColoredVertexies[2].TextureCoordinates.X = f左U値; + this.cvPositionColoredVertexies[2].TextureCoordinates.Y = f下V値; + + this.cvPositionColoredVertexies[3].Position.X = fx; + this.cvPositionColoredVertexies[3].Position.Y = -fy; + this.cvPositionColoredVertexies[3].Position.Z = depth; + this.cvPositionColoredVertexies[3].Color = color; + this.cvPositionColoredVertexies[3].TextureCoordinates.X = f右U値; + this.cvPositionColoredVertexies[3].TextureCoordinates.Y = f下V値; + + this.tレンダリングステートの設定(device); + + var matrix = Matrix.Identity * Matrix.Scaling(new Vector3(xScale, yScale, 1f)); + matrix *= Matrix.Translation(x - SampleFramework.GameWindowSize.Width / 2.0f + fx, -(y - SampleFramework.GameWindowSize.Height / 2.0f + fy), 0f); + + device.SetTransform(TransformState.World, matrix); + device.SetTexture(0, this.texture); + device.VertexFormat = PositionColoredTexturedVertex.Format; + device.DrawUserPrimitives(PrimitiveType.TriangleStrip, 2, this.cvPositionColoredVertexies); + + //----------------- + #endregion + } + else + { + #region [ (B) 回転あり ] + //----------------- + float fx = ((float)rc画像内の描画領域.Width) / 2f; + float fy = ((float)rc画像内の描画領域.Height) / 2f; + float f左U値 = ((float)rc画像内の描画領域.Left) / ((float)this.szテクスチャサイズ.Width); + float f右U値 = ((float)rc画像内の描画領域.Right) / ((float)this.szテクスチャサイズ.Width); + float f上V値 = ((float)rc画像内の描画領域.Top) / ((float)this.szテクスチャサイズ.Height); + float f下V値 = ((float)rc画像内の描画領域.Bottom) / ((float)this.szテクスチャサイズ.Height); + this.color4.Alpha = ((float)this._opacity) / 255f; + int color = ToArgb(this.color4); + + if (this.cvPositionColoredVertexies == null) + this.cvPositionColoredVertexies = new PositionColoredTexturedVertex[4]; + + // #27122 2012.1.13 from: 以下、マネージドオブジェクト(=ガベージ)の量産を抑えるため、new は使わず、メンバに値を1つずつ直接上書きする。 + + this.cvPositionColoredVertexies[0].Position.X = -fx; + this.cvPositionColoredVertexies[0].Position.Y = fy; + this.cvPositionColoredVertexies[0].Position.Z = depth; + this.cvPositionColoredVertexies[0].Color = color; + this.cvPositionColoredVertexies[0].TextureCoordinates.X = f左U値; + this.cvPositionColoredVertexies[0].TextureCoordinates.Y = f上V値; + + this.cvPositionColoredVertexies[1].Position.X = fx; + this.cvPositionColoredVertexies[1].Position.Y = fy; + this.cvPositionColoredVertexies[1].Position.Z = depth; + this.cvPositionColoredVertexies[1].Color = color; + this.cvPositionColoredVertexies[1].TextureCoordinates.X = f右U値; + this.cvPositionColoredVertexies[1].TextureCoordinates.Y = f上V値; + + this.cvPositionColoredVertexies[2].Position.X = -fx; + this.cvPositionColoredVertexies[2].Position.Y = -fy; + this.cvPositionColoredVertexies[2].Position.Z = depth; + this.cvPositionColoredVertexies[2].Color = color; + this.cvPositionColoredVertexies[2].TextureCoordinates.X = f左U値; + this.cvPositionColoredVertexies[2].TextureCoordinates.Y = f下V値; + + this.cvPositionColoredVertexies[3].Position.X = fx; + this.cvPositionColoredVertexies[3].Position.Y = -fy; + this.cvPositionColoredVertexies[3].Position.Z = depth; + this.cvPositionColoredVertexies[3].Color = color; + this.cvPositionColoredVertexies[3].TextureCoordinates.X = f右U値; + this.cvPositionColoredVertexies[3].TextureCoordinates.Y = f下V値; + + this.tレンダリングステートの設定(device); + + float n描画領域内X = x + (rc画像内の描画領域.Width / 2.0f); + float n描画領域内Y = y + (rc画像内の描画領域.Height / 2.0f); + var vc3移動量 = new Vector3(n描画領域内X - (((float)device.Viewport.Width) / 2f), -(n描画領域内Y - (((float)device.Viewport.Height) / 2f)), 0f); + + var matrix = Matrix.Identity * Matrix.Scaling(new Vector3(xScale, yScale, 1f)); + matrix *= Matrix.Translation(x - SampleFramework.GameWindowSize.Width / 2.0f + fx, -(y - SampleFramework.GameWindowSize.Height / 2.0f + fy), 0f); + matrix *= Matrix.RotationZ(this.fZ軸中心回転); + matrix *= Matrix.Translation(vc3移動量); + device.SetTransform(TransformState.World, matrix); + + device.SetTexture(0, this.texture); + device.VertexFormat = PositionColoredTexturedVertex.Format; + device.DrawUserPrimitives(PrimitiveType.TriangleStrip, 2, this.cvPositionColoredVertexies); + //----------------- + #endregion + } + } + #region [ IDisposable 実装 ] //----------------- diff --git a/TJAPlayer3/Common/Easing.cs b/TJAPlayer3/Common/Easing.cs index dc863fea..6d4f4ae2 100644 --- a/TJAPlayer3/Common/Easing.cs +++ b/TJAPlayer3/Common/Easing.cs @@ -9,7 +9,7 @@ namespace TJAPlayer3 { class Easing { - public int EaseIn(CCounter counter, int startPoint, int endPoint, CalcType type) + public int EaseIn(CCounter counter, float startPoint, float endPoint, CalcType type) { StartPoint = startPoint; EndPoint = endPoint; @@ -46,11 +46,14 @@ namespace TJAPlayer3 CounterValue /= TimeMs; Value = -Sa * (Math.Sqrt(1 - CounterValue * CounterValue) - 1) + StartPoint; break; + case CalcType.Linear: //Linear + Value = Sa * (CounterValue / TimeMs) + StartPoint; + break; } return (int)Value; } - public int EaseOut(CCounter counter, int startPoint, int endPoint, CalcType type) + public int EaseOut(CCounter counter, float startPoint, float endPoint, CalcType type) { StartPoint = startPoint; EndPoint = endPoint; @@ -91,15 +94,102 @@ namespace TJAPlayer3 CounterValue--; Value = Sa * Math.Sqrt(1 - CounterValue * CounterValue) + StartPoint; break; + case CalcType.Linear: //Linear + CounterValue /= TimeMs; + Value = Sa * CounterValue + StartPoint; + break; } return (int)Value; } + public float EaseInOut(CCounter counter, float startPoint, float endPoint, CalcType type) + { + StartPoint = startPoint; + EndPoint = endPoint; + Sa = EndPoint - StartPoint; + TimeMs = counter.n終了値; + Type = type; + CounterValue = counter.n現在の値; - private int StartPoint; - private int EndPoint; - private int Sa; - private int TimeMs; + switch (Type) + { + case CalcType.Quadratic: //Quadratic + CounterValue /= TimeMs / 2; + if (CounterValue < 1) + { + Value = Sa / 2 * CounterValue * CounterValue + StartPoint; + break; + } + CounterValue--; + Value = -Sa / 2 * (CounterValue * (CounterValue - 2) - 1) + StartPoint; + break; + case CalcType.Cubic: //Cubic + CounterValue /= TimeMs / 2; + if (CounterValue < 1) + { + Value = Sa / 2 * CounterValue * CounterValue * CounterValue + StartPoint; + break; + } + CounterValue -= 2; + Value = Sa / 2 * (CounterValue * CounterValue * CounterValue + 2) + StartPoint; + break; + case CalcType.Quartic: //Quartic + CounterValue /= TimeMs / 2; + if (CounterValue < 1) + { + Value = Sa / 2 * CounterValue * CounterValue * CounterValue * CounterValue + StartPoint; + break; + } + CounterValue -= 2; + Value = -Sa / 2 * (CounterValue * CounterValue * CounterValue * CounterValue - 2) + StartPoint; + break; + case CalcType.Quintic: //Quintic + CounterValue /= TimeMs; + CounterValue /= TimeMs / 2; + if (CounterValue < 1) + { + Value = Sa / 2 * CounterValue * CounterValue * CounterValue * CounterValue * CounterValue + StartPoint; + break; + } + CounterValue -= 2; + Value = Sa / 2 * (CounterValue * CounterValue * CounterValue * CounterValue * CounterValue + 2) + StartPoint; + break; + case CalcType.Sinusoidal: //Sinusoidal + Value = -Sa / 2 * (Math.Cos(Math.PI * CounterValue / TimeMs) - 1) + StartPoint; + break; + case CalcType.Exponential: //Exponential + CounterValue /= TimeMs / 2; + if (CounterValue < 1) + { + Value = Sa / 2 * Math.Pow(2, 10 * (CounterValue - 1)) + StartPoint; + break; + } + CounterValue--; + Value = Sa / 2 * (-Math.Pow(2, -10 * CounterValue) + 2) + StartPoint; + break; + case CalcType.Circular: //Circular + CounterValue /= TimeMs / 2; + if (CounterValue < 1) + { + Value = -Sa / 2 * (Math.Sqrt(1 - CounterValue * CounterValue) - 1) + StartPoint; + break; + } + CounterValue -= 2; + Value = Sa / 2 * (Math.Sqrt(1 - CounterValue * CounterValue) + 1) + StartPoint; + break; + case CalcType.Linear: //Linear + CounterValue /= TimeMs; + Value = Sa * CounterValue + StartPoint; + break; + } + + return (float)Value; + } + + private float StartPoint; + private float EndPoint; + private float Sa; + private double TimeMs; private CalcType Type; private double CounterValue; private double Value; @@ -111,7 +201,8 @@ namespace TJAPlayer3 Quintic, Sinusoidal, Exponential, - Circular + Circular, + Linear } } } \ No newline at end of file diff --git a/TJAPlayer3/Common/TJAPlayer3.cs b/TJAPlayer3/Common/TJAPlayer3.cs index d3a132b1..eb910cc3 100644 --- a/TJAPlayer3/Common/TJAPlayer3.cs +++ b/TJAPlayer3/Common/TJAPlayer3.cs @@ -1944,7 +1944,26 @@ for (int i = 0; i < 3; i++) { break; } - actScanningLoudness.On進行描画(); + actScanningLoudness.On進行描画(); + + if (!ConfigIni.bTokkunMode) + { + float screen_ratiox = TJAPlayer3.Skin.Resolution[0] / 1280.0f; + float screen_ratioy = TJAPlayer3.Skin.Resolution[1] / 720.0f; + var mat = Matrix.LookAtLH(new Vector3(-fCamXOffset * screen_ratiox, fCamYOffset * screen_ratioy, (float)(-SampleFramework.GameWindowSize.Height / (fCamZoomFactor * 2) * Math.Sqrt(3.0))), new Vector3(-fCamXOffset * screen_ratiox, fCamYOffset * screen_ratioy, 0f), new Vector3(0f, 1f, 0f)); + mat *= Matrix.RotationYawPitchRoll(0, 0, C変換.DegreeToRadian(fCamRotation)); + mat *= Matrix.Scaling(fCamXScale, fCamYScale, 1f); + this.Device.SetTransform(TransformState.View, mat); + + if (TJAPlayer3.DTX != null) + { + //object rendering + foreach (KeyValuePair pair in TJAPlayer3.DTX.listObj) + { + pair.Value.tDraw(); + } + } + } if (r現在のステージ != null && r現在のステージ.eステージID != CStage.Eステージ.起動 && TJAPlayer3.Tx.Network_Connection != null) { @@ -1969,16 +1988,40 @@ for (int i = 0; i < 3; i++) { this.Device.EndScene(); // Present()は game.csのOnFrameEnd()に登録された、GraphicsDeviceManager.game_FrameEnd() 内で実行されるので不要 // (つまり、Present()は、Draw()完了後に実行される) #if !GPUFlushAfterPresent - actFlushGPU?.On進行描画(); // Flush GPU // EndScene()~Present()間 (つまりVSync前) でFlush実行 + actFlushGPU?.On進行描画(); // Flush GPU // EndScene()~Present()間 (つまりVSync前) でFlush実行 #endif + foreach(var capture in ConfigIni.KeyAssign.System.Capture) + { + if (TJAPlayer3.Input管理.Keyboard.bキーが押された(capture.コード)) + { + if (TJAPlayer3.Input管理.Keyboard.bキーが押されている((int)SlimDXKeys.Key.LeftControl)) + { + if (r現在のステージ.eステージID != CStage.Eステージ.演奏) + { + RefleshSkin(); + r現在のステージ.On非活性化(); + r現在のステージ.On活性化(); + } + } + else + { + // Debug.WriteLine( "capture: " + string.Format( "{0:2x}", (int) e.KeyCode ) + " " + (int) e.KeyCode ); + string strFullPath = + Path.Combine(TJAPlayer3.strEXEのあるフォルダ, "Capture_img"); + strFullPath = Path.Combine(strFullPath, DateTime.Now.ToString("yyyyMMddHHmmss") + ".png"); + SaveResultScreen(strFullPath); + } + } + } + /* if ( Sound管理?.GetCurrentSoundDeviceType() != "DirectSound" ) { Sound管理?.t再生中の処理をする(); // サウンドバッファの更新; 画面描画と同期させることで、スクロールをスムーズにする } - */ - + */ + #region [ 全画面_ウインドウ切り替え ] if ( this.b次のタイミングで全画面_ウィンドウ切り替えを行う ) { @@ -3389,18 +3432,6 @@ for (int i = 0; i < 3; i++) { } else { - for ( int i = 0; i < 0x10; i++ ) - { - if ( ConfigIni.KeyAssign.System.Capture[ i ].コード > 0 && - e.KeyCode == DeviceConstantConverter.KeyToKeyCode( (SlimDXKeys.Key) ConfigIni.KeyAssign.System.Capture[ i ].コード ) ) - { - // Debug.WriteLine( "capture: " + string.Format( "{0:2x}", (int) e.KeyCode ) + " " + (int) e.KeyCode ); - string strFullPath = - Path.Combine( TJAPlayer3.strEXEのあるフォルダ, "Capture_img" ); - strFullPath = Path.Combine( strFullPath, DateTime.Now.ToString( "yyyyMMddHHmmss" ) + ".png" ); - SaveResultScreen( strFullPath ); - } - } } } private void Window_MouseUp( object sender, MouseEventArgs e ) @@ -3426,8 +3457,21 @@ for (int i = 0; i < 3; i++) { ConfigIni.nウインドウwidth = (ConfigIni.bウィンドウモード) ? base.Window.ClientSize.Width : currentClientSize.Width; // #23510 2010.10.31 yyagi add ConfigIni.nウインドウheight = (ConfigIni.bウィンドウモード) ? base.Window.ClientSize.Height : currentClientSize.Height; - } + } #endregion + #endregion + + #region [ EXTENDED VARIABLES ] + public static float fCamXOffset; + public static float fCamYOffset; + + public static float fCamZoomFactor = 1.0f; + public static float fCamRotation; + + public static float fCamXScale = 1.0f; + public static float fCamYScale = 1.0f; + + public static Color4 borderColor = new Color4(1f, 0f, 0f, 0f); #endregion } } diff --git a/TJAPlayer3/Databases/DBCharacter.cs b/TJAPlayer3/Databases/DBCharacter.cs index 72deb878..aecc1dc3 100644 --- a/TJAPlayer3/Databases/DBCharacter.cs +++ b/TJAPlayer3/Databases/DBCharacter.cs @@ -6,6 +6,18 @@ namespace TJAPlayer3 { class DBCharacter { + public class CharacterEffect + { + public CharacterEffect() + { + Gauge = "Normal"; + } + + + [JsonProperty("gauge")] + public string Gauge; + } + public class CharacterData { public CharacterData() diff --git a/TJAPlayer3/Databases/DBPuchichara.cs b/TJAPlayer3/Databases/DBPuchichara.cs index 0da29ffb..c07467ab 100644 --- a/TJAPlayer3/Databases/DBPuchichara.cs +++ b/TJAPlayer3/Databases/DBPuchichara.cs @@ -6,6 +6,30 @@ namespace TJAPlayer3 { class DBPuchichara { + public class PuchicharaEffect + { + public PuchicharaEffect() + { + AllPurple = false; + Autoroll = 0; + ShowAdlib = false; + SplitLane = false; + } + + + [JsonProperty("allpurple")] + public bool AllPurple; + + [JsonProperty("AutoRoll")] + public int Autoroll; + + [JsonProperty("showadlib")] + public bool ShowAdlib; + + [JsonProperty("splitlane")] + public bool SplitLane; + } + public class PuchicharaData { public PuchicharaData() diff --git a/TJAPlayer3/Songs/CBoxDef.cs b/TJAPlayer3/Songs/CBoxDef.cs index b4c3e19d..c673e5d7 100644 --- a/TJAPlayer3/Songs/CBoxDef.cs +++ b/TJAPlayer3/Songs/CBoxDef.cs @@ -31,10 +31,13 @@ namespace TJAPlayer3 public int BoxChara; public bool IsChangedBoxChara; public string DefaultPreimage; - public string ScenePreset; - - // コンストラクタ - + public string ScenePreset; + + private readonly string langTITLE = "#TITLE" + CLangManager.fetchLang().ToUpper(); + private readonly string langBOXEXPLANATION = "#BOXEXPLANATION" + CLangManager.fetchLang().ToUpper(); + + // コンストラクタ + public CBoxDef() { for (int i = 0; i < 3; i++) @@ -79,11 +82,14 @@ namespace TJAPlayer3 str = str.Substring( 0, str.IndexOf( ';' ) ); } - char[] ignoreChars = new char[] { ':', ' ', '\t' }; - - if ( str.StartsWith( "#TITLE", StringComparison.OrdinalIgnoreCase ) ) + char[] ignoreChars = new char[] { ':', ' ', '\t' }; + if (str.StartsWith(langTITLE, StringComparison.OrdinalIgnoreCase)) { - this.Title = str.Substring( 6 ).Trim( ignoreChars ); + this.Title = str.Substring(8).Trim(ignoreChars); + } + else if(str.StartsWith("#TITLE", StringComparison.OrdinalIgnoreCase)) + { + if (this.Title == "") this.Title = str.Substring(6).Trim(ignoreChars); } else if( str.StartsWith( "#GENRE", StringComparison.OrdinalIgnoreCase ) ) { @@ -142,12 +148,16 @@ namespace TJAPlayer3 } else { - for(int i = 0; i < 3; i++) - { - if (str.StartsWith("#BOXEXPLANATION" + (i + 1).ToString(), StringComparison.OrdinalIgnoreCase)) - { - this.strBoxText[i] = str.Substring(16).Trim(ignoreChars); - } + for(int i = 0; i < 3; i++) + { + if (str.StartsWith(langBOXEXPLANATION + (i + 1).ToString(), StringComparison.OrdinalIgnoreCase)) + { + this.strBoxText[i] = str.Substring(18).Trim(ignoreChars); + } + else if (str.StartsWith("#BOXEXPLANATION" + (i + 1).ToString(), StringComparison.OrdinalIgnoreCase)) + { + if (this.strBoxText[i] == "") this.strBoxText[i] = str.Substring(16).Trim(ignoreChars); + } } } } diff --git a/TJAPlayer3/Songs/CDTX.cs b/TJAPlayer3/Songs/CDTX.cs index 51334777..ea5905e9 100644 --- a/TJAPlayer3/Songs/CDTX.cs +++ b/TJAPlayer3/Songs/CDTX.cs @@ -12,6 +12,10 @@ using FDK; using FDK.ExtensionMethods; using System.Linq; using TJAPlayer3; +using SharpDX; + +using Point = System.Drawing.Point; +using Color = System.Drawing.Color; namespace TJAPlayer3 { @@ -21,6 +25,8 @@ namespace TJAPlayer3 public enum E種別 { DTX, GDA, G2D, BMS, BME, SMF } + public List listErrors = new List(); + private int nNowReadLine; // クラス public class CAVI : IDisposable @@ -410,7 +416,58 @@ namespace TJAPlayer3 public int nList上の位置; public bool IsFixedSENote; public bool IsHitted = false; - public bool IsMissed = false; + public bool IsMissed = false; + + + + //EXTENDED COMMANDS + public int fCamTimeMs; + public string strCamEaseType; + public Easing.CalcType fCamMoveType; + + public float fCamScrollStartX; + public float fCamScrollStartY; + public float fCamScrollEndX; + public float fCamScrollEndY; + + public float fCamRotationStart; + public float fCamRotationEnd; + + public float fCamZoomStart; + public float fCamZoomEnd; + + public float fCamScaleStartX; + public float fCamScaleStartY; + public float fCamScaleEndX; + public float fCamScaleEndY; + + public Color4 borderColor; + + public int fObjTimeMs; + public string strObjName; + public string strObjEaseType; + public Easing.CalcType objCalcType; + + public float fObjX; + public float fObjY; + + public float fObjStart; + public float fObjEnd; + + public CSongObject obj; + + public string strTargetTxName; + public string strNewPath; + + public string strConfigValue; + + public double dbAnimInterval; + + public int intFrame; + + public EGameType eGameType; + // + public bool bBPMチップである { @@ -524,11 +581,11 @@ namespace TJAPlayer3 "小節線", "拍線", "??", "??", "AVI", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", - //システム(移動予定) - "SCROLL", "DELAY", "ゴーゴータイム開始", "ゴーゴータイム終了", "??", "??", "??", "??", - "??", "??", "??", "??", "??", "??", "??", "??", - - "??", "??", "??", "??", "??", "??", "??", "??", + //システム(移動予定) + "SCROLL", "DELAY", "ゴーゴータイム開始", "ゴーゴータイム終了", "カメラ移動開始(縦)", "カメラ移動終了(縦)", "カメラ移動開始(横)", "カメラ移動終了(横)", + "カメラズーム開始", "カメラズーム終了", "カメラ回転開始", "カメラ回転終了", "カメラスケーリング開始(横)", "カメラスケーリング終了(横)", "カメラスケーリング開始(縦)", "カメラスケーリング終了(縦)", + + "ボーダーカラー変更", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", "??", @@ -1383,7 +1440,13 @@ namespace TJAPlayer3 public bool IsEnabledFixSENote; public int FixSENote; - public GaugeIncreaseMode GaugeIncreaseMode; + public GaugeIncreaseMode GaugeIncreaseMode; + + #region [ EXTENDED VARiABLES ] + public Dictionary listObj; + public Dictionary listTextures; + public Dictionary listOriginalTextures; + #endregion @@ -1958,6 +2021,30 @@ namespace TJAPlayer3 case Eランダムモード.OFF: default: break; + } + + if (TJAPlayer3.Tx.Puchichara[PuchiChara.tGetPuchiCharaIndexByName(TJAPlayer3.GetActualPlayer(nPlayerSide))].effect.AllPurple) + { + foreach (var chip in this.listChip) + { + switch (chip.nチャンネル番号) + { + case 0x11: + chip.nチャンネル番号 = 0x101; + break; + case 0x12: + chip.nチャンネル番号 = 0x101; + break; + case 0x13: + chip.nチャンネル番号 = 0x101; + chip.nSenote = 6; + break; + case 0x14: + chip.nチャンネル番号 = 0x101; + chip.nSenote = 5; + break; + } + } } if (eRandom != Eランダムモード.OFF) @@ -3228,6 +3315,7 @@ namespace TJAPlayer3 // private static readonly HashSet valableTokens = new HashSet(@"TIT|LEV|BPM|WAV|OFF|BAL|EXA|DAN|REN|BAL|SON|SEV|SCO|COU|STY|TOW|GAM|LIF|DEM|SID|SUB|GEN|MOV|BGI|BGM|HID|GAU|LYR|#HB|#BM".Split('|')); + private int nDifficulty; /// /// 新型。 @@ -3239,6 +3327,7 @@ namespace TJAPlayer3 /// 譜面のデータ private void t入力_V4(string strInput, int difficulty) { + nDifficulty = difficulty; if (!String.IsNullOrEmpty(strInput)) //空なら通さない { @@ -3412,6 +3501,7 @@ namespace TJAPlayer3 //string strWrite = ""; for (int i = 0; strSplitした後の譜面.Length > i; i++) { + nNowReadLine++; str = strSplitした後の譜面[i]; //strWrite += str; //if( !str.StartsWith( "#" ) && !string.IsNullOrEmpty( this.strTemp ) ) @@ -3489,7 +3579,20 @@ namespace TJAPlayer3 new Regex(@"^(#[A-Z]+)(?:\s?)(.+?)?$", RegexOptions.Compiled); private static readonly Regex BranchStartArgumentRegex = - new Regex(@"^([^,\s]+)\s*,\s*([^,\s]+)\s*,\s*([^,\s]+)$", RegexOptions.Compiled); + new Regex(@"^([^,\s]+)\s*,\s*([^,\s]+)\s*,\s*([^,\s]+)$", RegexOptions.Compiled); + + private void AddError(string command, string argument) + { + listErrors.Add($"コメントアウトを除く{(Difficulty)nDifficulty}の{nNowReadLine}行目の{command}が正しくありません。値が{argument}になっています"); + } + private void AddError_Single(string str) + { + listErrors.Add($"コメントアウトを除く{(Difficulty)nDifficulty}の{nNowReadLine}行目の{str}"); + } + private void AddError(string str) + { + listErrors.Add(str); + } private string[] SplitComma(string input) { @@ -3670,7 +3773,12 @@ namespace TJAPlayer3 else if (command == "#BPMCHANGE") { - double dbBPM = Convert.ToDouble(argument); + double dbBPM; + if (!double.TryParse(argument, out dbBPM)) + { + AddError(command, argument); + dbBPM = 150; + } this.dbNowBPM = dbBPM; if (dbBPM > MaxBPM) @@ -3726,7 +3834,16 @@ namespace TJAPlayer3 //iが入っていた場合、複素数スクロールとみなす。 double[] dbComplexNum = new double[2]; - this.tParsedComplexNumber(argument, ref dbComplexNum); + try + { + this.tParsedComplexNumber(argument, ref dbComplexNum); + } + catch(Exception ex) + { + AddError(command, argument); + dbComplexNum[0] = 1.0; + dbComplexNum[1] = 0.0; + } this.dbNowScroll = dbComplexNum[0]; this.dbNowScrollY = dbComplexNum[1]; @@ -3772,7 +3889,13 @@ namespace TJAPlayer3 } else { - double dbSCROLL = Convert.ToDouble(argument); + double dbSCROLL = 1.0; + if (!double.TryParse(argument, out dbSCROLL)) + { + AddError(command, argument); + dbSCROLL = 1; + } + this.dbNowScroll = dbSCROLL; this.dbNowScrollY = 0.0; @@ -3820,8 +3943,15 @@ namespace TJAPlayer3 WarnSplitLength("#MEASURE subsplit", strArray, 2); double[] dbLength = new double[2]; - dbLength[0] = Convert.ToDouble(strArray[0]); - dbLength[1] = Convert.ToDouble(strArray[1]); + try + { + dbLength[0] = Convert.ToDouble(strArray[0]); + dbLength[1] = Convert.ToDouble(strArray[1]); + } + catch(Exception ex) + { + AddError(command, argument); + } double db小節長倍率 = dbLength[0] / dbLength[1]; this.dbBarLength = db小節長倍率; @@ -3846,7 +3976,13 @@ namespace TJAPlayer3 } else if (command == "#DELAY") { - double nDELAY = (Convert.ToDouble(argument) * 1000.0); + double nDELAY = 0; + if (!double.TryParse(argument, out nDELAY)) + { + AddError(command, argument); + nDELAY = 0; + } + nDELAY *= 1000; this.listDELAY.Add(this.n内部番号DELAY1to, new CDELAY() { n内部番号 = this.n内部番号DELAY1to, n表記上の番号 = 0, nDELAY値 = (int)nDELAY, delay_bmscroll_time = this.dbLastBMScrollTime, delay_bpm = this.dbNowBPM, delay_course = this.n現在のコース, delay_time = this.dbLastTime }); @@ -3903,7 +4039,2121 @@ namespace TJAPlayer3 // チップを配置。 this.listChip.Add(chip); + } + + + else if (command == "#CAMVMOVESTART") + { + if (currentCamVMoveChip == null) + { + //starts vertical camera moving + //arguments: ,,, + var chip = new CChip(); + + chip.nチャンネル番号 = 0xA0; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 0; + + try + { + string[] args = argument.Split(','); + chip.fCamScrollStartY = float.Parse(args[0]); + chip.fCamScrollEndY = float.Parse(args[1]); + chip.strCamEaseType = args[2]; + + var type = args[3]; + var eType = Easing.CalcType.Quadratic; + switch (type) + { + case "CUBIC": + eType = Easing.CalcType.Cubic; + break; + case "QUARTIC": + eType = Easing.CalcType.Quartic; + break; + case "QUINTIC": + eType = Easing.CalcType.Quintic; + break; + case "SINUSOIDAL": + eType = Easing.CalcType.Sinusoidal; + break; + case "EXPONENTIAL": + eType = Easing.CalcType.Exponential; + break; + case "CIRCULAR": + eType = Easing.CalcType.Circular; + break; + case "LINEAR": + eType = Easing.CalcType.Linear; + break; + default: + break; + } + + chip.fCamMoveType = eType; + + currentCamVMoveChip = chip; + + // チップを配置。 + this.listChip.Add(chip); + } + catch (Exception ex) + { + AddError(command, argument); + } + } + else + { + AddError_Single("Missing #CAMVMOVEEND"); + Trace.TraceInformation("TJA ERROR: Missing #CAMVMOVEEND"); + } + } + else if (command == "#CAMVMOVEEND") + { + if (currentCamVMoveChip != null) + { + //ends vertical camera moving + var chip = new CChip(); + + chip.nチャンネル番号 = 0xA1; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 1; + + var index = this.listChip.IndexOf(currentCamVMoveChip); + var msDiff = chip.n発声時刻ms - currentCamVMoveChip.n発声時刻ms; + + currentCamVMoveChip.fCamTimeMs = msDiff; + this.listChip[index] = currentCamVMoveChip; + + currentCamVMoveChip = null; + + // チップを配置。 + this.listChip.Add(chip); + } + else + { + AddError_Single("Missing #CAMVMOVESTART"); + Trace.TraceInformation("TJA ERROR: Missing #CAMVMOVESTART"); + } + } + else if (command == "#CAMHMOVESTART") + { + if (currentCamHMoveChip == null) + { + //starts horizontal camera moving + //arguments: ,,, + var chip = new CChip(); + + chip.nチャンネル番号 = 0xA2; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 1; + + try + { + string[] args = argument.Split(','); + chip.fCamScrollStartX = float.Parse(args[0]); + chip.fCamScrollEndX = float.Parse(args[1]); + chip.strCamEaseType = args[2]; + + var type = args[3]; + var eType = Easing.CalcType.Quadratic; + switch (type) + { + case "CUBIC": + eType = Easing.CalcType.Cubic; + break; + case "QUARTIC": + eType = Easing.CalcType.Quartic; + break; + case "QUINTIC": + eType = Easing.CalcType.Quintic; + break; + case "SINUSOIDAL": + eType = Easing.CalcType.Sinusoidal; + break; + case "EXPONENTIAL": + eType = Easing.CalcType.Exponential; + break; + case "CIRCULAR": + eType = Easing.CalcType.Circular; + break; + case "LINEAR": + eType = Easing.CalcType.Linear; + break; + default: + break; + } + + chip.fCamMoveType = eType; + + currentCamHMoveChip = chip; + + // チップを配置。 + this.listChip.Add(chip); + } + catch (Exception ex) + { + AddError(command, argument); + } + } + else + { + AddError_Single("Missing #CAMHMOVEEND"); + Trace.TraceInformation("TJA ERROR: Missing #CAMHMOVEEND"); + } + } + else if (command == "#CAMHMOVEEND") + { + if (currentCamHMoveChip != null) + { + //ends horizontal camera moving + var chip = new CChip(); + + chip.nチャンネル番号 = 0xA3; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 1; + + var index = this.listChip.IndexOf(currentCamHMoveChip); + var msDiff = chip.n発声時刻ms - currentCamHMoveChip.n発声時刻ms; + + currentCamHMoveChip.fCamTimeMs = msDiff; + this.listChip[index] = currentCamHMoveChip; + + currentCamHMoveChip = null; + + // チップを配置。 + this.listChip.Add(chip); + } + else + { + AddError_Single("Missing #CAMHMOVESTART"); + Trace.TraceInformation("TJA ERROR: Missing #CAMHMOVESTART"); + } + } + else if (command == "#CAMZOOMSTART") + { + if (currentCamZoomChip == null) + { + //starts zooming in/out the screen + //arguments: ,,, + var chip = new CChip(); + + chip.nチャンネル番号 = 0xA4; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 1; + + try + { + string[] args = argument.Split(','); + chip.fCamZoomStart = float.Parse(args[0]); + chip.fCamZoomEnd = float.Parse(args[1]); + chip.strCamEaseType = args[2]; + + var type = args[3]; + var eType = Easing.CalcType.Quadratic; + switch (type) + { + case "CUBIC": + eType = Easing.CalcType.Cubic; + break; + case "QUARTIC": + eType = Easing.CalcType.Quartic; + break; + case "QUINTIC": + eType = Easing.CalcType.Quintic; + break; + case "SINUSOIDAL": + eType = Easing.CalcType.Sinusoidal; + break; + case "EXPONENTIAL": + eType = Easing.CalcType.Exponential; + break; + case "CIRCULAR": + eType = Easing.CalcType.Circular; + break; + case "LINEAR": + eType = Easing.CalcType.Linear; + break; + default: + break; + } + + chip.fCamMoveType = eType; + + currentCamZoomChip = chip; + + // チップを配置。 + this.listChip.Add(chip); + } + catch (Exception ex) + { + AddError(command, argument); + } + } + else + { + AddError_Single("Missing #CAMZOOMEND"); + Trace.TraceInformation("TJA ERROR: Missing #CAMZOOMEND"); + } + } + else if (command == "#CAMZOOMEND") + { + if (currentCamZoomChip != null) + { + //stops zooming + var chip = new CChip(); + + chip.nチャンネル番号 = 0xA5; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 1; + + var index = this.listChip.IndexOf(currentCamZoomChip); + var msDiff = chip.n発声時刻ms - currentCamZoomChip.n発声時刻ms; + + currentCamZoomChip.fCamTimeMs = msDiff; + this.listChip[index] = currentCamZoomChip; + + currentCamZoomChip = null; + + // チップを配置。 + this.listChip.Add(chip); + } + else + { + AddError_Single("Missing #CAMZOOMSTART"); + Trace.TraceInformation("TJA ERROR: Missing #CAMZOOMSTART"); + } + } + else if (command == "#CAMROTATIONSTART") + { + if (currentCamRotateChip == null) + { + //starts rotating the screen + //arguments: ,,, + var chip = new CChip(); + + chip.nチャンネル番号 = 0xA6; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 1; + + try + { + string[] args = argument.Split(','); + chip.fCamRotationStart = float.Parse(args[0]); + chip.fCamRotationEnd = float.Parse(args[1]); + chip.strCamEaseType = args[2]; + + var type = args[3]; + var eType = Easing.CalcType.Quadratic; + switch (type) + { + case "CUBIC": + eType = Easing.CalcType.Cubic; + break; + case "QUARTIC": + eType = Easing.CalcType.Quartic; + break; + case "QUINTIC": + eType = Easing.CalcType.Quintic; + break; + case "SINUSOIDAL": + eType = Easing.CalcType.Sinusoidal; + break; + case "EXPONENTIAL": + eType = Easing.CalcType.Exponential; + break; + case "CIRCULAR": + eType = Easing.CalcType.Circular; + break; + case "LINEAR": + eType = Easing.CalcType.Linear; + break; + default: + break; + } + + chip.fCamMoveType = eType; + + currentCamRotateChip = chip; + + // チップを配置。 + this.listChip.Add(chip); + } + catch (Exception ex) + { + AddError(command, argument); + } + } + else + { + AddError_Single("Missing #CAMROTATIONEND"); + Trace.TraceInformation("TJA ERROR: Missing #CAMROTATIONEND"); + } + } + else if (command == "#CAMROTATIONEND") + { + if (currentCamRotateChip != null) + { + //stops screen rotation + var chip = new CChip(); + + chip.nチャンネル番号 = 0xA7; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 1; + + var index = this.listChip.IndexOf(currentCamRotateChip); + var msDiff = chip.n発声時刻ms - currentCamRotateChip.n発声時刻ms; + + currentCamRotateChip.fCamTimeMs = msDiff; + this.listChip[index] = currentCamRotateChip; + + currentCamRotateChip = null; + + // チップを配置。 + this.listChip.Add(chip); + } + else + { + AddError_Single("Missing #CAMROTATIONSTART"); + Trace.TraceInformation("TJA ERROR: Missing #CAMROTATIONSTART"); + } + } + else if (command == "#CAMVSCALESTART") + { + if (currentCamVScaleChip == null) + { + //starts vertical camera scale changing + //arguments: ,,, + var chip = new CChip(); + + chip.nチャンネル番号 = 0xA8; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 1; + + try + { + string[] args = argument.Split(','); + chip.fCamScaleStartY = float.Parse(args[0]); + chip.fCamScaleEndY = float.Parse(args[1]); + chip.strCamEaseType = args[2]; + + var type = args[3]; + var eType = Easing.CalcType.Quadratic; + switch (type) + { + case "CUBIC": + eType = Easing.CalcType.Cubic; + break; + case "QUARTIC": + eType = Easing.CalcType.Quartic; + break; + case "QUINTIC": + eType = Easing.CalcType.Quintic; + break; + case "SINUSOIDAL": + eType = Easing.CalcType.Sinusoidal; + break; + case "EXPONENTIAL": + eType = Easing.CalcType.Exponential; + break; + case "CIRCULAR": + eType = Easing.CalcType.Circular; + break; + case "LINEAR": + eType = Easing.CalcType.Linear; + break; + default: + break; + } + + chip.fCamMoveType = eType; + + currentCamVScaleChip = chip; + + // チップを配置。 + this.listChip.Add(chip); + } + catch (Exception ex) + { + AddError(command, argument); + } + } + else + { + AddError_Single("Missing #CAMVSCALEEND"); + Trace.TraceInformation("TJA ERROR: Missing #CAMVSCALEEND"); + } + } + else if (command == "#CAMVSCALEEND") + { + if (currentCamVScaleChip != null) + { + //ends vertical camera scaling + var chip = new CChip(); + + chip.nチャンネル番号 = 0xA9; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 1; + + var index = this.listChip.IndexOf(currentCamVScaleChip); + var msDiff = chip.n発声時刻ms - currentCamVScaleChip.n発声時刻ms; + + currentCamVScaleChip.fCamTimeMs = msDiff; + this.listChip[index] = currentCamVScaleChip; + + currentCamVScaleChip = null; + + // チップを配置。 + this.listChip.Add(chip); + } + else + { + AddError_Single("Missing #CAMVSCALESTART"); + Trace.TraceInformation("TJA ERROR: Missing #CAMVSCALESTART"); + } + } + else if (command == "#CAMHSCALESTART") + { + if (currentCamHScaleChip == null) + { + //starts horizontal camera scale changing + //arguments: ,,, + var chip = new CChip(); + + chip.nチャンネル番号 = 0xB0; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 1; + + try + { + string[] args = argument.Split(','); + chip.fCamScaleStartX = float.Parse(args[0]); + chip.fCamScaleEndX = float.Parse(args[1]); + chip.strCamEaseType = args[2]; + + var type = args[3]; + var eType = Easing.CalcType.Quadratic; + switch (type) + { + case "CUBIC": + eType = Easing.CalcType.Cubic; + break; + case "QUARTIC": + eType = Easing.CalcType.Quartic; + break; + case "QUINTIC": + eType = Easing.CalcType.Quintic; + break; + case "SINUSOIDAL": + eType = Easing.CalcType.Sinusoidal; + break; + case "EXPONENTIAL": + eType = Easing.CalcType.Exponential; + break; + case "CIRCULAR": + eType = Easing.CalcType.Circular; + break; + case "LINEAR": + eType = Easing.CalcType.Linear; + break; + default: + break; + } + + chip.fCamMoveType = eType; + + currentCamHScaleChip = chip; + + // チップを配置。 + this.listChip.Add(chip); + } + catch (Exception ex) + { + AddError(command, argument); + } + } + else + { + AddError_Single("Missing #CAMHSCALEEND"); + Trace.TraceInformation("TJA ERROR: Missing #CAMHSCALEEND"); + } + } + else if (command == "#CAMHSCALEEND") + { + if (currentCamHScaleChip != null) + { + //ends horizontal camera scaling + var chip = new CChip(); + + chip.nチャンネル番号 = 0xB1; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 1; + + var index = this.listChip.IndexOf(currentCamHScaleChip); + var msDiff = chip.n発声時刻ms - currentCamHScaleChip.n発声時刻ms; + + currentCamHScaleChip.fCamTimeMs = msDiff; + this.listChip[index] = currentCamHScaleChip; + + currentCamHScaleChip = null; + + // チップを配置。 + this.listChip.Add(chip); + } + else + { + AddError_Single("Missing #CAMHSCALESTART"); + Trace.TraceInformation("TJA ERROR: Missing #CAMHSCALESTART"); + } + } + else if (command == "#BORDERCOLOR") + { + //sets border color + //arguments: ,, + var chip = new CChip(); + + chip.nチャンネル番号 = 0xB2; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 1; + + string[] args = argument.Split(','); + chip.borderColor = new Color4(1f, float.Parse(args[0]) / 255, float.Parse(args[1]) / 255, float.Parse(args[2]) / 255); + + // チップを配置。 + this.listChip.Add(chip); + } + else if (command == "#CAMHOFFSET") + { + if (currentCamHMoveChip == null) + { + //sets camera x offset + //argument: + var chip = new CChip(); + + chip.nチャンネル番号 = 0xB3; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 1; + + if (float.TryParse(argument, out float value)) + { + chip.fCamScrollStartX = value; + chip.fCamScrollEndX = value; + } + else + { + AddError(command, argument); + } + chip.strCamEaseType = "IN_OUT"; + + // チップを配置。 + this.listChip.Add(chip); + } + else + { + AddError_Single("Missing #CAMHMOVEEND"); + Trace.TraceInformation("TJA ERROR: Missing #CAMHMOVEEND"); + } + } + else if (command == "#CAMVOFFSET") + { + if (currentCamVMoveChip == null) + { + //sets camera y offset + //argument: + var chip = new CChip(); + + chip.nチャンネル番号 = 0xB4; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 1; + + if (float.TryParse(argument, out float value)) + { + chip.fCamScrollStartY = float.Parse(argument); + chip.fCamScrollEndY = float.Parse(argument); + } + else + { + AddError(command, argument); + } + chip.strCamEaseType = "IN_OUT"; + + // チップを配置。 + this.listChip.Add(chip); + } + else + { + AddError_Single("Missing #CAMVMOVEEND"); + Trace.TraceInformation("TJA ERROR: Missing #CAMVMOVEEND"); + } + } + else if (command == "#CAMZOOM") + { + if (currentCamZoomChip == null) + { + //sets camera zoom factor + //argument: + var chip = new CChip(); + + chip.nチャンネル番号 = 0xB5; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 1; + + if (float.TryParse(argument, out float value)) + { + chip.fCamZoomStart = float.Parse(argument); + chip.fCamZoomEnd = float.Parse(argument); + } + else + { + AddError(command, argument); + } + chip.strCamEaseType = "IN_OUT"; + + // チップを配置。 + this.listChip.Add(chip); + } + else + { + AddError_Single("Missing #CAMZOOMEND"); + Trace.TraceInformation("TJA ERROR: Missing #CAMZOOMEND"); + } + } + else if (command == "#CAMROTATION") + { + if (currentCamRotateChip == null) + { + //sets camera rotation + //argument: + var chip = new CChip(); + + chip.nチャンネル番号 = 0xB6; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 1; + + if (float.TryParse(argument, out float value)) + { + chip.fCamRotationStart = float.Parse(argument); + chip.fCamRotationEnd = float.Parse(argument); + } + else + { + AddError(command, argument); + } + chip.strCamEaseType = "IN_OUT"; + + // チップを配置。 + this.listChip.Add(chip); + } + else + { + AddError_Single("Missing #CAMROTATIONEND"); + Trace.TraceInformation("TJA ERROR: Missing #CAMROTATIONEND"); + } + } + else if (command == "#CAMHSCALE") + { + if (currentCamHScaleChip == null) + { + //sets camera x scale + //argument: + var chip = new CChip(); + + chip.nチャンネル番号 = 0xB7; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 1; + + if (float.TryParse(argument, out float value)) + { + chip.fCamScaleStartX = float.Parse(argument); + chip.fCamScaleEndX = float.Parse(argument); + } + else + { + AddError(command, argument); + } + chip.strCamEaseType = "IN_OUT"; + + // チップを配置。 + this.listChip.Add(chip); + } + else + { + AddError_Single("Missing #CAMHSCALEEND"); + Trace.TraceInformation("TJA ERROR: Missing #CAMHSCALEEND"); + } + } + else if (command == "#CAMVSCALE") + { + if (currentCamVScaleChip == null) + { + //sets camera y scale + //argument: + var chip = new CChip(); + + chip.nチャンネル番号 = 0xB8; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 1; + + if (float.TryParse(argument, out float value)) + { + chip.fCamScaleStartY = float.Parse(argument); + chip.fCamScaleEndY = float.Parse(argument); + } + else + { + AddError(command, argument); + } + chip.strCamEaseType = "IN_OUT"; + + // チップを配置。 + this.listChip.Add(chip); + } + else + { + AddError_Single("Missing #CAMVSCALEEND"); + Trace.TraceInformation("TJA ERROR: Missing #CAMVSCALEEND"); + } + } + else if (command == "#CAMRESET") + { + //resets camera properties + var chip = new CChip(); + + chip.nチャンネル番号 = 0xB9; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 1; + + chip.fCamScrollStartX = 0.0f; + chip.fCamScrollEndX = 0.0f; + chip.fCamScrollStartY = 0.0f; + chip.fCamScrollEndY = 0.0f; + + chip.fCamZoomStart = 1.0f; + chip.fCamZoomEnd = 1.0f; + chip.fCamRotationStart = 0.0f; + chip.fCamRotationEnd = 0.0f; + + chip.fCamScaleStartX = 1.0f; + chip.fCamScaleEndX = 1.0f; + chip.fCamScaleStartY = 1.0f; + chip.fCamScaleEndY = 1.0f; + + chip.strCamEaseType = "IN_OUT"; + + // チップを配置。 + this.listChip.Add(chip); + } + else if (command == "#ENABLEDORON") + { + //resets camera properties + var chip = new CChip(); + + chip.nチャンネル番号 = 0xBA; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 1; + + // チップを配置。 + this.listChip.Add(chip); + } + else if (command == "#DISABLEDORON") + { + //resets camera properties + var chip = new CChip(); + + chip.nチャンネル番号 = 0xBB; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 1; + + // チップを配置。 + this.listChip.Add(chip); + } + else if (command == "#ADDOBJECT") + { + //adds object + var chip = new CChip(); + + chip.nチャンネル番号 = 0xBC; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 1; + + try + { + string[] args = argument.Split(','); + + chip.strObjName = args[0]; + chip.fObjX = float.Parse(args[1]); + chip.fObjY = float.Parse(args[2]); + var txPath = this.strフォルダ名 + args[3]; + Trace.TraceInformation("" + this.bSession譜面を読み込む); + if (this.bSession譜面を読み込む) + { + var obj = new CSongObject(chip.strObjName, chip.fObjX, chip.fObjY, txPath); + this.listObj.Add(args[0], obj); + } + + // チップを配置。 + this.listChip.Add(chip); + } + catch (Exception ex) + { + AddError(command, argument); + } + } + else if (command == "#REMOVEOBJECT") + { + //removes object + var chip = new CChip(); + + chip.nチャンネル番号 = 0xBD; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 1; + + chip.strObjName = argument; + + // チップを配置。 + this.listChip.Add(chip); + } + else if (command == "#OBJVMOVESTART") + { + string[] args = argument.Split(','); + + try + { + string name = args[0]; + + if (!currentObjAnimations.ContainsKey("vmove_" + name)) + { + //starts vertical object movement + //arguments: ,,, + var chip = new CChip(); + + chip.nチャンネル番号 = 0xBE; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 0; + + chip.strObjName = args[0]; + chip.fObjStart = float.Parse(args[1]); + chip.fObjEnd = float.Parse(args[2]); + chip.strObjEaseType = args[3]; + + var type = args[4]; + var eType = Easing.CalcType.Quadratic; + switch (type) + { + case "CUBIC": + eType = Easing.CalcType.Cubic; + break; + case "QUARTIC": + eType = Easing.CalcType.Quartic; + break; + case "QUINTIC": + eType = Easing.CalcType.Quintic; + break; + case "SINUSOIDAL": + eType = Easing.CalcType.Sinusoidal; + break; + case "EXPONENTIAL": + eType = Easing.CalcType.Exponential; + break; + case "CIRCULAR": + eType = Easing.CalcType.Circular; + break; + case "LINEAR": + eType = Easing.CalcType.Linear; + break; + default: + break; + } + + chip.objCalcType = eType; + + currentObjAnimations.Add("vmove_" + name, chip); + + // チップを配置。 + this.listChip.Add(chip); + } + else + { + AddError_Single("Missing #OBJVMOVEEND"); + Trace.TraceInformation("TJA ERROR: Missing #OBJVMOVEEND"); + } + } + catch (Exception ex) + { + AddError(command, argument); + } + } + else if (command == "#OBJVMOVEEND") + { + string name = argument; + + if (currentObjAnimations.ContainsKey("vmove_" + name)) + { + //ends vertical camera moving + var chip = new CChip(); + + chip.nチャンネル番号 = 0xBF; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 1; + chip.strObjName = argument; + + currentObjAnimations.TryGetValue("vmove_" + name, out CChip startChip); + + var index = this.listChip.IndexOf(startChip); + var msDiff = chip.n発声時刻ms - startChip.n発声時刻ms; + + startChip.fObjTimeMs = msDiff; + this.listChip[index] = startChip; + + currentObjAnimations.Remove("vmove_" + name); + + // チップを配置。 + this.listChip.Add(chip); + } + else + { + AddError_Single("Missing #OBJVMOVESTART"); + Trace.TraceInformation("TJA ERROR: Missing #OBJVMOVESTART"); + } + } + else if (command == "#OBJHMOVESTART") + { + string[] args = argument.Split(','); + try + { + string name = args[0]; + + if (!currentObjAnimations.ContainsKey("hmove_" + name)) + { + //starts horizontal object movement + //arguments: ,,, + var chip = new CChip(); + + chip.nチャンネル番号 = 0xC0; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 0; + + chip.strObjName = args[0]; + chip.fObjStart = float.Parse(args[1]); + chip.fObjEnd = float.Parse(args[2]); + chip.strObjEaseType = args[3]; + + var type = args[4]; + var eType = Easing.CalcType.Quadratic; + switch (type) + { + case "CUBIC": + eType = Easing.CalcType.Cubic; + break; + case "QUARTIC": + eType = Easing.CalcType.Quartic; + break; + case "QUINTIC": + eType = Easing.CalcType.Quintic; + break; + case "SINUSOIDAL": + eType = Easing.CalcType.Sinusoidal; + break; + case "EXPONENTIAL": + eType = Easing.CalcType.Exponential; + break; + case "CIRCULAR": + eType = Easing.CalcType.Circular; + break; + case "LINEAR": + eType = Easing.CalcType.Linear; + break; + default: + break; + } + + chip.objCalcType = eType; + + currentObjAnimations.Add("hmove_" + name, chip); + + // チップを配置。 + this.listChip.Add(chip); + } + else + { + AddError_Single("Missing #OBJHMOVEEND"); + Trace.TraceInformation("TJA ERROR: Missing #OBJHMOVEEND"); + } + } + catch (Exception ex) + { + AddError(command, argument); + } + } + else if (command == "#OBJHMOVEEND") + { + string name = argument; + + if (currentObjAnimations.ContainsKey("hmove_" + name)) + { + //ends horizontal camera moving + var chip = new CChip(); + + chip.nチャンネル番号 = 0xC1; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 1; + chip.strObjName = argument; + + currentObjAnimations.TryGetValue("hmove_" + name, out CChip startChip); + + var index = this.listChip.IndexOf(startChip); + var msDiff = chip.n発声時刻ms - startChip.n発声時刻ms; + + startChip.fObjTimeMs = msDiff; + this.listChip[index] = startChip; + + currentObjAnimations.Remove("hmove_" + name); + + // チップを配置。 + this.listChip.Add(chip); + } + else + { + AddError_Single("Missing #OBJHMOVESTART"); + Trace.TraceInformation("TJA ERROR: Missing #OBJHMOVESTART"); + } + } + else if (command == "#OBJVSCALESTART") + { + string[] args = argument.Split(','); + try + { + string name = args[0]; + + if (!currentObjAnimations.ContainsKey("vscale_" + name)) + { + var chip = new CChip(); + + chip.nチャンネル番号 = 0xC2; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 0; + + chip.strObjName = args[0]; + chip.fObjStart = float.Parse(args[1]); + chip.fObjEnd = float.Parse(args[2]); + chip.strObjEaseType = args[3]; + + var type = args[4]; + var eType = Easing.CalcType.Quadratic; + switch (type) + { + case "CUBIC": + eType = Easing.CalcType.Cubic; + break; + case "QUARTIC": + eType = Easing.CalcType.Quartic; + break; + case "QUINTIC": + eType = Easing.CalcType.Quintic; + break; + case "SINUSOIDAL": + eType = Easing.CalcType.Sinusoidal; + break; + case "EXPONENTIAL": + eType = Easing.CalcType.Exponential; + break; + case "CIRCULAR": + eType = Easing.CalcType.Circular; + break; + case "LINEAR": + eType = Easing.CalcType.Linear; + break; + default: + break; + } + + chip.objCalcType = eType; + + currentObjAnimations.Add("vscale_" + name, chip); + + // チップを配置。 + this.listChip.Add(chip); + } + else + { + AddError_Single("Missing #OBJVSCALEEND"); + Trace.TraceInformation("TJA ERROR: Missing #OBJVSCALEEND"); + } + } + catch (Exception ex) + { + AddError(command, argument); + } + } + else if (command == "#OBJVSCALEEND") + { + string name = argument; + + if (currentObjAnimations.ContainsKey("vscale_" + name)) + { + var chip = new CChip(); + + chip.nチャンネル番号 = 0xC3; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 1; + chip.strObjName = argument; + + currentObjAnimations.TryGetValue("vscale_" + name, out CChip startChip); + + var index = this.listChip.IndexOf(startChip); + var msDiff = chip.n発声時刻ms - startChip.n発声時刻ms; + + startChip.fObjTimeMs = msDiff; + this.listChip[index] = startChip; + + currentObjAnimations.Remove("vscale_" + name); + + // チップを配置。 + this.listChip.Add(chip); + } + else + { + AddError_Single("Missing #OBJVSCALESTART"); + Trace.TraceInformation("TJA ERROR: Missing #OBJVSCALESTART"); + } + } + else if (command == "#OBJHSCALESTART") + { + string[] args = argument.Split(','); + try + { + string name = args[0]; + + if (!currentObjAnimations.ContainsKey("hscale_" + name)) + { + var chip = new CChip(); + + chip.nチャンネル番号 = 0xC4; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 0; + + chip.strObjName = args[0]; + chip.fObjStart = float.Parse(args[1]); + chip.fObjEnd = float.Parse(args[2]); + chip.strObjEaseType = args[3]; + + var type = args[4]; + var eType = Easing.CalcType.Quadratic; + switch (type) + { + case "CUBIC": + eType = Easing.CalcType.Cubic; + break; + case "QUARTIC": + eType = Easing.CalcType.Quartic; + break; + case "QUINTIC": + eType = Easing.CalcType.Quintic; + break; + case "SINUSOIDAL": + eType = Easing.CalcType.Sinusoidal; + break; + case "EXPONENTIAL": + eType = Easing.CalcType.Exponential; + break; + case "CIRCULAR": + eType = Easing.CalcType.Circular; + break; + case "LINEAR": + eType = Easing.CalcType.Linear; + break; + default: + break; + } + + chip.objCalcType = eType; + + currentObjAnimations.Add("hscale_" + name, chip); + + // チップを配置。 + this.listChip.Add(chip); + } + else + { + AddError_Single("Missing #OBJHSCALEEND"); + Trace.TraceInformation("TJA ERROR: Missing #OBJHSCALEEND"); + } + } + catch (Exception ex) + { + AddError(command, argument); + } + } + else if (command == "#OBJHSCALEEND") + { + string name = argument; + + if (currentObjAnimations.ContainsKey("hscale_" + name)) + { + var chip = new CChip(); + + chip.nチャンネル番号 = 0xC5; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 1; + chip.strObjName = argument; + + currentObjAnimations.TryGetValue("hscale_" + name, out CChip startChip); + + var index = this.listChip.IndexOf(startChip); + var msDiff = chip.n発声時刻ms - startChip.n発声時刻ms; + + startChip.fObjTimeMs = msDiff; + this.listChip[index] = startChip; + + currentObjAnimations.Remove("hscale_" + name); + + // チップを配置。 + this.listChip.Add(chip); + } + else + { + AddError_Single("Missing #OBJHSCALESTART"); + Trace.TraceInformation("TJA ERROR: Missing #OBJHSCALESTART"); + } + } + else if (command == "#OBJROTATIONSTART") + { + string[] args = argument.Split(','); + try + { + string name = args[0]; + + if (!currentObjAnimations.ContainsKey("rotation_" + name)) + { + var chip = new CChip(); + + chip.nチャンネル番号 = 0xC6; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 0; + + chip.strObjName = args[0]; + chip.fObjStart = float.Parse(args[1]); + chip.fObjEnd = float.Parse(args[2]); + chip.strObjEaseType = args[3]; + + var type = args[4]; + var eType = Easing.CalcType.Quadratic; + switch (type) + { + case "CUBIC": + eType = Easing.CalcType.Cubic; + break; + case "QUARTIC": + eType = Easing.CalcType.Quartic; + break; + case "QUINTIC": + eType = Easing.CalcType.Quintic; + break; + case "SINUSOIDAL": + eType = Easing.CalcType.Sinusoidal; + break; + case "EXPONENTIAL": + eType = Easing.CalcType.Exponential; + break; + case "CIRCULAR": + eType = Easing.CalcType.Circular; + break; + case "LINEAR": + eType = Easing.CalcType.Linear; + break; + default: + break; + } + + chip.objCalcType = eType; + + currentObjAnimations.Add("rotation_" + name, chip); + + // チップを配置。 + this.listChip.Add(chip); + } + else + { + AddError_Single("Missing #OBJROTATIONEND"); + Trace.TraceInformation("TJA ERROR: Missing #OBJROTATIONEND"); + } + } + catch (Exception ex) + { + AddError(command, argument); + } + } + else if (command == "#OBJROTATIONEND") + { + string name = argument; + + if (currentObjAnimations.ContainsKey("rotation_" + name)) + { + var chip = new CChip(); + + chip.nチャンネル番号 = 0xC7; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 1; + chip.strObjName = argument; + + currentObjAnimations.TryGetValue("rotation_" + name, out CChip startChip); + + var index = this.listChip.IndexOf(startChip); + var msDiff = chip.n発声時刻ms - startChip.n発声時刻ms; + + startChip.fObjTimeMs = msDiff; + this.listChip[index] = startChip; + + currentObjAnimations.Remove("rotation_" + name); + + // チップを配置。 + this.listChip.Add(chip); + } + else + { + AddError_Single("Missing #OBJROTATIONSTART"); + Trace.TraceInformation("TJA ERROR: Missing #OBJROTATIONSTART"); + } + } + else if (command == "#OBJOPACITYSTART") + { + string[] args = argument.Split(','); + try + { + string name = args[0]; + + if (!currentObjAnimations.ContainsKey("opacity_" + name)) + { + var chip = new CChip(); + + chip.nチャンネル番号 = 0xC8; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 0; + + chip.strObjName = args[0]; + chip.fObjStart = float.Parse(args[1]); + chip.fObjEnd = float.Parse(args[2]); + chip.strObjEaseType = args[3]; + + var type = args[4]; + var eType = Easing.CalcType.Quadratic; + switch (type) + { + case "CUBIC": + eType = Easing.CalcType.Cubic; + break; + case "QUARTIC": + eType = Easing.CalcType.Quartic; + break; + case "QUINTIC": + eType = Easing.CalcType.Quintic; + break; + case "SINUSOIDAL": + eType = Easing.CalcType.Sinusoidal; + break; + case "EXPONENTIAL": + eType = Easing.CalcType.Exponential; + break; + case "CIRCULAR": + eType = Easing.CalcType.Circular; + break; + case "LINEAR": + eType = Easing.CalcType.Linear; + break; + default: + break; + } + + chip.objCalcType = eType; + + currentObjAnimations.Add("opacity_" + name, chip); + + // チップを配置。 + this.listChip.Add(chip); + } + else + { + AddError_Single("Missing #OBJOPACITYEND"); + Trace.TraceInformation("TJA ERROR: Missing #OBJOPACITYEND"); + } + } + catch (Exception ex) + { + AddError(command, argument); + } + } + else if (command == "#OBJOPACITYEND") + { + string name = argument; + + if (currentObjAnimations.ContainsKey("opacity_" + name)) + { + var chip = new CChip(); + + chip.nチャンネル番号 = 0xC9; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 1; + chip.strObjName = argument; + + currentObjAnimations.TryGetValue("opacity_" + name, out CChip startChip); + + var index = this.listChip.IndexOf(startChip); + var msDiff = chip.n発声時刻ms - startChip.n発声時刻ms; + + startChip.fObjTimeMs = msDiff; + this.listChip[index] = startChip; + + currentObjAnimations.Remove("opacity_" + name); + + // チップを配置。 + this.listChip.Add(chip); + } + else + { + AddError_Single("Missing #OBJOPACITYSTART"); + Trace.TraceInformation("TJA ERROR: Missing #OBJOPACITYSTART"); + } + } + else if (command == "#OBJCOLOR") + { + var chip = new CChip(); + + chip.nチャンネル番号 = 0xCA; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 1; + + try + { + string[] args = argument.Split(','); + chip.strObjName = args[0]; + chip.borderColor = new Color4(1f, float.Parse(args[1]) / 255, float.Parse(args[2]) / 255, float.Parse(args[3]) / 255); + + // チップを配置。 + this.listChip.Add(chip); + } + catch (Exception ex) + { + AddError(command, argument); + } + } + else if (command == "#OBJY") + { + string[] args = argument.Split(','); + try + { + string name = args[0]; + + if (!currentObjAnimations.ContainsKey("vmove_" + name)) + { + var chip = new CChip(); + + chip.nチャンネル番号 = 0xCB; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 0; + + chip.strObjName = args[0]; + chip.fObjStart = float.Parse(args[1]); + chip.fObjEnd = float.Parse(args[1]); + chip.strObjEaseType = "IN_OUT"; + + // チップを配置。 + this.listChip.Add(chip); + } + else + { + AddError_Single("Missing #OBJVMOVEEND"); + Trace.TraceInformation("TJA ERROR: Missing #OBJVMOVEEND"); + } + } + catch (Exception ex) + { + AddError(command, argument); + } + } + else if (command == "#OBJX") + { + string[] args = argument.Split(','); + try + { + string name = args[0]; + + if (!currentObjAnimations.ContainsKey("hmove_" + name)) + { + var chip = new CChip(); + + chip.nチャンネル番号 = 0xCC; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 0; + + chip.strObjName = args[0]; + chip.fObjStart = float.Parse(args[1]); + chip.fObjEnd = float.Parse(args[1]); + chip.strObjEaseType = "IN_OUT"; + + // チップを配置。 + this.listChip.Add(chip); + } + else + { + AddError_Single("Missing #OBJHMOVEEND"); + Trace.TraceInformation("TJA ERROR: Missing #OBJHMOVEEND"); + } + } + catch (Exception ex) + { + AddError(command, argument); + } + } + else if (command == "#OBJVSCALE") + { + string[] args = argument.Split(','); + try + { + string name = args[0]; + + if (!currentObjAnimations.ContainsKey("vscale_" + name)) + { + var chip = new CChip(); + + chip.nチャンネル番号 = 0xCD; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 0; + + chip.strObjName = args[0]; + chip.fObjStart = float.Parse(args[1]); + chip.fObjEnd = float.Parse(args[1]); + chip.strObjEaseType = "IN_OUT"; + + // チップを配置。 + this.listChip.Add(chip); + } + else + { + AddError_Single("Missing #OBJVSCALEEND"); + Trace.TraceInformation("TJA ERROR: Missing #OBJVSCALEEND"); + } + } + catch (Exception ex) + { + AddError(command, argument); + } + } + else if (command == "#OBJHSCALE") + { + string[] args = argument.Split(','); + try + { + string name = args[0]; + + if (!currentObjAnimations.ContainsKey("hscale_" + name)) + { + var chip = new CChip(); + + chip.nチャンネル番号 = 0xCE; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 0; + + chip.strObjName = args[0]; + chip.fObjStart = float.Parse(args[1]); + chip.fObjEnd = float.Parse(args[1]); + chip.strObjEaseType = "IN_OUT"; + + // チップを配置。 + this.listChip.Add(chip); + } + else + { + AddError_Single("Missing #OBJHSCALEEND"); + Trace.TraceInformation("TJA ERROR: Missing #OBJHSCALEEND"); + } + } + catch (Exception ex) + { + AddError(command, argument); + } + } + else if (command == "#OBJROTATION") + { + string[] args = argument.Split(','); + try + { + string name = args[0]; + + if (!currentObjAnimations.ContainsKey("rotation_" + name)) + { + var chip = new CChip(); + + chip.nチャンネル番号 = 0xCF; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 0; + + chip.strObjName = args[0]; + chip.fObjStart = float.Parse(args[1]); + chip.fObjEnd = float.Parse(args[1]); + chip.strObjEaseType = "IN_OUT"; + + // チップを配置。 + this.listChip.Add(chip); + } + else + { + AddError_Single("Missing #OBJROTATIONEND"); + Trace.TraceInformation("TJA ERROR: Missing #OBJROTATIONEND"); + } + } + catch (Exception ex) + { + AddError(command, argument); + } + } + else if (command == "#OBJOPACITY") + { + string[] args = argument.Split(','); + try + { + string name = args[0]; + + if (!currentObjAnimations.ContainsKey("opacity_" + name)) + { + var chip = new CChip(); + + chip.nチャンネル番号 = 0xD0; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 0; + + chip.strObjName = args[0]; + chip.fObjStart = float.Parse(args[1]); + chip.fObjEnd = float.Parse(args[1]); + chip.strObjEaseType = "IN_OUT"; + + // チップを配置。 + this.listChip.Add(chip); + } + else + { + AddError_Single("Missing #OBJOPACITYEND"); + Trace.TraceInformation("TJA ERROR: Missing #OBJOPACITYEND"); + } + } + catch (Exception ex) + { + AddError(command, argument); + } + } + else if (command == "#CHANGETEXTURE") + { + var chip = new CChip(); + + chip.nチャンネル番号 = 0xD1; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 1; + + string[] args = argument.Split(','); + try + { + chip.strTargetTxName = args[0].Replace("/", "\\"); + chip.strNewPath = this.strフォルダ名 + args[1]; + + if (this.bSession譜面を読み込む) + { + if (!this.listOriginalTextures.ContainsKey(chip.strTargetTxName)) + { + TJAPlayer3.Tx.trackedTextures.TryGetValue(chip.strTargetTxName, out CTexture oldTx); + this.listOriginalTextures.Add(chip.strTargetTxName, new CTexture(oldTx)); + } + if (!this.listTextures.ContainsKey(chip.strNewPath)) + { + CTexture tx = TJAPlayer3.Tx.TxCSong(chip.strNewPath); + this.listTextures.Add(chip.strNewPath, tx); + } + } + + // チップを配置。 + this.listChip.Add(chip); + } + catch (Exception ex) + { + AddError(command, argument); + } + } + else if (command == "#RESETTEXTURE") + { + var chip = new CChip(); + + chip.nチャンネル番号 = 0xD2; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 1; + + chip.strTargetTxName = argument.Replace("/", "\\"); + + // チップを配置。 + this.listChip.Add(chip); + } + else if (command == "#SETCONFIG") + { + var chip = new CChip(); + + chip.nチャンネル番号 = 0xD3; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 1; + + chip.strConfigValue = argument; + + // チップを配置。 + this.listChip.Add(chip); + } + else if (command == "#OBJANIMSTART") + { + var chip = new CChip(); + + chip.nチャンネル番号 = 0xD4; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 1; + + string[] args = argument.Split(','); + try + { + chip.strObjName = args[0]; + chip.dbAnimInterval = double.Parse(args[1]); + + // チップを配置。 + this.listChip.Add(chip); + } + catch (Exception ex) + { + AddError(command, argument); + } + } + else if (command == "#OBJANIMSTARTLOOP") + { + var chip = new CChip(); + + chip.nチャンネル番号 = 0xD5; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 1; + + string[] args = argument.Split(','); + try + { + chip.strObjName = args[0]; + chip.dbAnimInterval = double.Parse(args[1]); + + // チップを配置。 + this.listChip.Add(chip); + } + catch (Exception ex) + { + AddError(command, argument); + } + } + else if (command == "#OBJANIMEND") + { + var chip = new CChip(); + + chip.nチャンネル番号 = 0xD6; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 1; + + chip.strObjName = argument; + + // チップを配置。 + this.listChip.Add(chip); + } + else if (command == "#OBJFRAME") + { + var chip = new CChip(); + + chip.nチャンネル番号 = 0xD7; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 1; + + string[] args = argument.Split(','); + try + { + chip.strObjName = args[0]; + chip.intFrame = int.Parse(args[1]); + + // チップを配置。 + this.listChip.Add(chip); + } + catch (Exception ex) + { + AddError(command, argument); + } + } + else if (command == "#GAMETYPE") + { + var chip = new CChip(); + + chip.nチャンネル番号 = 0xD8; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 1; + switch(argument) + { + case "Taiko": + chip.eGameType = EGameType.TAIKO; + break; + case "Konga": + chip.eGameType = EGameType.KONGA; + break; + } + + // チップを配置。 + this.listChip.Add(chip); + } + else if (command == "#SPLITLANE") + { + var chip = new CChip(); + + chip.nチャンネル番号 = 0xD9; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 1; + + // チップを配置。 + this.listChip.Add(chip); + } + else if (command == "#MERGELANE") + { + var chip = new CChip(); + + chip.nチャンネル番号 = 0xE3; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 1; + + // チップを配置。 + this.listChip.Add(chip); + } + else if (command == "#BARLINE") + { + var chip = new CChip(); + + chip.nチャンネル番号 = 0xE4; + chip.n発声位置 = ((this.n現在の小節数) * 384); + chip.dbBPM = this.dbNowBPM; + chip.dbSCROLL = this.dbNowScroll; + chip.dbSCROLL_Y = this.dbNowScrollY; + chip.n発声時刻ms = (int)this.dbNowTime; + chip.fNow_Measure_m = this.fNow_Measure_m; + chip.fNow_Measure_s = this.fNow_Measure_s; + chip.n整数値_内部番号 = 1; + chip.bHideBarLine = false; + + // チップを配置。 + this.listChip.Add(chip); } + else if (command == "#SECTION") { //分岐:条件リセット @@ -6358,7 +8608,11 @@ namespace TJAPlayer3 this.listLine = new List(); this.listLyric = new List(); this.listLyric2 = new List(); - this.List_DanSongs = new List(); + this.List_DanSongs = new List(); + this.listObj = new Dictionary(); + this.listTextures = new Dictionary(); + this.listOriginalTextures = new Dictionary(); + this.currentObjAnimations = new Dictionary(); base.On活性化(); } public override void On非活性化() @@ -6467,7 +8721,44 @@ namespace TJAPlayer3 if (this.listLyric2 != null) { this.listLyric2.Clear(); + } + + + + if (this.listObj != null) + { + foreach (KeyValuePair pair in this.listObj) + { + pair.Value.tDispose(); + } + this.listObj.Clear(); + } + + if (this.listOriginalTextures != null) + { + foreach (KeyValuePair pair in this.listOriginalTextures) + { + string txPath = pair.Key; + CTexture originalTx = pair.Value; + TJAPlayer3.Tx.trackedTextures.TryGetValue(txPath, out CTexture oldTx); + + if (oldTx != originalTx) + { + oldTx.UpdateTexture(TJAPlayer3.app.Device, originalTx.texture, originalTx.sz画像サイズ.Width, originalTx.sz画像サイズ.Height); + } + } + this.listOriginalTextures.Clear(); + } + + if (this.listTextures != null) + { + foreach (KeyValuePair pair in this.listTextures) + { + pair.Value.Dispose(); + } + this.listTextures.Clear(); } + base.On非活性化(); } public override void OnManagedリソースの作成() @@ -6542,8 +8833,17 @@ namespace TJAPlayer3 private int[] n無限管理WAV; private int[] nRESULTIMAGE用優先順位; private int[] nRESULTMOVIE用優先順位; - private int[] nRESULTSOUND用優先順位; - + private int[] nRESULTSOUND用優先順位; + + private CChip currentCamVMoveChip; + private CChip currentCamHMoveChip; + private CChip currentCamRotateChip; + private CChip currentCamZoomChip; + private CChip currentCamVScaleChip; + private CChip currentCamHScaleChip; + + private Dictionary currentObjAnimations; + private void t行のコメント処理(ref string strText) { int nCommentPos = strText.IndexOf("//"); diff --git a/TJAPlayer3/Songs/Extended/CSongObject.cs b/TJAPlayer3/Songs/Extended/CSongObject.cs new file mode 100644 index 00000000..bba1ab1d --- /dev/null +++ b/TJAPlayer3/Songs/Extended/CSongObject.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Diagnostics; +using System.IO; +using SharpDX; +using FDK; + +namespace TJAPlayer3 +{ + class CSongObject + { + public CSongObject(string name, float x, float y, string path) + { + this.name = path; + this.isVisible = false; + + this.x = x; + this.y = y; + this.rotation = 0f; + this.opacity = 255; + this.xScale = 1.0f; + this.yScale = 1.0f; + this.color = new Color4(1f, 1f, 1f, 1f); + this.frame = 0; + + FileAttributes attr = File.GetAttributes(path); + + if ((attr & FileAttributes.Directory) == FileAttributes.Directory) + { + textures = TJAPlayer3.Tx.TxCSongFolder(path); + } + else + { + textures = new CTexture[1]; + textures[0] = TJAPlayer3.Tx.TxCSong(path); + } + } + + public void tStartAnimation(double animInterval, bool loop) + { + counter.t開始(0, textures.Length - 1, animInterval, TJAPlayer3.Timer); + counter.n現在の値 = this.frame; + + this.isLooping = loop; + this.isAnimating = true; + } + + public void tStopAnimation() + { + counter.t停止(); + this.isAnimating = false; + } + + public void tDraw() + { + if (isAnimating) + { + if (isLooping) counter.t進行Loop(); + else + { + counter.t進行(); + if (counter.b終了値に達した) this.tStopAnimation(); + } + + frame = counter.n現在の値; + } + + CTexture tx = this.textures[frame]; + if (frame + 1 > textures.Length) return; + if (tx == null) return; + + tx.fZ軸中心回転 = C変換.DegreeToRadian(this.rotation); + tx.color4 = this.color; + tx.Opacity = this.opacity; + + float screen_ratiox = TJAPlayer3.Skin.Resolution[0] / 1280.0f; + float screen_ratioy = TJAPlayer3.Skin.Resolution[1] / 720.0f; + if (isVisible) tx.t2D描画SongObj(TJAPlayer3.app.Device, (int)(this.x * screen_ratiox), (int)(this.y * screen_ratioy), this.xScale * screen_ratiox, this.yScale * screen_ratioy); + } + + public void tDispose() + { + this.isVisible = false; + foreach (CTexture tx in textures) + { + if (tx != null) tx.Dispose(); + } + } + + private CCounter counter = new CCounter(); + private bool isAnimating; + private bool isLooping; + + public CTexture[] textures; + + public string name; + public bool isVisible; + + public float x; + public float y; + public float rotation; + public int opacity; + public float xScale; + public float yScale; + public Color4 color; + + public int frame; + } +} \ No newline at end of file diff --git a/TJAPlayer3/Stages/01.StartUp/CCharacter.cs b/TJAPlayer3/Stages/01.StartUp/CCharacter.cs index e0820e85..c67ac7a5 100644 --- a/TJAPlayer3/Stages/01.StartUp/CCharacter.cs +++ b/TJAPlayer3/Stages/01.StartUp/CCharacter.cs @@ -11,6 +11,7 @@ namespace TJAPlayer3 class CCharacter { public DBCharacter.CharacterData metadata; + public DBCharacter.CharacterEffect effect; public DBUnlockables.CUnlockConditions unlock; public string _path; @@ -24,6 +25,12 @@ namespace TJAPlayer3 else metadata = new DBCharacter.CharacterData(); + // Character metadata + if (File.Exists($@"{path}\Effects.json")) + effect = ConfigManager.GetConfig($@"{path}\Effects.json"); + else + effect = new DBCharacter.CharacterEffect(); + // Character unlockables if (File.Exists($@"{path}\Unlock.json")) unlock = ConfigManager.GetConfig($@"{path}\Unlock.json"); diff --git a/TJAPlayer3/Stages/01.StartUp/CPuchichara.cs b/TJAPlayer3/Stages/01.StartUp/CPuchichara.cs index 8fd06b40..9fbec8a2 100644 --- a/TJAPlayer3/Stages/01.StartUp/CPuchichara.cs +++ b/TJAPlayer3/Stages/01.StartUp/CPuchichara.cs @@ -15,6 +15,7 @@ namespace TJAPlayer3 public CTexture render; public CSkin.Cシステムサウンド welcome; public DBPuchichara.PuchicharaData metadata; + public DBPuchichara.PuchicharaEffect effect; public DBUnlockables.CUnlockConditions unlock; public string _path; @@ -41,6 +42,12 @@ namespace TJAPlayer3 else metadata = new DBPuchichara.PuchicharaData(); + // Puchichara metadata + if (File.Exists($@"{path}\Effects.json")) + effect = ConfigManager.GetConfig($@"{path}\Effects.json"); + else + effect = new DBPuchichara.PuchicharaEffect(); + // Puchichara unlockables if (File.Exists($@"{path}\Unlock.json")) unlock = ConfigManager.GetConfig($@"{path}\Unlock.json"); diff --git a/TJAPlayer3/Stages/01.StartUp/TextureLoader.cs b/TJAPlayer3/Stages/01.StartUp/TextureLoader.cs index a4ba9f2a..a1e5ca14 100644 --- a/TJAPlayer3/Stages/01.StartUp/TextureLoader.cs +++ b/TJAPlayer3/Stages/01.StartUp/TextureLoader.cs @@ -71,6 +71,8 @@ namespace TJAPlayer3 const string ROLL = @"Roll\"; const string SPLASH = @"Splash\"; + public Dictionary trackedTextures = new Dictionary(); + public TextureLoader() { @@ -109,6 +111,33 @@ namespace TJAPlayer3 return TJAPlayer3.tテクスチャの生成(CSkin.Path(BASE + GAME + GENRE + FileName + ".png")); } + internal CTexture TxCSong(string path) + { + return TxCUntrackedSong(path); + } + + private CTexture[] TxCSong(int count, string format, int start = 0) + { + return TxCSong(format, Enumerable.Range(start, count).Select(o => o.ToString()).ToArray()); + } + + private CTexture[] TxCSong(string format, params string[] parts) + { + return parts.Select(o => TxCSong(string.Format(format, o))).ToArray(); + } + + public CTexture[] TxCSongFolder(string folder) + { + var count = TJAPlayer3.t連番画像の枚数を数える(folder); + var texture = count == 0 ? null : TxCSong(count, folder + "{0}.png"); + return texture; + } + + internal CTexture TxCUntrackedSong(string path) + { + return TJAPlayer3.tテクスチャの生成(path); + } + public void LoadTexture() { #region 共通 @@ -400,6 +429,7 @@ namespace TJAPlayer3 Note_Swap = TxC(GAME + @"Swap.png"); Note_Kusu = TxC(GAME + @"Kusu.png"); Note_FuseRoll = TxC(GAME + @"FuseRoll.png"); + Note_Adlib = TxC(GAME + @"Adlib.png"); Judge_Frame = TxC(GAME + @"Notes.png"); @@ -2204,6 +2234,7 @@ namespace TJAPlayer3 Note_Swap, Note_Kusu, Note_FuseRoll, + Note_Adlib, SENotesExtension, Notes_Arm, ChipEffect, diff --git a/TJAPlayer3/Stages/06.SongLoading/CStage曲読み込み.cs b/TJAPlayer3/Stages/06.SongLoading/CStage曲読み込み.cs index 73a0a8dd..0e06b861 100644 --- a/TJAPlayer3/Stages/06.SongLoading/CStage曲読み込み.cs +++ b/TJAPlayer3/Stages/06.SongLoading/CStage曲読み込み.cs @@ -503,6 +503,15 @@ namespace TJAPlayer3 if (TJAPlayer3.ConfigIni.nPlayerCount >= 5) TJAPlayer3.DTX_5P = new CDTX(str, false, 1.0, ini.stファイル.BGMAdjust, 0, 4, true, TJAPlayer3.stage選曲.n確定された曲の難易度[4]); + if (TJAPlayer3.DTX.listErrors.Count != 0) + { + string message = ""; + foreach (var text in TJAPlayer3.DTX.listErrors) + { + System.Windows.Forms.MessageBox.Show(text, "譜面にエラーが見つかりました"); + } + } + Trace.TraceInformation( "---- Song information -----------------" ); Trace.TraceInformation( "TITLE: {0}", TJAPlayer3.DTX.TITLE ); Trace.TraceInformation( "FILE: {0}", TJAPlayer3.DTX.strファイル名の絶対パス ); diff --git a/TJAPlayer3/Stages/07.Game/CAct演奏ゲージ共通.cs b/TJAPlayer3/Stages/07.Game/CAct演奏ゲージ共通.cs index 2070e39d..031e271e 100644 --- a/TJAPlayer3/Stages/07.Game/CAct演奏ゲージ共通.cs +++ b/TJAPlayer3/Stages/07.Game/CAct演奏ゲージ共通.cs @@ -111,8 +111,20 @@ namespace TJAPlayer3 //ダメージ値の計算は太鼓の達人譜面Wikiのものを参考にしました。 for (int i = 0; i < 5; i++) - { - this.db現在のゲージ値[i] = 0; + { + var chara = TJAPlayer3.Tx.Characters[TJAPlayer3.SaveFileInstances[TJAPlayer3.GetActualPlayer(nPlayer)].data.Character]; + switch(chara.effect.Gauge) + { + case "Normal": + this.db現在のゲージ値[i] = 0; + break; + case "Hard": + this.db現在のゲージ値[i] = 100; + break; + case "Extreme": + this.db現在のゲージ値[i] = 100; + break; + } } //ゲージのMAXまでの最低コンボ数を計算 @@ -330,14 +342,42 @@ namespace TJAPlayer3 } for (int i = 0; i < 3; i++) - { - dbゲージ増加量[i][nPlayer] = increase[i]; + { + var chara = TJAPlayer3.Tx.Characters[TJAPlayer3.SaveFileInstances[TJAPlayer3.GetActualPlayer(nPlayer)].data.Character]; + switch (chara.effect.Gauge) + { + case "Normal": + dbゲージ増加量[i][nPlayer] = increase[i]; + break; + case "Hard": + dbゲージ増加量[i][nPlayer] = increase[i] / 2.0f; + break; + case "Extreme": + dbゲージ増加量[i][nPlayer] = increase[i] / 4.0f; + break; + } } for (int i = 0; i < 3; i++) - { - dbゲージ増加量_Branch[i, 0][nPlayer] = increaseBranch[i, 0]; - dbゲージ増加量_Branch[i, 1][nPlayer] = increaseBranch[i, 1]; - dbゲージ増加量_Branch[i, 2][nPlayer] = increaseBranch[i, 2]; + { + var chara = TJAPlayer3.Tx.Characters[TJAPlayer3.SaveFileInstances[TJAPlayer3.GetActualPlayer(nPlayer)].data.Character]; + switch (chara.effect.Gauge) + { + case "Normal": + dbゲージ増加量_Branch[i, 0][nPlayer] = increaseBranch[i, 0]; + dbゲージ増加量_Branch[i, 1][nPlayer] = increaseBranch[i, 1]; + dbゲージ増加量_Branch[i, 2][nPlayer] = increaseBranch[i, 2]; + break; + case "Hard": + dbゲージ増加量_Branch[i, 0][nPlayer] = increaseBranch[i, 0] / 2.0f; + dbゲージ増加量_Branch[i, 1][nPlayer] = increaseBranch[i, 1] / 2.0f; + dbゲージ増加量_Branch[i, 2][nPlayer] = increaseBranch[i, 2] / 2.0f; + break; + case "Extreme": + dbゲージ増加量_Branch[i, 0][nPlayer] = increaseBranch[i, 0] / 4.0f; + dbゲージ増加量_Branch[i, 1][nPlayer] = increaseBranch[i, 1] / 4.0f; + dbゲージ増加量_Branch[i, 2][nPlayer] = increaseBranch[i, 2] / 4.0f; + break; + } } #endregion } @@ -425,10 +465,20 @@ namespace TJAPlayer3 else fDamage = this.dbゲージ増加量[2][nPlayer]; - if (fDamage >= 0) { fDamage = -fDamage; + } + + var chara = TJAPlayer3.Tx.Characters[TJAPlayer3.SaveFileInstances[TJAPlayer3.GetActualPlayer(nPlayer)].data.Character]; + switch (chara.effect.Gauge) + { + case "Hard": + fDamage = -25; + break; + case "Extreme": + fDamage = -50; + break; } if (this.bRisky) diff --git a/TJAPlayer3/Stages/07.Game/CStage演奏画面共通.cs b/TJAPlayer3/Stages/07.Game/CStage演奏画面共通.cs index 55ccdf9f..e29fb913 100644 --- a/TJAPlayer3/Stages/07.Game/CStage演奏画面共通.cs +++ b/TJAPlayer3/Stages/07.Game/CStage演奏画面共通.cs @@ -400,6 +400,8 @@ namespace TJAPlayer3 this.bLEVELHOLD = new bool[]{ false, false, false, false, false }; this.JPOSCROLLX = new int[5]; this.JPOSCROLLY = new int[5]; + eFirstGameType = new EGameType[5]; + bSplitLane = new bool[5]; // Double play set here @@ -418,6 +420,7 @@ namespace TJAPlayer3 for (int i = 0; i < TJAPlayer3.ConfigIni.nPlayerCount; i++) { actGauge.Init(TJAPlayer3.ConfigIni.nRisky, i); // #23559 2011.7.28 yyagi + eFirstGameType[i] = TJAPlayer3.ConfigIni.nGameType[i]; } this.nPolyphonicSounds = TJAPlayer3.ConfigIni.nPoliphonicSounds; e判定表示優先度 = TJAPlayer3.ConfigIni.e判定表示優先度; @@ -488,11 +491,27 @@ namespace TJAPlayer3 // this.gclatencymode = GCSettings.LatencyMode; // GCSettings.LatencyMode = GCLatencyMode.Batch; // 演奏画面中はGCを抑止する this.bIsAlreadyCleared = new bool[5]; + for (int player = 0; player < TJAPlayer3.ConfigIni.nPlayerCount; player++) + { + var chara = TJAPlayer3.Tx.Characters[TJAPlayer3.SaveFileInstances[TJAPlayer3.GetActualPlayer(player)].data.Character]; + switch (chara.effect.Gauge) + { + case "Normal": + bIsAlreadyCleared[player] = false; + break; + case "Hard": + case "Extreme": + bIsAlreadyCleared[player] = true; + break; + } + } this.bIsAlreadyMaxed = new bool[5]; this.ListDan_Number = 0; this.IsDanFailed = false; - } + + this.objHandlers = new Dictionary(); + } public void ftDanReSetScoreNiji(int songNotes, int ballons) @@ -528,10 +547,27 @@ namespace TJAPlayer3 this.ctチップ模様アニメ.Bass = null; this.ctチップ模様アニメ.Taiko = null; + this.ctCamHMove = null; + this.ctCamVMove = null; + this.ctCamHScale = null; + this.ctCamVScale = null; + this.ctCamRotation = null; + this.ctCamZoom = null; + + TJAPlayer3.borderColor = new SharpDX.Color4(0f, 0f, 0f, 0f); + TJAPlayer3.fCamXOffset = 0.0f; + TJAPlayer3.fCamYOffset = 0.0f; + TJAPlayer3.fCamXScale = 1.0f; + TJAPlayer3.fCamYScale = 1.0f; + TJAPlayer3.fCamRotation = 0.0f; + TJAPlayer3.fCamZoomFactor = 1.0f; + for (int i = 0; i < 5; i++) { ctChipAnime[i] = null; ctChipAnimeLag[i] = null; + TJAPlayer3.ConfigIni.nGameType[i] = eFirstGameType[i]; + bSplitLane[i] = false; } listWAV.Clear(); @@ -876,6 +912,8 @@ namespace TJAPlayer3 protected int nWaitButton; protected int[] nStoredHit; + private EGameType[] eFirstGameType; + protected bool[] bSplitLane; public CDTX.CChip[] chip現在処理中の連打チップ = new CDTX.CChip[ 5 ]; @@ -1653,7 +1691,7 @@ namespace TJAPlayer3 { return tチップのヒット処理( nHitTime, pChip, screenmode, bCorrectLane, nNowInput, 0 ); } - protected unsafe E判定 tチップのヒット処理(long nHitTime, CDTX.CChip pChip, E楽器パート screenmode, bool bCorrectLane, int nNowInput, int nPlayer) + protected unsafe E判定 tチップのヒット処理(long nHitTime, CDTX.CChip pChip, E楽器パート screenmode, bool bCorrectLane, int nNowInput, int nPlayer, bool rollEffectHit = false) { //unsafeコードにつき、デバッグ中の変更厳禁! @@ -1697,16 +1735,18 @@ namespace TJAPlayer3 if (!bAutoPlay && eJudgeResult != E判定.Miss) { CLagLogger.Add(nPlayer, pChip); - } + } + + var puchichara = TJAPlayer3.Tx.Puchichara[PuchiChara.tGetPuchiCharaIndexByName(TJAPlayer3.GetActualPlayer(nPlayer))]; if (NotesManager.IsRoll(pChip)) { #region[ Drumroll ] //--------------------------- this.b連打中[nPlayer] = true; - if (bAutoPlay) + if (bAutoPlay || rollEffectHit) { - int rollSpeed = TJAPlayer3.ConfigIni.nRollsPerSec; + int rollSpeed = bAutoPlay ? TJAPlayer3.ConfigIni.nRollsPerSec : puchichara.effect.Autoroll; if (TJAPlayer3.ConfigIni.bAIBattleMode && nPlayer == 1) rollSpeed = TJAPlayer3.ConfigIni.apAIPerformances[TJAPlayer3.ConfigIni.nAILevel - 1].nRollSpeed; @@ -1740,7 +1780,7 @@ namespace TJAPlayer3 } } } - else + if (!bAutoPlay && !rollEffectHit) { this.eRollState = E連打State.roll; this.tRollProcess(pChip, (CSound管理.rc演奏用タイマ.n現在時刻 * (((double)TJAPlayer3.ConfigIni.n演奏速度) / 20.0)), 1, nNowInput, 0, nPlayer); @@ -1757,7 +1797,7 @@ namespace TJAPlayer3 this.b連打中[nPlayer] = true; this.actChara.b風船連打中[nPlayer] = true; - if (bAutoPlay) + if (bAutoPlay || rollEffectHit) { bool IsKusudama = NotesManager.IsKusudama(pChip); @@ -1777,14 +1817,12 @@ namespace TJAPlayer3 if (balloon != 0 && this.bPAUSE == false) { - int rollSpeed = TJAPlayer3.ConfigIni.nRollsPerSec; - if (TJAPlayer3.ConfigIni.bAIBattleMode && nPlayer == 1) - rollSpeed = TJAPlayer3.ConfigIni.apAIPerformances[TJAPlayer3.ConfigIni.nAILevel - 1].nRollSpeed; + int rollSpeed = bAutoPlay ? balloon : puchichara.effect.Autoroll; - int balloonDuration = (pChip.nノーツ終了時刻ms - pChip.n発声時刻ms); + int balloonDuration = bAutoPlay ? (pChip.nノーツ終了時刻ms - pChip.n発声時刻ms) : 1000; if ((CSound管理.rc演奏用タイマ.n現在時刻 * (((double)TJAPlayer3.ConfigIni.n演奏速度) / 20.0)) > - (pChip.n発声時刻ms + (balloonDuration / balloon) * rollCount)) + (pChip.n発声時刻ms + (balloonDuration / (double)rollSpeed) * rollCount)) { if (this.nHand[nPlayer] == 0) this.nHand[nPlayer]++; @@ -1798,7 +1836,7 @@ namespace TJAPlayer3 } } } - else + if (!bAutoPlay && !rollEffectHit) { this.tBalloonProcess(pChip, (CSound管理.rc演奏用タイマ.n現在時刻 * (((double)TJAPlayer3.ConfigIni.n演奏速度) / 20.0)), nPlayer); } @@ -1881,6 +1919,19 @@ namespace TJAPlayer3 } } + var chara = TJAPlayer3.Tx.Characters[TJAPlayer3.SaveFileInstances[TJAPlayer3.GetActualPlayer(nPlayer)].data.Character]; + bool cleared = false; + switch (chara.effect.Gauge) + { + case "Normal": + cleared = (int)actGauge.db現在のゲージ値[nPlayer] >= 80; + break; + case "Hard": + case "Extreme": + cleared = (int)actGauge.db現在のゲージ値[nPlayer] > 0; + break; + } + if (eJudgeResult != E判定.Poor && eJudgeResult != E判定.Miss) { double dbUnit = (((60.0 / (TJAPlayer3.stage演奏ドラム画面.actPlayInfo.dbBPM[nPlayer])))); @@ -1898,7 +1949,7 @@ namespace TJAPlayer3 } this.bIsAlreadyMaxed[nPlayer] = true; } - if ((int)actGauge.db現在のゲージ値[nPlayer] >= 80 && this.bIsAlreadyCleared[nPlayer] == false) + if (cleared && this.bIsAlreadyCleared[nPlayer] == false) { if(TJAPlayer3.Skin.Characters_Become_Cleared_Ptn[Character] != 0 && actChara.CharaAction_Balloon_Delay[nPlayer].b終了値に達した) { @@ -1917,11 +1968,22 @@ namespace TJAPlayer3 { this.bIsAlreadyMaxed[nPlayer] = false; } - if ((int)actGauge.db現在のゲージ値[nPlayer] < 80 && this.bIsAlreadyCleared[nPlayer] == true) + if (!cleared && this.bIsAlreadyCleared[nPlayer] == true) { this.bIsAlreadyCleared[nPlayer] = false; TJAPlayer3.stage演奏ドラム画面.actBackground.ClearOut(nPlayer); - //CDTXMania.stage演奏ドラム画面.actBackground.ClearIn(nPlayer); + + switch (chara.effect.Gauge) + { + case "Hard": + case "Extreme": + { + CSound管理.rc演奏用タイマ.t一時停止(); + TJAPlayer3.DTX.t全チップの再生停止(); + ifp[nPlayer] = true; + } + break; + } } cInvisibleChip.ShowChipTemporally( pChip.e楽器パート ); } @@ -3871,49 +3933,361 @@ namespace TJAPlayer3 this.bIsGOGOTIME[ nPlayer ] = false; } break; -#endregion + #endregion -#region [ a0-a8: EmptySlot ] - case 0xa0: - case 0xa1: - case 0xa2: - case 0xa3: - case 0xa4: - case 0xa5: - case 0xa6: - case 0xa7: - case 0xa8: + #region [ EXTENDED COMMANDS ] + case 0xa0: //camera vertical move start + if (!pChip.bHit && (pChip.nバーからの距離dot.Drums < 0)) + { + pChip.bHit = true; + this.currentCamVMoveChip = pChip; + this.ctCamVMove = new CCounter(0, pChip.fCamTimeMs, 1, TJAPlayer3.Timer); + } break; -#endregion -#region [ B1~BC EmptySlot ] - case 0xb1: - case 0xb2: - case 0xb3: - case 0xb4: - case 0xb5: - case 0xb6: - case 0xb7: - case 0xb8: - case 0xb9: - case 0xba: - case 0xbb: - case 0xbc: - break; -#endregion -#region [ c4, c7, d5-d9: EmptySlot ] - case 0xc4: - case 0xc7: - case 0xd5: - case 0xd6: // BGA画像入れ替え - case 0xd7: + case 0xa1: //camera vertical move end + if (!pChip.bHit && (pChip.nバーからの距離dot.Drums < 0)) + { + pChip.bHit = true; + } + break; + case 0xa2: //camera horizontal move start + if (!pChip.bHit && (pChip.nバーからの距離dot.Drums < 0)) + { + pChip.bHit = true; + this.currentCamHMoveChip = pChip; + this.ctCamHMove = new CCounter(0, pChip.fCamTimeMs, 1, TJAPlayer3.Timer); + } + break; + case 0xa3: //camera horizontal move end + if (!pChip.bHit && (pChip.nバーからの距離dot.Drums < 0)) + { + pChip.bHit = true; + } + break; + case 0xa4: //camera zoom start + if (!pChip.bHit && (pChip.nバーからの距離dot.Drums < 0)) + { + pChip.bHit = true; + this.currentCamZoomChip = pChip; + this.ctCamZoom = new CCounter(0, pChip.fCamTimeMs, 1, TJAPlayer3.Timer); + } + break; + case 0xa5: //camera zoom end + if (!pChip.bHit && (pChip.nバーからの距離dot.Drums < 0)) + { + pChip.bHit = true; + } + break; + case 0xa6: //camera rotation start + if (!pChip.bHit && (pChip.nバーからの距離dot.Drums < 0)) + { + pChip.bHit = true; + this.currentCamRotateChip = pChip; + this.ctCamRotation = new CCounter(0, pChip.fCamTimeMs, 1, TJAPlayer3.Timer); + } + break; + case 0xa7: //camera rotation end + if (!pChip.bHit && (pChip.nバーからの距離dot.Drums < 0)) + { + pChip.bHit = true; + } + break; + case 0xa8: //camera vertical scaling start + if (!pChip.bHit && (pChip.nバーからの距離dot.Drums < 0)) + { + pChip.bHit = true; + this.currentCamVScaleChip = pChip; + this.ctCamVScale = new CCounter(0, pChip.fCamTimeMs, 1, TJAPlayer3.Timer); + } + break; + case 0xa9: //camera vertical scaling end + if (!pChip.bHit && (pChip.nバーからの距離dot.Drums < 0)) + { + pChip.bHit = true; + } + break; + case 0xb0: //camera horizontal scaling start + if (!pChip.bHit && (pChip.nバーからの距離dot.Drums < 0)) + { + pChip.bHit = true; + this.currentCamHScaleChip = pChip; + this.ctCamHScale = new CCounter(0, pChip.fCamTimeMs, 1, TJAPlayer3.Timer); + } + break; + case 0xb1: //camera horizontal scaling end + if (!pChip.bHit && (pChip.nバーからの距離dot.Drums < 0)) + { + pChip.bHit = true; + } + break; + case 0xb2: //change border color + if (!pChip.bHit && (pChip.nバーからの距離dot.Drums < 0)) + { + pChip.bHit = true; + TJAPlayer3.borderColor = pChip.borderColor; + } + break; + case 0xb3: //set camera x offset + if (!pChip.bHit && (pChip.nバーからの距離dot.Drums < 0)) + { + pChip.bHit = true; + + this.currentCamHMoveChip = pChip; + this.ctCamHMove = new CCounter(0, 0, 1, TJAPlayer3.Timer); + } + break; + case 0xb4: //set camera y offset + if (!pChip.bHit && (pChip.nバーからの距離dot.Drums < 0)) + { + pChip.bHit = true; + + this.currentCamVMoveChip = pChip; + this.ctCamVMove = new CCounter(0, 0, 1, TJAPlayer3.Timer); + } + break; + case 0xb5: //set camera zoom factor + if (!pChip.bHit && (pChip.nバーからの距離dot.Drums < 0)) + { + pChip.bHit = true; + + this.currentCamZoomChip = pChip; + this.ctCamZoom = new CCounter(0, 0, 1, TJAPlayer3.Timer); + } + break; + case 0xb6: //set camera rotation + if (!pChip.bHit && (pChip.nバーからの距離dot.Drums < 0)) + { + pChip.bHit = true; + + this.currentCamRotateChip = pChip; + this.ctCamRotation = new CCounter(0, 0, 1, TJAPlayer3.Timer); + } + break; + case 0xb7: //set camera x scale + if (!pChip.bHit && (pChip.nバーからの距離dot.Drums < 0)) + { + pChip.bHit = true; + + this.currentCamHScaleChip = pChip; + this.ctCamHScale = new CCounter(0, 0, 1, TJAPlayer3.Timer); + } + break; + case 0xb8: //set camera y scale + if (!pChip.bHit && (pChip.nバーからの距離dot.Drums < 0)) + { + pChip.bHit = true; + + this.currentCamVScaleChip = pChip; + this.ctCamVScale = new CCounter(0, 0, 1, TJAPlayer3.Timer); + } + break; + case 0xb9: //reset camera + if (!pChip.bHit && (pChip.nバーからの距離dot.Drums < 0)) + { + pChip.bHit = true; + + TJAPlayer3.borderColor = new SharpDX.Color4(0f, 0f, 0f, 0f); + + this.currentCamVMoveChip = pChip; + this.currentCamHMoveChip = pChip; + + this.currentCamZoomChip = pChip; + this.currentCamRotateChip = pChip; + + this.currentCamVScaleChip = pChip; + this.currentCamHScaleChip = pChip; + + this.ctCamVMove = new CCounter(0, 0, 1, TJAPlayer3.Timer); + this.ctCamHMove = new CCounter(0, 0, 1, TJAPlayer3.Timer); + + this.ctCamZoom = new CCounter(0, 0, 1, TJAPlayer3.Timer); + this.ctCamRotation = new CCounter(0, 0, 1, TJAPlayer3.Timer); + + this.ctCamVScale = new CCounter(0, 0, 1, TJAPlayer3.Timer); + this.ctCamHScale = new CCounter(0, 0, 1, TJAPlayer3.Timer); + } + break; + case 0xba: //enable doron + if (!pChip.bHit && (pChip.nバーからの距離dot.Drums < 0)) + { + pChip.bHit = true; + bCustomDoron = true; + } + break; + case 0xbb: //disable doron + if (!pChip.bHit && (pChip.nバーからの距離dot.Drums < 0)) + { + pChip.bHit = true; + bCustomDoron = false; + } + break; + case 0xbc: //add object + if (!pChip.bHit && (pChip.nバーからの距離dot.Drums < 0)) + { + pChip.bHit = true; + + dTX.listObj.TryGetValue(pChip.strObjName, out CSongObject obj); + obj.x = pChip.fObjX; + obj.y = pChip.fObjY; + obj.isVisible = true; + } + break; + case 0xbd: //remove object + if (!pChip.bHit && (pChip.nバーからの距離dot.Drums < 0)) + { + pChip.bHit = true; + + dTX.listObj.TryGetValue(pChip.strObjName, out CSongObject obj); + obj.isVisible = false; + } + break; + case 0xbe: //object animation start + case 0xc0: + case 0xc2: + case 0xc4: + case 0xc6: + case 0xc8: + if (!pChip.bHit && (pChip.nバーからの距離dot.Drums < 0)) + { + pChip.bHit = true; + + dTX.listObj.TryGetValue(pChip.strObjName, out pChip.obj); + objHandlers.Add(pChip, new CCounter(0, pChip.fObjTimeMs, 1, TJAPlayer3.Timer)); + } + break; + case 0xbf: //object animation end + case 0xc1: + case 0xc3: + case 0xc5: + case 0xc7: + case 0xc9: + if (!pChip.bHit && (pChip.nバーからの距離dot.Drums < 0)) + { + pChip.bHit = true; + } + break; + case 0xca: //set object color + if (!pChip.bHit && (pChip.nバーからの距離dot.Drums < 0)) + { + pChip.bHit = true; + + dTX.listObj.TryGetValue(pChip.strObjName, out CSongObject obj); + obj.color = pChip.borderColor; + } + break; + case 0xcb: //set object y + case 0xcc: //set object x + case 0xcd: //set object vertical scale + case 0xce: //set object horizontal scale + case 0xcf: //set object rotation + case 0xd0: //set object opacity + if (!pChip.bHit && (pChip.nバーからの距離dot.Drums < 0)) + { + pChip.bHit = true; + + dTX.listObj.TryGetValue(pChip.strObjName, out pChip.obj); + objHandlers.Add(pChip, new CCounter(0, 0, 1, TJAPlayer3.Timer)); + } + break; + case 0xd1: //change texture + if (!pChip.bHit && (pChip.nバーからの距離dot.Drums < 0)) + { + pChip.bHit = true; + + if (TJAPlayer3.Tx.trackedTextures.ContainsKey(pChip.strTargetTxName)) + { + TJAPlayer3.Tx.trackedTextures.TryGetValue(pChip.strTargetTxName, out CTexture oldTx); + dTX.listTextures.TryGetValue(pChip.strNewPath, out CTexture newTx); + + newTx.Opacity = oldTx.Opacity; + newTx.fZ軸中心回転 = oldTx.fZ軸中心回転; + newTx.vc拡大縮小倍率 = oldTx.vc拡大縮小倍率; + + oldTx.UpdateTexture(TJAPlayer3.app.Device, newTx.texture, newTx.sz画像サイズ.Width, newTx.sz画像サイズ.Height); + } + } + break; + case 0xd2: //reset texture + if (!pChip.bHit && (pChip.nバーからの距離dot.Drums < 0)) + { + pChip.bHit = true; + + if (TJAPlayer3.Tx.trackedTextures.ContainsKey(pChip.strTargetTxName)) + { + TJAPlayer3.Tx.trackedTextures.TryGetValue(pChip.strTargetTxName, out CTexture oldTx); + dTX.listOriginalTextures.TryGetValue(pChip.strTargetTxName, out CTexture originalTx); + + originalTx.Opacity = oldTx.Opacity; + originalTx.fZ軸中心回転 = oldTx.fZ軸中心回転; + originalTx.vc拡大縮小倍率 = oldTx.vc拡大縮小倍率; + + oldTx.UpdateTexture(TJAPlayer3.app.Device, originalTx.texture, originalTx.sz画像サイズ.Width, originalTx.sz画像サイズ.Height); + } + } + break; + case 0xd3: //set config + if (!pChip.bHit && (pChip.nバーからの距離dot.Drums < 0)) + { + pChip.bHit = true; + string[] split = pChip.strConfigValue.Split('='); + + //TJAPlayer3.Skin.t文字列から読み込み(pChip.strConfigValue, split[0]); + bConfigUpdated = true; + } + break; + case 0xd4: //start object animation + if (!pChip.bHit && (pChip.nバーからの距離dot.Drums < 0)) + { + pChip.bHit = true; + dTX.listObj.TryGetValue(pChip.strObjName, out CSongObject obj); + + obj.tStartAnimation(pChip.dbAnimInterval, false); + } + break; + case 0xd5: //start object animation (looping) + if (!pChip.bHit && (pChip.nバーからの距離dot.Drums < 0)) + { + pChip.bHit = true; + dTX.listObj.TryGetValue(pChip.strObjName, out CSongObject obj); + + obj.tStartAnimation(pChip.dbAnimInterval, true); + } + break; + case 0xd6: //end object animation + if (!pChip.bHit && (pChip.nバーからの距離dot.Drums < 0)) + { + pChip.bHit = true; + dTX.listObj.TryGetValue(pChip.strObjName, out CSongObject obj); + + obj.tStopAnimation(); + } + break; + case 0xd7: //set object frame + if (!pChip.bHit && (pChip.nバーからの距離dot.Drums < 0)) + { + pChip.bHit = true; + dTX.listObj.TryGetValue(pChip.strObjName, out CSongObject obj); + + obj.frame = pChip.intFrame; + } + break; + #endregion + +#region [ d8-d9: EXTENDED2 ] case 0xd8: - case 0xd9: - //case 0xe0: - if ( !pChip.bHit && ( pChip.nバーからの距離dot.Drums < 0 ) ) - { - pChip.bHit = true; - } - break; + if (!pChip.bHit && (pChip.nバーからの距離dot.Drums < 0)) + { + TJAPlayer3.ConfigIni.nGameType[nPlayer] = pChip.eGameType; + pChip.bHit = true; + } + break; + case 0xd9: + if (!pChip.bHit && (pChip.nバーからの距離dot.Drums < 0)) + { + bSplitLane[nPlayer] = true; + pChip.bHit = true; + } + break; #endregion #region [ da: ミキサーへチップ音追加 ] @@ -4088,10 +4462,27 @@ namespace TJAPlayer3 return true; } break; -#endregion + #endregion -#region [ その他(未定義) ] - default: + #region [ d8-d9: EXTENDED2 ] + case 0xe3: + if (!pChip.bHit && (pChip.nバーからの距離dot.Drums < 0)) + { + bSplitLane[nPlayer] = false; + pChip.bHit = true; + } + break; + case 0xe4: + if (!pChip.bHit && (pChip.nバーからの距離dot.Taiko < 0)) + { + pChip.bHit = true; + } + this.t進行描画_チップ_小節線(configIni, ref dTX, ref pChip, nPlayer); + break; + #endregion + + #region [ その他(未定義) ] + default: if ( !pChip.bHit && ( pChip.nバーからの距離dot.Drums < 0 ) ) { pChip.bHit = true; @@ -4101,7 +4492,146 @@ namespace TJAPlayer3 } } - return false; + + + #region [ EXTENDED CONTROLS ] + if (ctCamVMove != null) //vertical camera move + { + ctCamVMove.t進行(); + float value = 0.0f; + if (currentCamVMoveChip.strCamEaseType.Equals("IN")) value = easing.EaseIn(ctCamVMove, currentCamVMoveChip.fCamScrollStartY, currentCamVMoveChip.fCamScrollEndY, currentCamVMoveChip.fCamMoveType); + if (currentCamVMoveChip.strCamEaseType.Equals("OUT")) value = easing.EaseOut(ctCamVMove, currentCamVMoveChip.fCamScrollStartY, currentCamVMoveChip.fCamScrollEndY, currentCamVMoveChip.fCamMoveType); + if (currentCamVMoveChip.strCamEaseType.Equals("IN_OUT")) value = easing.EaseInOut(ctCamVMove, currentCamVMoveChip.fCamScrollStartY, currentCamVMoveChip.fCamScrollEndY, currentCamVMoveChip.fCamMoveType); + TJAPlayer3.fCamYOffset = float.IsNaN(value) ? currentCamVMoveChip.fCamScrollStartY : value; + + if (ctCamVMove.b終了値に達した) + { + ctCamVMove = null; + TJAPlayer3.fCamYOffset = currentCamVMoveChip.fCamScrollEndY; + } + } + + if (ctCamHMove != null) //horizontal camera move + { + ctCamHMove.t進行(); + float value = 0.0f; + if (currentCamHMoveChip.strCamEaseType.Equals("IN")) value = easing.EaseIn(ctCamHMove, currentCamHMoveChip.fCamScrollStartX, currentCamHMoveChip.fCamScrollEndX, currentCamHMoveChip.fCamMoveType); + if (currentCamHMoveChip.strCamEaseType.Equals("OUT")) value = easing.EaseOut(ctCamHMove, currentCamHMoveChip.fCamScrollStartX, currentCamHMoveChip.fCamScrollEndX, currentCamHMoveChip.fCamMoveType); + if (currentCamHMoveChip.strCamEaseType.Equals("IN_OUT")) value = easing.EaseInOut(ctCamHMove, currentCamHMoveChip.fCamScrollStartX, currentCamHMoveChip.fCamScrollEndX, currentCamHMoveChip.fCamMoveType); + TJAPlayer3.fCamXOffset = float.IsNaN(value) ? currentCamHMoveChip.fCamScrollStartX : value; + + if (ctCamHMove.b終了値に達した) + { + ctCamHMove = null; + TJAPlayer3.fCamXOffset = currentCamHMoveChip.fCamScrollEndX; + } + } + + if (ctCamZoom != null) //camera zoom + { + ctCamZoom.t進行(); + float value = 0.0f; + if (currentCamZoomChip.strCamEaseType.Equals("IN")) value = easing.EaseIn(ctCamZoom, currentCamZoomChip.fCamZoomStart, currentCamZoomChip.fCamZoomEnd, currentCamZoomChip.fCamMoveType); + if (currentCamZoomChip.strCamEaseType.Equals("OUT")) value = easing.EaseOut(ctCamZoom, currentCamZoomChip.fCamZoomStart, currentCamZoomChip.fCamZoomEnd, currentCamZoomChip.fCamMoveType); + if (currentCamZoomChip.strCamEaseType.Equals("IN_OUT")) value = easing.EaseInOut(ctCamZoom, currentCamZoomChip.fCamZoomStart, currentCamZoomChip.fCamZoomEnd, currentCamZoomChip.fCamMoveType); + TJAPlayer3.fCamZoomFactor = float.IsNaN(value) ? currentCamZoomChip.fCamZoomStart : value; + + if (ctCamZoom.b終了値に達した) + { + ctCamZoom = null; + TJAPlayer3.fCamZoomFactor = currentCamZoomChip.fCamZoomEnd; + } + } + + if (ctCamRotation != null) //camera rotation + { + ctCamRotation.t進行(); + float value = 0.0f; + if (currentCamRotateChip.strCamEaseType.Equals("IN")) value = easing.EaseIn(ctCamRotation, currentCamRotateChip.fCamRotationStart, currentCamRotateChip.fCamRotationEnd, currentCamRotateChip.fCamMoveType); + if (currentCamRotateChip.strCamEaseType.Equals("OUT")) value = easing.EaseOut(ctCamRotation, currentCamRotateChip.fCamRotationStart, currentCamRotateChip.fCamRotationEnd, currentCamRotateChip.fCamMoveType); + if (currentCamRotateChip.strCamEaseType.Equals("IN_OUT")) value = easing.EaseInOut(ctCamRotation, currentCamRotateChip.fCamRotationStart, currentCamRotateChip.fCamRotationEnd, currentCamRotateChip.fCamMoveType); + TJAPlayer3.fCamRotation = float.IsNaN(value) ? currentCamRotateChip.fCamRotationStart : value; + + if (ctCamRotation.b終了値に達した) + { + ctCamRotation = null; + TJAPlayer3.fCamRotation = currentCamRotateChip.fCamRotationEnd; + } + } + + if (ctCamVScale != null) //vertical camera scaling + { + ctCamVScale.t進行(); + float value = 0.0f; + if (currentCamVScaleChip.strCamEaseType.Equals("IN")) value = easing.EaseIn(ctCamVScale, currentCamVScaleChip.fCamScaleStartY, currentCamVScaleChip.fCamScaleEndY, currentCamVScaleChip.fCamMoveType); + if (currentCamVScaleChip.strCamEaseType.Equals("OUT")) value = easing.EaseOut(ctCamVScale, currentCamVScaleChip.fCamScaleStartY, currentCamVScaleChip.fCamScaleEndY, currentCamVScaleChip.fCamMoveType); + if (currentCamVScaleChip.strCamEaseType.Equals("IN_OUT")) value = easing.EaseInOut(ctCamVScale, currentCamVScaleChip.fCamScaleStartY, currentCamVScaleChip.fCamScaleEndY, currentCamVScaleChip.fCamMoveType); + TJAPlayer3.fCamYScale = float.IsNaN(value) ? currentCamVScaleChip.fCamScaleStartY : value; + + if (ctCamVScale.b終了値に達した) + { + ctCamVScale = null; + TJAPlayer3.fCamYScale = currentCamVScaleChip.fCamScaleEndY; + } + } + + if (ctCamHScale != null) //horizontal camera scaling + { + ctCamHScale.t進行(); + float value = 0.0f; + if (currentCamHScaleChip.strCamEaseType.Equals("IN")) value = easing.EaseIn(ctCamHScale, currentCamHScaleChip.fCamScaleStartX, currentCamHScaleChip.fCamScaleEndX, currentCamHScaleChip.fCamMoveType); + if (currentCamHScaleChip.strCamEaseType.Equals("OUT")) value = easing.EaseOut(ctCamHScale, currentCamHScaleChip.fCamScaleStartX, currentCamHScaleChip.fCamScaleEndX, currentCamHScaleChip.fCamMoveType); + if (currentCamHScaleChip.strCamEaseType.Equals("IN_OUT")) value = easing.EaseInOut(ctCamHScale, currentCamHScaleChip.fCamScaleStartX, currentCamHScaleChip.fCamScaleEndX, currentCamHScaleChip.fCamMoveType); + TJAPlayer3.fCamXScale = float.IsNaN(value) ? currentCamHScaleChip.fCamScaleStartX : value; + + if (ctCamHScale.b終了値に達した) + { + ctCamHScale = null; + TJAPlayer3.fCamXScale = currentCamHScaleChip.fCamScaleEndX; + } + } + + foreach (KeyValuePair pair in objHandlers) + { + CDTX.CChip chip = pair.Key; + CCounter counter = pair.Value; + + if (counter != null) + { + counter.t進行(); + + float value = 0.0f; + if (counter.b終了値に達した) + { + value = chip.fObjEnd; + counter = null; + } + else + { + if (chip.strObjEaseType.Equals("IN")) value = easing.EaseIn(counter, chip.fObjStart, chip.fObjEnd, chip.objCalcType); + if (chip.strObjEaseType.Equals("OUT")) value = easing.EaseOut(counter, chip.fObjStart, chip.fObjEnd, chip.objCalcType); + if (chip.strObjEaseType.Equals("IN_OUT")) value = easing.EaseInOut(counter, chip.fObjStart, chip.fObjEnd, chip.objCalcType); + value = float.IsNaN(value) ? chip.fObjStart : value; + } + + if (chip.nチャンネル番号 == 0xBE) chip.obj.y = value; + if (chip.nチャンネル番号 == 0xC0) chip.obj.x = value; + if (chip.nチャンネル番号 == 0xC2) chip.obj.yScale = value; + if (chip.nチャンネル番号 == 0xC4) chip.obj.xScale = value; + if (chip.nチャンネル番号 == 0xC6) chip.obj.rotation = value; + if (chip.nチャンネル番号 == 0xC8) chip.obj.opacity = (int)value; + + if (chip.nチャンネル番号 == 0xCB) chip.obj.y = value; + if (chip.nチャンネル番号 == 0xCC) chip.obj.x = value; + if (chip.nチャンネル番号 == 0xCD) chip.obj.yScale = value; + if (chip.nチャンネル番号 == 0xCE) chip.obj.xScale = value; + if (chip.nチャンネル番号 == 0xCF) chip.obj.rotation = value; + if (chip.nチャンネル番号 == 0xD0) chip.obj.opacity = (int)value; + } + } + #endregion + + return false; } protected bool t進行描画_チップ_連打( E楽器パート ePlayMode, int nPlayer ) @@ -4491,6 +5021,29 @@ namespace TJAPlayer3 AIBattleSections[i].IsAnimated = false; } + TJAPlayer3.fCamXOffset = 0; + + TJAPlayer3.fCamYOffset = 0; + + TJAPlayer3.fCamZoomFactor = 1.0f; + TJAPlayer3.fCamRotation = 0; + + TJAPlayer3.fCamXScale = 1.0f; + TJAPlayer3.fCamYScale = 1.0f; + + TJAPlayer3.borderColor = new SharpDX.Color4(1f, 0f, 0f, 0f); + + foreach (var chip in TJAPlayer3.DTX.listChip) + { + if (chip.obj == null) continue; + chip.obj.isVisible = false; + chip.obj.yScale = 1.0f; + chip.obj.xScale = 1.0f; + chip.obj.rotation = 0.0f; + chip.obj.opacity = 255; + chip.obj.frame = 0; + } + TJAPlayer3.DTX.t全チップの再生停止とミキサーからの削除(); this.t数値の初期化( true, true ); this.actAVI.tReset(); @@ -4502,6 +5055,9 @@ namespace TJAPlayer3 JPOSCROLLX[i] = 0; JPOSCROLLY[i] = 0; ifp[i] = false; + + TJAPlayer3.ConfigIni.nGameType[i] = eFirstGameType[i]; + bSplitLane[i] = false; } TJAPlayer3.stage演奏ドラム画面.On活性化(); for( int i = 0; i < TJAPlayer3.ConfigIni.nPlayerCount; i++ ) @@ -4937,5 +5493,30 @@ namespace TJAPlayer3 } } } - } + + + #region [EXTENDED COMMANDS] + private CCounter ctCamVMove; + private CCounter ctCamHMove; + private CCounter ctCamZoom; + private CCounter ctCamRotation; + private CCounter ctCamVScale; + private CCounter ctCamHScale; + + private CDTX.CChip currentCamVMoveChip; + private CDTX.CChip currentCamHMoveChip; + private CDTX.CChip currentCamZoomChip; + private CDTX.CChip currentCamRotateChip; + private CDTX.CChip currentCamVScaleChip; + private CDTX.CChip currentCamHScaleChip; + + private Dictionary camHandlers; + private Dictionary objHandlers; + + private Easing easing = new Easing(); + + public bool bCustomDoron = false; + private bool bConfigUpdated = false; + #endregion + } } diff --git a/TJAPlayer3/Stages/07.Game/Taiko/CStage演奏ドラム画面.cs b/TJAPlayer3/Stages/07.Game/Taiko/CStage演奏ドラム画面.cs index 7db4d1b7..f54d00dc 100644 --- a/TJAPlayer3/Stages/07.Game/Taiko/CStage演奏ドラム画面.cs +++ b/TJAPlayer3/Stages/07.Game/Taiko/CStage演奏ドラム画面.cs @@ -1849,7 +1849,7 @@ namespace TJAPlayer3 int n大音符 = (pChip.nチャンネル番号 == 0x11 || pChip.nチャンネル番号 == 0x12 ? 2 : 0); - this.tチップのヒット処理(pChip.n発声時刻ms, pChip, E楽器パート.TAIKO, true, nLane + n大音符, nPlayer); + this.tチップのヒット処理(pChip.n発声時刻ms, pChip, E楽器パート.TAIKO, true, nLane + n大音符, nPlayer, false); this.tサウンド再生(pChip, nPlayer); return; } @@ -1930,7 +1930,7 @@ namespace TJAPlayer3 #endregion #region[ HIDSUD & STEALTH ] - if( TJAPlayer3.ConfigIni.eSTEALTH[TJAPlayer3.GetActualPlayer(nPlayer)] == Eステルスモード.STEALTH ) + if( TJAPlayer3.ConfigIni.eSTEALTH[TJAPlayer3.GetActualPlayer(nPlayer)] == Eステルスモード.STEALTH || TJAPlayer3.stage演奏ドラム画面.bCustomDoron) { pChip.bShow = false; } @@ -1949,6 +1949,18 @@ namespace TJAPlayer3 float play_bpm_time = this.GetNowPBMTime(dTX, 0); y += NotesManager.GetNoteY(pChip, time * pChip.dbBPM, _scrollSpeed, TJAPlayer3.Skin.Game_Notes_Interval, play_bpm_time, configIni.eScrollMode, false); + } + + if (bSplitLane[nPlayer] || TJAPlayer3.Tx.Puchichara[PuchiChara.tGetPuchiCharaIndexByName(TJAPlayer3.GetActualPlayer(nPlayer))].effect.SplitLane) + { + if (NotesManager.IsDonNote(pChip)) + { + y -= TJAPlayer3.Skin.Game_Notes_Size[1] / 3; + } + else if (NotesManager.IsKaNote(pChip)) + { + y += TJAPlayer3.Skin.Game_Notes_Size[1] / 3; + } } if ( pChip.nバーからの距離dot.Drums < 0 ) @@ -2106,7 +2118,13 @@ namespace TJAPlayer3 } case 0x1F: + { + NotesManager.DisplayNote(nPlayer, x, y, pChip, num9); + } + break; default: + { + } break; } @@ -2203,9 +2221,29 @@ namespace TJAPlayer3 y += NotesManager.GetNoteY(pChip, time * pChip.dbBPM, _scrollSpeed, TJAPlayer3.Skin.Game_Notes_Interval, play_bpm_time, configIni.eScrollMode, false); } + if (bSplitLane[nPlayer] || TJAPlayer3.Tx.Puchichara[PuchiChara.tGetPuchiCharaIndexByName(TJAPlayer3.GetActualPlayer(nPlayer))].effect.SplitLane) + { + if (TJAPlayer3.ConfigIni.nGameType[nPlayer] == EGameType.KONGA) + { + if (NotesManager.IsClapRoll(pChip)) + { + } + else if (NotesManager.IsYellowRoll(pChip)) + { + y += TJAPlayer3.Skin.Game_Notes_Size[1] / 2; + y末端 += TJAPlayer3.Skin.Game_Notes_Size[1] / 2; + } + else if (NotesManager.IsRoll(pChip)) + { + y -= TJAPlayer3.Skin.Game_Notes_Size[1] / 2; + y末端 -= TJAPlayer3.Skin.Game_Notes_Size[1] / 2; + } + } + } + #region[ HIDSUD & STEALTH ] - if (TJAPlayer3.ConfigIni.eSTEALTH[TJAPlayer3.GetActualPlayer(nPlayer)] == Eステルスモード.STEALTH) + if (TJAPlayer3.ConfigIni.eSTEALTH[TJAPlayer3.GetActualPlayer(nPlayer)] == Eステルスモード.STEALTH || TJAPlayer3.stage演奏ドラム画面.bCustomDoron) { pChip.bShow = false; } @@ -2401,11 +2439,17 @@ namespace TJAPlayer3 } } } + if (pChip.n発声時刻ms < nowTime && pChip.nノーツ終了時刻ms > nowTime) - { + { + var puchichara = TJAPlayer3.Tx.Puchichara[PuchiChara.tGetPuchiCharaIndexByName(TJAPlayer3.GetActualPlayer(nPlayer))]; + //時間内でかつ0x9Aじゃないならならヒット処理 - if (!NotesManager.IsRollEnd(pChip) && (nPlayer != 1 ? TJAPlayer3.ConfigIni.b太鼓パートAutoPlay[nPlayer] : (TJAPlayer3.ConfigIni.b太鼓パートAutoPlay[nPlayer] || TJAPlayer3.ConfigIni.bAIBattleMode))) - this.tチップのヒット処理(pChip.n発声時刻ms, pChip, E楽器パート.TAIKO, false, 0, nPlayer); + if (!NotesManager.IsRollEnd(pChip) && + ((nPlayer != 1 ? TJAPlayer3.ConfigIni.b太鼓パートAutoPlay[nPlayer] : + (TJAPlayer3.ConfigIni.b太鼓パートAutoPlay[nPlayer] || TJAPlayer3.ConfigIni.bAIBattleMode)) || + puchichara.effect.Autoroll > 0)) + this.tチップのヒット処理(pChip.n発声時刻ms, pChip, E楽器パート.TAIKO, false, 0, nPlayer, puchichara.effect.Autoroll > 0); } } #endregion @@ -2472,7 +2516,7 @@ namespace TJAPlayer3 else { //this.tx小節線.t2D描画( CDTXMania.app.Device, x - 3, y, new Rectangle( 0, 0, 3, 130 ) ); - TJAPlayer3.Tx.Bar?.t2D描画( TJAPlayer3.app.Device, x + ((TJAPlayer3.Skin.Game_Notes_Size[0] - TJAPlayer3.Tx.Bar.szテクスチャサイズ.Width) / 2), y, new Rectangle( 0, 0, TJAPlayer3.Tx.Bar_Branch.szテクスチャサイズ.Width, TJAPlayer3.Skin.Game_Notes_Size[1]) ); + TJAPlayer3.Tx.Bar?.t2D描画( TJAPlayer3.app.Device, x + ((TJAPlayer3.Skin.Game_Notes_Size[0] - TJAPlayer3.Tx.Bar.szテクスチャサイズ.Width) / 2), y, new Rectangle( 0, 0, TJAPlayer3.Tx.Bar.szテクスチャサイズ.Width, TJAPlayer3.Skin.Game_Notes_Size[1]) ); } } } diff --git a/TJAPlayer3/Stages/07.Game/Taiko/NotesManager.cs b/TJAPlayer3/Stages/07.Game/Taiko/NotesManager.cs index 0f11858b..ea9d7ce8 100644 --- a/TJAPlayer3/Stages/07.Game/Taiko/NotesManager.cs +++ b/TJAPlayer3/Stages/07.Game/Taiko/NotesManager.cs @@ -154,6 +154,18 @@ namespace TJAPlayer3 return chip.nチャンネル番号 == 0x1C; } + public static bool IsDonNote(CDTX.CChip chip) + { + if (chip == null) return false; + return chip.nチャンネル番号 == 0x11 || chip.nチャンネル番号 == 0x13 || chip.nチャンネル番号 == 0x1A; + } + + public static bool IsKaNote(CDTX.CChip chip) + { + if (chip == null) return false; + return chip.nチャンネル番号 == 0x12 || chip.nチャンネル番号 == 0x14 || chip.nチャンネル番号 == 0x1B; + } + public static bool IsSmallNote(CDTX.CChip chip, bool blue) { if (chip == null) return false; @@ -360,6 +372,16 @@ namespace TJAPlayer3 TJAPlayer3.Tx.Note_Kusu?.t2D描画(TJAPlayer3.app.Device, x, y, new Rectangle(0, frame, length, TJAPlayer3.Skin.Game_Notes_Size[1])); return; } + else if (IsADLIB(chip)) + { + var puchichara = TJAPlayer3.Tx.Puchichara[PuchiChara.tGetPuchiCharaIndexByName(TJAPlayer3.GetActualPlayer(player))]; + if (puchichara.effect.ShowAdlib) + { + TJAPlayer3.Tx.Note_Adlib?.tUpdateOpacity(50); + TJAPlayer3.Tx.Note_Adlib?.t2D描画(TJAPlayer3.app.Device, x, y, new Rectangle(0, frame, length, TJAPlayer3.Skin.Game_Notes_Size[1])); + } + return; + } TJAPlayer3.Tx.Notes[(int)_gt]?.t2D描画(TJAPlayer3.app.Device, x, y, new Rectangle(noteType * TJAPlayer3.Skin.Game_Notes_Size[0], frame, length, TJAPlayer3.Skin.Game_Notes_Size[1])); } diff --git a/TJAPlayer3/Stages/08.Result/CStage結果.cs b/TJAPlayer3/Stages/08.Result/CStage結果.cs index b0291367..1e53585b 100644 --- a/TJAPlayer3/Stages/08.Result/CStage結果.cs +++ b/TJAPlayer3/Stages/08.Result/CStage結果.cs @@ -467,6 +467,7 @@ namespace TJAPlayer3 float starRate; float redStarRate; + float[] modMultipliers = { TJAPlayer3.stage選曲.actPlayOption.tGetModMultiplier(CActPlayOption.EBalancingType.COINS, false, 0), @@ -476,6 +477,59 @@ namespace TJAPlayer3 TJAPlayer3.stage選曲.actPlayOption.tGetModMultiplier(CActPlayOption.EBalancingType.COINS, false, 4) }; + float getCoinMul(int player) + { + var chara = TJAPlayer3.Tx.Characters[TJAPlayer3.SaveFileInstances[TJAPlayer3.GetActualPlayer(player)].data.Character]; + var puchichara = TJAPlayer3.Tx.Puchichara[PuchiChara.tGetPuchiCharaIndexByName(TJAPlayer3.GetActualPlayer(player))]; + + float charamul = 1.0f; + switch(chara.metadata.Rarity) + { + case "Poor": + charamul = 0.8f; + break; + case "Common": + charamul = 1.0f; + break; + case "Uncommon": + charamul = 1.1f; + break; + case "Rare": + charamul = 1.2f; + break; + case "Epic": + charamul = 1.3f; + break; + case "Legendary": + charamul = 1.5f; + break; + } + + float puchimul = 1.0f; + switch (puchichara.metadata.Rarity) + { + case "Poor": + puchimul = 0.8f; + break; + case "Common": + puchimul = 1.0f; + break; + case "Uncommon": + puchimul = 1.1f; + break; + case "Rare": + puchimul = 1.2f; + break; + case "Epic": + puchimul = 1.3f; + break; + case "Legendary": + puchimul = 1.5f; + break; + } + return charamul * puchimul; + } + if (TJAPlayer3.stage選曲.n確定された曲の難易度[0] == (int)Difficulty.Tower) { diffModifier = 3; @@ -505,7 +559,7 @@ namespace TJAPlayer3 // this.nEarnedMedalsCount[0] = stars; this.nEarnedMedalsCount[0] = 5 + (int)((diffModifier * (starRate + redStarRate)) * (floorRate * lengthBonus)) + clearModifier; - this.nEarnedMedalsCount[0] = Math.Max(5, (int)(this.nEarnedMedalsCount[0] * modMultipliers[0])); + this.nEarnedMedalsCount[0] = Math.Max(5, (int)(this.nEarnedMedalsCount[0] * modMultipliers[0] * getCoinMul(0))); } else if (TJAPlayer3.stage選曲.n確定された曲の難易度[0] == (int)Difficulty.Dan) { @@ -560,7 +614,7 @@ namespace TJAPlayer3 else { this.nEarnedMedalsCount[0] = 10 + goukakuModifier + clearModifier + (int)(partialScore * dAccuracyRate); - this.nEarnedMedalsCount[0] = Math.Max(10, (int)(this.nEarnedMedalsCount[0] * modMultipliers[0])); + this.nEarnedMedalsCount[0] = Math.Max(10, (int)(this.nEarnedMedalsCount[0] * modMultipliers[0] * getCoinMul(0))); } } else @@ -619,7 +673,7 @@ namespace TJAPlayer3 else { this.nEarnedMedalsCount[i] = 5 + (int)((diffModifier * (starRate + redStarRate)) * dAccuracyRate) + clearModifier + scoreRankModifier; - this.nEarnedMedalsCount[i] = Math.Max(5, (int)(this.nEarnedMedalsCount[i] * modMultipliers[i])); + this.nEarnedMedalsCount[i] = Math.Max(5, (int)(this.nEarnedMedalsCount[i] * modMultipliers[i] * getCoinMul(i))); } } } @@ -2018,7 +2072,7 @@ namespace TJAPlayer3 } else { - return new bool[] { actParameterPanel.gaugeValues[0] >= 80, actParameterPanel.gaugeValues[1] >= 80, actParameterPanel.gaugeValues[2] >= 80, actParameterPanel.gaugeValues[3] >= 80, actParameterPanel.gaugeValues[4] >= 80 }; + return new bool[] { TJAPlayer3.stage演奏ドラム画面.bIsAlreadyCleared[0], TJAPlayer3.stage演奏ドラム画面.bIsAlreadyCleared[1], TJAPlayer3.stage演奏ドラム画面.bIsAlreadyCleared[2], TJAPlayer3.stage演奏ドラム画面.bIsAlreadyCleared[3], TJAPlayer3.stage演奏ドラム画面.bIsAlreadyCleared[4] }; } } } diff --git a/TJAPlayer3/TJAPlayer3.csproj b/TJAPlayer3/TJAPlayer3.csproj index 0d85f3fd..94f8b22c 100644 --- a/TJAPlayer3/TJAPlayer3.csproj +++ b/TJAPlayer3/TJAPlayer3.csproj @@ -160,6 +160,7 @@ + diff --git a/Test/Global/Characters/Template/Effects.json b/Test/Global/Characters/Template/Effects.json new file mode 100644 index 00000000..332f0350 --- /dev/null +++ b/Test/Global/Characters/Template/Effects.json @@ -0,0 +1,3 @@ +{ + "gauge":"Normal" +} \ No newline at end of file diff --git a/Test/Global/PuchiChara/Template/Effects.json b/Test/Global/PuchiChara/Template/Effects.json new file mode 100644 index 00000000..a318efb7 --- /dev/null +++ b/Test/Global/PuchiChara/Template/Effects.json @@ -0,0 +1,6 @@ +{ + "allpurple":false, + "autoroll":0, + "showadlib":false, + "splitlane":false +} \ No newline at end of file diff --git a/Test/Licenses/TJAPlayer3-Extended.txt b/Test/Licenses/TJAPlayer3-Extended.txt new file mode 100644 index 00000000..b301a9bc --- /dev/null +++ b/Test/Licenses/TJAPlayer3-Extended.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 J.MIR + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/Test/Songs/01 OpenTaiko Chapter I/box.def b/Test/Songs/01 OpenTaiko Chapter I/box.def index efd59f7f..463cb5ef 100644 --- a/Test/Songs/01 OpenTaiko Chapter I/box.def +++ b/Test/Songs/01 OpenTaiko Chapter I/box.def @@ -1,8 +1,12 @@ #TITLE:OpenTaiko Chapter I +#TITLEJA:OpenTaiko チャプター I #GENRE:OpenTaiko Chapter I #BOXEXPLANATION1:Play awesome community- #BOXEXPLANATION2:made songs submitted #BOXEXPLANATION3:for OpenTaiko ! +#BOXEXPLANATIONJA1:OpenTaikoコミュニティの +#BOXEXPLANATIONJA2:方たちが作った曲が +#BOXEXPLANATIONJA3:あそべるよ! #BOXTYPE:3 #BGTYPE:6 #BOXCOLOR:#f76b20 diff --git a/Test/Songs/02 OpenTaiko Chapter II/box.def b/Test/Songs/02 OpenTaiko Chapter II/box.def index a9dc574c..8367b7c0 100644 --- a/Test/Songs/02 OpenTaiko Chapter II/box.def +++ b/Test/Songs/02 OpenTaiko Chapter II/box.def @@ -1,4 +1,5 @@ #TITLE:OpenTaiko Chapter II +#TITLEJA:OpenTaiko チャプター II #GENRE:OpenTaiko Chapter II #BOXEXPLANATION1:Play awesome community- #BOXEXPLANATION2:made songs submitted diff --git a/Test/Songs/L1 Collaborations/box.def b/Test/Songs/L1 Collaborations/box.def index f23fbab1..dfe1da3a 100644 --- a/Test/Songs/L1 Collaborations/box.def +++ b/Test/Songs/L1 Collaborations/box.def @@ -1,8 +1,12 @@ #TITLE:Collaborations +#TITLEJA:コラボ曲 #GENRE:Collaborations #BOXEXPLANATION1:Enjoy songs from projects #BOXEXPLANATION2:the OpenTaiko team #BOXEXPLANATION3:collaborated with ! +#BOXEXPLANATIONJA1:OpenTaikoチームと +#BOXEXPLANATIONJA2:コラボした曲が +#BOXEXPLANATIONJA3:あそべるよ! #BGTYPE:3 #BGCOLOR:#a200ff #BOXTYPE:0 diff --git a/Test/Songs/L2 Custom Charts/box.def b/Test/Songs/L2 Custom Charts/box.def index bbf64abb..98d4e80a 100644 --- a/Test/Songs/L2 Custom Charts/box.def +++ b/Test/Songs/L2 Custom Charts/box.def @@ -1,10 +1,14 @@ #TITLE:Custom Charts +#TITLEJA:カスタム譜面 #GENRE:Custom Charts #FORECOLOR:#FFFFFF #BACKCOLOR:#316700 #BOXEXPLANATION1:Play a wide range #BOXEXPLANATION2:of custom charts #BOXEXPLANATION3:from the community ! +#BOXEXPLANATIONJA1:君自身が導入した +#BOXEXPLANATIONJA2:譜面があそべるよ! +#BOXEXPLANATIONJA3:カスタム譜面はここに入れてね! #BGTYPE:4 #BGCOLOR:#00fc15 #BOXTYPE:0 diff --git a/Test/Songs/L3 Downloaded Songs/box.def b/Test/Songs/L3 Downloaded Songs/box.def index 125b32ba..2f094d09 100644 --- a/Test/Songs/L3 Downloaded Songs/box.def +++ b/Test/Songs/L3 Downloaded Songs/box.def @@ -1,8 +1,12 @@ #TITLE:Downloaded Songs +#TITLEJA:CDNからダウンロードした曲 #GENRE:Download #BOXEXPLANATION1: Play songs downloaded #BOXEXPLANATION2: from the Online Lounge ! #BOXEXPLANATION3: +#BOXEXPLANATIONJA1: オンラインラウンジから +#BOXEXPLANATIONJA2: ダウンロードした曲が +#BOXEXPLANATIONJA3: あそべるよ! #BGCOLOR:#ff00a2 #BOXCOLOR:#ff00a2 #BOXTYPE:0 diff --git a/Test/Songs/S1 Dan-i Dojo/box.def b/Test/Songs/S1 Dan-i Dojo/box.def index cdb1a912..53468db6 100644 --- a/Test/Songs/S1 Dan-i Dojo/box.def +++ b/Test/Songs/S1 Dan-i Dojo/box.def @@ -1,8 +1,12 @@ #TITLE:Dan-i Dojo +#TITLEJA:段位道場 #GENRE:段位道場 #BOXEXPLANATION1:Play multiple charts in continuation #BOXEXPLANATION2:following challenging exams #BOXEXPLANATION3:in order to get a PASS rank ! +#BOXEXPLANATIONJA1:曲を連続で演奏して +#BOXEXPLANATIONJA2:条件をクリアすれば +#BOXEXPLANATIONJA3:称号がもらえるモードだよ! #BOXTYPE:0 #BGTYPE:7 #BOXCOLOR:#3e51c9 diff --git a/Test/Songs/S2 Taiko Towers/01 - Sweet/box.def b/Test/Songs/S2 Taiko Towers/01 - Sweet/box.def index 6237de92..3c853ac1 100644 --- a/Test/Songs/S2 Taiko Towers/01 - Sweet/box.def +++ b/Test/Songs/S2 Taiko Towers/01 - Sweet/box.def @@ -1,7 +1,10 @@ -#TITLE:Tower (甘口) +#TITLE:Tower (Sweet) +#TITLEJA:甘口 #GENRE:太鼓タワー #BOXEXPLANATION1:Easy tower charts for #BOXEXPLANATION2:players of all skill ranges ! +#BOXEXPLANATIONJA1:かんたんだよ! +#BOXEXPLANATIONJA2:楽しんでね! #BACKCOLOR:#222222 #BOXCOLOR:#f6ff00 #BOXTYPE:0 diff --git a/Test/Songs/S2 Taiko Towers/02 - Spicy/box.def b/Test/Songs/S2 Taiko Towers/02 - Spicy/box.def index a89c3ea2..d4ddc583 100644 --- a/Test/Songs/S2 Taiko Towers/02 - Spicy/box.def +++ b/Test/Songs/S2 Taiko Towers/02 - Spicy/box.def @@ -1,7 +1,10 @@ -#TITLE:Tower (辛口) +#TITLE:Tower (Spicy) +#TITLEJA:辛口 #GENRE:太鼓タワー #BOXEXPLANATION1:Difficult Tower charts #BOXEXPLANATION2:for true champions ! +#BOXEXPLANATIONJA1:むずかしいよ! +#BOXEXPLANATIONJA2:楽しんでね! #BACKCOLOR:#222222 #BOXCOLOR:#ff5e00 #BOXTYPE:0 diff --git a/Test/Songs/S2 Taiko Towers/box.def b/Test/Songs/S2 Taiko Towers/box.def index 46245bb6..909b8c0c 100644 --- a/Test/Songs/S2 Taiko Towers/box.def +++ b/Test/Songs/S2 Taiko Towers/box.def @@ -1,8 +1,12 @@ #TITLE:Taiko Towers +#TITLEJA:太鼓タワー #GENRE:太鼓タワー #BOXEXPLANATION1:Play long charts within a limited #BOXEXPLANATION2:count of lives and reach #BOXEXPLANATION3:the top of the tower ! +#BOXEXPLANATIONJA1:曲を演奏して頂上まで +#BOXEXPLANATIONJA2:たどり着いたらクリアだよ! +#BOXEXPLANATIONJA3:ミスをするとHPが減るから気を付けて! #BACKCOLOR:#222222 #BOXCOLOR:#ffb300 #BOXTYPE:0 diff --git a/Test/Songs/X1 Favorite/box.def b/Test/Songs/X1 Favorite/box.def index d083aae7..e16c5e8c 100644 --- a/Test/Songs/X1 Favorite/box.def +++ b/Test/Songs/X1 Favorite/box.def @@ -1,10 +1,14 @@ #TITLE:Favorite songs +#TITLEJA:おきにいり #GENRE:Favorite #FORECOLOR:#FFFFFF #BACKCOLOR:#673100 #BOXEXPLANATION1:Challenge some of #BOXEXPLANATION2:your favorite songs ! #BOXEXPLANATION3:(Toggle with Left CTRL) +#BOXEXPLANATIONJA1:おきにいりに +#BOXEXPLANATIONJA2:登録をした曲が +#BOXEXPLANATIONJA3:遊べるよ!(とても便利!) #BGTYPE:10 #BOXTYPE:0 #BOXCOLOR:#c71b3b \ No newline at end of file diff --git a/Test/Songs/X2 Recent/box.def b/Test/Songs/X2 Recent/box.def index 21b1ed6d..df319920 100644 --- a/Test/Songs/X2 Recent/box.def +++ b/Test/Songs/X2 Recent/box.def @@ -1,7 +1,11 @@ #TITLE:Recently played songs +#TITLEJA:最近遊んだ曲 #GENRE:最近遊んだ曲 #FORECOLOR:#FFFFFF #BACKCOLOR:#164748 #BOXEXPLANATION1:Play recently played songs ! +#BOXEXPLANATIONJA1:何回か前までの +#BOXEXPLANATIONJA2:遊んだ曲が選べるよ +#BOXEXPLANATIONJA3:お気に入りならお気に入り登録をしよう! #BGTYPE:9 #BOXTYPE:9 \ No newline at end of file diff --git a/Test/Songs/X3 Search By Difficulty/box.def b/Test/Songs/X3 Search By Difficulty/box.def index cd5ac27a..62f01838 100644 --- a/Test/Songs/X3 Search By Difficulty/box.def +++ b/Test/Songs/X3 Search By Difficulty/box.def @@ -1,9 +1,12 @@ #TITLE:Search by difficulty +#TITLEJA:むずかしさから探す #GENRE:SearchD #FORECOLOR:#FFFFFF #BACKCOLOR:#213d18 #BOXEXPLANATION1:Search and play songs that #BOXEXPLANATION2:fit your level ! +#BOXEXPLANATIONJA1:難易度やレベルで検索するよ +#BOXEXPLANATIONJA2:とても便利! #BGTYPE:1 #BOXTYPE:0 #BOXCOLOR:#5ac736 diff --git a/Test/System/SimpleStyle (1080p)/Graphics/5_Game/Adlib.png b/Test/System/SimpleStyle (1080p)/Graphics/5_Game/Adlib.png new file mode 100644 index 0000000000000000000000000000000000000000..60b4cba8722c5d0a0d1deacdbf806ead56604933 GIT binary patch literal 72337 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 WaLQrR1qb{E|5O#V6e{E_L;nwbHs-|u literal 0 HcmV?d00001 diff --git a/Test/System/SimpleStyle/Graphics/5_Game/Adlib.png b/Test/System/SimpleStyle/Graphics/5_Game/Adlib.png new file mode 100644 index 0000000000000000000000000000000000000000..b412cc5c88ad1adefc2feb13d1f9885066a3ef01 GIT binary patch literal 24781 zcmeHvcTkhfyLKo-Kzc`7h(SOI1VTvyh;#xXy-Nv6fFPYf0Ht?O0YOwy>4->2!Gcr~ zrAQS;kt$WBDxe^o;M?b%nQz{2&hL*ilgvP#XZPM~cdxy7=XtKV? zrl?xZ9dQ=+qs1~=Pi|Zbj0=uOfTd2(UI<|6zSV$`dV@MYkmP%2A%}aepWN&3e;;b?uD@uRfeOGHI9=Xc@$V_G5j`PMY-DKsENTe)GURGWnO16Logm@D%!BFpjJ&JBEiQSbcl&@ z@d+fVfx+Z@&>!RT@-;I06W%-EcNWNe$OdD4W#wdGvR+=Ye{T^$)CnSk{63)nu|eX{>zwbWn_fX_Q3`o4iBxZ z20rW`h4aA@aHwCG7Sj(|fIlyS;X3><-gDl5C-m9bb?n1YaA|D!V8sk{t)8{0j<)Md|wZdtu1S zN$|qB;bncj-F{UZ5{}X^L92n~Wnh1mn0R7{uH**fJwWir`H%wss;mwJdLq6q{ zkn(Ujc_pMWTp6LHjQGpQ3hy64_QgX~IhYJw;aAP!!l200AybPv^i(pyuX6HiP+I;31$C03V-M8@X+}Wetutv|6mVfXi6vl zieCy{6uSNu1OLjH;$0NF{uKlN%9!F^|7&zH{`E42_a;99k;tz~?g~f<`8A8q#ZXTh zPz$&Tuwahdx=Ai!@YS~s005419{y1QvTyN`3+ahyBOUsAAUh9S>``nc7XSbPptUtD zg5Q6+eSyejd8bqTO==M*H5w?J6mlB$(olFNn2$b?c4GPwIBy!U5*$Q(j{bIGr{9&j z+Sj(aIv)ei;luKTog`Q>s?n(urHL|y_ra(<)me6ZY6b=dQ8ekvR_c?6-Jrn0t1SH= z8MbrG?@C!VlzG4TIXymM_goZf|q z*5vyb2@oz`8;aCu;hLOpF^;^``Mtcbh17Drg}&vKMz-s$wV3X8NbEp|SfuoxV~fJ1 zo#~GF=V#F^Co~e}^Q`nUurB84fnp$rC`ZkwME#Y?({-+^Ln;ZEdYI%dY*jPG z{wNeYud3^11f5mcswQ=MZ+U*`&8lj`&u0kiA5iN@f)nL5FMkOGsz>Z2+w`AUl zeAPmoCo!T^D1K>XnsD8JJoDA3Z>s_4_)9BQpC|Z)x6u1Ewv%!rhO7opPVzfHGvU{x zmAt~B`R+~J2~EL}3}}>s=#P0C`0b6`>ZOr}Rkzzd-Memrc(7B1bD!T<+1cr34JN%h z*+u$tc{b5b9Owr?NCO8zz=47Xuro%nTT^Csw2LhglSiCO)iAmHVK3-dlu4NWUanY%RCop(zw-Dm$!GXTm*5pP$sv!q6B^d!5D@sYnwM zuq|EEn~e@yT`s~ss4TfMYb-k#cf?p_<4Ewa9UuZY3|#cJFy)riq9ZY8w9t=1^e5{+ z00LHag@#;vpI-+_PSQHXr>@WMXGUM8_Fxe%@o`HouY9>o6IR!nUTwnRR zo)_Go34I+CaL`kB-5PP*j%AOzlx=XTx>_LH)2PS%4$xz>pZ*-ZD*BN*Fmhu2f`IbJ zZ?Zy9rmS}-=D%#b4Q|+%`V1$TIXYg0r>D@J#V$uW5f`rVir7A{+syTq2RqS^vk&GQ z)R5tNyUnwJW%u9FpQCOBL$rXTgKww8zkj~>W!$s(b%&~XQ{+YoXU?mOB4bx0lr!l2 zJe9vJUANw78QcAm5Yw_*U|Hjomam)66opfQev~{-twj*J#B=2)lj1<`ojZNp@G6f@ zT>;i|{CLTtbj6R@A1z6J?qPsas6EMuDjV%65|Ad8CHZDOvB#H=MaKDK*~2Z8(2+d} zh{k;{!?Flb?nKbDxR4fs7J^5#itv-W4(PQXb9y`5LaYJ(5gW{FG5a7N>t}kd0W^g_ z?r_3Crll9-=4WfCetz3pRb#rZXTEig&a)|Q@}4ej`-o;R-=ot;zMCSh0qtK71UKns z1MMGwOL>(kG@iNE6XDpL#JZ*45qk^$bz>G;!oQwj3b^=l@!(zpJnB?SkOuWb6_wzV z92yUg$^iDY9@>_SA+AmIHpAyS?8}taKCF5dJVA!Yn(#(8u*l4m_rMq57PiRsK1y;k zeb}5_kyBrqKo3ZWt$SsR;|((V0U1MQ(hUZV9Syb}zM7Uh*=l_tHP?~Da`E}CRiERN z#!bZ^-ZS1mZxvwmga7NQ?eY!RY5e?VM`uLCE(fvq=Lga1WKin+$WG zJ3O0hUlN+8UyH1?oT1`~eIFnGXfr|Ooz+jv9tD=w%%kUkU%9tT>rDg*(;xUgI)L># zijKCg*>d$wU2bl^$=@)(5RB3JDKqDpjn-mJKMiJ!O)Z=&we<`xAJVR*&$)cSxppB0T;(L`mH{_D(SVw6rE}|7g>(b7qnMl+4o=gWajA0y7*ou)z)T z-u)}&2CW&CiQ^$C7H#b$I0H6BgP!F6RaUt|A;k5;$%lQ$+sTTjM3kH-p=774#@_ZLA53N zQtmp9oITo5I7-aTv-VH0h`Be`cd717S5EnguQ;M{b1|CsBs)imFozLsYJUX#o2f>r z6A%4vg4y4D@r2Hl)zrY37zjo&4}j>XjR?K!CwrEiGxNqbJ=KTp^<$;;j}>XJ5yio! z?Sq|VEJcHI?H~C4$D{0;6vDBU&>P|{HkrXy3Dqys zPK%#*|2D~=F48_iyvVzzy|AdQPs=4Bx)DAOWEc>A&?bJt3U$Xnc)KZ@mcQ+KTFDOQ zlWW>*z(R@G*5mQ@e(3^Q18={mKQDU~zPUcrQ*KX)f8sSLxu5*_*@}JVOpIREd)8S- z4t;Pi=d8^JBnlX}l(eVu-7C>O6^}W_8~D;|S#EApIhR4?h9CG;O4vl=?s#8K^gNK& z!yzKL(6>P6+0(BlOGqT}qngX7m#kscLc4h}HXhtpEOU(V?e+ySKqsh}&X7f}jFE$p zb&#usuV$!-2gF03hGytT5OT!rmSOd3F~ zTW~=;X2+>&f62ubHky=6{X?HN+XzMpO~(^R*W+?a((>%tH54Bo-+Re#dsFV)GfQGC zg5M2IYd-9Jzog5F*ExO#I&_Tv6!p-F%PtR(jTuncV||%5O4s_e8g}}iSMB{^b3M~7WalT~)>)jP_JWzV$NHK9Zd%c`$KuuSEyV$M9$fEEdzXw8@nN~8Oz3)a`99iIPTzZX2zDEEG&-y$&rw($iWU`d0Grttrv38tjAt!KSE(P=@H*CUI zLK$8X(?6)>dACe+6ZyVsM`(o2uGfq>#v{jv5 zO4@LkHBE|fz2+hqG=~}QkIXVLy2Z|#J{Zf|Cd1x%dqdi8>+Azw1DU)K=Q4nHo zbn(>}ueRWx@h^Dz^<7t(qDPgrs`1MG`C_c0;*Z9zz&oX3$A`UEYLE=a!^9LV-*{ez zL?>})8J{KkF)n`aN@Qc}?d)B86?nh>;ai2A*oc;}u`1W(xjXrLIxkkQ2r_u-(gvj# zACtc4EKzv(%RxeF!c43{z46cWGDTDGBW*ReE#)DQ$arxE?KPT%6!~)%o}((~!Zw*k zM8*>_+H{>Ls1S<+Nmp%eFBUg;eynnNB5Z6s!=WGFJ)Y!Yl-y=LgCePb^Vsr_NPQX; zBxr;^ojSkextrdW-;vKMR^vMFGWW%%AN?)u+?dm}poiP)*2jwiNP3QP2ANJE{dcQ* zjXOlF9KVw0(W!@Qnl?{sd)C`t#kk40VWthsu(%R&*T!N+sqqwld6!;almXFs)f<0Y zUta%Be=PT?YAneqB4zG`n~?A4$?pzVfB|$WhBaApJmdDYUEz=HxWZ|sBvy@*JrIj5 z#oA|6tP9KUVsyB6#R*v=_tZ39txmY<8t*xu?$f|2DX)e6ERoTO{;(0z5f|g*tGfN3 zQ?_=?2Oo6pF}GBg-4UxDHAS96qI{rK5}O624deVU+j;arx}^Te$olkW-7%dS*>7l* z<+_cf*eBVjEcI{MKdYH~r5ZwY6p7vFYLD)G+r;ML>0;=2o4`ad<0h_6y3|V!=pehL zt00x$F06Fp{_~VA(6~lPTN=W8GLQ9ox z7a!mHxarx&@(c~SVF!7+);3efW16WlxW2dBZMC`cEcHFB2v|@MtDbIZn|ktvOG6Hi zYy#8wxZ*K@G`omsEO(!5YDi3e$V>?F9hPr=STt%XPA@@CmylcMQsNgZ-VD;HFkw}6 zajN{1*3Z}b>QY(BleMMD&0?o~52qva+t%{ywN41fv1T_p^=?7K(J9LZ^(U^=E)v#0 zCB|J6_Vw;jVC{XDYdpRW>$(j(c{*~7L{3F>!|$1iYQ(wgj<7p^ z5yLRTxHZ=dUR58xA>m2al5CTG`?^4~vxlCnlki)v-m?Zn8})lma;xRnU349e*wicp z^1Qy#gBJ7TgdidnPqm|uK@`gD%4lbmxcrc&a*)xr{m{cl@5GpO3AwUWhSsY^`r1$)tB7lj|%u_?y zg`Ht;)K9*V7d?wqYV>~iDJU18t*6)CrFc$Hm0MXXB%XPt zb1vvY97yBw^yxCo?8^*JPetEkZOFw2d$!sQAr;E!he+x#zO2KxZmoNb=Rvm5xN`Nn zp3!9}IRL5bao;{D@_r;wq7FzH>ljOCHM{y@KXK{0a9CFJ{yOHa`8As`X>KJ#Ugd{0 z6PkhjsSJlT|F8P2GLWJ=3Oohgd#8J*;orR=CfK2tcmaC&3ezj zX<|GTejZvvFq5xUAV@uX^JaK`2`jtyPVMM&`rFyvOl-wFvwNj91YSWiNR$Wft*eIL zAL!66Vyk$bd}H$DbXN}lA%-`!;$))ZR|=x_Hg<9BoS1fdl_3j{*lJ$49Yu9QG#Qt< zArh$=!7`(cBAMBYuI`^`#Q|Qaot!V`rS2Z3(d`CAL zMxTa}%5i$M3@q#`c3D4xp^uwc+L{3FSuoIMb;&DczzOFH7J-0kI|H0A{9aw^Mn-hu z{CBrbRWb>kvT4u0h8MDhsOCMO_0W#8K1o~3HCU0gVAI`dQ5si-;15mIT!j{CMPT&L zzOW-a>|MEw!Ro!^6SwSmJ`%a>BT#*~^KG&PZ{u zkAplyDhfDQIEAf23Acsn_~TkFj%!$hqL+yNQjYq$rQdC%*{*VpPB&cF%(|FwP^`5z@M6kh~4$2?)GaqPOA z!W-_!vt4T#Q&0Y1wN%2pZ6HdGfNsxs*zE)`!8rJ+xoF~Sx@o$PXo)t4er7M%Y1(FU zym%3weqLp1cHb-$uyy1#J(YQ6E{%Gt-LaiuU#=aN9gZEqJH6m3<6Y{!{Yrzxm0F0e ztn)G73W>dpZ;l$y86a)`k+#WD^dw{yaFXf=Rb7-5%`?thcaOJxXfeysLt(!cm2h0 zP?d(|g~TNrNucTFhtU^fE>l!Kipob(`6wzMMdhQYd=!hkD~Zd6hDgMM^XGJiXTPsqr~-5;`%6YeU!L9N?ac$u8$JeM~UmB z#Pw0)`Y3UIl(;@hTpuN_j}q5MiR+`p^-<#bC~j zluTYqCNCwEmy*d#$>gPE@=`K+DVe;KOkPSRFC~+glF3WS#&T3a`I!FH(CjB?< literal 0 HcmV?d00001