Compare commits

...

2 Commits

Author SHA1 Message Date
Ryan Rix 99e5a41917 splat. i beat it! 2023-04-07 19:07:54 -07:00
Ryan Rix 3969216d7d try to fix finish state 2023-04-07 18:51:46 -07:00
5 changed files with 82 additions and 16 deletions

View File

@ -17,24 +17,36 @@ or maybe it's a roguelite deckbuilder... Let's try that:
I haven't actually beat this yet. That doesn't mean you can't? In theory? I don't know what happens when you run out of stage cards is what I am saying 😇
Some notes:
- the longer the straight is, the more you'll accelerate. Probably worth making the longest straight 50 meters or so or injecting a braking-zone card between long straight and hard turns to make sure the player has the right resources
- card values are all fucked up, this is just a first playtest..
#+begin_src python :tangle ~/org/group-b/prototype.py
from group_b.action_deck import ActionDeck, ActionCard
from group_b.player import PlayerState
import os
p = PlayerState()
os.system('cls' if os.name=='nt' else 'clear')
print("Stage start. Ready?")
while len(p._pace_note_queue) > 0:
print(p.resources())
print()
print(', '.join([str(c) for c in p._pace_note_queue]))
print("you can:", [f"{idx}: {str(c)}" for idx, c in enumerate(p.hand())])
choice = int(input("action index: "))
os.system('cls' if os.name=='nt' else 'clear')
card = p.hand()[choice]
p.perform_action(card)
p.draw()
print(p.resources())
p.check_damage()
print("You've beat the stage!")
#+end_src
Once it's possible to complete a stage the next logical step would be to add (speed*distance) timing to the stage so that you can see how fast you progress through and race against known seeds?
@ -77,7 +89,7 @@ A player can see =NOTE_LOOKAHEAD= cards in to the future. there is a difficulty
#+begin_src python :tangle ~/org/group-b/group_b/player.py :noweb yes
from .action_deck import ActionDeck, ActionCard
from .stage_deck import StageDeck, StraightCard
from .stage_deck import StageDeck, StageDeckEmpty, StraightCard
class PlayerState():
START_HAND = 4
@ -135,7 +147,10 @@ class PlayerState():
current_stage_note.discard()
action.discard()
self.hand().remove(action)
self._pace_note_queue.append(self._stage.draw())
try:
self._pace_note_queue.append(self._stage.draw())
except StageDeckEmpty:
pass
def check_damage(self):
if self._resources.car_health <= 0:
@ -274,8 +289,9 @@ class ActionDeck(Deck):
def load_cards(self):
cards = [ActionCard(name="accelerate", deck=self)] * 3
cards.extend([ActionCard(name="gun it!", deck=self)] * 2)
cards.extend([ActionCard(name="brake", deck=self)] * 3)
cards.extend([ActionCard(name="brake", deck=self)] * 5)
cards.extend([ActionCard(name="coast", deck=self)] * 2)
cards.extend([ActionCard(name="find flow", deck=self)] * 2)
return cards
@ -306,7 +322,7 @@ class ActionCard(Card):
elif name == "coast":
return dict(
speed=0,
focus=2,
focus=1,
momentum=-0.25,
tire_wear=0,
car_health=0,
@ -315,12 +331,22 @@ class ActionCard(Card):
return dict(
speed=1,
focus=-2,
momentum=0.25,
momentum=0.5,
tire_wear=-0.5,
car_health=-0.05,
)
elif name == "find flow":
return dict(
speed=0,
focus=4,
momentum=0,
tire_wear=-0.5,
car_health=-0.05,
)
#+end_src
speed should not be set by the cards but calculated from momentum... The user is managing the momentum and focus to get the most speed with the least damage/wear.
** Stage Deck
The Stage Deck is what defines a rally stage. This version of it is procedurally generated where there are 2x as many turns as straights [[(StageCardWeight)]], and the straights' lengths are weighted toward being shorter [[(StraightCardWeight)]]. You could imagine a =StageDeck= class that pulls its list of cards from a rough take on famous stages and could be paired with art of them.
@ -335,12 +361,19 @@ from enum import Enum
from random import randint, choice, choices
class StageDeck(Deck):
DEFAULT_DECK_SIZE=25
def load_cards(self):
cards = list()
cards.extend(StageCard.generate(self, cnt=15))
cards.extend(StageCard.generate(self, cnt=self.DEFAULT_DECK_SIZE))
return cards
def draw(self) -> Card:
if len(self._cards) == 0:
raise StageDeckEmpty()
return self._cards.pop()
@dataclass
class StageCard(Card):
# turn w/ numeric modifier (max speed you can take the turn)
@ -359,6 +392,8 @@ class StageCard(Card):
cls_list = choices([TurnCard, StraightCard], weights=weights, k=cnt)
return [real_cls.generate(deck) for real_cls in cls_list]
class StageDeckEmpty(BaseException):
pass
#+end_src
=Card= sub-classes are expected to implement =can_pass_with= which take a =PlayerState= and an =ActionCard= to evaluate whether it is safe for a Player to progress through. For example, the =TurnCard= compares the speed, health, etc of the user to ensure they aren't taken a corner too quickly.
@ -392,7 +427,7 @@ class TurnCard(StageCard):
def can_pass_with(self, player, action: ActionCard) -> bool:
# TKTKTK use certain action cards as pass?
if player._resources.speed > self.modifier:
if int(player._resources.speed) > self.modifier:
return False
if player._resources.focus <= 0:
return False

View File

@ -4,8 +4,9 @@ class ActionDeck(Deck):
def load_cards(self):
cards = [ActionCard(name="accelerate", deck=self)] * 3
cards.extend([ActionCard(name="gun it!", deck=self)] * 2)
cards.extend([ActionCard(name="brake", deck=self)] * 3)
cards.extend([ActionCard(name="brake", deck=self)] * 5)
cards.extend([ActionCard(name="coast", deck=self)] * 2)
cards.extend([ActionCard(name="find flow", deck=self)] * 2)
return cards
@ -36,7 +37,7 @@ class ActionCard(Card):
elif name == "coast":
return dict(
speed=0,
focus=2,
focus=1,
momentum=-0.25,
tire_wear=0,
car_health=0,
@ -45,7 +46,15 @@ class ActionCard(Card):
return dict(
speed=1,
focus=-2,
momentum=0.25,
momentum=0.5,
tire_wear=-0.5,
car_health=-0.05,
)
elif name == "find flow":
return dict(
speed=0,
focus=4,
momentum=0,
tire_wear=-0.5,
car_health=-0.05,
)

View File

@ -1,5 +1,5 @@
from .action_deck import ActionDeck, ActionCard
from .stage_deck import StageDeck, StraightCard
from .stage_deck import StageDeck, StageDeckEmpty, StraightCard
class PlayerState():
START_HAND = 4
@ -57,7 +57,10 @@ class PlayerState():
current_stage_note.discard()
action.discard()
self.hand().remove(action)
self._pace_note_queue.append(self._stage.draw())
try:
self._pace_note_queue.append(self._stage.draw())
except StageDeckEmpty:
pass
def check_damage(self):
if self._resources.car_health <= 0:

View File

@ -7,12 +7,19 @@ from enum import Enum
from random import randint, choice, choices
class StageDeck(Deck):
DEFAULT_DECK_SIZE=25
def load_cards(self):
cards = list()
cards.extend(StageCard.generate(self, cnt=15))
cards.extend(StageCard.generate(self, cnt=self.DEFAULT_DECK_SIZE))
return cards
def draw(self) -> Card:
if len(self._cards) == 0:
raise StageDeckEmpty()
return self._cards.pop()
@dataclass
class StageCard(Card):
# turn w/ numeric modifier (max speed you can take the turn)
@ -30,6 +37,9 @@ class StageCard(Card):
weights = [10, 5] # (ref:StageCardWeight)
cls_list = choices([TurnCard, StraightCard], weights=weights, k=cnt)
return [real_cls.generate(deck) for real_cls in cls_list]
class StageDeckEmpty(BaseException):
pass
class CardShape(str, Enum):
RIGHT = "right"
@ -57,7 +67,7 @@ class TurnCard(StageCard):
def can_pass_with(self, player, action: ActionCard) -> bool:
# TKTKTK use certain action cards as pass?
if player._resources.speed > self.modifier:
if int(player._resources.speed) > self.modifier:
return False
if player._resources.focus <= 0:
return False

View File

@ -1,17 +1,26 @@
from group_b.action_deck import ActionDeck, ActionCard
from group_b.player import PlayerState
import os
p = PlayerState()
os.system('cls' if os.name=='nt' else 'clear')
print("Stage start. Ready?")
while len(p._pace_note_queue) > 0:
print(p.resources())
print(f"{len(p._stage._cards)} notes left... keep pushing!")
print()
print(', '.join([str(c) for c in p._pace_note_queue]))
print("you can:", [f"{idx}: {str(c)}" for idx, c in enumerate(p.hand())])
choice = int(input("action index: "))
os.system('cls' if os.name=='nt' else 'clear')
card = p.hand()[choice]
p.perform_action(card)
p.draw()
print(p.resources())
p.check_damage()
print("You've beat the stage!")