Skip to content

Commit

Permalink
feat: add grooveline multiball
Browse files Browse the repository at this point in the history
  • Loading branch information
unRARed committed Dec 21, 2024
1 parent 5cf03e3 commit 7bf17d6
Show file tree
Hide file tree
Showing 8 changed files with 103 additions and 24 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,16 @@ graph TD
ATTRACT[/"Attract Mode"/] -- press start --> BASE[/"Base Mode"/]
BASE -- fuel up --> GREEN_FLAG[/"Green Flag Mode"/]
GREEN_FLAG -- make 3 laps --> RANDOM1{"Random<br>Event"}
GREEN_FLAG -- make 10 laps --> GROOVELINE[/"Grooveline Mode"/]
GREEN_FLAG -- make 10 laps --> GL_MODE[/"Grooveline Mode"/]
RANDOM1 -- fuel -->
PIT_CHECK{"Fuel, Oil or Tires need attention?"}
RANDOM1 -- tires --> PIT_CHECK
RANDOM1 -- oil --> PIT_CHECK
RANDOM1 -- bad luck --> BALL_DRAINS((("Ball Drains")))
PIT_CHECK -- yes --> BASE
PIT_CHECK -- no --> GREEN_FLAG
GL_MODE --> GL_MULTI("Grooveline Multiball")
GL_MULTI -- make 3 laps --> GL_MULTI_ADD_BALL("Add a Ball")
```

Expand Down
21 changes: 10 additions & 11 deletions docs/RULES.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,30 +20,28 @@ Racers, on your mark...
- Top left gate is closed.
- Standard scoring described here

### Green-flag 1/4
### Green-flag

The race begins!

- Activated when fuel, oil, and tires reach max level
- Top left gate is open allowing a counter-clockwise orbit
- Bottom-most 3 inserts on South-East chain tracks current orbit
- 3 successful orbits:
- Awards a bonus (TBD)
- Resets the inserts
- Lights one of the 4 traffic signal inserts
- Awards a bonus (TODO)

### Grooveline 2/4
### Grooveline 1/4

The fastest way around the track.

- North-West chain of clear inserts.
- Spells out G-R-O-O-V-E-L-I-N-E.
- Rolling over the North-West rollover advances a letter
- With all letters lit, Spinner activates "Shake your Groove Thing"
- Completing lights one of the 4 traffic signal inserts
- Making a lap during Green Flag lights one letter
- Lighting all 10 letters:
- Activates Shake your Groove Thing Multiball
- Lights one of the 4 traffic signal inserts
- **Resets after each ball**

### Grand Prix 3/4
### Grand Prix 2/4

It's the name of the game!

Expand All @@ -61,7 +59,7 @@ It's the name of the game!
- Activates Grand Prix Multiball
- Lights one of the 4 traffic signal inserts

### Pit Row Hurry-up 4/4
### Pit Row Hurry-up

Every driver's gotta pit Cole...

Expand Down Expand Up @@ -99,6 +97,7 @@ Every driver's gotta pit Cole...
#### Shake your Groove Thing Multiball (2-ball)

- Spinner and Grooveline rollover awards 2x scoring
- Add single ball by completing 3 laps within 15 seconds

#### Grand Prix Multiball (3-ball)

Expand Down
2 changes: 1 addition & 1 deletion modes/base/config/base.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

mode:
start_events: ball_starting
priority: 50
priority: 10
code: base.Base

ball_saves:
Expand Down
14 changes: 13 additions & 1 deletion modes/grooveline/config/grooveline.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,17 @@
mode:
start_events:
- logicblock_grooveline_counter_complete
stop_events:
- multiball_grooveline_ended
restart_on_next_ball: false
priority: 100
priority: 200

multiballs:
grooveline:
ball_count: 1
ball_count_type: add
shoot_again: 15s
start_events: mode_grooveline_started
# Making 3 laps adds 1 ball
add_a_ball_events:
- player_grooveline_counter_count{current_player.grooveline_counter_count == 3}
10 changes: 9 additions & 1 deletion tests/death_save.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ def _start(self):
self.advance_time_and_run(4)
self.assertEqual(1, self.machine.playfield.balls)

# assumes base mode is running (game started)
def _start_green_flag(self):
self._start()
# Player must "fill up" to start racing
self.assertEqual(
1, self.machine.game.player.level_fuel)
Expand All @@ -56,3 +56,11 @@ def _complete_lap(self):
self.hit_and_release_switch("s_spinner")
self.hit_and_release_switch("s_grooveline")
self.advance_time_and_run(1)

# assumes green_flag mode is running
def _start_grooveline(self):
self.machine.events. \
post("logicblock_grooveline_counter_complete")
self.advance_time_and_run(1)
self.advance_time_and_run(4)
self.assertModeRunning("grooveline")
3 changes: 3 additions & 0 deletions tests/death_save_game_testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,8 @@ def _start(self):
def _start_green_flag(self):
death_save._start_green_flag(self)

def _start_grooveline(self):
death_save._start_grooveline(self)

def _complete_lap(self):
death_save._complete_lap(self)
8 changes: 8 additions & 0 deletions tests/test_green_flag_mode.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ def test_scoring(self):
# driver for the mini coils
self.assertLightColor('x_loop_gate', 'black')

self._start()
self._start_green_flag()

# Mini coils is activated making it
Expand Down Expand Up @@ -40,6 +41,8 @@ def test_laps(self):
for event in random_events:
self.mock_event(event)
self.assertEqual(0, self._events.get(event, 0))

self._start()
self._start_green_flag()

for i in range(3):
Expand Down Expand Up @@ -83,6 +86,7 @@ def test_qualification(self):
self.assertModeNotRunning("green_flag")

def test_random_degrade_fuel_event(self):
self._start()
self._start_green_flag()
self.machine.events.post("degrade_fuel")
self.advance_time_and_run(1)
Expand All @@ -100,6 +104,7 @@ def test_random_degrade_fuel_event(self):
self.assertModeNotRunning("green_flag")

def test_random_degrade_oil_event(self):
self._start()
self._start_green_flag()
self.machine.events.post("degrade_oil")
self.advance_time_and_run(1)
Expand All @@ -119,6 +124,7 @@ def test_random_degrade_oil_event(self):
# self.machine.events.post("green_flag_smooth_sailing")

def test_random_degrade_tires_event(self):
self._start()
self._start_green_flag()
self.machine.events.post("degrade_tires")
self.advance_time_and_run(1)
Expand All @@ -136,6 +142,7 @@ def test_random_degrade_tires_event(self):
self.assertModeNotRunning("green_flag")

def test_random_degrade_all_event(self):
self._start()
self._start_green_flag()
self.machine.events.post("degrade_all")
self.advance_time_and_run(1)
Expand All @@ -158,6 +165,7 @@ def test_random_degrade_all_event(self):

# All bad luck events disable the flippers
def test_random_bad_luck_event(self):
self._start()
self._start_green_flag()
self.assertTrue(
self.machine.flippers["left_flipper"]._enabled
Expand Down
65 changes: 56 additions & 9 deletions tests/test_grooveline_mode.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

class TestGroovelineMode(DeathSaveGameTesting):

# Player qualifies by making 10 laps during
# green_flag mode on a single ball.
def test_qualification(self):
self._start()
self._start_green_flag()

self.hit_and_release_switch("s_spinner")
self.hit_and_release_switch("s_grooveline")
self._complete_lap()
self.assertEqual(
1, self.machine.game.player.grooveline_counter_count)

Expand All @@ -17,8 +19,7 @@ def test_qualification(self):
self.assertModeNotRunning("green_flag")

# Count doesn't increase outside of green_flag mode
self.hit_and_release_switch("s_spinner")
self.hit_and_release_switch("s_grooveline")
self._complete_lap()
self.assertEqual(
1, self.machine.game.player.grooveline_counter_count)

Expand Down Expand Up @@ -47,14 +48,60 @@ def test_qualification(self):
0, self.machine.game.player.grooveline_counter_count)

# Players hits the grooveline 10 times (10 laps)
for i in range(10):
# mock the event, so we avoid the random events
self.machine.events. \
post("logicblock_seq_lap_complete")
self.advance_time_and_run(1)
self._start_grooveline()

# Counter resets
self.assertEqual(
0, self.machine.game.player.grooveline_counter_count)
# And grooveline mode begins (multiball)

def test_multiball(self):
self._start_multiball()

# Player launches the ball
self.hit_and_release_switch("s_shooter_lane")
self.hit_switch_and_run("s_podium_advance2", 4)
self.assertEqual(2, self.machine.playfield.balls)

# ensure add a ball time has expired
self.advance_time_and_run(15)

# ball drains
self.hit_switch_and_run("s_trough1", 4)
self.hit_and_release_switch("s_shooter_lane")

self.assertModeRunning("grooveline")

def test_add_a_ball(self):
self._start_multiball()

# Player launches the ball
self.hit_and_release_switch("s_shooter_lane")
self.hit_switch_and_run("s_podium_advance2", 4)
self.assertEqual(2, self.machine.playfield.balls)

# Player completes 3 laps
for i in range(3):
self._complete_lap()

# Another a ball is added
self.assertEqual(0,
self.machine.ball_devices["bd_trough"].balls)
self.assertEqual(1,
self.machine.ball_devices["bd_shooter_lane"].balls)

# Player launches this ball, too
self.hit_and_release_switch("s_shooter_lane")
self.hit_switch_and_run("s_podium_advance2", 4)
self.assertEqual(3, self.machine.playfield.balls)

def _start_multiball(self):
self._start()
self._start_green_flag()
self._start_grooveline()
self.assertEqual(1, self.machine.playfield.balls)
# A ball is ejected to the shooter lane
self.assertEqual(1,
self.machine.ball_devices["bd_trough"].balls)
self.assertEqual(1,
self.machine.ball_devices["bd_shooter_lane"].balls)

0 comments on commit 7bf17d6

Please sign in to comment.