Compare commits
2 Commits
3ea76a97e7
...
99e5a41917
Author | SHA1 | Date |
---|---|---|
Ryan Rix | 99e5a41917 | |
Ryan Rix | 3969216d7d |
51
README.org
51
README.org
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
11
prototype.py
11
prototype.py
|
@ -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!")
|
||||
|
|
Loading…
Reference in New Issue