mirror of
https://github.com/rr-/pq-cli.git
synced 2026-09-28 22:33:59 -06:00
mechanic: refactor creating new player
This commit is contained in:
+14
-19
@@ -3,11 +3,6 @@ import typing as T
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
|
||||||
def level_up_time(level) -> int:
|
|
||||||
# seconds
|
|
||||||
return 20 * level * 60
|
|
||||||
|
|
||||||
|
|
||||||
class Traits(enum.Enum):
|
class Traits(enum.Enum):
|
||||||
name = "Name"
|
name = "Name"
|
||||||
race = "Race"
|
race = "Race"
|
||||||
@@ -26,6 +21,20 @@ class Stat(enum.Enum):
|
|||||||
mp_max = "MP Max"
|
mp_max = "MP Max"
|
||||||
|
|
||||||
|
|
||||||
|
class Equipment(enum.Enum):
|
||||||
|
weapon = "Weapon"
|
||||||
|
shield = "Shield"
|
||||||
|
helm = "Helm"
|
||||||
|
hauberk = "Hauberk"
|
||||||
|
brassairts = "Brassairts"
|
||||||
|
vambraces = "Vambraces"
|
||||||
|
gauntlets = "Gauntlets"
|
||||||
|
gambeson = "Gambeson"
|
||||||
|
cuisses = "Cuisses"
|
||||||
|
greaves = "Greaves"
|
||||||
|
sollerets = "Sollerets"
|
||||||
|
|
||||||
|
|
||||||
PRIME_STATS = [
|
PRIME_STATS = [
|
||||||
Stat.strength,
|
Stat.strength,
|
||||||
Stat.condition,
|
Stat.condition,
|
||||||
@@ -38,20 +47,6 @@ PRIME_STATS = [
|
|||||||
ALL_STATS = PRIME_STATS + [Stat.hp_max, Stat.mp_max]
|
ALL_STATS = PRIME_STATS + [Stat.hp_max, Stat.mp_max]
|
||||||
|
|
||||||
|
|
||||||
EQUIPS = [
|
|
||||||
"Weapon",
|
|
||||||
"Shield",
|
|
||||||
"Helm",
|
|
||||||
"Hauberk",
|
|
||||||
"Brassairts",
|
|
||||||
"Vambraces",
|
|
||||||
"Gauntlets",
|
|
||||||
"Gambeson",
|
|
||||||
"Cuisses",
|
|
||||||
"Greaves",
|
|
||||||
"Sollerets",
|
|
||||||
]
|
|
||||||
|
|
||||||
SPELLS = [
|
SPELLS = [
|
||||||
"Slime Finger",
|
"Slime Finger",
|
||||||
"Rabbit Punch",
|
"Rabbit Punch",
|
||||||
|
|||||||
+142
-17
@@ -1,9 +1,15 @@
|
|||||||
import datetime
|
import datetime
|
||||||
|
import enum
|
||||||
import random
|
import random
|
||||||
import typing as T
|
import typing as T
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass, field
|
||||||
|
|
||||||
from pqcli.config import CLASSES, PRIME_STATS, RACES, Class, Race, Stat
|
from pqcli.config import *
|
||||||
|
|
||||||
|
|
||||||
|
def level_up_time(level: int) -> int:
|
||||||
|
# seconds
|
||||||
|
return 20 * level * 60
|
||||||
|
|
||||||
|
|
||||||
def generate_name() -> str:
|
def generate_name() -> str:
|
||||||
@@ -20,7 +26,7 @@ def generate_name() -> str:
|
|||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Stats:
|
class Stats:
|
||||||
def __init__(self):
|
def __init__(self) -> None:
|
||||||
self.values = {stat: 0 for stat in Stat}
|
self.values = {stat: 0 for stat in Stat}
|
||||||
|
|
||||||
def __iter__(self) -> T.Iterable[T.Tuple[Stat, int]]:
|
def __iter__(self) -> T.Iterable[T.Tuple[Stat, int]]:
|
||||||
@@ -34,24 +40,145 @@ class Stats:
|
|||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Player:
|
class Item:
|
||||||
name: str
|
name: str
|
||||||
stats: Stats
|
quantity: int
|
||||||
race: Race
|
|
||||||
class_: Class
|
|
||||||
birthday: datetime.datetime
|
@dataclass
|
||||||
|
class Spell:
|
||||||
|
name: str
|
||||||
|
level: int
|
||||||
|
|
||||||
|
|
||||||
|
class Inventory:
|
||||||
|
def __init__(self, items: T.Optional[T.List[Item]] = []) -> None:
|
||||||
|
self.items = [] if items is None else items
|
||||||
|
|
||||||
|
def add(self, item_name: str, quantity: int) -> None:
|
||||||
|
for item in self.items:
|
||||||
|
if item.name == item_name:
|
||||||
|
item.quantity += quantity
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
self.items.append(Item(name=item_name, quantity=quantity))
|
||||||
|
|
||||||
|
|
||||||
|
class SpellBook:
|
||||||
|
def __init__(self, spells: T.Optional[T.List[Item]] = None) -> None:
|
||||||
|
self.spells = [] if spells is None else spells
|
||||||
|
|
||||||
|
def add(self, spell_name: str, level: int) -> None:
|
||||||
|
for item in self.spells:
|
||||||
|
if item.name == spell_name:
|
||||||
|
item.level += level
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
self.spells.append(Spell(name=spell_name, level=level))
|
||||||
|
|
||||||
|
|
||||||
|
class Bar:
|
||||||
|
def __init__(self, max_: int, position: int = 0) -> None:
|
||||||
|
self.position = position
|
||||||
|
self.max_ = max_
|
||||||
|
|
||||||
|
|
||||||
|
class TaskType(enum.Enum):
|
||||||
|
task = "task"
|
||||||
|
plot = "plot"
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Task:
|
||||||
|
task_type: TaskType
|
||||||
|
length: int
|
||||||
|
description: str
|
||||||
|
|
||||||
|
|
||||||
|
class Player:
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
name: str,
|
||||||
|
birthday: datetime.datetime,
|
||||||
|
race: Race,
|
||||||
|
class_: Class,
|
||||||
|
stats: Stats,
|
||||||
|
) -> None:
|
||||||
|
self.name: str = name
|
||||||
|
self.birthday: datetime.datetime = birthday
|
||||||
|
self.race: Race = race
|
||||||
|
self.class_: Class = class_
|
||||||
|
self.stats: Stats = stats
|
||||||
|
self.level = 1
|
||||||
|
self.act = 0
|
||||||
|
|
||||||
|
self.queue: T.List[Task] = [
|
||||||
|
Task(
|
||||||
|
TaskType.task,
|
||||||
|
10,
|
||||||
|
"Experiencing an enigmatic and foreboding night vision",
|
||||||
|
),
|
||||||
|
Task(
|
||||||
|
TaskType.task,
|
||||||
|
6,
|
||||||
|
"Much is revealed about that wise old bastard you'd underestimated",
|
||||||
|
),
|
||||||
|
Task(
|
||||||
|
TaskType.task,
|
||||||
|
6,
|
||||||
|
"A shocking series of events leaves you alone and bewildered, but resolute",
|
||||||
|
),
|
||||||
|
Task(
|
||||||
|
TaskType.task,
|
||||||
|
4,
|
||||||
|
"Drawing upon an unrealized reserve of determination, you set out on a long and dangerous journey",
|
||||||
|
),
|
||||||
|
Task(TaskType.plot, 2, "Loading"),
|
||||||
|
]
|
||||||
|
|
||||||
|
self.exp_bar = Bar(max_=level_up_time(1))
|
||||||
|
self.encum_bar = Bar(max_=stats[Stat.strength] + 10)
|
||||||
|
self.quest_bar = Bar(max_=1)
|
||||||
|
self.task_bar = Bar(max_=2000)
|
||||||
|
self.plot_bar = Bar(max_=sum(task.length for task in self.queue))
|
||||||
|
|
||||||
|
self.inventory = Inventory([Item(name="Gold", quantity=0)])
|
||||||
|
self.spell_book = SpellBook()
|
||||||
|
self.equipment: T.Dict[Equipment, str] = {
|
||||||
|
Equipment.weapon: "Sharp Rock",
|
||||||
|
Equipment.hauberk: "-3 Burlap",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def special_item() -> str:
|
||||||
|
return interesting_item() + " of " + random.choice(ITEM_OFS)
|
||||||
|
|
||||||
|
|
||||||
|
def interesting_item() -> str:
|
||||||
|
return random.choice(ITEM_ATTRIB) + " " + random.choice(SPECIALS)
|
||||||
|
|
||||||
|
|
||||||
|
def boring_item() -> str:
|
||||||
|
return random.choice(BORING_ITEMS)
|
||||||
|
|
||||||
|
|
||||||
|
def win_item(player: Player) -> None:
|
||||||
|
player.inventory.add(special_item(), 1)
|
||||||
|
|
||||||
|
|
||||||
class Roster:
|
class Roster:
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.players: T.List[Player] = []
|
self.players: T.List[Player] = []
|
||||||
|
|
||||||
|
def add_player(self, player: Player) -> None:
|
||||||
|
self.players.append(player)
|
||||||
|
|
||||||
|
|
||||||
class StatsBuilder:
|
class StatsBuilder:
|
||||||
def __init__(self):
|
def __init__(self) -> None:
|
||||||
self.history: T.List[Stats] = []
|
self.history: T.List[Stats] = []
|
||||||
|
|
||||||
def roll(self):
|
def roll(self) -> Stats:
|
||||||
stats = Stats()
|
stats = Stats()
|
||||||
for stat in PRIME_STATS:
|
for stat in PRIME_STATS:
|
||||||
stats[stat] = (
|
stats[stat] = (
|
||||||
@@ -67,18 +194,16 @@ class StatsBuilder:
|
|||||||
self.history.append(stats)
|
self.history.append(stats)
|
||||||
return stats
|
return stats
|
||||||
|
|
||||||
def unroll(self):
|
def unroll(self) -> Stats:
|
||||||
self.history.pop()
|
self.history.pop()
|
||||||
return self.history[-1]
|
return self.history[-1]
|
||||||
|
|
||||||
|
|
||||||
def create_player(stats_builder: StatsBuilder) -> Player:
|
def create_player(
|
||||||
|
name: str, race: Race, class_: Class, stats: Stats
|
||||||
|
) -> Player:
|
||||||
now = datetime.datetime.now()
|
now = datetime.datetime.now()
|
||||||
random.seed(now)
|
random.seed(now)
|
||||||
return Player(
|
return Player(
|
||||||
birthday=now,
|
birthday=now, name=name, race=race, class_=class_, stats=stats
|
||||||
name=generate_name(),
|
|
||||||
stats=stats_builder.roll(),
|
|
||||||
race=random.choice(RACES),
|
|
||||||
class_=random.choice(CLASSES),
|
|
||||||
)
|
)
|
||||||
|
|||||||
+18
-30
@@ -5,15 +5,15 @@ import urwid
|
|||||||
import urwid_readline
|
import urwid_readline
|
||||||
|
|
||||||
from pqcli.config import CLASSES, PRIME_STATS, RACES
|
from pqcli.config import CLASSES, PRIME_STATS, RACES
|
||||||
from pqcli.mechanic import Player, StatsBuilder, create_player, generate_name
|
from pqcli.mechanic import Stats, StatsBuilder, generate_name
|
||||||
from pqcli.ui.button import MenuButton
|
from pqcli.ui.button import MenuButton
|
||||||
from pqcli.ui.line_box import LineBox
|
from pqcli.ui.line_box import LineBox
|
||||||
|
|
||||||
|
|
||||||
class StatsBox(urwid.Filler):
|
class StatsBox(urwid.Filler):
|
||||||
def __init__(self, player: Player, stats_builder: StatsBuilder) -> None:
|
def __init__(self) -> None:
|
||||||
self.player = player
|
self.stats_builder = StatsBuilder()
|
||||||
self.stats_builder = stats_builder
|
self.stats = self.stats_builder.roll()
|
||||||
self.stat_labels = {stat: urwid.Text("0") for stat in PRIME_STATS}
|
self.stat_labels = {stat: urwid.Text("0") for stat in PRIME_STATS}
|
||||||
self.total_label = urwid.Text("0")
|
self.total_label = urwid.Text("0")
|
||||||
self.update_values()
|
self.update_values()
|
||||||
@@ -59,48 +59,46 @@ class StatsBox(urwid.Filler):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def on_roll_press(self, _user_data: T.Any) -> None:
|
def on_roll_press(self, _user_data: T.Any) -> None:
|
||||||
self.player.stats = self.stats_builder.roll()
|
self.stats = self.stats_builder.roll()
|
||||||
self.update_values()
|
self.update_values()
|
||||||
|
|
||||||
def on_unroll_press(self, _user_data: T.Any) -> None:
|
def on_unroll_press(self, _user_data: T.Any) -> None:
|
||||||
try:
|
try:
|
||||||
self.player.stats = self.stats_builder.unroll()
|
self.stats = self.stats_builder.unroll()
|
||||||
except IndexError:
|
except IndexError:
|
||||||
return
|
return
|
||||||
self.update_values()
|
self.update_values()
|
||||||
|
|
||||||
def update_values(self) -> None:
|
def update_values(self) -> None:
|
||||||
for stat, edit in self.stat_labels.items():
|
for stat, edit in self.stat_labels.items():
|
||||||
edit.set_text(str(self.player.stats[stat]))
|
edit.set_text(str(self.stats[stat]))
|
||||||
self.total_label.set_text(
|
self.total_label.set_text(
|
||||||
str(
|
str(sum(self.stats[stat] for stat in self.stat_labels.keys()))
|
||||||
sum(
|
|
||||||
self.player.stats[stat] for stat in self.stat_labels.keys()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class RaceBox(LineBox):
|
class RaceBox(LineBox):
|
||||||
def __init__(self, player: Player) -> None:
|
def __init__(self) -> None:
|
||||||
race_checkboxes = []
|
race_checkboxes = []
|
||||||
|
self.race = random.choice(RACES)
|
||||||
for race in RACES:
|
for race in RACES:
|
||||||
urwid.RadioButton(
|
urwid.RadioButton(
|
||||||
group=race_checkboxes,
|
group=race_checkboxes,
|
||||||
label=race.name,
|
label=race.name,
|
||||||
state=race.name == player.race.name,
|
state=race.name == self.race.name,
|
||||||
)
|
)
|
||||||
super().__init__(urwid.ListBox(race_checkboxes), title="Race")
|
super().__init__(urwid.ListBox(race_checkboxes), title="Race")
|
||||||
|
|
||||||
|
|
||||||
class ClassBox(LineBox):
|
class ClassBox(LineBox):
|
||||||
def __init__(self, player: Player) -> None:
|
def __init__(self) -> None:
|
||||||
class_checkboxes = []
|
class_checkboxes = []
|
||||||
|
self.class_ = random.choice(CLASSES)
|
||||||
for class_ in CLASSES:
|
for class_ in CLASSES:
|
||||||
urwid.RadioButton(
|
urwid.RadioButton(
|
||||||
group=class_checkboxes,
|
group=class_checkboxes,
|
||||||
label=class_.name,
|
label=class_.name,
|
||||||
state=class_.name == player.class_.name,
|
state=class_.name == self.class_.name,
|
||||||
)
|
)
|
||||||
super().__init__(urwid.ListBox(class_checkboxes), title="Class")
|
super().__init__(urwid.ListBox(class_checkboxes), title="Class")
|
||||||
|
|
||||||
@@ -110,24 +108,17 @@ class NewGameView(urwid.Pile):
|
|||||||
self.on_confirm = on_confirm
|
self.on_confirm = on_confirm
|
||||||
self.on_cancel = on_cancel
|
self.on_cancel = on_cancel
|
||||||
|
|
||||||
stats_builder = StatsBuilder()
|
race_box = RaceBox()
|
||||||
self.player = create_player(stats_builder)
|
class_box = ClassBox()
|
||||||
|
stats_box = StatsBox()
|
||||||
race_box = RaceBox(self.player)
|
|
||||||
class_box = ClassBox(self.player)
|
|
||||||
stats_box = StatsBox(self.player, stats_builder)
|
|
||||||
|
|
||||||
self.char_name_edit = urwid_readline.ReadlineEdit(
|
self.char_name_edit = urwid_readline.ReadlineEdit(
|
||||||
"Name: ", self.player.name
|
"Name: ", generate_name()
|
||||||
)
|
)
|
||||||
generate_char_name_btn = MenuButton(
|
generate_char_name_btn = MenuButton(
|
||||||
"Generate random name", on_press=self.on_generate_char_name_press
|
"Generate random name", on_press=self.on_generate_char_name_press
|
||||||
)
|
)
|
||||||
|
|
||||||
urwid.connect_signal(
|
|
||||||
self.char_name_edit, "postchange", self.on_char_name_change
|
|
||||||
)
|
|
||||||
|
|
||||||
super().__init__(
|
super().__init__(
|
||||||
[
|
[
|
||||||
(1, urwid.Filler(self.char_name_edit)),
|
(1, urwid.Filler(self.char_name_edit)),
|
||||||
@@ -154,9 +145,6 @@ class NewGameView(urwid.Pile):
|
|||||||
self.char_name_edit.edit_text = generate_name()
|
self.char_name_edit.edit_text = generate_name()
|
||||||
self.char_name_edit.edit_pos = len(self.char_name_edit.edit_text)
|
self.char_name_edit.edit_pos = len(self.char_name_edit.edit_text)
|
||||||
|
|
||||||
def on_char_name_change(self, widget: urwid.Text, old_text: str) -> None:
|
|
||||||
self.player.name = widget.edit_text
|
|
||||||
|
|
||||||
def on_generate_char_name_press(self, _user_data: T.Any) -> None:
|
def on_generate_char_name_press(self, _user_data: T.Any) -> None:
|
||||||
self.generate_random_char_name()
|
self.generate_random_char_name()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user