c082b3b4df7ed83bf73ba3980cb509ffdcbb4161
[super-star-trek.git] / sst.py
1 """
2 sst.py =-- Super Star Trek in Python
3
4 Control flow of this translation is pretty much identical to the C version
5 (and thus like the ancestral FORTRAN) but the data structures are
6 radically different -- the Python code makes heavy use of objects.
7
8 Note that the game.quad, game.snap.galaxy and game.snap.chart members
9 are not actually arrays but dictioaries indixed by coord tuples.  Be setting
10 the hash of a coord equal to the hash of a literal tuple containing its
11 coordinate data, we ensure these can be indexed both ways.
12
13 """
14 import math
15
16 PHASEFAC        = 2.0
17 GALSIZE         = 8
18 NINHAB          = GALSIZE * GALSIZE / 2
19 MAXUNINHAB      = 10
20 PLNETMAB        = NINHAB + MAXUNINHAB
21 QUADSIZE        = 10
22 BASEMAX         = 5
23 FULLCREW        = 428    # BSD Trek was 387, that's wrong
24 MAXKLGAME       = 127
25 MAXKLQUAD       = 9
26 FOREVER         = 1e30
27
28 # These macros hide the difference between 0-origin and 1-origin addressing.
29 # They're a step towards de-FORTRANizing the code.
30 def VALID_QUADRANT(x,y): ((x)>=1 and (x)<=GALSIZE and (y)>=1 and (y)<=GALSIZE)
31 def VALID_SECTOR(x, y): ((x)>=1 and (x)<=QUADSIZE and (y)>=1 and (y)<=QUADSIZE)
32
33 # These types have not been dealt with yet 
34 IHQUEST = '?',
35 IHWEB = '#',
36 IHMATER0 = '-',
37 IHMATER1 = 'o',
38 IHMATER2 = '0',
39
40 class coord:
41     def __init(self, x=None, y=None):
42         self.x = x
43         self.y = y
44     def invalidate(self):
45         self.x = self.y = None
46     def is_valid(self):
47         return self.x != None and self.y != None
48     def __eq__(self, other):
49         return self.x == other.y and self.x == other.y
50     def __add__(self, other):
51         return coord(self.x+self.x, self.y+self.y)
52     def __sub__(self, other):
53         return coord(self.x-self.x, self.y-self.y)
54     def distance(self, other):
55         return math.sqrt((self.x - other.x)**2 + (self.y - other.y)**2)
56     def sgn(self):
57         return coord(self.x / abs(x), self.y / abs(y));
58     def __hash__(self):
59         return hash((x, y))
60     def __str__(self):
61         return "%d - %d" % (self.x, self.y)
62
63 class feature:
64     "A feature in the current quadrant (ship, star, black hole, base, etc)." 
65     def __init__(self):
66         self.type = None        # name of feature type
67         self.sector = None      # sector location
68     def distance(self):
69         return self.sector.distance(game.sector)
70     def __str__(self):
71         "This will be overridden by subclasses."
72         return self.name[0]
73     def sectormove(self, dest):
74         "Move this feature within the current quadrant." 
75         if self.sector:
76             game.quad[self.sector] = None
77         game.quad[dest] = self
78         self.sector = dest
79
80 class ship(feature):
81     "A starship, frindly or enemy." 
82     def __init__(self, type, power):
83         feature.__init__(self)
84         self.type = type        # klingon, romulan, commander,
85                                 # supercommander, tholian,
86                                 # enterprise, faerie queene.
87         self.power = power      # power
88         if self.type in ("Klingon", "Commander", "Super-Commander"):
89             game.remkl += 1
90         elif self.type == "Romulan":
91             game.romrem += 1
92     def __del__(self):
93         if self.type in ("Klingon", "Commander", "Super-Commander"):
94             game.remkl -= 1
95         elif self.type == "Romulan":
96             game.romrem -= 1
97
98 class space(feature):
99     "Empty space.  Has no state, just knows how to identify iself."
100     def __str__(self):
101         return '*'
102
103 class star(feature):
104     "A star.  Has no state, just knows how to identify iself."
105     def __str__(self):
106         return '*'
107
108 class planet(feature):
109     "A planet.  May be inhabited or not, may hold dilithium crystals or not."
110     def __init(self):
111         feature.__init__(self)
112         self.name = None
113         self.crystals = None    # "absent", "present", or "mined"
114         self.inhabited = False
115         self.known = "unknown"  # Other values: "known" and "shuttle down"
116         game.state.planets.append(self)
117     def __del__(self):
118         game.state.planets.remove(self)
119     def __str__(self):
120         if self.inhabited:
121             return '@'
122         else:
123             return 'P'
124
125 class web(feature):
126     "A bit of Tholian web.  Has no state, just knows how to identify iself."
127     def __str__(self):
128         return '*'
129
130 class blackhole(feature):
131     "A black hole.  Has no hair, just knows how to identify iself."
132     def __str__(self):
133         return ' '
134
135 class starbase(feature):
136     "Starbases also have no features, just a location."
137     def __init(self, quadrant):
138         feature.__init__(self)
139         self.quadrant = quadrant
140         game.state.bases.append(self)
141     def __del__(self):
142         game.state.bases.remove(self)
143     def __str__(self):
144         return 'B'
145
146 class quadrant:
147     def __init__(self):
148         self.stars = None
149         self.planet = None
150         self.starbase = None
151         self.klingons = None
152         self.romulans = None
153         self.supernova = None
154         self.charted = None
155         self.status = "secure"  # Other valuues: "distressed", "enslaved"
156     def enemies(self):
157         "List enemies in this quadrant."
158         lst = []
159         for feature in self.quad.values:
160             if not isinstance(feature, ship):
161                 continue
162             if feature.name not in ("Enterprise", "Faerie Queene"):
163                 lst.append(feature)
164         return lst
165
166 class page:
167     "A chart page.  The starchart is a 2D array of these."
168     def __init__(self):
169         self.stars = None       # Will hold a number
170         self.starbase = None    # Will hold a bool
171         self.klingons = None    # Will hold a number
172
173 class snapshot:
174     "State of the universe.  The galaxy is a 2D array of these."
175     def __init__(self):
176         self.crew = None        # crew complement
177         self.remkl = None       # remaining klingons
178         self.remcom = None      # remaining commanders
179         self.nscrem = None      # remaining super commanders
180         self.starkl = None      # destroyed stars
181         self.basekl = None      # destroyed bases
182         self.nromrem = None     # Romulans remaining
183         self.nplankl = None     # destroyed uninhabited planets self.nworldkl = None    # destroyed inhabited planets
184         self.planets = [];      # List of planets known
185         self.date = None        # stardate
186         self.remres = None      # remaining resources
187         self. remtime = None    # remaining time
188         self.bases = []         # Base quadrant coordinates
189         self.kcmdr = []         # Commander quadrant coordinates
190         self.kscmdr = None      # Supercommander quadrant coordinates
191         self.galaxy = {}        # Dictionary of quadrant objects
192         self.chart = {}         # Dictionary of page objects
193
194 def damaged(dev):
195     return game.damage[dev] != 0.0
196
197 class event:
198     def __init__(self):
199         self.date = None        # The only mandatory attribute
200
201 class game:
202     def __init__(self):
203         self.options = []               # List of option strings
204         self.state = snapshot()         # State of the universe
205         self.snapsht = snapshot()       # For backwards timetravel
206         self.quad = {}                  # contents of our quadrant
207         self.kpower = {}                # enemy energy levels
208         self.kdist = {}                 # enemy distances
209         self.kavgd = {}                 # average distances
210         self.damage = {}                # damage encountered
211         self.future = []                # future events
212         self.passwd = None              # Self Destruct password
213         # Coordinate members start here
214         self.enemies = {}                       # enemy sector locations
215         self.quadrant = None            # where we are
216         self.sector = None
217         self.tholian = None             # coordinates of Tholian
218         self.base = None                # position of base in current quadrant
219         self.battle = None              # base coordinates being attacked
220         self.plnet = None               # location of planet in quadrant
221         self.probec = None              # current probe quadrant
222         # Flag members start here
223         self.gamewon = None             # Finished!
224         self.ididit = None              # action taken -- allows enemy to attack
225         self.alive = None               # we are alive (not killed)
226         self.justin = None              # just entered quadrant
227         self.shldup = None              # shields are up
228         self.shldchg = None             # shield changing (affects efficiency)
229         self.comhere = None             # commander here
230         self.ishere = None              # super-commander in quadrant
231         self.iscate = None              # super commander is here
232         self.ientesc = None             # attempted escape from supercommander
233         self.ithere = None              # Tholian is here 
234         self.resting = None             # rest time
235         self.icraft = None              # Kirk in Galileo
236         self.landed = None              # party on planet or on ship
237         self.alldone = None             # game is now finished
238         self.neutz = None               # Romulan Neutral Zone
239         self.isarmed = None             # probe is armed
240         self.inorbit = None             # orbiting a planet
241         self.imine = None               # mining
242         self.icrystl = None             # dilithium crystals aboard
243         self.iseenit = None             # seen base attack report
244         self.thawed = None              # thawed game
245         # String members start here
246         self.condition = None           # green, yellow, red, docked, dead,
247         self.iscraft = None             # onship, offship, removed
248         self.skill = None               # levels: none, novice, fair, good,
249                                         # expert, emeritus
250         # Integer nembers sart here
251 x       self.inkling = None             # initial number of klingons
252         self.inbase = None              # initial number of bases
253         self.incom = None               # initial number of commanders
254         self.inscom = None              # initial number of commanders
255         self.inrom = None               # initial number of commanders
256         self.instar = None              # initial stars
257         self.intorps = None             # initial/max torpedoes
258         self.torps = None               # number of torpedoes
259         self.ship = None                # ship type -- 'E' is Enterprise
260         self.abandoned = None           # count of crew abandoned in space
261         self.length = None              # length of game
262         self.klhere = None              # klingons here
263         self.casual = None              # causalties
264         self.nhelp = None               # calls for help
265         self.nkinks = None              # count of energy-barrier crossings
266         self.iplnet = None              # planet # in quadrant
267         self.inplan = None              # initial planets
268         self.irhere = None              # Romulans in quadrant
269         self.isatb = None               # =1 if super commander is attacking base
270         self.tourn = None               # tournament number
271         self.proben = None              # number of moves for probe
272         self.nprobes = None             # number of probes available
273         # Float members start here
274         self.inresor = None             # initial resources
275         self.intime = None              # initial time
276         self.inenrg = None              # initial/max energy
277         self.inshld = None              # initial/max shield
278         self.inlsr = None               # initial life support resources
279         self.indate = None              # initial date
280         self.energy = None              # energy level
281         self.shield = None              # shield level
282         self.warpfac = None             # warp speed
283         self.wfacsq = None              # squared warp factor
284         self.lsupres = None             # life support reserves
285         self.dist = None                # movement distance
286         self.direc = None               # movement direction
287         self.optime = None              # time taken by current operation
288         self.docfac = None              # repair factor when docking (constant?)
289         self.damfac = None              # damage factor
290         self.lastchart = None           # time star chart was last updated
291         self.cryprob = None             # probability that crystal will work
292         self.probex = None              # location of probe
293         self.probey = None              #
294         self.probeinx = None            # probe x,y increment
295         self.probeiny = None            #
296         self.height = None              # height of orbit around planet
297
298