Skip to content

Commit

Permalink
(#11) sbasketball implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
Difegue committed Feb 1, 2023
1 parent 2cf87d0 commit e2000da
Show file tree
Hide file tree
Showing 3 changed files with 180 additions and 47 deletions.
2 changes: 1 addition & 1 deletion LCDonald.Core/Games/KnucklesTreasureHunt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ protected override void UpdateCore()
if (ThreadSafeEmeraldList().Count == 0)
{
_isInputBlocked = true;
_blockedCustomUpdates = 1; // Block one custom update so that emerald spawn doesn't happen instantly
BlockCustomUpdates(1); // Block one custom update so that emerald spawn doesn't happen instantly
}
}

Expand Down
211 changes: 172 additions & 39 deletions LCDonald.Core/Games/ShadowBasketball.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace LCDonald.Core.Games
{
Expand Down Expand Up @@ -54,9 +55,9 @@ public override List<string> GetAllGameElements()
BALL_21, BALL_22, BALL_23,
HANDS_21, HANDS_22, HANDS_23,
OMEGA_1, OMEGA_2, OMEGA_3,
HANDS_1, HANDS_2, HANDS_3,
BALL_11, BALL_12, BALL_13,
HANDS_1, HANDS_2, HANDS_3,

BALL_11, BALL_12, BALL_13,
SHADOW_1, SHADOW_2, SHADOW_3
};
}
Expand All @@ -79,34 +80,37 @@ public override List<LCDGameInput> GetAvailableInputs()
},
new LCDGameInput
{
Name = "Ball",
Description = "Shoot a Basketball",
Name = "Basket",
Description = "Make a basket",
KeyCode = 18, // space
}
};
}

private int _shadowPosition;
private int _omegaPosition; // TODO must be list
private List<int> _omegaPositions = new();
private int _ballPosition;
private bool _handsUp;
private List<int> _handPositions = new();

private int _goalsScored;
private int _ballsIntercepted;
private int _level;

protected override List<string> GetVisibleElements()
{
var handsPosition = _omegaPosition + (_handsUp ? 20 : 0);

var elements = new List<string>
{
"omega-" + _omegaPosition,
"hands-" + handsPosition,
"ball-" + _ballPosition,
"shadow-" + _shadowPosition
};

// Threadsafe list copies
foreach (var pos in new List<int>(_omegaPositions))
elements.Add("omega-" + pos);

foreach (var pos in new List<int>(_handPositions))
elements.Add("hands-" + pos);

// 8-segment display
switch (_goalsScored % 10)
{
Expand Down Expand Up @@ -162,16 +166,16 @@ protected override List<string> GetVisibleElements()

public override void InitializeGameState()
{
_shadowPosition = 1;
_omegaPosition = 1;
_shadowPosition = 2;
_omegaPositions = new() { 2 };
_ballPosition = 0;
_handsUp = false;
_handPositions = new() { 2 };
_goalsScored = 0;
_ballsIntercepted = 0;
_level = 0;

_customUpdateSpeed = 800;

StartupMusic();
}

Expand All @@ -189,79 +193,208 @@ public override void HandleInputs(List<LCDGameInput> pressedInputs)
{
_shadowPosition++;
}
else if (input.Name == "Ball" && _ballPosition == 0)
else if (input.Name == "Basket" && _ballPosition == 0)
{
_ballPosition = _shadowPosition + 10;
// TODO sound
SetBallSlowdown(true);
}
}
}

private void SetBallSlowdown(bool slowdown)
{
// This simulates a weird behavior in the OG game where the defenders move more slowly when a ball is out.
if (slowdown)
_customUpdateSpeed += 50;
else
_customUpdateSpeed -= 50;
}

private bool _ballHalfStep = false;
protected override void UpdateCore()
{
// Unused in this game
if (_ballPosition == 0) return;

// Move ball forward -- takes 2 update cycles to move 1 space
if (_ballHalfStep)
{
_ballHalfStep = false;
_ballPosition += 10;
}
else
_ballHalfStep = true;


if (_ballPosition > 40)
{
QueueSound(new LCDGameSound("../common/hit.ogg"));
_goalsScored += 2;
_ballPosition = 0;
SetBallSlowdown(false);
return;
}

if (_ballPosition > 23)
_ballPosition = 32;

if (_handPositions.Contains(_ballPosition))
{
_ballsIntercepted++;
_isInputBlocked = true;
QueueSound(new LCDGameSound("../common/miss.ogg"));

BlinkElement("omega-" + _ballPosition % 10, 2);
BlinkElement("hands-" + _ballPosition, 2);
BlinkElement("ball-" + _ballPosition, 2);

_ballPosition = 0;
SetBallSlowdown(false);
}
}

public override void CustomUpdate()
{
if (_goalsScored >= 30)
Victory();
_isInputBlocked = false;

if (_goalsScored >= 18)
{
_isInputBlocked = true;
QueueSound(new LCDGameSound("../common/level_up.ogg"));
_ballsIntercepted = 0;
_goalsScored = 0;
_level++;

// Speed up
_customUpdateSpeed -= 125;
_customUpdateSpeed -= 100;

_omegaPositions.Clear();
_handPositions.Clear();

// Add various amount of defenders depending on the level
// Level 1-2: One defender
// Level 3-4: Two defenders
// Level 5: Three defenders
var pos = _rng.Next(1, 4);
_omegaPositions.Add(pos);
_handPositions.Add(pos);

if (_level >= 2)
AddOmega();

if (_level == 4)
AddOmega();

return;
}

if (_level == 4)
if (_level == 5)
{
Victory();
return;
}

// Move ball forward
if (_ballPosition != 0)
_ballPosition += 10;
// Move defenders
if (_omegaPositions.Count < 3)
for (var i = 0; i < _omegaPositions.Count; i++)
{
var pos = _omegaPositions[i];

bool hasDodgedCar = false;
bool hasBeenHit = false;

// Randomly shift left/right if the position isn't already taken
var newPos = pos + _rng.Next(-1, 2);

// Only count a row as dodged if the player hasn't been hit
if (hasDodgedCar && !hasBeenHit)
{
QueueSound(new LCDGameSound("../common/hit.ogg"));
_goalsScored++;
}
// Check boundaries
if (newPos == 0)
newPos = 3;

if (_ballsIntercepted == 5)
if (newPos == 4)
newPos = 1;

// If the spot is already taken, use the other only left one (neither pos nor newPos)
if (newPos != pos && _omegaPositions.Contains(newPos))
{
var l = new List<int> { 1, 2, 3 };
l.Remove(pos);
l.Remove(newPos);
newPos = l.First();
}

_omegaPositions[i] = newPos;
_handPositions[i] = newPos;
}

// 33% chance to raise hands (+20 to pos so it matches ball positioning)
for (var i = 0; i < _handPositions.Count; i++)
_handPositions[i] = _rng.Next(0, 3) == 0 ? _handPositions[i] % 10 + 20 : _handPositions[i] % 10;

if (_ballsIntercepted >= 5)
{
GameOver();
return;
}

}

private void AddOmega()
{
var pos = 1;
// Incredibly unefficient
while (_omegaPositions.Contains(pos))
pos = _rng.Next(1, 4);

_omegaPositions.Add(pos);
_handPositions.Add(pos);
}

private void GameOver()
{
_shadowPosition = -1;
_omegaPositions.Clear();
_handPositions.Clear();
_goalsScored = -1;
_ballPosition = 0;
_level = 0;

GenericGameOverAnimation(new List<string> { SHADOW_1 });
GenericGameOverAnimation(new List<string> { SHADOW_2, OMEGA_2, HANDS_22 });
Stop();
}

private void Victory()
{
_shadowPosition = -1;
_omegaPositions.Clear();
_handPositions.Clear();
_goalsScored = -1;
_ballPosition = 0;
_level = 0;

GenericVictoryAnimation(new List<string> { SHADOW_1 });
QueueSound(new LCDGameSound("../common/game_win_short.ogg"));

// 2x move across screen left to right shooting baskets
var victoryFrame1 = new List<string> { SHADOW_1, BALL_11 };
var victoryFrame2 = new List<string> { SHADOW_1, BALL_21 };
var victoryFrame3 = new List<string> { SHADOW_1, BALL_32 };
var victoryFrame4 = new List<string> { SHADOW_2, BALL_12 };
var victoryFrame5 = new List<string> { SHADOW_2, BALL_22 };
var victoryFrame6 = new List<string> { SHADOW_2, BALL_32 };
var victoryFrame7 = new List<string> { SHADOW_3, BALL_13 };
var victoryFrame8 = new List<string> { SHADOW_3, BALL_23 };
var victoryFrame9 = new List<string> { SHADOW_3, BALL_32 };


var victoryAnimation = new List<List<string>> { victoryFrame1, victoryFrame1, victoryFrame1, victoryFrame1, victoryFrame2, victoryFrame2, victoryFrame2, victoryFrame2,
victoryFrame3, victoryFrame3, victoryFrame3, victoryFrame3, victoryFrame4, victoryFrame4, victoryFrame4, victoryFrame4,
victoryFrame5, victoryFrame5, victoryFrame5, victoryFrame5, victoryFrame6, victoryFrame6, victoryFrame6, victoryFrame6,
victoryFrame7, victoryFrame7, victoryFrame7, victoryFrame7, victoryFrame8, victoryFrame8, victoryFrame8, victoryFrame8,
victoryFrame9, victoryFrame9, victoryFrame9, victoryFrame9, victoryFrame1, victoryFrame1, victoryFrame1, victoryFrame1,
victoryFrame2, victoryFrame2, victoryFrame2, victoryFrame2, victoryFrame3, victoryFrame3, victoryFrame3, victoryFrame3,
victoryFrame4, victoryFrame4, victoryFrame4, victoryFrame4, victoryFrame5, victoryFrame5, victoryFrame5, victoryFrame5,
victoryFrame6, victoryFrame6, victoryFrame6, victoryFrame6, victoryFrame7, victoryFrame7, victoryFrame7, victoryFrame7,
victoryFrame8, victoryFrame8, victoryFrame8, victoryFrame8, victoryFrame9, victoryFrame9, victoryFrame9, victoryFrame9};

PlayAnimation(victoryAnimation);
Stop();
}

}
}
14 changes: 7 additions & 7 deletions LCDonald.Core/Model/LCDGameBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -242,14 +242,14 @@ public List<string> GetVisibleGameElements()
// Add elements that are blinking, remove the ones that aren't
foreach (var element in _blinkingElements.Keys)
{
if (!_blinkingElements.ContainsKey(element)) continue;
if (_blinkingElements.TryGetValue(element, out var value)) {
var isVisible = value % 1 != 0.5;

var isVisible = _blinkingElements[element] % 1 != 0.5;

if (isVisible)
visibleElements.Add(element);
else
visibleElements.Remove(element);
if (isVisible)
visibleElements.Add(element);
else
visibleElements.Remove(element);
}
}

return visibleElements;
Expand Down

0 comments on commit e2000da

Please sign in to comment.