"""
sst.py =-- Super Star Trek in Python
-This code is a Python translation of a C translation of a FORTRAN original.
-The FORTRANness still shows in many ways, notably the use of a lot of
-parallel arrays where a more modern language would use structures
-or objects. (However, 1-origin array indexing was fixed.)
+This code is a Python translation of a C translation of a FORTRAN
+original dating back to 1973. Beautiful Python it is not. But it
+works.
Dave Matuszek says:
features that I liked. I also took a peek at the DECUS version (a
port, less sources, to the PDP-10), and some other variations.
-1, Compared to the original UT version, I've changed the "help" command to
-"call" and the "terminate" command to "quit" to better match
-user expectations. The DECUS version apparently made those changes
-as well as changing "freeze" to "save". However I like "freeze".
-(Both "freeze" and "save" work in SST2K.)
+1, Compared to the original UT version, I've changed the "help"
+command to "call" and the "terminate" command to "quit" to better
+match user expectations. The DECUS version apparently made those
+changes as well as changing "freeze" to "save". However I like
+"freeze". (Both "freeze" and "save" work in SST2K.)
2. The experimental deathray originally had only a 5% chance of
success, but could be used repeatedly. I guess after a couple
the LRSCAN command is no longer needed. (Controlled by OPTION_AUTOSCAN
and turned off if game type is "plain" or "almy".)
"""
-import os,sys,math,curses,time,atexit,readline,cPickle,random,getopt,copy
+import os, sys, math, curses, time, readline, cPickle, random, copy
SSTDOC = "/usr/share/doc/sst/sst.doc"
DOC_NAME = "sst.doc"
return math.sqrt((self.i - other.i)**2 + (self.j - other.j)**2)
def bearing(self, other=None):
if not other: other = coord(0, 0)
- return 1.90985*math.atan2(self.i-other.i, self.j-other.j)
+ return 1.90985*math.atan2(self.j-other.j, self.i-other.i)
def sgn(self):
s = coord()
if self.i == 0:
else:
motion = game.skill
# calculate preferred number of steps
- if motion < 0:
- nsteps = -motion
- else:
- nsteps = motion
+ nsteps = abs(int(motion))
if motion > 0 and nsteps > mdist:
nsteps = mdist; # don't overshoot
if nsteps > QUADSIZE:
m.i = 0
if 2.0 * abs(m.j) < abs(game.sector.i-enemy.kloc.i):
m.j = 0
- if m.i != 0:
- if m.i*motion < 0:
- m.i = -1
- else:
- m.i = 1
- if m.j != 0:
- if m.j*motion < 0:
- m.j = -1
- else:
- m.j = 1
+ m = (motion * m).sgn()
next = enemy.kloc
# main move loop
for ll in range(nsteps):
for i in range(QUADSIZE):
if game.quad[0][i]!=IHWEB and game.quad[0][i]!=IHT:
return
- if game.quad[QUADSIZE][i]!=IHWEB and game.quad[QUADSIZE][i]!=IHT:
+ if game.quad[QUADSIZE-1][i]!=IHWEB and game.quad[QUADSIZE-1][i]!=IHT:
return
if game.quad[i][0]!=IHWEB and game.quad[i][0]!=IHT:
return
- if game.quad[i][QUADSIZE]!=IHWEB and game.quad[i][QUADSIZE]!=IHT:
+ if game.quad[i][QUADSIZE-1]!=IHWEB and game.quad[i][QUADSIZE-1]!=IHT:
return
# All plugged up -- Tholian splits
game.quad[game.tholian.kloc.i][game.tholian.kloc.j]=IHWEB
def torpedo(origin, course, dispersion, number, nburst):
"Let a photon torpedo fly"
+ if not damaged(DSRSENS) or game.condition=="docked":
+ setwnd(srscan_window)
+ else:
+ setwnd(message_window)
shoved = False
ac = course + 0.25*dispersion
angle = (15.0-ac)*0.5235988
delta = coord(-math.sin(angle), math.cos(angle))
bigger = max(abs(delta.i), abs(delta.j))
delta /= bigger
- x = origin.i; y = origin.j
w = coord(0, 0); jw = coord(0, 0)
- if not damaged(DSRSENS) or game.condition=="docked":
- setwnd(srscan_window)
- else:
- setwnd(message_window)
+ ungridded = copy.copy(origin)
# Loop to move a single torpedo
- for step in range(1, 15+1):
- x += delta.i
- y += delta.j
- w = coord(x, y).snaptogrid()
+ for step in range(1, QUADSIZE*2):
+ ungridded += delta
+ w = ungridded.snaptogrid()
if not VALID_SECTOR(w.i, w.j):
break
iquad=game.quad[w.i][w.j]
shoved = True
elif iquad in (IHC, IHS, IHR, IHK): # Hit a regular enemy
# find the enemy
- if withprob(0.05):
+ if iquad in (IHC, IHS) and withprob(0.05):
prout(crmena(True, iquad, "sector", w) + _(" uses anti-photon device;"))
prout(_(" torpedo neutralized."))
return None
hit = enemy.kpower*math.pow(dustfac,enemy.kavgd)
enemy.kpower *= 0.75
else: # Enemy uses photon torpedo
- #course2 = (enemy.kloc-game.sector).bearing()
+ # We should be able to make the bearing() method work here
course = 1.90985*math.atan2(game.sector.j-enemy.kloc.j, enemy.kloc.i-game.sector.i)
hit = 0
proutn(_("***TORPEDO INCOMING"))
prout(_(" the Captain's psychological profile.\""))
scanner.chew()
return None
- return 1.90985932*math.atan2(delta.j, delta.i)
+ return delta.bearing()
def photon():
"Launch photon torpedo."
if i==1 and key == "IHEOL":
# direct all torpedoes at one target
while i < n:
- target.append(targets[0])
+ target.append(target[0])
course.append(course[0])
i += 1
break
- scanner.push(key)
+ scanner.push(scanner.token)
target.append(scanner.getcoord())
if target[-1] == None:
return
- course.append(targetcheck(target[1]))
- if course[i] == None:
+ course.append(targetcheck(target[-1]))
+ if course[-1] == None:
return
scanner.chew()
- if i == 0:
+ if len(target) == 0:
# prompt for each one
for i in range(n):
proutn(_("Target sector for torpedo number %d- ") % (i+1))
game.resting = False
game.optime = 0
-# A nova occurs. It is the result of having a star hit with a
-# photon torpedo, or possibly of a probe warhead going off.
-# Stars that go nova cause stars which surround them to undergo
-# the same probabilistic process. Klingons next to them are
-# destroyed. And if the starship is next to it, it gets zapped.
-# If the zap is too much, it gets destroyed.
-
def nova(nov):
"Star goes nova."
course = (0.0, 10.5, 12.0, 1.5, 9.0, 0.0, 3.0, 7.5, 6.0, 4.5)
prompt_window = None
curwnd = None
-def outro():
- "Wrap up, either normally or due to signal"
- if game.options & OPTION_CURSES:
- #clear()
- #curs_set(1)
- #refresh()
- #resetterm()
- #echo()
- curses.endwin()
- sys.stdout.write('\n')
- if logfp:
- logfp.close()
-
def iostart():
global stdscr, rows
- #setlocale(LC_ALL, "")
- #bindtextdomain(PACKAGE, LOCALEDIR)
- #textdomain(PACKAGE)
- if atexit.register(outro):
- sys.stderr.write("Unable to register outro(), exiting...\n")
- raise SysExit,1
if not (game.options & OPTION_CURSES):
ln_env = os.getenv("LINES")
if ln_env:
else:
stdscr = curses.initscr()
stdscr.keypad(True)
- #saveterm()
curses.nonl()
curses.cbreak()
- curses.start_color()
- curses.init_pair(curses.COLOR_BLACK, curses.COLOR_BLACK, curses.COLOR_BLACK)
- curses.init_pair(curses.COLOR_GREEN, curses.COLOR_GREEN, curses.COLOR_BLACK)
- curses.init_pair(curses.COLOR_RED, curses.COLOR_RED, curses.COLOR_BLACK)
- curses.init_pair(curses.COLOR_CYAN, curses.COLOR_CYAN, curses.COLOR_BLACK)
- curses.init_pair(curses.COLOR_WHITE, curses.COLOR_WHITE, curses.COLOR_BLACK)
- curses.init_pair(curses.COLOR_MAGENTA, curses.COLOR_MAGENTA, curses.COLOR_BLACK)
- curses.init_pair(curses.COLOR_BLUE, curses.COLOR_BLUE, curses.COLOR_BLACK)
- curses.init_pair(curses.COLOR_YELLOW, curses.COLOR_YELLOW, curses.COLOR_BLACK)
- #noecho()
global fullscreen_window, srscan_window, report_window, status_window
global lrscan_window, message_window, prompt_window
(rows, columns) = stdscr.getmaxyx()
prompt_window = curses.newwin(1, 0, rows-2, 0)
message_window.scrollok(True)
setwnd(fullscreen_window)
- textcolor(DEFAULT)
-
-def textcolor(color):
- "Set text foreground color. Presently a stub."
- pass # FIXME
def ioend():
- "Wrap up I/O. Presently a stub."
- pass
+ "Wrap up I/O."
+ if game.options & OPTION_CURSES:
+ stdscr.keypad(False)
+ curses.echo()
+ curses.nocbreak()
+ curses.endwin()
def waitfor():
"Wait for user action -- OK to do nothing if on a TTY"
if game.options & OPTION_CURSES:
- stsdcr.getch()
+ stdscr.getch()
def announce():
skip(1)
pause_game()
clrscr()
else:
- proutn("\n")
+ try:
+ curwnd.move(y+1, 0)
+ except curses.error:
+ pass
else:
global linecount
linecount += 1
time.sleep(0.03)
proutn(c)
if game.options & OPTION_CURSES:
- wrefresh(curwnd)
+ curwnd.refresh()
else:
sys.stdout.flush()
if not replayfp or replayfp.closed:
prout(_("Ensign Chekov- \"Course laid in, Captain.\""))
# the actual deltas get computed here
delta = coord()
- delta.i = dquad.j-game.quadrant.j + 0.1*(dsect.j-game.sector.j)
- delta.j = game.quadrant.i-dquad.i + 0.1*(game.sector.i-dsect.i)
+ delta.j = dquad.j-game.quadrant.j + 0.1*(dsect.j-game.sector.j)
+ delta.i = game.quadrant.i-dquad.i + 0.1*(game.sector.i-dsect.i)
else: # manual
while key == "IHEOL":
proutn(_("X and Y displacements- "))
return
# Make sure enough time is left for the trip
- game.optime = 10.0*game.dist/game.wfacsq
+ game.optime = 10.0*game.dist/game.warpfac**2
if game.optime >= 0.8*game.state.remtime:
skip(1)
prout(_("First Officer Spock- \"Captain, I compute that such"))
game.energy -= game.dist*game.warpfac*game.warpfac*game.warpfac*(game.shldup+1)
if game.energy <= 0:
finish(FNRG)
- game.optime = 10.0*game.dist/game.wfacsq
+ game.optime = 10.0*game.dist/game.warpfac**2
if twarp:
timwrp()
if blooey:
return
oldfac = game.warpfac
game.warpfac = scanner.real
- game.wfacsq=game.warpfac*game.warpfac
if game.warpfac <= oldfac or game.warpfac <= 6.0:
prout(_("Helmsman Sulu- \"Warp factor %d, Captain.\"") %
int(game.warpfac))
finish(FSNOVAED)
return
game.warpfac = randreal(6.0, 8.0)
- game.wfacsq = game.warpfac * game.warpfac
prout(_("Warp factor set to %d") % int(game.warpfac))
power = 0.75*game.energy
game.dist = power/(game.warpfac*game.warpfac*game.warpfac*(game.shldup+1))
distreq = randreal(math.sqrt(2))
if distreq < game.dist:
game.dist = distreq
- game.optime = 10.0*game.dist/game.wfacsq
+ game.optime = 10.0*game.dist/game.warpfac**2
game.direc = randreal(12) # How dumb!
game.justin = False
game.inorbit = False
game.ididit = True
return
-# Here's how the mayday code works:
-#
-# First, the closest starbase is selected. If there is a a starbase
-# in your own quadrant, you are in good shape. This distance takes
-# quadrant distances into account only.
-#
-# A magic number is computed based on the distance which acts as the
-# probability that you will be rematerialized. You get three tries.
-#
-# When it is determined that you should be able to be rematerialized
-# (i.e., when the probability thing mentioned above comes up
-# positive), you are put into that quadrant (anywhere). Then, we try
-# to see if there is a spot adjacent to the star- base. If not, you
-# can't be rematerialized!!! Otherwise, it drops you there. It only
-# tries five times to find a spot to drop you. After that, it's your
-# problem.
-
def mayday():
"Yell for help from nearest starbase."
# There's more than one way to move in this game!
elif m == 3: proutn(_("3rd"))
proutn(_(" attempt to re-materialize ") + crmshp())
game.quad[ix][iy]=(IHMATER0,IHMATER1,IHMATER2)[m-1]
- textcolor("red")
+ #textcolor("red")
warble()
if randreal() > probf:
break
prout(_("fails."))
curses.delay_output(500)
- textcolor(None)
+ #textcolor(None)
if m > 3:
game.quad[ix][iy]=IHQUEST
game.alive = False
finish(FMATERIALIZE)
return
game.quad[ix][iy]=game.ship
- textcolor("green")
+ #textcolor("green")
prout(_("succeeds."))
- textcolor(None)
+ #textcolor(None)
dock(False)
skip(1)
prout(_("Lt. Uhura- \"Captain, we made it!\""))
-# Abandon Ship (the BSD-Trek description)
-#
-# The ship is abandoned. If your current ship is the Faire
-# Queene, or if your shuttlecraft is dead, you're out of
-# luck. You need the shuttlecraft in order for the captain
-# (that's you!!) to escape.
-#
-# Your crew can beam to an inhabited starsystem in the
-# quadrant, if there is one and if the transporter is working.
-# If there is no inhabited starsystem, or if the transporter
-# is out, they are left to die in outer space.
-#
-# If there are no starbases left, you are captured by the
-# Klingons, who torture you mercilessly. However, if there
-# is at least one starbase, you are returned to the
-# Federation in a prisoner of war exchange. Of course, this
-# can't happen unless you have taken some prisoners.
-
def abandon():
"Abandon ship."
scanner.chew()
game.lsupres=game.inlsr=3.0
game.shldup=False
game.warpfac=5.0
- game.wfacsq=25.0
return
# Code from planets.c begins here.
"Light up an individual dot in a sector."
if goodScan or (abs(i-game.sector.i)<= 1 and abs(j-game.sector.j) <= 1):
if (game.quad[i][j]==IHMATER0) or (game.quad[i][j]==IHMATER1) or (game.quad[i][j]==IHMATER2) or (game.quad[i][j]==IHE) or (game.quad[i][j]==IHF):
- if game.condition == "red": textcolor("red")
- elif game.condition == "green": textcolor("green")
- elif game.condition == "yellow": textcolor("yellow")
- elif game.condition == "docked": textcolor("cyan")
- elif game.condition == "dead": textcolor("brown")
+ #if game.condition == "red": textcolor("red")
+ #elif game.condition == "green": textcolor("green")
+ #elif game.condition == "yellow": textcolor("yellow")
+ #elif game.condition == "docked": textcolor("cyan")
+ #elif game.condition == "dead": textcolor("brown")
if game.quad[i][j] != game.ship:
highvideo()
proutn("%c " % game.quad[i][j])
- textcolor(None)
+ #textcolor(None)
else:
proutn("- ")
for j in range(QUADSIZE):
sectscan(goodScan, i, j)
skip(1)
-
+
def eta():
"Use computer to get estimated time of arrival for a warp jump."
w1 = coord(); w2 = coord()
if choose():
return # frozen game
# Prepare the Enterprise
- game.alldone = game.gamewon = False
+ game.alldone = game.gamewon = game.shldchg = game.shldup = False
game.ship = IHE
game.state.crew = FULLCREW
game.energy = game.inenrg = 5000.0
game.shield = game.inshld = 2500.0
- game.shldchg = False
- game.shldup = False
game.inlsr = 4.0
game.lsupres = 4.0
game.quadrant = randplace(GALSIZE)
game.torps = game.intorps = 10
game.nprobes = randrange(2, 5)
game.warpfac = 5.0
- game.wfacsq = game.warpfac * game.warpfac
for i in range(NDEVICES):
game.damage[i] = 0.0
# Set up assorted game parameters
def listCommands():
"Generate a list of legal commands."
- proutn(_("LEGAL COMMANDS ARE:"))
- for (k, key) in enumerate(commands):
+ prout(_("LEGAL COMMANDS ARE:"))
+ emitted = 0
+ for key in commands:
if not commands[key] or (commands[key] & game.options):
- if k % 5 == 0:
+ proutn("%-12s " % key)
+ emitted += 1
+ if emitted % 5 == 4:
skip(1)
- proutn("%-12s " % key)
skip(1)
def helpme():
clrscr()
if line == '':
return None
- # Skip leading white space
- line = line.lstrip()
if not line:
continue
else:
self.type = "IHALPHA"
self.real = None
return "IHALPHA"
- def push(self, tok):
+ def append(self, tok):
self.inqueue.append(tok)
+ def push(self, tok):
+ self.inqueue.insert(0, tok)
def waiting(self):
return self.inqueue
def chew(self):
atover(True)
if __name__ == '__main__':
+ import getopt, socket
try:
global line, thing, game, idebug
game = None
game = gamestate()
idebug = 0
game.options = OPTION_ALL &~ (OPTION_IOMODES | OPTION_PLAIN | OPTION_ALMY)
- # Disable curses mode until the game logic is working.
- # if os.getenv("TERM"):
- # game.options |= OPTION_CURSES | OPTION_SHOWME
- # else:
- game.options |= OPTION_TTY
+ if os.getenv("TERM"):
+ game.options |= OPTION_CURSES
+ else:
+ game.options |= OPTION_TTY
seed = int(time.time())
(options, arguments) = getopt.getopt(sys.argv[1:], "r:s:tx")
for (switch, val) in options:
if logfp:
logfp.write("# seed %s\n" % seed)
logfp.write("# options %s\n" % " ".join(arguments))
+ logfp.write("# recorded by %s@%s on %s\n" % \
+ (os.getenv("LOGNAME"),socket.gethostname(),time.ctime()))
random.seed(seed)
scanner = sstscanner()
- map(scanner.push, arguments)
+ map(scanner.append, arguments)
try:
iostart()
while True: # Play a game
ioend()
raise SystemExit, 0
except KeyboardInterrupt:
- print""
+ if logfp:
+ logfp.close()
+ print ""
pass