projects
/
super-star-trek.git
/ blobdiff
commit
grep
author
committer
pickaxe
?
search:
re
summary
|
shortlog
|
log
|
commit
|
commitdiff
|
tree
raw
|
inline
| side by side
Document an interface fix.
[super-star-trek.git]
/
sst.py
diff --git
a/sst.py
b/sst.py
index a2cedc575a37e2a08472aec68a0cb3483a6b6383..242022296e03d3d7835693ebd498a0eebb75845f 100755
(executable)
--- a/
sst.py
+++ b/
sst.py
@@
-1,4
+1,4
@@
-#!/usr/bin/env python
2
+#!/usr/bin/env python
"""
sst.py -- Super Star Trek 2K
"""
sst.py -- Super Star Trek 2K
@@
-12,6
+12,8
@@
See the doc/HACKING file in the distribution for designers notes and advice
on how to modify (and how not to modify!) this code.
"""
from __future__ import print_function, division
on how to modify (and how not to modify!) this code.
"""
from __future__ import print_function, division
+# Runs under Python 2 an Python 3. Preserve this property!
+# SPDX-License-Identifier: BSD-2-clause
import os, sys, math, curses, time, pickle, copy, gettext, getpass
import getopt, socket, locale
import os, sys, math, curses, time, pickle, copy, gettext, getpass
import getopt, socket, locale
@@
-29,50
+31,64
@@
try:
except NameError:
my_input = input
except NameError:
my_input = input
-version = "2.
4
"
+version = "2.
5
"
docpath = (".", "doc/", "/usr/share/doc/sst/")
def _(st):
return gettext.gettext(st)
docpath = (".", "doc/", "/usr/share/doc/sst/")
def _(st):
return gettext.gettext(st)
-# This is all encapsulated not just for logging but because someday
-# we'll probably want to replace it with something like an LCG that
-# can be forward-ported off Python.
-
-import random
+# Rolling our own LCG because Python changed its incompatibly in 3.2.
+# Thus, we need to have our own to be 2/3 polyglot, which will also
+# be helpful when we forwrard-port.
class randomizer:
class randomizer:
+ # LCG PRNG parameters tested against
+ # Knuth vol. 2. by the authors of ADVENT
+ LCG_A = 1093
+ LCG_C = 221587
+ LCG_M = 1048576
+
+ @staticmethod
+ def random():
+ old_x = game.lcg_x
+ game.lcg_x = (randomizer.LCG_A * game.lcg_x + randomizer.LCG_C) % randomizer.LCG_M
+ return old_x / randomizer.LCG_M;
+
@staticmethod
def withprob(p):
@staticmethod
def withprob(p):
- v = random.random()
- if logfp:
- logfp.write("#withprob(%.2f) -> %s\n" % (p, v < p))
+ v = random
izer
.random()
+
#
if logfp:
+
#
logfp.write("#withprob(%.2f) -> %s\n" % (p, v < p))
return v < p
@staticmethod
def integer(*args):
return v < p
@staticmethod
def integer(*args):
- s = random.randrange(*args)
- if logfp:
- logfp.write("#randrange%s -> %s\n" % (args, s))
- return s
+ v = randomizer.random()
+ if len(args) == 1:
+ v = int(v * args[0])
+ else:
+ v = args[0] + int(v * (args[1] - args[0]))
+ #if logfp:
+ # logfp.write("#integer%s -> %s\n" % (args, v))
+ return int(v)
@staticmethod
def real(*args):
@staticmethod
def real(*args):
- v = random.random()
+ v = random
izer
.random()
if len(args) == 1:
v *= args[0] # from [0, args[0])
elif len(args) == 2:
v = args[0] + v*(args[1]-args[0]) # from [args[0], args[1])
if len(args) == 1:
v *= args[0] # from [0, args[0])
elif len(args) == 2:
v = args[0] + v*(args[1]-args[0]) # from [args[0], args[1])
- if logfp:
- logfp.write("#real%s -> %f\n" % (args, v))
+
#
if logfp:
+
#
logfp.write("#real%s -> %f\n" % (args, v))
return v
@staticmethod
def seed(n):
return v
@staticmethod
def seed(n):
- if logfp:
- logfp.write("#seed(%d)\n" % n)
- random.seed(n)
+
#
if logfp:
+
#
logfp.write("#seed(%d)\n" % n)
+ game.lcg_x = n % randomizer.LCG_M
GALSIZE = 8 # Galaxy size in quadrants
NINHAB = (GALSIZE * GALSIZE // 2) # Number of inhabited worlds
GALSIZE = 8 # Galaxy size in quadrants
NINHAB = (GALSIZE * GALSIZE // 2) # Number of inhabited worlds
@@
-118,8
+134,8
@@
class JumpOut(Exception):
class Coord:
def __init__(self, x=None, y=None):
class Coord:
def __init__(self, x=None, y=None):
- self.i = x
- self.j = y
+ self.i = x
# Row
+ self.j = y
# Column
def valid_quadrant(self):
return self.i >= 0 and self.i < GALSIZE and self.j >= 0 and self.j < GALSIZE
def valid_sector(self):
def valid_quadrant(self):
return self.i >= 0 and self.i < GALSIZE and self.j >= 0 and self.j < GALSIZE
def valid_sector(self):
@@
-162,13
+178,13
@@
class Coord:
s = Coord()
if self.i == 0:
s.i = 0
s = Coord()
if self.i == 0:
s.i = 0
- elif s.i < 0:
- s.i =-1
+ elif s
elf
.i < 0:
+ s.i =
-1
else:
s.i = 1
if self.j == 0:
s.j = 0
else:
s.i = 1
if self.j == 0:
s.j = 0
- elif s.j < 0:
+ elif s
elf
.j < 0:
s.j = -1
else:
s.j = 1
s.j = -1
else:
s.j = 1
@@
-293,6
+309,7
@@
OPTION_CLOAK = 0x80004000 # Enable BSD-Trek capture (Almy, 2013).
OPTION_PLAIN = 0x01000000 # user chose plain game
OPTION_ALMY = 0x02000000 # user chose Almy variant
OPTION_COLOR = 0x04000000 # enable color display (ESR, 2010)
OPTION_PLAIN = 0x01000000 # user chose plain game
OPTION_ALMY = 0x02000000 # user chose Almy variant
OPTION_COLOR = 0x04000000 # enable color display (ESR, 2010)
+OPTION_DOTFILL = 0x08000000 # fix dotfill glitch in chart (ESR, 2019)
# Define devices
DSRSENS = 0
# Define devices
DSRSENS = 0
@@
-469,6
+486,7
@@
class Gamestate:
self.iscloaked = False # Cloaking device on?
self.ncviol = 0 # Algreon treaty violations
self.isviolreported = False # We have been warned
self.iscloaked = False # Cloaking device on?
self.ncviol = 0 # Algreon treaty violations
self.isviolreported = False # We have been warned
+ self.lcg_x = 0 # LCG generator value
def remkl(self):
return sum([q.klingons for (_i, _j, q) in list(self.state.traverse())])
def recompute(self):
def remkl(self):
return sum([q.klingons for (_i, _j, q) in list(self.state.traverse())])
def recompute(self):
@@
-786,7
+804,7
@@
def movescom(iq, avoid):
if communicating():
announce()
prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
if communicating():
announce()
prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
- prout
n
(_(" a planet in Quadrant %s has been destroyed") % game.state.kscmdr)
+ prout(_(" a planet in Quadrant %s has been destroyed") % game.state.kscmdr)
prout(_(" by the Super-commander.\""))
break
return True # looks good!
prout(_(" by the Super-commander.\""))
break
return True # looks good!
@@
-819,7
+837,7
@@
def supercommander():
sc = game.state.kscmdr
for (i, base) in enumerate(game.state.baseq):
basetbl.append((i, (base - sc).distance()))
sc = game.state.kscmdr
for (i, base) in enumerate(game.state.baseq):
basetbl.append((i, (base - sc).distance()))
- if
game.state.baseq
> 1:
+ if
len(game.state.baseq)
> 1:
basetbl.sort(key=lambda x: x[1])
# look for nearest base without a commander, no Enterprise, and
# without too many Klingons, and not already under attack.
basetbl.sort(key=lambda x: x[1])
# look for nearest base without a commander, no Enterprise, and
# without too many Klingons, and not already under attack.
@@
-892,7
+910,7
@@
def supercommander():
prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") \
% game.state.kscmdr)
prout(_(" reports that it is under attack from the Klingon Super-commander."))
prout(_("Lt. Uhura- \"Captain, the starbase in Quadrant %s") \
% game.state.kscmdr)
prout(_(" reports that it is under attack from the Klingon Super-commander."))
- prout
n
(_(" It can survive until stardate %d.\"") \
+ prout(_(" It can survive until stardate %d.\"") \
% int(scheduled(FSCDBAS)))
if not game.resting:
return
% int(scheduled(FSCDBAS)))
if not game.resting:
return
@@
-910,7
+928,7
@@
def supercommander():
return
announce()
prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
return
announce()
prout(_("Lt. Uhura- \"Captain, Starfleet Intelligence reports"))
- prout
n(_(" the Super-commander is in Quadrant %s,
") % game.state.kscmdr)
+ prout
(_(" the Super-commander is in Quadrant %s.
") % game.state.kscmdr)
return
def movetholian():
return
def movetholian():
@@
-1722,7
+1740,11
@@
def torps():
proutn(_("Number of torpedoes to fire- "))
continue # Go back around to get a number
else: # key == "IHREAL"
proutn(_("Number of torpedoes to fire- "))
continue # Go back around to get a number
else: # key == "IHREAL"
- n = scanner.int()
+ try:
+ n = scanner.int()
+ except TypeError:
+ huh()
+ return
if n <= 0: # abort command
scanner.chew()
return
if n <= 0: # abort command
scanner.chew()
return
@@
-2067,7
+2089,6
@@
def phasers():
scanner.chew()
key = "IHEOL"
hits[k] = 0 # prevent overflow -- thanks to Alexei Voitenko
scanner.chew()
key = "IHEOL"
hits[k] = 0 # prevent overflow -- thanks to Alexei Voitenko
- k += 1
continue
if key == "IHEOL":
scanner.chew()
continue
if key == "IHEOL":
scanner.chew()
@@
-2097,7
+2118,7
@@
def phasers():
# abort out
scanner.chew()
return
# abort out
scanner.chew()
return
- hits
[k] = scanner.real
+ hits
.append(scanner.real)
rpow += scanner.real
# If total requested is too much, inform and start over
if rpow > avail:
rpow += scanner.real
# If total requested is too much, inform and start over
if rpow > avail:
@@
-2105,7
+2126,6
@@
def phasers():
scanner.chew()
return
key = scanner.nexttok() # scan for next value
scanner.chew()
return
key = scanner.nexttok() # scan for next value
- k += 1
if rpow == 0.0:
# zero energy -- abort
scanner.chew()
if rpow == 0.0:
# zero energy -- abort
scanner.chew()
@@
-2775,7
+2795,8
@@
def nova(nov):
finish(FNOVA)
return
# add in course nova contributes to kicking starship
finish(FNOVA)
return
# add in course nova contributes to kicking starship
- bump += (game.sector-hits[-1]).sgn()
+ if hits:
+ bump += (game.sector-hits[-1]).sgn()
elif iquad == 'K': # kill klingon
deadkl(neighbor, iquad, neighbor)
elif iquad in ('C','S','R'): # Damage/destroy big enemies
elif iquad == 'K': # kill klingon
deadkl(neighbor, iquad, neighbor)
elif iquad in ('C','S','R'): # Damage/destroy big enemies
@@
-3860,7
+3881,7
@@
def imove(icourse=None, noattack=False):
newquadrant(noattack)
break
elif check_collision(w):
newquadrant(noattack)
break
elif check_collision(w):
- pr
int("Collision detected"
)
+ pr
out(_("Collision detected")
)
break
else:
game.sector = w
break
else:
game.sector = w
@@
-5304,6
+5325,8
@@
def chart():
show = ".1."
elif game.state.galaxy[i][j].charted:
show = "%3d" % (game.state.chart[i][j].klingons*100 + game.state.chart[i][j].starbase * 10 + game.state.chart[i][j].stars)
show = ".1."
elif game.state.galaxy[i][j].charted:
show = "%3d" % (game.state.chart[i][j].klingons*100 + game.state.chart[i][j].starbase * 10 + game.state.chart[i][j].stars)
+ if (game.options & OPTION_DOTFILL):
+ show = show.replace(" ", ".")
else:
show = "..."
proutn(show)
else:
show = "..."
proutn(show)
@@
-5966,11
+5989,11
@@
def choose():
scanner.nexttok()
if scanner.sees("plain"):
# Approximates the UT FORTRAN version.
scanner.nexttok()
if scanner.sees("plain"):
# Approximates the UT FORTRAN version.
- game.options &=~ (OPTION_THOLIAN | OPTION_PLANETS | OPTION_THINGY | OPTION_PROBE | OPTION_RAMMING | OPTION_MVBADDY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS | OPTION_COLOR | OPTION_CAPTURE | OPTION_CLOAK)
+ game.options &=~ (OPTION_THOLIAN | OPTION_PLANETS | OPTION_THINGY | OPTION_PROBE | OPTION_RAMMING | OPTION_MVBADDY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS | OPTION_COLOR | OPTION_CAPTURE | OPTION_CLOAK
| OPTION_DOTFILL
)
game.options |= OPTION_PLAIN
elif scanner.sees("almy"):
# Approximates Tom Almy's version.
game.options |= OPTION_PLAIN
elif scanner.sees("almy"):
# Approximates Tom Almy's version.
- game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS | OPTION_COLOR)
+ game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS | OPTION_COLOR
| OPTION_DOTFILL
)
game.options |= OPTION_ALMY
elif scanner.sees("fancy") or scanner.sees("\n"):
pass
game.options |= OPTION_ALMY
elif scanner.sees("fancy") or scanner.sees("\n"):
pass
@@
-6034,6
+6057,7
@@
def newqad():
game.iplnet = None
game.neutz = game.inorbit = game.landed = False
game.ientesc = game.iseenit = game.isviolreported = False
game.iplnet = None
game.neutz = game.inorbit = game.landed = False
game.ientesc = game.iseenit = game.isviolreported = False
+ game.tholian = None
# Create a blank quadrant
game.quad = fill2d(QUADSIZE, lambda i, j: '.')
if game.iscate:
# Create a blank quadrant
game.quad = fill2d(QUADSIZE, lambda i, j: '.')
if game.iscate: