mirror of
https://github.com/rr-/pq-cli.git
synced 2026-11-12 22:40:36 -07:00
random: port Alea, one generator per character
pqcli used Python's global Mersenne Twister, seeded once from the clock. Upstream uses Johannes Baagøe's Alea, with Random(n) = uint32() % n, and keeps the generator state with each character. The port matches the JS output bit for bit, including UTF-16 seeding of non-BMP characters. Each Player now owns an Alea that is pickled with the save, and Simulation.tick draws from it. Saves without one get a fresh generator. As upstream does, a new character's game continues from the state the kept stat roll was made from. The parity traces are re-recorded, since every random number changes.
This commit is contained in:
11 files changed
+5741
-5452
No files matched your search
@@ -9,6 +9,7 @@ from pqcli import lingo
|
||||
from pqcli.config import Class, Race
|
||||
from pqcli.game_data import GameData
|
||||
from pqcli.mechanic import Player, Stats, create_player
|
||||
from pqcli.random import RngState
|
||||
from pqcli.roster import Roster
|
||||
from pqcli.ui.base import BaseUserInterface
|
||||
from pqcli.ui.curses.colors import (
|
||||
@@ -156,8 +157,8 @@ class CursesUserInterface(BaseUserInterface):
|
||||
view.on_cancel += lambda: self._switch_to_create_char_class_view(
|
||||
player_name, race, class_
|
||||
)
|
||||
view.on_confirm += lambda stats: self._create_character(
|
||||
player_name, race, class_, stats
|
||||
view.on_confirm += lambda stats, seed: self._create_character(
|
||||
player_name, race, class_, stats, seed
|
||||
)
|
||||
self._switch_view(view)
|
||||
|
||||
@@ -196,9 +197,14 @@ class CursesUserInterface(BaseUserInterface):
|
||||
self._view.start()
|
||||
|
||||
def _create_character(
|
||||
self, name: str, race: Race, class_: Class, stats: Stats
|
||||
self,
|
||||
name: str,
|
||||
race: Race,
|
||||
class_: Class,
|
||||
stats: Stats,
|
||||
seed: RngState,
|
||||
) -> None:
|
||||
player = create_player(name, race, class_, stats)
|
||||
player = create_player(name, race, class_, stats, seed)
|
||||
self.roster.players.append(player)
|
||||
if self.args.use_saves:
|
||||
self.roster.save()
|
||||
|
||||
@@ -55,7 +55,7 @@ class ChooseCharacterStatsView(BaseView):
|
||||
elif self._active_widget == 1:
|
||||
self._stats = self._stats_builder.unroll()
|
||||
elif self._active_widget == 2:
|
||||
self.on_confirm(self._stats)
|
||||
self.on_confirm(self._stats, self._stats_builder.seed)
|
||||
elif self._active_widget == 3:
|
||||
self.on_cancel()
|
||||
else:
|
||||
@@ -68,7 +68,7 @@ class ChooseCharacterStatsView(BaseView):
|
||||
self._stats = self._stats_builder.unroll()
|
||||
|
||||
elif key == curses.KEY_F10:
|
||||
self.on_confirm(self._stats)
|
||||
self.on_confirm(self._stats, self._stats_builder.seed)
|
||||
|
||||
elif key in KEYS_CYCLE:
|
||||
self._active_widget = (self._active_widget + 1) % 4
|
||||
|
||||
Reference in new issue
Block a user