X-Git-Url: https://jxself.org/git/?p=super-star-trek.git;a=blobdiff_plain;f=sst.py;h=3c985160fba4019a27ce677f09b12dd9040f7eb4;hp=9b35fd7e4a0c2ced7d9d32cfc247e929b6df0576;hb=0a154af018fad598ab67742e26429e7272fc5c2e;hpb=ccda4abcc6bba597d5732842258b971d056e1980 diff --git a/sst.py b/sst.py index 9b35fd7..3c98516 100755 --- a/sst.py +++ b/sst.py @@ -12,6 +12,7 @@ See the doc/HACKING file in the distribution for designers notes and advice on how to modify (and how not to modify!) this code. """ import os, sys, math, curses, time, pickle, random, copy, gettext, getpass +import getopt, socket, locale # This import only works on Unixes. The intention is to enable # Ctrl-P, Ctrl-N, and friends in Cmd. @@ -22,7 +23,7 @@ except ImportError: version = "2.1" -docpath = (".", "../doc", "/usr/share/doc/sst") +docpath = (".", "doc/", "/usr/share/doc/sst/") def _(st): return gettext.gettext(st) @@ -211,22 +212,23 @@ class Event: # game options OPTION_ALL = 0xffffffff OPTION_TTY = 0x00000001 # old interface -OPTION_CURSES = 0x00000002 # new interface -OPTION_IOMODES = 0x00000003 # cover both interfaces -OPTION_PLANETS = 0x00000004 # planets and mining -OPTION_THOLIAN = 0x00000008 # Tholians and their webs (UT 1979 version) -OPTION_THINGY = 0x00000010 # Space Thingy can shoot back (Stas, 2005) -OPTION_PROBE = 0x00000020 # deep-space probes (DECUS version, 1980) -OPTION_SHOWME = 0x00000040 # bracket Enterprise in chart -OPTION_RAMMING = 0x00000080 # enemies may ram Enterprise (Almy) -OPTION_MVBADDY = 0x00000100 # more enemies can move (Almy) -OPTION_BLKHOLE = 0x00000200 # black hole may timewarp you (Stas, 2005) -OPTION_BASE = 0x00000400 # bases have good shields (Stas, 2005) -OPTION_WORLDS = 0x00000800 # logic for inhabited worlds (ESR, 2006) -OPTION_AUTOSCAN = 0x00001000 # automatic LRSCAN before CHART (ESR, 2006) -OPTION_PLAIN = 0x01000000 # user chose plain game -OPTION_ALMY = 0x02000000 # user chose Almy variant -OPTION_COLOR = 0x04000000 # enable color display (experimental, ESR, 2010) +OPTION_CURSES = 0x00000002 # new interface +OPTION_IOMODES = 0x00000003 # cover both interfaces +OPTION_PLANETS = 0x00000004 # planets and mining +OPTION_THOLIAN = 0x00000008 # Tholians and their webs (UT 1979 version) +OPTION_THINGY = 0x00000010 # Space Thingy can shoot back (Stas, 2005) +OPTION_PROBE = 0x00000020 # deep-space probes (DECUS version, 1980) +OPTION_SHOWME = 0x00000040 # bracket Enterprise in chart +OPTION_RAMMING = 0x00000080 # enemies may ram Enterprise (Almy) +OPTION_MVBADDY = 0x00000100 # more enemies can move (Almy) +OPTION_BLKHOLE = 0x00000200 # black hole may timewarp you (Stas, 2005) +OPTION_BASE = 0x00000400 # bases have good shields (Stas, 2005) +OPTION_WORLDS = 0x00000800 # logic for inhabited worlds (ESR, 2006) +OPTION_AUTOSCAN = 0x00001000 # automatic LRSCAN before CHART (ESR, 2006) +OPTION_PLAIN = 0x01000000 # user chose plain game +OPTION_ALMY = 0x02000000 # user chose Almy variant +OPTION_COLOR = 0x04000000 # enable color display (ESR, 2010) +OPTION_CAPTURE = 0x80000000 # Enable BSD-Trek capture (Almy, 2013). # Define devices DSRSENS = 0 @@ -393,6 +395,9 @@ class Gamestate: self.perdate = 0.0 # rate of kills self.idebug = False # Debugging instrumentation enabled? self.statekscmdr = None # No SuperCommander coordinates yet. + self.brigcapacity = 400 # Enterprise brig capacity + self.brigfree = 400 # How many klingons can we put in the brig? + self.kcaptured = 0 # Total Klingons captured, for scoring. def recompute(self): # Stas thinks this should be (C expression): # game.state.remkl + len(game.state.kcmdr) > 0 ? @@ -1982,7 +1987,67 @@ def phasers(): game.shldup = False overheat(rpow) -# Code from events,c begins here. + +def capture(): + game.ididit = False # Nothing if we fail + Time = 0.0; + + # Make sure there is room in the brig */ + if game.brigfree == 0: + prout(_("Security reports the brig is already full.")) + return; + + if damaged(DRADIO): + prout(_("Uhura- \"We have no subspace radio communication, sir.\"")) + return + + if damaged(DTRANSP): + prout(_("Scotty- \"Transporter damaged, sir.\"")) + return + + # find out if there are any at all + if game.klhere < 1: + prout(_("Uhura- \"Getting no response, sir.\"")) + return + + # if there is more than one Klingon, find out which one */ + # Cruddy, just takes one at random. Should ask the captain. + # Nah, just select the weakest one since it is most likely to + # surrender (Tom Almy mod) + klingons = [e for e in game.enemies if e.type == 'K'] + weakest = sorted(klingons, key=lambda e: e.power) + Time = 0.05 # This action will take some time + game.ididit = True # So any others can strike back + + # check out that Klingon + # The algorithm isn't that great and could use some more + # intelligent design + # x = 300 + 25*skill; + x = game.energy / (weakest.power * len(klingons)) + x *= 2.5; # would originally have been equivalent of 1.4, + # but we want command to work more often, more humanely */ + #prout(_("Prob = %d (%.4f)\n", i, x)) + # x = 100; // For testing, of course! + if x > randreal(100): + # guess what, he surrendered!!! */ + prout(_("Klingon captain at %s surrenders.") % weakest.location) + i = randreal(200) + if i > 0: + prout(_("%d Klingons commit suicide rather than be taken captive.") % 200 - i) + if i > brigfree: + prout(_("%d Klingons die because there is no room for them in the brig.") % i-brigfree) + i = brigfree + brigfree -= i + prout(_("%d captives taken") % i) + deadkl(weakest.location, weakest.type, game.sector) + if (game.state.remkl + len(game.state.kcmdr) + game.state.nscrem)<=0: + finish(FWON) + return + + # big surprise, he refuses to surrender */ + prout(_("Fat chance, captain!")) + +# Code from events.c begins here. # This isn't a real event queue a la BSD Trek yet -- you can only have one # event of each type active at any given time. Mostly these means we can @@ -2234,16 +2299,16 @@ def events(): unschedule(FBATTAK) unschedule(FCDBAS) continue + ibq = None # Force battle location to persist past loop try: for ibq in game.state.baseq: for cmdr in game.state.kcmdr: if ibq == cmdr and ibq != game.quadrant and ibq != game.state.kscmdr: raise JumpOut - else: - # no match found -- try later - schedule(FBATTAK, expran(0.3*game.intime)) - unschedule(FCDBAS) - continue + # no match found -- try later + schedule(FBATTAK, expran(0.3*game.intime)) + unschedule(FCDBAS) + continue except JumpOut: pass # commander + starbase combination found -- launch attack @@ -2398,8 +2463,8 @@ def events(): if q.klingons >= MAXKLQUAD or q.supernova: continue raise JumpOut - else: - continue # search for eligible quadrant failed + # search for eligible quadrant failed + continue except JumpOut: w = m # deliver the child @@ -2558,33 +2623,37 @@ def nova(nov): elif iquad == 'K': # kill klingon deadkl(neighbor, iquad, neighbor) elif iquad in ('C','S','R'): # Damage/destroy big enemies + target = None for ll in range(len(game.enemies)): if game.enemies[ll].location == neighbor: + target = game.enemies[ll] break - game.enemies[ll].power -= 800.0 # If firepower is lost, die - if game.enemies[ll].power <= 0.0: - deadkl(neighbor, iquad, neighbor) - break - newc = neighbor + neighbor - hits[-1] - proutn(crmena(True, iquad, "sector", neighbor) + _(" damaged")) - if not newc.valid_sector(): - # can't leave quadrant - skip(1) - break - iquad1 = game.quad[newc.i][newc.j] - if iquad1 == ' ': - proutn(_(", blasted into ") + crmena(False, ' ', "sector", newc)) - skip(1) - deadkl(neighbor, iquad, newc) - break - if iquad1 != '.': - # can't move into something else - skip(1) - break - proutn(_(", buffeted to Sector %s") % newc) - game.quad[neighbor.i][neighbor.j] = '.' - game.quad[newc.i][newc.j] = iquad - game.enemies[ll].move(newc) + if target is not None: + target.power -= 800.0 # If firepower is lost, die + if target.power <= 0.0: + deadkl(neighbor, iquad, neighbor) + continue # neighbor loop + # Else enemy gets flung by the blast wave + newc = neighbor + neighbor - hits[-1] + proutn(crmena(True, iquad, "sector", neighbor) + _(" damaged")) + if not newc.valid_sector(): + # can't leave quadrant + skip(1) + continue + iquad1 = game.quad[newc.i][newc.j] + if iquad1 == ' ': + proutn(_(", blasted into ") + crmena(False, ' ', "sector", newc)) + skip(1) + deadkl(neighbor, iquad, newc) + continue + if iquad1 != '.': + # can't move into something else + skip(1) + continue + proutn(_(", buffeted to Sector %s") % newc) + game.quad[neighbor.i][neighbor.j] = '.' + game.quad[newc.i][newc.j] = iquad + target.move(newc) # Starship affected by nova -- kick it away. dist = kount*0.1 direc = ncourse[3*(bump.i+1)+bump.j+2] @@ -2796,6 +2865,9 @@ def finish(ifin): prout(_("You have smashed the Klingon invasion fleet and saved")) prout(_("the Federation.")) + if game.alive and game.brigcapacity-game.brigfree > 0: + game.kcaptured += game.brigcapacity-game.brigfree + prout(_("The %d captured Klingons are transferred to Star Fleet Command.") % (game.brigcapacity-game.brigfree)) game.gamewon = True if game.alive: badpt = badpoints() @@ -2997,6 +3069,7 @@ def score(): + 20*(game.inrom - game.state.nromrem) \ + 200*(game.inscom - game.state.nscrem) \ - game.state.nromrem \ + + 3 * game.kcaptured \ - badpoints() if not game.alive: game.score -= 200 @@ -3014,6 +3087,9 @@ def score(): if game.incom - len(game.state.kcmdr): prout(_("%6d Klingon commanders destroyed %5d") % (game.incom - len(game.state.kcmdr), 50*(game.incom - len(game.state.kcmdr)))) + if game.kcaptured: + prout(_("%d Klingons captured %5d") % + (game.kcaptured, 3 * game.kcaptured)) if game.inscom - game.state.nscrem: prout(_("%6d Super-Commander destroyed %5d") % (game.inscom - game.state.nscrem, 200*(game.inscom - game.state.nscrem))) @@ -3135,7 +3211,6 @@ def iostart(): # for the older ones we probably need to set C locale, and python3 # has no problems at all if sys.version_info[0] < 3: - import locale locale.setlocale(locale.LC_ALL, "") gettext.bindtextdomain("sst", "/usr/local/share/locale") gettext.textdomain("sst") @@ -3515,6 +3590,8 @@ def imove(icourse=None, noattack=False): # check for edge of galaxy kinks = 0 while True: + + kink = False if icourse.final.i < 0: icourse.final.i = -icourse.final.i @@ -3562,9 +3639,11 @@ def imove(icourse=None, noattack=False): if iquad in ('T', 'K', 'C', 'S', 'R', '?'): for enemy in game.enemies: if enemy.location == game.sector: - break - collision(rammed=False, enemy=enemy) - return True + collision(rammed=False, enemy=enemy) + return True + # This should not happen + prout(_("Which way did he go?")) + return False elif iquad == ' ': skip(1) prouts(_("***RED ALERT! RED ALERT!")) @@ -3653,7 +3732,7 @@ def dock(verbose): prout(crmshp() + _(" not adjacent to base.")) return game.condition = "docked" - if "verbose": + if verbose: prout(_("Docked.")) game.ididit = True if game.energy < game.inenrg: @@ -3662,6 +3741,10 @@ def dock(verbose): game.torps = game.intorps game.lsupres = game.inlsr game.state.crew = FULLCREW + if game.brigcapacity-game.brigfree > 0: + prout(_("%d captured Klingons transferred to base") % (game.brigcapacity-game.brigfree)) + game.kcaptured += game.brigcapacity-game.brigfree + game.brigfree = game.brigcapacity if not damaged(DRADIO) and \ ((is_scheduled(FCDBAS) or game.isatb == 1) and not game.iseenit): # get attack report from base @@ -3679,7 +3762,7 @@ def cartesian(loc1=None, loc2=None): def getcourse(isprobe): "Get a course and distance from the user." - key = 0 + key = "" dquad = copy.copy(game.quadrant) navmode = "unspecified" itemp = "curt" @@ -3821,16 +3904,14 @@ class course: if self.bearing < 0.0: self.bearing += 12.0 self.angle = ((15.0 - self.bearing) * 0.5235988) - if origin is None: - self.origin = cartesian(game.quadrant, game.sector) - else: - self.origin = cartesian(game.quadrant, origin) self.increment = Coord(-math.sin(self.angle), math.cos(self.angle)) bigger = max(abs(self.increment.i), abs(self.increment.j)) self.increment /= bigger self.moves = int(round(10*self.distance*bigger)) self.reset() self.final = (self.location + self.moves*self.increment).roundtogrid() + self.location = self.origin + self.nextlocation = None def reset(self): self.location = self.origin self.step = 0 @@ -4247,11 +4328,15 @@ def mayday(): # There's one in this quadrant ddist = (game.base - game.sector).distance() else: + ibq = None # Force base-quadrant game to persist past loop ddist = FOREVER for ibq in game.state.baseq: xdist = QUADSIZE * (ibq - game.quadrant).distance() if xdist < ddist: ddist = xdist + if ibq is None: + prout(_("No starbases remain. You are alone in a hostile galaxy.")) + return # Since starbase not in quadrant, set up new quadrant game.quadrant = ibq newqad() @@ -4363,12 +4448,13 @@ def abandon(): while True: # position next to base by trial and error game.quad[game.sector.i][game.sector.j] = '.' + l = QUADSIZE for l in range(QUADSIZE): game.sector = game.base.scatter() if game.sector.valid_sector() and \ game.quad[game.sector.i][game.sector.j] == '.': break - if l < QUADSIZE+1: + if l < QUADSIZE: break # found a spot game.sector.i=QUADSIZE/2 game.sector.j=QUADSIZE/2 @@ -4394,6 +4480,7 @@ def abandon(): game.lsupres=game.inlsr=3.0 game.shldup=False game.warpfac=5.0 + game.brigfree = game.brigcapacity = 300 return # Code from planets.c begins here. @@ -4913,6 +5000,18 @@ def report(): game.iseenit = True if game.casual: prout(_("%d casualt%s suffered so far.") % (game.casual, ("y", "ies")[game.casual!=1])) + if game.brigcapacity != game.brigfree: + embriggened = brigcapacity-brigfree + if embriggened == 1: + prout(_("1 Klingon in brig")) + else: + prout(_("%d Klingons in brig.") % embriggened) + if game.kcaptured == 0: + pass + elif game.kcaptured == 1: + prout(_("1 captured Klingon turned in to Starfleet.")) + else: + prout(_("%d captured Klingons turned in to Star Fleet.") % game.kcaptured) if game.nhelp: prout(_("There were %d call%s for help.") % (game.nhelp, ("" , _("s"))[game.nhelp!=1])) if game.ship == 'E': @@ -4930,7 +5029,7 @@ def report(): proutn(_("An armed deep space probe is in ")) else: proutn(_("A deep space probe is in ")) - prout("Quadrant %s." % game.probec) + prout("Quadrant %s." % game.probe.quadrant()) if game.icrystl: if game.cryprob <= .05: prout(_("Dilithium crystals aboard ship... not yet used.")) @@ -5043,13 +5142,20 @@ def chart(): def sectscan(goodScan, i, j): "Light up an individual dot in a sector." if goodScan or (abs(i-game.sector.i)<= 1 and abs(j-game.sector.j) <= 1): - textcolor({"green":GREEN, - "yellow":YELLOW, - "red":RED, - "docked":CYAN, - "dead":BROWN}[game.condition]) - if game.quad[i][j] != game.ship: - highvideo() + if game.quad[i][j] in ('E', 'F'): + textcolor({"green":GREEN, + "yellow":YELLOW, + "red":RED, + "docked":CYAN, + "dead":BROWN}[game.condition]) + else: + textcolor({'?':LIGHTMAGENTA, + 'K':LIGHTRED, + 'S':LIGHTRED, + 'C':LIGHTRED, + 'R':LIGHTRED, + 'T':LIGHTRED, + }.get(game.quad[i][j], DEFAULT)) proutn("%c " % game.quad[i][j]) textcolor(DEFAULT) else: @@ -5680,17 +5786,16 @@ def choose(): 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) + game.options &=~ (OPTION_THOLIAN | OPTION_PLANETS | OPTION_THINGY | OPTION_PROBE | OPTION_RAMMING | OPTION_MVBADDY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS | OPTION_COLOR | OPTION_CAPTURE) game.options |= OPTION_PLAIN elif scanner.sees("almy"): # Approximates Tom Almy's version. - game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS) + game.options &=~ (OPTION_THINGY | OPTION_BLKHOLE | OPTION_BASE | OPTION_WORLDS | OPTION_COLOR) game.options |= OPTION_ALMY elif scanner.sees("fancy") or scanner.sees("\n"): pass elif len(scanner.token): proutn(_("What is \"%s\"?") % scanner.token) - game.options &=~ OPTION_COLOR setpassword() if game.passwd == "debug": game.idebug = True @@ -5889,7 +5994,6 @@ commands = [ ("IMPULSE", 0), ("REST", 0), ("WARP", 0), - ("SCORE", 0), ("SENSORS", OPTION_PLANETS), ("ORBIT", OPTION_PLANETS), ("TRANSPORT", OPTION_PLANETS), @@ -5907,12 +6011,14 @@ commands = [ ("ABANDON", 0), ("DESTRUCT", 0), ("DEATHRAY", 0), + ("CAPTURE", OPTION_CAPTURE), ("DEBUG", 0), ("MAYDAY", 0), ("SOS", 0), # Synonym for MAYDAY ("CALL", 0), # Synonym for MAYDAY ("QUIT", 0), ("HELP", 0), + ("SCORE", 0), ("", 0), ] @@ -6059,8 +6165,6 @@ def makemoves(): hitme = True elif cmd == "WARP": # warp setwarp() - elif cmd == "SCORE": # score - score() elif cmd == "SENSORS": # sensors sensor() elif cmd == "ORBIT": # orbit @@ -6110,6 +6214,8 @@ def makemoves(): deathray() if game.ididit: hitme = True + elif cmd == "CAPTURE": + capture() elif cmd == "DEBUGCMD": # What do we want for debug??? debugme() elif cmd == "MAYDAY": # Call for help @@ -6120,6 +6226,8 @@ def makemoves(): game.alldone = True # quit the game elif cmd == "HELP": helpme() # get help + elif cmd == "SCORE": + score() # see current score while True: if game.alldone: break # Game has ended @@ -6369,7 +6477,6 @@ def debugme(): atover(True) if __name__ == '__main__': - import getopt, socket try: #global line, thing, game game = None