9 Commits
Author SHA1 Message Date
rr- ef9a7f9e20 ui: allow loading characters directly from cli 2020-09-16 22:13:07 +02:00
rr- 1ad563ad93 misc: release 1.0.2 2020-08-17 09:12:56 +02:00
rr- 29207c1d4c misc: remove unused imports 2020-08-17 09:12:56 +02:00
CJ Kucera 67c3888f82 docs: add troubleshooting section 2020-06-22 21:57:43 +02:00
rr- d4675c747a misc: require windows-curses for Windows 2020-05-07 15:36:41 +02:00
Petr Gašparík c5f0c60ec8 roster: fix overwriting old saves on Windows 2020-05-07 15:27:56 +02:00
rr- fc4dcff9e3 ui/curses: fix division by zero 2020-05-07 15:04:58 +02:00
rr- f8a030a648 misc: release 1.0.1 2019-04-10 20:09:47 +02:00
rr- 82c8d21395 ui/curses: fix division by zero 2019-04-10 20:09:22 +02:00
15 changed files with 93 additions and 29 deletions
+11
View File
@@ -41,3 +41,14 @@ $ git clone https://github.com/rr-/pq-cli.git
$ cd pq-cli $ cd pq-cli
$ pip install --user . $ pip install --user .
``` ```
## Troubleshooting
### `_curses.error: init_pair() returned ERR`
If running on Linux and you get the error `_curses.error: init_pair() returned ERR`,
try making sure that your `$TERM` variable is set to a value which supports
256 colors, such as via the following:
TERM=xterm-256color pqcli
+33 -1
View File
@@ -1,8 +1,11 @@
import argparse import argparse
import sys
import typing as T
from pathlib import Path from pathlib import Path
import xdg import xdg
from pqcli.mechanic import Player
from pqcli.roster import Roster from pqcli.roster import Roster
from pqcli.ui.basic import BasicUserInterface from pqcli.ui.basic import BasicUserInterface
from pqcli.ui.curses import CursesUserInterface from pqcli.ui.curses import CursesUserInterface
@@ -44,15 +47,44 @@ def parse_args() -> argparse.Namespace:
help=argparse.SUPPRESS, help=argparse.SUPPRESS,
) )
parser.add_argument("--cheats", action="store_true", help="???") parser.add_argument("--cheats", action="store_true", help="???")
parser.add_argument(
"--list-saves",
action="store_true",
help="list saved characters and exit",
)
parser.add_argument(
"--load-save",
type=int,
metavar="NUM",
help="play chosen character",
)
return parser.parse_args() return parser.parse_args()
def list_players(roster: Roster, file: T.Optional[T.Any] = None) -> None:
for i, player in enumerate(roster.players, start=1):
print(f"{i}. {player.name}", file=file)
def main() -> None: def main() -> None:
args = parse_args() args = parse_args()
roster = Roster.load(SAVE_PATH) roster = Roster.load(SAVE_PATH)
if args.list_saves:
list_players(roster)
exit(0)
player: T.Optional[Player] = None
if args.load_save:
try:
player = list(roster.players)[args.load_save - 1]
except IndexError:
print(f"Invalid player. Available players:", file=sys.stderr)
list_players(roster, file=sys.stderr)
exit(1)
try: try:
ui = args.ui(roster, args) ui = args.ui(roster, player, args)
ui.run() ui.run()
finally: finally:
if args.use_saves: if args.use_saves:
+2
View File
@@ -29,6 +29,8 @@ class Roster:
tmp_path.parent.mkdir(parents=True, exist_ok=True) tmp_path.parent.mkdir(parents=True, exist_ok=True)
tmp_path.write_bytes(pickle.dumps(self.players)) tmp_path.write_bytes(pickle.dumps(self.players))
if self.path.exists(): if self.path.exists():
if old_path.exists():
old_path.unlink()
self.path.rename(old_path) self.path.rename(old_path)
tmp_path.rename(self.path) tmp_path.rename(self.path)
+9 -1
View File
@@ -1,13 +1,21 @@
import abc import abc
import argparse import argparse
import typing as T
from pqcli.mechanic import Player
from pqcli.roster import Roster from pqcli.roster import Roster
class BaseUserInterface(abc.ABC): class BaseUserInterface(abc.ABC):
def __init__(self, roster: Roster, args: argparse.Namespace) -> None: def __init__(
self,
roster: Roster,
player: T.Optional[Player],
args: argparse.Namespace,
) -> None:
self.roster = roster self.roster = roster
self.args = args self.args = args
self.player = player
@abc.abstractmethod @abc.abstractmethod
def run(self) -> None: def run(self) -> None:
+11 -3
View File
@@ -32,8 +32,13 @@ class MainMenu(enum.IntEnum):
class BasicUserInterface(BaseUserInterface): class BasicUserInterface(BaseUserInterface):
def __init__(self, roster: Roster, args: argparse.Namespace) -> None: def __init__(
super().__init__(roster, args) self,
roster: Roster,
player: T.Optional[Player],
args: argparse.Namespace,
) -> None:
super().__init__(roster, player, args)
def signal_handler(sig: T.Any, frame: T.Any) -> None: def signal_handler(sig: T.Any, frame: T.Any) -> None:
logging.info("Quitting") logging.info("Quitting")
@@ -51,7 +56,10 @@ class BasicUserInterface(BaseUserInterface):
) )
self.logo() self.logo()
self.main_menu() if self.player:
self.play(self.player)
else:
self.main_menu()
def logo(self) -> None: def logo(self) -> None:
print(LOGO) print(LOGO)
+12 -5
View File
@@ -39,8 +39,10 @@ class StopMainLoop(Exception):
class CursesUserInterface(BaseUserInterface): class CursesUserInterface(BaseUserInterface):
def __init__(self, roster: Roster, args: argparse.Namespace) -> None: def __init__(
super().__init__(roster, args) self, roster: Roster, player: Player, args: argparse.Namespace
) -> None:
super().__init__(roster, player, args)
os.environ.setdefault("ESCDELAY", "25") os.environ.setdefault("ESCDELAY", "25")
self._screen = curses.initscr() self._screen = curses.initscr()
self._screen.nodelay(True) self._screen.nodelay(True)
@@ -77,7 +79,10 @@ class CursesUserInterface(BaseUserInterface):
def run(self) -> None: def run(self) -> None:
try: try:
self._switch_to_roster_view() if self.player:
self._switch_to_game_view(self.player)
else:
self._switch_to_roster_view()
while True: while True:
key = T.cast(int, self._screen.getch()) key = T.cast(int, self._screen.getch())
@@ -130,8 +135,10 @@ class CursesUserInterface(BaseUserInterface):
view.on_cancel += lambda: self._switch_to_create_char_race_view( view.on_cancel += lambda: self._switch_to_create_char_race_view(
player_name, race player_name, race
) )
view.on_confirm += lambda class_: self._switch_to_create_char_stats_view( view.on_confirm += (
player_name, race, class_ lambda class_: self._switch_to_create_char_stats_view(
player_name, race, class_
)
) )
self._switch_view(view) self._switch_view(view)
@@ -3,10 +3,8 @@ import typing as T
from pqcli.lingo import act_name, to_roman from pqcli.lingo import act_name, to_roman
from pqcli.roster import Roster from pqcli.roster import Roster
from pqcli.ui.curses.event_handler import EventHandler
from pqcli.ui.curses.util import KEYS_CANCEL, Choice from pqcli.ui.curses.util import KEYS_CANCEL, Choice
from pqcli.ui.curses.views.menu_view import MenuView from pqcli.ui.curses.views.menu_view import MenuView
from pqcli.ui.curses.widgets import Menu
class ChooseCharacterView(MenuView): class ChooseCharacterView(MenuView):
@@ -1,14 +1,7 @@
import curses
import typing as T import typing as T
from pqcli.lingo import to_roman
from pqcli.mechanic import InventoryItem, Player from pqcli.mechanic import InventoryItem, Player
from pqcli.ui.curses.widgets import ( from pqcli.ui.curses.widgets import Focusable
DataTable,
Focusable,
ProgressBar,
WindowWrapper,
)
from .progress_bar_window import DataTableProgressBarWindow from .progress_bar_window import DataTableProgressBarWindow
@@ -2,7 +2,7 @@ import typing as T
from pqcli.lingo import act_name from pqcli.lingo import act_name
from pqcli.mechanic import Player from pqcli.mechanic import Player
from pqcli.ui.curses.widgets import Focusable, ListBox, WindowWrapper from pqcli.ui.curses.widgets import Focusable
from .progress_bar_window import ListBoxProgressBarWindow from .progress_bar_window import ListBoxProgressBarWindow
@@ -1,7 +1,7 @@
import typing as T import typing as T
from pqcli.mechanic import Player from pqcli.mechanic import Player
from pqcli.ui.curses.widgets import Focusable, ListBox, WindowWrapper from pqcli.ui.curses.widgets import Focusable
from .progress_bar_window import ListBoxProgressBarWindow from .progress_bar_window import ListBoxProgressBarWindow
-1
View File
@@ -1,4 +1,3 @@
import functools
import typing as T import typing as T
from pqcli.ui.curses.event_handler import EventHandler from pqcli.ui.curses.event_handler import EventHandler
-1
View File
@@ -1,5 +1,4 @@
import curses import curses
import enum
import typing as T import typing as T
from pqcli.ui.curses.colors import COLOR_HIGHLIGHT, has_colors from pqcli.ui.curses.colors import COLOR_HIGHLIGHT, has_colors
+1 -2
View File
@@ -1,5 +1,4 @@
import curses import curses
import enum
import typing as T import typing as T
from pqcli.ui.curses.colors import COLOR_HIGHLIGHT, has_colors from pqcli.ui.curses.colors import COLOR_HIGHLIGHT, has_colors
@@ -37,7 +36,7 @@ class ListBox(Scrollable):
del self._items[idx : idx + count] del self._items[idx : idx + count]
def select(self, idx: T.Optional[int]) -> None: def select(self, idx: T.Optional[int]) -> None:
if idx < 0: if idx < 0 and len(self._items):
idx %= len(self._items) idx %= len(self._items)
self._selected = idx self._selected = idx
+4 -1
View File
@@ -25,7 +25,10 @@ class ProgressBar(WindowWrapper):
return None return None
time_then, pos_then = self._last_tick time_then, pos_then = self._last_tick
time_now, pos_now = datetime.datetime.now(), self._cur_pos time_now, pos_now = datetime.datetime.now(), self._cur_pos
speed = (pos_now - pos_then) / (time_now - time_then).total_seconds() div = (time_now - time_then).total_seconds()
if div == 0:
return None
speed = (pos_now - pos_then) / div
if not speed: if not speed:
return None return None
return datetime.timedelta(seconds=(self._max_pos - pos_now) / speed) return datetime.timedelta(seconds=(self._max_pos - pos_now) / speed)
+7 -2
View File
@@ -5,12 +5,17 @@ setup(
author_email="rr-@sakuya.pl", author_email="rr-@sakuya.pl",
name="pqcli", name="pqcli",
long_description="Progress Quest: the CLI edition", long_description="Progress Quest: the CLI edition",
version="1.0", version="1.0.2",
url="https://github.com/rr-/pq-cli.git", url="https://github.com/rr-/pq-cli.git",
packages=find_packages(), packages=find_packages(),
entry_points={"console_scripts": ["pqcli = pqcli.__main__:main"]}, entry_points={"console_scripts": ["pqcli = pqcli.__main__:main"]},
package_dir={"pqcli": "pqcli"}, package_dir={"pqcli": "pqcli"},
install_requires=["xdg", "urwid", "urwid_readline"], install_requires=[
"xdg",
"urwid",
"urwid_readline",
'windows-curses;platform_system=="Windows"',
],
classifiers=[ classifiers=[
"Environment :: Console", "Environment :: Console",
"Development Status :: 4 - Beta", "Development Status :: 4 - Beta",