611 lines
13 KiB
C#
611 lines
13 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using Godot;
|
|
using Godot.Bridge;
|
|
using Godot.NativeInterop;
|
|
|
|
[ScriptPath("res://Scripts/Events/BearFortDuoMinigame.cs")]
|
|
public partial class BearFortDuoMinigame : EventCaller
|
|
{
|
|
public partial class Balls
|
|
{
|
|
public Sprite2D obj;
|
|
|
|
public BearFortDuoMinigame parent;
|
|
|
|
public Vector2 target;
|
|
|
|
public Vector2 mid;
|
|
|
|
public Vector2 start;
|
|
|
|
public float time;
|
|
|
|
private Area2D area;
|
|
|
|
private bool delete;
|
|
|
|
private float current;
|
|
|
|
public void Start()
|
|
{
|
|
BearFortDuoMinigame bearFortDuoMinigame = parent;
|
|
Sprite2D obj = new Sprite2D
|
|
{
|
|
Texture = parent.ball.Texture,
|
|
Position = parent.baller.Position + new Vector2(20f, -50f)
|
|
};
|
|
Sprite2D node = obj;
|
|
this.obj = obj;
|
|
bearFortDuoMinigame.AddChild(node, forceReadableName: false, InternalMode.Disabled);
|
|
time = Main.RandomRange(180, 300);
|
|
start = this.obj.GlobalPosition;
|
|
if (Main.RandomRange(0, 10) < 2)
|
|
{
|
|
target = new Vector2(parent.kanako.GlobalPosition.X, 30f);
|
|
}
|
|
else
|
|
{
|
|
target = new Vector2(Main.RandomRange(-170, -72), 30f);
|
|
}
|
|
mid = new Vector2(target.X, -550f);
|
|
this.obj.AddChild(area = new Area2D
|
|
{
|
|
CollisionLayer = 4u,
|
|
CollisionMask = 4u
|
|
}, forceReadableName: false, InternalMode.Disabled);
|
|
area.AddChild(new CollisionShape2D
|
|
{
|
|
Shape = new CircleShape2D()
|
|
}, forceReadableName: false, InternalMode.Disabled);
|
|
area.SetMeta(parent.ballTag, this.obj);
|
|
}
|
|
|
|
public void Delete()
|
|
{
|
|
delete = true;
|
|
current = 0f;
|
|
area.SetDeferred("monitorable", false);
|
|
area.SetDeferred("monitoring", false);
|
|
}
|
|
|
|
public void Update()
|
|
{
|
|
if (delete)
|
|
{
|
|
if (current < 30f)
|
|
{
|
|
current += Main.deltaTime;
|
|
obj.Modulate = Main.colorWhite.Lerp(Main.colorClear, current / 30f);
|
|
obj.Scale = Vector2.One.Lerp(Vector2.One * 1.2f, current / 30f);
|
|
}
|
|
else
|
|
{
|
|
parent.balls.Remove(this);
|
|
obj.QueueFree();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
obj.GlobalPosition = Common.Beizier(start, mid, target, current / time);
|
|
current += Main.deltaTime;
|
|
obj.RotationDegrees += Main.deltaTime;
|
|
if (current >= time)
|
|
{
|
|
Delete();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
[Export(PropertyHint.None, "")]
|
|
private RichTextLabel indicator;
|
|
|
|
[Export(PropertyHint.None, "")]
|
|
private RichTextLabel help;
|
|
|
|
[Export(PropertyHint.None, "")]
|
|
private Sprite2D ball;
|
|
|
|
[Export(PropertyHint.None, "")]
|
|
private Sprite2D shootLine;
|
|
|
|
[Export(PropertyHint.None, "")]
|
|
private Entity baller;
|
|
|
|
[Export(PropertyHint.None, "")]
|
|
private Node2D[] kPoints;
|
|
|
|
[Export(PropertyHint.None, "")]
|
|
private Node2D[] cPoints;
|
|
|
|
[Export(PropertyHint.None, "")]
|
|
private Area2D[] collider;
|
|
|
|
[Export(PropertyHint.None, "")]
|
|
private Node2D ballerMove;
|
|
|
|
[Export(PropertyHint.None, "")]
|
|
private Node2D camPos;
|
|
|
|
[Export(PropertyHint.None, "")]
|
|
private Node2D pencil;
|
|
|
|
[Export(PropertyHint.None, "")]
|
|
private Node2D bridge;
|
|
|
|
[Export(PropertyHint.None, "")]
|
|
private Node2D penceller;
|
|
|
|
[Export(PropertyHint.None, "")]
|
|
private Node2D bridgeBlocker;
|
|
|
|
public Entity player;
|
|
|
|
public Entity kanako;
|
|
|
|
private int state = -1;
|
|
|
|
private int lives;
|
|
|
|
private int score;
|
|
|
|
private float cd;
|
|
|
|
private float iframes;
|
|
|
|
private float pencilCD;
|
|
|
|
private Coroutine shoot;
|
|
|
|
private Coroutine tossing;
|
|
|
|
private Vector2 ballerpos;
|
|
|
|
private int[] pos = new int[2];
|
|
|
|
private static readonly Dictionary<int, int> count = new Dictionary<int, int>
|
|
{
|
|
{ 2, 3 },
|
|
{ 3, 2 },
|
|
{ 4, 1 }
|
|
};
|
|
|
|
private List<Balls> balls = new List<Balls>();
|
|
|
|
public const float height = -300f;
|
|
|
|
private readonly Vector2 colOffset = new Vector2(0f, -20f);
|
|
|
|
public readonly StringName ballTag = "BBall";
|
|
|
|
public void StartEvent()
|
|
{
|
|
Main.inEvent = Coroutine.Start(BBallTalk());
|
|
}
|
|
|
|
public IEnumerator BBallTalk()
|
|
{
|
|
if (SaveFile.HasFlag(SaveFile.Flags.BBallPity2) && !SaveFile.HasFlag(SaveFile.Flags.BBallPitied))
|
|
{
|
|
SaveFile.AddFlag(SaveFile.Flags.BBallPitied);
|
|
Room.current.eventPointers[0].QueueFree();
|
|
TextSystem.GetText("BBallPity");
|
|
SaveFile.AddFlag(SaveFile.Flags.BearFortLeftMinigame);
|
|
while (TextSystem.instance.Visible)
|
|
{
|
|
yield return null;
|
|
}
|
|
Coroutine w = Coroutine.Start(BridgeOpen());
|
|
while (!w.done)
|
|
{
|
|
yield return null;
|
|
}
|
|
yield break;
|
|
}
|
|
if (!SaveFile.HasFlag(SaveFile.Flags.BBallTalk1))
|
|
{
|
|
TextSystem.GetText("BearFortBBall1");
|
|
while (TextSystem.instance.Visible)
|
|
{
|
|
yield return null;
|
|
}
|
|
if (!SaveFile.HasFlag(SaveFile.Flags.WeirdStart) && TextSystem.lastPrompt == 0)
|
|
{
|
|
yield break;
|
|
}
|
|
}
|
|
else if (!SaveFile.HasFlag(SaveFile.Flags.BBallTalk2))
|
|
{
|
|
TextSystem.GetText("BBallTalk1.5");
|
|
while (TextSystem.instance.Visible)
|
|
{
|
|
yield return null;
|
|
}
|
|
if (TextSystem.lastPrompt == 0)
|
|
{
|
|
yield break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (SaveFile.HasFlag(SaveFile.Flags.BearFortLeftMinigame))
|
|
{
|
|
TextSystem.GetText("BBallAfter");
|
|
while (TextSystem.instance.Visible)
|
|
{
|
|
yield return null;
|
|
}
|
|
yield break;
|
|
}
|
|
TextSystem.GetText("BBallRepeat");
|
|
while (TextSystem.instance.Visible)
|
|
{
|
|
yield return null;
|
|
}
|
|
if (TextSystem.lastPrompt == 1)
|
|
{
|
|
yield break;
|
|
}
|
|
}
|
|
StartGame();
|
|
}
|
|
|
|
private void StartGame()
|
|
{
|
|
SaveFile.AddFlag(SaveFile.Flags.BBallPlayedOnce);
|
|
SaveFile.AddFlag(SaveFile.Flags.BBallTalk2);
|
|
state = 0;
|
|
pos[0] = 1;
|
|
score = 0;
|
|
lives = 3;
|
|
pencilCD = 150f;
|
|
help.Text = "[center][color=gray]" + Texts.FindDiag("BBallInstructions")[0].text;
|
|
pos[1] = 1;
|
|
ballerpos = baller.GlobalPosition;
|
|
player = Player.instance;
|
|
kanako = Player.instance.followers[0];
|
|
kanako.anim.Play(SaveFile.HasFlag(SaveFile.Flags.WeirdStart) ? "Stand" : "Surprise");
|
|
kanako.sprite.FlipH = true;
|
|
player.sprite.FlipH = true;
|
|
baller.sprite.FlipH = true;
|
|
baller.anim.Play("Idle");
|
|
player.anim.Play("BattleIdle");
|
|
CameraController.instance.follow = null;
|
|
kanako.doTrail = true;
|
|
player.doTrail = true;
|
|
Audio.PlaySound("snd_weaponpull.wav");
|
|
}
|
|
|
|
public override void _Process(double delta)
|
|
{
|
|
if (cd > 0f)
|
|
{
|
|
cd -= Main.deltaTime;
|
|
}
|
|
if (iframes > 0f)
|
|
{
|
|
iframes -= Main.deltaTime;
|
|
}
|
|
switch (state)
|
|
{
|
|
case 0:
|
|
Audio.ChangeMusic(null);
|
|
cd = 60f;
|
|
state = 1;
|
|
break;
|
|
case 1:
|
|
if (cd <= 0f)
|
|
{
|
|
help.Visible = true;
|
|
Room.current.DoMusic(1);
|
|
IndicatorCD();
|
|
}
|
|
break;
|
|
case 2:
|
|
case 3:
|
|
case 4:
|
|
case 5:
|
|
if (cd <= 0f)
|
|
{
|
|
IndicatorCD();
|
|
}
|
|
break;
|
|
case 6:
|
|
{
|
|
if (!Audio.music.Playing)
|
|
{
|
|
Main.inEvent = Coroutine.Start(End(score >= 10));
|
|
return;
|
|
}
|
|
if (pencilCD > 0f)
|
|
{
|
|
pencilCD -= Main.deltaTime;
|
|
if (pencil.Visible)
|
|
{
|
|
pencil.GlobalPosition += Vector2.Right * Main.deltaTime * 2f;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Audio.PlaySound("snd_arrow.wav");
|
|
Main.SetActive(pencil, state: true);
|
|
pencil.GlobalPosition = new Vector2(-300f, player.GlobalPosition.Y - 16f);
|
|
pencilCD = Main.RandomRange(180, 250);
|
|
}
|
|
if (help.Visible)
|
|
{
|
|
help.Visible = false;
|
|
shootLine.Visible = true;
|
|
}
|
|
if (shoot == null || shoot.done)
|
|
{
|
|
if (Input.IsActionJustPressed(Main.keys[4]))
|
|
{
|
|
shoot = Coroutine.Start(Shoot());
|
|
}
|
|
if (Input.IsActionJustPressed(Main.keys[0]))
|
|
{
|
|
if (pos[0] > 0)
|
|
{
|
|
pos[0]--;
|
|
}
|
|
}
|
|
else if (Input.IsActionJustPressed(Main.keys[1]) && pos[0] < 2)
|
|
{
|
|
pos[0]++;
|
|
}
|
|
}
|
|
if (Input.IsActionJustPressed(Main.keys[2]))
|
|
{
|
|
if (pos[1] > 0)
|
|
{
|
|
pos[1]--;
|
|
}
|
|
}
|
|
else if (Input.IsActionJustPressed(Main.keys[3]) && pos[1] < 2)
|
|
{
|
|
pos[1]++;
|
|
}
|
|
if (cd <= 0f && (tossing == null || tossing.done))
|
|
{
|
|
tossing = Coroutine.Start(TossBall());
|
|
}
|
|
for (int num = balls.Count - 1; num >= 0; num--)
|
|
{
|
|
balls[num].Update();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if (state > -1)
|
|
{
|
|
Player.instance.canInput = false;
|
|
CameraController.instance.GlobalPosition = CameraController.instance.GlobalPosition.Lerp(camPos.GlobalPosition, 0.2f * Main.deltaTime);
|
|
kanako.GlobalPosition = kanako.GlobalPosition.Lerp(kPoints[pos[1]].GlobalPosition, 0.2f * Main.deltaTime);
|
|
player.GlobalPosition = player.GlobalPosition.Lerp(cPoints[pos[0]].GlobalPosition, 0.2f * Main.deltaTime);
|
|
baller.GlobalPosition = baller.GlobalPosition.Lerp(ballerMove.GlobalPosition, 0.2f * Main.deltaTime);
|
|
collider[0].GlobalPosition = kanako.GlobalPosition + colOffset;
|
|
collider[1].GlobalPosition = player.GlobalPosition + colOffset;
|
|
shootLine.GlobalPosition = new Vector2(shootLine.GlobalPosition.X, player.GlobalPosition.Y - 16f);
|
|
}
|
|
}
|
|
|
|
private IEnumerator Shoot()
|
|
{
|
|
bool hit = false;
|
|
player.anim.Play("AttackReady");
|
|
for (float a = 0f; a < 7f; a += Main.deltaTime)
|
|
{
|
|
yield return null;
|
|
}
|
|
for (int i = 0; i < balls.Count; i++)
|
|
{
|
|
if (balls[i].obj.GlobalPosition.X > -170f && Mathf.Abs(balls[i].obj.GlobalPosition.Y - shootLine.GlobalPosition.Y) < 17f)
|
|
{
|
|
Audio.PlaySound("snd_bomb.wav");
|
|
balls[i].Delete();
|
|
score++;
|
|
indicator.Text = score.ToString().PadLeft(2, '0');
|
|
hit = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!hit)
|
|
{
|
|
Audio.PlaySound("snd_curtgunshot.ogg");
|
|
BattleDR.ShowFloatingText("MISS", player.GlobalPosition);
|
|
}
|
|
for (float a = 0f; a < 25f; a += Main.deltaTime)
|
|
{
|
|
yield return null;
|
|
}
|
|
player.anim.Play("BattleIdle");
|
|
}
|
|
|
|
private IEnumerator End(bool won = false)
|
|
{
|
|
Main.SetActive(pencil, state: false);
|
|
shootLine.Visible = false;
|
|
Coroutine coroutine = tossing;
|
|
if (coroutine != null && !coroutine.done)
|
|
{
|
|
Coroutine.Stop(tossing);
|
|
}
|
|
Coroutine coroutine2 = shoot;
|
|
if (coroutine2 != null && !coroutine2.done)
|
|
{
|
|
Coroutine.Stop(shoot);
|
|
}
|
|
Audio.ChangeMusic(null);
|
|
state = -1;
|
|
for (int num = balls.Count - 1; num >= 0; num--)
|
|
{
|
|
balls[num].Delete();
|
|
}
|
|
if (won)
|
|
{
|
|
Audio.PlaySound("snd_won.wav");
|
|
}
|
|
else
|
|
{
|
|
Audio.PlaySound("snd_error.wav");
|
|
}
|
|
baller.anim.Play("Idle");
|
|
while (balls.Count > 0)
|
|
{
|
|
for (int num2 = balls.Count - 1; num2 >= 0; num2--)
|
|
{
|
|
balls[num2].Update();
|
|
}
|
|
yield return null;
|
|
}
|
|
player.LookAt(baller.GlobalPosition);
|
|
player.UpdateAnim(force: true);
|
|
kanako.LookAt(baller.GlobalPosition);
|
|
kanako.UpdateAnim(force: true);
|
|
if (won)
|
|
{
|
|
TextSystem.GetText("BBallWon");
|
|
SaveFile.AddFlag(SaveFile.Flags.BearFortLeftMinigame);
|
|
while (TextSystem.instance.Visible)
|
|
{
|
|
yield return null;
|
|
}
|
|
Coroutine w = Coroutine.Start(BridgeOpen());
|
|
while (w.done)
|
|
{
|
|
yield return null;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SaveFile.AddFlag(SaveFile.Flags.BBallKanakoTalk1);
|
|
if (!SaveFile.HasFlag(SaveFile.Flags.BBallPity1))
|
|
{
|
|
TextSystem.GetText("BBallLost");
|
|
SaveFile.AddFlag(SaveFile.Flags.BBallPity1);
|
|
}
|
|
else if (!SaveFile.HasFlag(SaveFile.Flags.BBallPity2))
|
|
{
|
|
TextSystem.GetText("BBallLost2");
|
|
SaveFile.AddFlag(SaveFile.Flags.BBallPity2);
|
|
}
|
|
while (TextSystem.instance.Visible)
|
|
{
|
|
yield return null;
|
|
}
|
|
}
|
|
Coroutine c = Coroutine.Start(CameraController.PanToObj(kanako));
|
|
while (!c.done)
|
|
{
|
|
baller.GlobalPosition = baller.GlobalPosition.Lerp(ballerpos, 0.1f * Main.deltaTime);
|
|
yield return null;
|
|
}
|
|
if (won)
|
|
{
|
|
penceller.GlobalPosition = new Vector2(-300f, -100f);
|
|
}
|
|
indicator.Text = "";
|
|
Room.current.DoMusic();
|
|
baller.Position = ballerpos;
|
|
}
|
|
|
|
private IEnumerator BridgeOpen()
|
|
{
|
|
Audio.PlaySound("snd_shadowpendant_ch1.wav");
|
|
Main.SetActive(bridge, state: true);
|
|
for (float a = 0f; a < 60f; a += Main.deltaTime)
|
|
{
|
|
bridge.Modulate = Main.colorClear.Lerp(Main.colorWhite, a / 60f);
|
|
yield return null;
|
|
}
|
|
bridgeBlocker.QueueFree();
|
|
SaveFile.AddFlag(SaveFile.Flags.BBallKanakoTalk1);
|
|
SaveFile.AddFlag(SaveFile.Flags.BBallKanakoTalk2);
|
|
}
|
|
|
|
public void KanakoHit(Node other)
|
|
{
|
|
if ((!other.HasMeta(ballTag) && other.GetParent() != pencil) || !(iframes <= 0f))
|
|
{
|
|
return;
|
|
}
|
|
iframes = 30f;
|
|
Audio.PlaySound("snd_hurt1.wav");
|
|
CameraController.Shake(10f);
|
|
bool flag = false;
|
|
for (int i = 0; i < balls.Count; i++)
|
|
{
|
|
if (other.GetParent() == balls[i].obj)
|
|
{
|
|
balls[i].Delete();
|
|
flag = true;
|
|
break;
|
|
}
|
|
}
|
|
if (flag)
|
|
{
|
|
BattleDR.ShowFloatingText("-1", kanako.GlobalPosition);
|
|
kanako.Shake(10f, 1f);
|
|
}
|
|
else
|
|
{
|
|
BattleDR.ShowFloatingText("-1", player.GlobalPosition);
|
|
player.Shake(10f, 1f);
|
|
}
|
|
lives--;
|
|
if (score > 0)
|
|
{
|
|
score--;
|
|
indicator.Text = score.ToString().PadLeft(2, '0');
|
|
}
|
|
}
|
|
|
|
public IEnumerator TossBall()
|
|
{
|
|
cd = Main.RandomRange(80, 120);
|
|
baller.anim.Play("TossReady");
|
|
baller.Shake(Main.RandomRange(20, 40), 1f);
|
|
while (baller.shake > 0f)
|
|
{
|
|
yield return null;
|
|
}
|
|
baller.anim.Play("TossDo");
|
|
balls.Add(new Balls
|
|
{
|
|
parent = this
|
|
});
|
|
List<Balls> list = balls;
|
|
list[list.Count - 1].Start();
|
|
for (float a = 0f; a < 30f; a += Main.deltaTime)
|
|
{
|
|
yield return null;
|
|
}
|
|
baller.anim.Play("Idle");
|
|
}
|
|
|
|
private void IndicatorCD()
|
|
{
|
|
player.doTrail = false;
|
|
kanako.doTrail = false;
|
|
state++;
|
|
if (state == 5)
|
|
{
|
|
cd = 60f;
|
|
indicator.Text = "GO";
|
|
}
|
|
else if (state == 6)
|
|
{
|
|
indicator.Text = "00";
|
|
}
|
|
else
|
|
{
|
|
cd = 60f;
|
|
indicator.Text = "0" + count[state];
|
|
}
|
|
}
|
|
|
|
}
|