1cf20dc175ed24dd115673f7863754b23f6cc703
[super-star-trek.git] / src / sst.py
1 """
2 sst.py =-- Super Star Trek in Python
3
4 """
5 import os, sys, math, curses
6
7 SSTDOC = "/usr/share/doc/sst/sst.doc"
8
9 # Stub to be replaced
10 def _(str): return str
11
12 PHASEFAC        = 2.0
13 GALSIZE         = 8
14 NINHAB          = (GALSIZE * GALSIZE / 2)
15 MAXUNINHAB      = 10
16 PLNETMAX        = (NINHAB + MAXUNINHAB)
17 QUADSIZE        = 10
18 BASEMAX         = (GALSIZE * GALSIZE / 12)
19 MAXKLGAME       = 127
20 MAXKLQUAD       = 9
21 FULLCREW        = 428   # BSD Trek was 387, that's wrong 
22 FOREVER         = 1e30
23
24 # These functions hide the difference between 0-origin and 1-origin addressing.
25 def VALID_QUADRANT(x, y):       return ((x)>=1 and (x)<=GALSIZE and (y)>=1 and (y)<=GALSIZE)
26 def VALID_SECTOR(x, y): return ((x)>=1 and (x)<=QUADSIZE and (y)>=1 and (y)<=QUADSIZE)
27
28 def square(i):          return ((i)*(i))
29 def distance(c1, c2):   return math.sqrt(square(c1.x - c2.x) + square(c1.y - c2.y))
30 def invalidate(w):      w.x = w.y = 0
31 def is_valid(w):        return (w.x != 0 and w.y != 0)
32
33 class coord:
34     def __init(self, x=None, y=None):
35         self.x = x
36         self.y = y
37     def invalidate(self):
38         self.x = self.y = None
39     def is_valid(self):
40         return self.x != None and self.y != None
41     def __eq__(self, other):
42         return self.x == other.y and self.x == other.y
43     def __add__(self, other):
44         return coord(self.x+self.x, self.y+self.y)
45     def __sub__(self, other):
46         return coord(self.x-self.x, self.y-self.y)
47     def distance(self, other):
48         return math.sqrt((self.x - other.x)**2 + (self.y - other.y)**2)
49     def sgn(self):
50         return coord(self.x / abs(x), self.y / abs(y));
51     def __hash__(self):
52         return hash((x, y))
53     def __str__(self):
54         return "%d - %d" % (self.x, self.y)
55
56 class planet:
57     def __init(self):
58         self.name = None        # string-valued if inhabited
59         self.w = coord()        # quadrant located
60         self.pclass = None      # could be ""M", "N", "O", or "destroyed"
61         self.crystals = None    # could be "mined", "present", "absent"
62         self.known = None       # could be "unknown", "known", "shuttle_down"
63
64 # How to represent features
65 IHR = 'R',
66 IHK = 'K',
67 IHC = 'C',
68 IHS = 'S',
69 IHSTAR = '*',
70 IHP = 'P',
71 IHW = '@',
72 IHB = 'B',
73 IHBLANK = ' ',
74 IHDOT = '.',
75 IHQUEST = '?',
76 IHE = 'E',
77 IHF = 'F',
78 IHT = 'T',
79 IHWEB = '#',
80 IHMATER0 = '-',
81 IHMATER1 = 'o',
82 IHMATER2 = '0'
83
84 NOPLANET = None
85 class quadrant:
86     def __init(self):
87         self.stars = None
88         self.planet = None
89         self.starbase = None
90         self.klingons = None
91         self.romulans = None
92         self.supernova = None
93         self.charted = None
94         self.status = None      # Could be "secure", "distressed", "enslaved"
95
96 class page:
97     def __init(self):
98         self.stars = None
99         self.starbase = None
100         self.klingons = None
101
102 class snapshot:
103     def __init(self):
104         self.snap = False       # snapshot taken
105         self.crew = None        # crew complement
106         self.remkl = None       # remaining klingons
107         self.remcom = None      # remaining commanders
108         self.nscrem = None      # remaining super commanders
109         self.rembase = None     # remaining bases
110         self.starkl = None      # destroyed stars
111         self.basekl = None      # destroyed bases
112         self.nromrem = None     # Romulans remaining
113         self.nplankl = None     # destroyed uninhabited planets
114         self.nworldkl = None    # destroyed inhabited planets
115         self.planets = []       # Planet information
116         for i in range(PLNETMAX):
117             self.planets.append(planet())
118         self.date = None        # stardate
119         self.remres = None      # remaining resources
120         self.remtime = None     # remaining time
121         self.baseq = []         # Base quadrant coordinates
122         for i in range(BASEMAX+1):
123             self.baseq.append(coord())
124         self.kcmdr = []         # Commander quadrant coordinates
125         for i in range(QUADSIZE+1):
126             self.kcmdr.append(coord())
127         self.kscmdr = coord()   # Supercommander quadrant coordinates
128         self.galaxy = []        # The Galaxy (subscript 0 not used)
129         for i in range(GALSIZE+1):
130             self.chart.append([])
131             for j in range(GALSIZE+1):
132                 self.galaxy[i].append(quadrant())
133         self.chart = []         # the starchart (subscript 0 not used)
134         for i in range(GALSIZE+1):
135             self.chart.append([])
136             for j in range(GALSIZE+1):
137                 self.chart[i].append(page())
138
139 class event:
140     def __init__(self):
141         self.date = None        # A real number
142         self.quadrant = None    # A coord structure
143
144 # game options 
145 OPTION_ALL      = 0xffffffff
146 OPTION_TTY      = 0x00000001    # old interface 
147 OPTION_CURSES   = 0x00000002    # new interface 
148 OPTION_IOMODES  = 0x00000003    # cover both interfaces 
149 OPTION_PLANETS  = 0x00000004    # planets and mining 
150 OPTION_THOLIAN  = 0x00000008    # Tholians and their webs 
151 OPTION_THINGY   = 0x00000010    # Space Thingy can shoot back 
152 OPTION_PROBE    = 0x00000020    # deep-space probes 
153 OPTION_SHOWME   = 0x00000040    # bracket Enterprise in chart 
154 OPTION_RAMMING  = 0x00000080    # enemies may ram Enterprise 
155 OPTION_MVBADDY  = 0x00000100    # more enemies can move 
156 OPTION_BLKHOLE  = 0x00000200    # black hole may timewarp you 
157 OPTION_BASE     = 0x00000400    # bases have good shields 
158 OPTION_WORLDS   = 0x00000800    # logic for inhabited worlds 
159 OPTION_PLAIN    = 0x01000000    # user chose plain game 
160 OPTION_ALMY     = 0x02000000    # user chose Almy variant 
161
162 # Define devices 
163 DSRSENS = 0
164 DLRSENS = 1
165 DPHASER = 2
166 DPHOTON = 3
167 DLIFSUP = 4
168 DWARPEN = 5
169 DIMPULS = 6
170 DSHIELD = 7
171 DRADIO  = 0
172 DSHUTTL = 9
173 DCOMPTR = 10
174 DNAVSYS = 11
175 DTRANSP = 12
176 DSHCTRL = 13
177 DDRAY   = 14
178 DDSP    = 15
179 NDEVICES= 16    # Number of devices
180
181 def damaged(dev):       return (game.damage[dev] != 0.0)
182
183 # Define future events 
184 FSPY    = 0     # Spy event happens always (no future[] entry)
185                 # can cause SC to tractor beam Enterprise
186 FSNOVA  = 1     # Supernova
187 FTBEAM  = 2     # Commander tractor beams Enterprise
188 FSNAP   = 3     # Snapshot for time warp
189 FBATTAK = 4     # Commander attacks base
190 FCDBAS  = 5     # Commander destroys base
191 FSCMOVE = 6     # Supercommander moves (might attack base)
192 FSCDBAS = 7     # Supercommander destroys base
193 FDSPROB = 8     # Move deep space probe
194 FDISTR  = 9     # Emit distress call from an inhabited world 
195 FENSLV  = 10    # Inhabited word is enslaved */
196 FREPRO  = 11    # Klingons build a ship in an enslaved system
197 NEVENTS = 12
198
199 #
200 # abstract out the event handling -- underlying data structures will change
201 # when we implement stateful events
202
203 def findevent(evtype):  return game.future[evtype]
204
205 class gamestate:
206     def __init__(self):
207         self.options = None     # Game options
208         self.state = None       # A snapshot structure
209         self.snapsht = None     # Last snapshot taken for time-travel purposes
210         self.quad = [[IHDOT * (QUADSIZE+1)] * (QUADSIZE+1)]     # contents of our quadrant
211         self.kpower = [[0 * (QUADSIZE+1)] * (QUADSIZE+1)]       # enemy energy levels
212         self.kdist = [[0 * (QUADSIZE+1)] * (QUADSIZE+1)]        # enemy distances
213         self.kavgd = [[0 * (QUADSIZE+1)] * (QUADSIZE+1)]        # average distances
214         self.damage = [0] * NDEVICES    # damage encountered
215         self.future = [0.0] * NEVENTS   # future events
216         for i in range(NEVENTS):
217             self.future.append(event())
218         self.passwd  = None;            # Self Destruct password
219         self.ks = [[None * (QUADSIZE+1)] * (QUADSIZE+1)]        # enemy sector locations
220         self.quadrant = None    # where we are in the large
221         self.sector = None      # where we are in the small
222         self.tholian = None     # coordinates of Tholian
223         self.base = None        # position of base in current quadrant
224         self.battle = None      # base coordinates being attacked
225         self.plnet = None       # location of planet in quadrant
226         self.probec = None      # current probe quadrant
227         self.gamewon = False    # Finished!
228         self.ididit = False     # action taken -- allows enemy to attack
229         self.alive = False      # we are alive (not killed)
230         self.justin = False     # just entered quadrant
231         self.shldup = False     # shields are up
232         self.shldchg = False    # shield is changing (affects efficiency)
233         self.comhere = False    # commander here
234         self.ishere = False     # super-commander in quadrant
235         self.iscate = False     # super commander is here
236         self.ientesc = False    # attempted escape from supercommander
237         self.ithere = False     # Tholian is here 
238         self.resting = False    # rest time
239         self.icraft = False     # Kirk in Galileo
240         self.landed = False     # party on planet (true), on ship (false)
241         self.alldone = False    # game is now finished
242         self.neutz = False      # Romulan Neutral Zone
243         self.isarmed = False    # probe is armed
244         self.inorbit = False    # orbiting a planet
245         self.imine = False      # mining
246         self.icrystl = False    # dilithium crystals aboard
247         self.iseenit = False    # seen base attack report
248         self.thawed = False     # thawed game
249         self.condition = None   # "green", "yellow", "red", "docked", "dead"
250         self.iscraft = None     # "onship", "offship", "removed"
251         self.skill = None       # Player skill level
252         self.inkling = 0        # initial number of klingons
253         self.inbase = 0         # initial number of bases
254         self.incom = 0          # initial number of commanders
255         self.inscom = 0         # initial number of commanders
256         self.inrom = 0          # initial number of commanders
257         self.instar = 0         # initial stars
258         self.intorps = 0        # initial/max torpedoes
259         self.torps = 0          # number of torpedoes
260         self.ship = 0           # ship type -- 'E' is Enterprise
261         self.abandoned = 0      # count of crew abandoned in space
262         self.length = 0         # length of game
263         self.klhere = 0         # klingons here
264         self.casual = 0         # causalties
265         self.nhelp = 0          # calls for help
266         self.nkinks = 0         # count of energy-barrier crossings
267         self.iplnet = 0         # planet # in quadrant
268         self.inplan = 0         # initial planets
269         self.nenhere = 0        # number of enemies in quadrant
270         self.irhere = 0         # Romulans in quadrant
271         self.isatb = 0          # =1 if super commander is attacking base
272         self.tourn = 0          # tournament number
273         self.proben = 0         # number of moves for probe
274         self.nprobes = 0        # number of probes available
275         self.inresor = 0.0      # initial resources
276         self.intime = 0.0       # initial time
277         self.inenrg = 0.0       # initial/max energy
278         self.inshld = 0.0       # initial/max shield
279         self.inlsr = 0.0        # initial life support resources
280         self.indate = 0.0       # initial date
281         self.energy = 0.0       # energy level
282         self.shield = 0.0       # shield level
283         self.warpfac = 0.0      # warp speed
284         self.wfacsq = 0.0       # squared warp factor
285         self.lsupres = 0.0      # life support reserves
286         self.dist = 0.0         # movement distance
287         self.direc = 0.0        # movement direction
288         self.optime = 0.0       # time taken by current operation
289         self.docfac = 0.0       # repair factor when docking (constant?)
290         self.damfac = 0.0       # damage factor
291         self.lastchart = 0.0    # time star chart was last updated
292         self.cryprob = 0.0      # probability that crystal will work
293         self.probex = 0.0       # location of probe
294         self.probey = 0.0       #
295         self.probeinx = 0.0     # probe x,y increment
296         self.probeiny = 0.0     #
297         self.height = 0.0       # height of orbit around planet
298