MAXBURST = 3
MINCMDR = 10
-# These functions hide the difference between 0-origin and 1-origin addressing.
-def VALID_QUADRANT(x, y): return ((x)>=0 and (x)<GALSIZE and (y)>=0 and (y)<GALSIZE)
-def VALID_SECTOR(x, y): return ((x)>=0 and (x)<QUADSIZE and (y)>=0 and (y)<QUADSIZE)
-
# How to represent features
IHR = 'R',
IHK = 'K',
def __init__(self, x=None, y=None):
self.i = x
self.j = y
+ def valid_quadrant(self):
+ return self.i>=0 and self.i<GALSIZE and self.j>=0 and self.j<GALSIZE
+ def valid_sector(self):
+ return self.i>=0 and self.i<QUADSIZE and self.j>=0 and self.j<QUADSIZE
def invalidate(self):
self.i = self.j = None
def is_valid(self):
return coord(self.i/other, self.j/other)
def __rdiv__(self, other):
return coord(self.i/other, self.j/other)
- def snaptogrid(self):
+ def roundtogrid(self):
+ return coord(int(round(self.i)), int(round(self.j)))
+ def trunctogrid(self):
return coord(int(round(self.i)), int(round(self.j)))
def distance(self, other=None):
if not other: other = coord(0, 0)
def welcoming(iq):
"Would this quadrant welcome another Klingon?"
- return VALID_QUADRANT(iq.i,iq.j) and \
+ return iq.valid_quadrant() and \
not game.state.galaxy[iq.i][iq.j].supernova and \
game.state.galaxy[iq.i][iq.j].klingons < MAXKLQUAD
finish(FWON)
return
-def torpedo(origin, course, dispersion, number, nburst):
+def torpedo(origin, bearing, 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
- bullseye = (15.0 - course)*0.5235988
- delta = coord(-math.sin(angle), math.cos(angle))
- bigger = max(abs(delta.i), abs(delta.j))
- delta /= bigger
- w = coord(0, 0); jw = coord(0, 0)
- ungridded = copy.copy(origin)
+ ac = bearing + 0.25*dispersion # dispersion is a random variable
+ bullseye = (15.0 - bearing)*0.5235988
+ track = course(bearing=ac, distance=QUADSIZE, origin=cartesian(origin))
+ jw = coord(0, 0)
# Loop to move a single torpedo
for step in range(1, QUADSIZE*2):
- ungridded += delta
- w = ungridded.snaptogrid()
- if not VALID_SECTOR(w.i, w.j):
+ track.next()
+ w = track.sector()
+ if not w.valid_sector():
break
iquad=game.quad[w.i][w.j]
tracktorpedo(origin, w, step, number, nburst, iquad)
# We may be displaced.
if game.landed or game.condition=="docked":
return hit # Cheat if on a planet
- ang = angle + 2.5*(randreal()-0.5)
+ ang = track.angle + 2.5*(randreal()-0.5)
temp = math.fabs(math.sin(ang))
if math.fabs(math.cos(ang)) > temp:
temp = math.fabs(math.cos(ang))
yy = math.cos(ang)/temp
jw.i = int(w.i+xx+0.5)
jw.j = int(w.j+yy+0.5)
- if not VALID_SECTOR(jw.i, jw.j):
+ if not jw.valid_sector():
return hit
if game.quad[jw.i][jw.j]==IHBLANK:
finish(FHOLE)
break
kp = math.fabs(enemy.kpower)
h1 = 700.0 + randrange(100) - \
- 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-angle))
+ 1000.0 * (w-origin).distance() * math.fabs(math.sin(bullseye-track.angle))
h1 = math.fabs(h1)
if kp < h1:
h1 = kp
return None
proutn(crmena(True, iquad, "sector", w))
# If enemy damaged but not destroyed, try to displace
- ang = angle + 2.5*(randreal()-0.5)
+ ang = track.angle + 2.5*(randreal()-0.5)
temp = math.fabs(math.sin(ang))
if math.fabs(math.cos(ang)) > temp:
temp = math.fabs(math.cos(ang))
yy = math.cos(ang)/temp
jw.i = int(w.i+xx+0.5)
jw.j = int(w.j+yy+0.5)
- if not VALID_SECTOR(jw.i, jw.j):
+ if not jw.valid_sector():
prout(_(" damaged but not destroyed."))
return
if game.quad[jw.i][jw.j]==IHBLANK:
def targetcheck(w):
"Return None if target is invalid, otherwise return a course angle."
- if not VALID_SECTOR(w.i, w.j):
+ if not w.valid_sector():
huh()
return None
delta = coord()
supercommander()
elif evcode == FDSPROB: # Move deep space probe
schedule(FDSPROB, 0.01)
- if game.probe.next():
- if not VALID_QUADRANT(game.probe.loc.i, game.probe.loc.j) or \
- game.state.galaxy[game.probe.loc.i][game.probe.loc.j].supernova:
+ if game.probe.next(grain=QUADSIZE):
+ if not game.probe.quadrant().valid_quadrant() or \
+ game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j].supernova:
# Left galaxy or ran into supernova
if communicating():
announce()
skip(1)
proutn(_("Lt. Uhura- \"The deep space probe "))
- if not VALID_QUADRANT(game.probe.loc.i, game.probe.loc.j):
- proutn(_("has left the galaxy.\""))
+ if not game.probe.quadrant().valid_quadrant():
+ prout(_("has left the galaxy.\""))
else:
- proutn(_("is no longer transmitting.\""))
+ prout(_("is no longer transmitting.\""))
unschedule(FDSPROB)
continue
if communicating():
#announce()
skip(1)
- prout(_("Lt. Uhura- \"The deep space probe is now in Quadrant %s.\"") % game.probe.loc)
- pdest = game.state.galaxy[game.probe.loc.i][game.probe.loc.j]
+ prout(_("Lt. Uhura- \"The deep space probe is now in Quadrant %s.\"") % game.probe.quadrant())
+ pdest = game.state.galaxy[game.probe.quadrant().i][game.probe.quadrant().j]
if communicating():
- chp = game.state.chart[game.probe.loc.i][game.probe.loc.j]
+ chp = game.state.chart[game.probe.quadrant().i][game.probe.quadrant().j]
chp.klingons = pdest.klingons
chp.starbase = pdest.starbase
chp.stars = pdest.stars
if game.probe.moves == 0 and game.isarmed and pdest.stars:
supernova(game.probe) # fire in the hole!
unschedule(FDSPROB)
- if game.state.galaxy[game.quadrant.i][game.quadrant.j].supernova:
+ if game.state.galaxy[game.quadrant().i][game.quadrant().j].supernova:
return
elif evcode == FDISTR: # inhabited system issues distress call
unschedule(FDISTR)
continue # full right now
# reproduce one Klingon
w = ev.quadrant
+ m = coord()
if game.klhere >= MAXKLQUAD:
try:
# this quadrant not ok, pick an adjacent one
- for i in range(w.i - 1, w.i + 2):
- for j in range(w.j - 1, w.j + 2):
- if not VALID_QUADRANT(i, j):
+ for m.i in range(w.i - 1, w.i + 2):
+ for m.j in range(w.j - 1, w.j + 2):
+ if not m.valid_quadrant():
continue
- q = game.state.galaxy[w.i][w.j]
+ q = game.state.galaxy[m.i][m.j]
# check for this quad ok (not full & no snova)
if q.klingons >= MAXKLQUAD or q.supernova:
continue
else:
continue # search for eligible quadrant failed
except "FOUNDIT":
- w.i = i; w.j = j
+ w = m
# deliver the child
game.state.remkl += 1
q.klingons += 1
game.enemies.append(newkling())
# recompute time left
game.recompute()
- # report the disaster if we can
if communicating():
if game.quadrant == w:
prout(_("Spock- sensors indicate the Klingons have"))
if offset.j==0 and offset.i==0:
continue
neighbor = start + offset
- if not VALID_SECTOR(neighbor.j, neighbor.i):
+ if not neighbor.valid_sector():
continue
iquad = game.quad[neighbor.i][neighbor.j]
# Empty space ends reaction
break
newc = neighbor + neighbor - hits[mm]
proutn(crmena(True, iquad, "sector", neighbor) + _(" damaged"))
- if not VALID_SECTOR(newc.i, newc.j):
+ if not newc.valid_sector():
# can't leave quadrant
skip(1)
break
dist = 0.0
if dist == 0.0:
return
- course = course(distance=dist, bearing=direc, warp=4)
- game.optime = course.time()
+ course = course(bearing=direc, distance=dist)
+ game.optime = course.time(warp=4)
skip(1)
prout(_("Force of nova displaces starship."))
imove(course, novapush=True)
- game.optime = course.time()
+ game.optime = course.time(warp=4)
return
def supernova(w):
y += deltay
w.i = int(round(x))
w.j = int(round(y))
- if not VALID_SECTOR(w.i, w.j):
+ if not w.valid_sector():
# Leaving quadrant -- allow final enemy attack
# Don't do it if being pushed by Nova
if len(game.enemies) != 0 and not novapush:
# because it involves giving x and y motions, yet the coordinates
# are always displayed y - x, where +y is downward!
+def cartesian(loc1=None, loc2=None):
+ if loc1 is None:
+ return game.quadrant * QUADSIZE + game.sector
+ elif loc2 is None:
+ return game.quadrant * QUADSIZE + loc1
+ else:
+ return loc1 * QUADSIZE + loc2
+
def getcourse(isprobe):
"Get a course and distance from the user."
key = 0
prout(_("(Manual movement assumed.)"))
navmode = "manual"
break
+ delta = coord()
if navmode == "automatic":
while key == "IHEOL":
if isprobe:
dsect.i = xi
dsect.j = xj
itemp = "normal"
- if not VALID_QUADRANT(dquad.i,dquad.j) or not VALID_SECTOR(dsect.i,dsect.j):
+ if not dquad.valid_quadrant() or not dsect.valid_sector():
huh()
raise TrekError
skip(1)
else:
prout(_("Ensign Chekov- \"Course laid in, Captain.\""))
# the actual deltas get computed here
- delta = coord()
delta.j = dquad.j-game.quadrant.j + (dsect.j-game.sector.j)/(QUADSIZE*1.0)
delta.i = game.quadrant.i-dquad.i + (game.sector.i-dsect.i)/(QUADSIZE*1.0)
else: # manual
skip(1)
prout(_("Helmsman Sulu- \"Aye, Sir.\""))
scanner.chew()
- return course(delta.distance(), delta.bearing(), isprobe=isprobe)
+ return course(bearing=delta.bearing(), distance=delta.distance())
class course:
- # Eventually, we want to consolidate all course compuation here,
- # including for torpedos and the Enterprise.
- def __init__(self, distance, bearing, warp=None, isprobe=False):
- # Course actually laid in -- thisis straight from the old getcd().
+ def __init__(self, bearing, distance, origin=None):
self.distance = distance
self.bearing = bearing
- self.warp = warp or game.warpfac
- self.isprobe = isprobe
- # This odd relic suggests that the bearing() code we inherited from
- # FORTRAN is actually computing clockface directions.
+ # The bearing() code we inherited from FORTRAN is actually computing
+ # clockface directions!
if self.bearing < 0.0:
self.bearing += 12.0
- # This code was moved from the probe() routine
- if isprobe:
- angle = ((15.0 - self.bearing) * 0.5235988)
- self.increment = coord(-math.sin(angle), math.cos(angle))
- bigger = max(abs(self.increment.i), abs(self.increment.j))
- self.increment /= bigger
- self.location = coord(game.quadrant.i*QUADSIZE + game.sector.i,
- game.quadrant.j*QUADSIZE + game.sector.j)
- self.loc = copy.copy(game.quadrant)
- self.moves = 10.0*self.distance*bigger +0.5
- def power(self):
- return self.distance*(self.warp**3)*(game.shldup+1)
- def time(self):
- return 10.0*self.distance/self.warp**2
- def next(self):
- "Next location on course, currently only at quadrant granularity."
- self.location += self.increment
- newloc = (self.location / float(QUADSIZE)).snaptogrid()
- if not newloc == self.loc:
- self.loc = newloc
+ self.angle = ((15.0 - self.bearing) * 0.5235988)
+ if origin is None:
+ self.location = cartesian(game.quadrant, game.sector)
+ else:
+ self.location = 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 = 10*self.distance*bigger +0.5
+ def next(self, grain=1):
+ "Next step on course."
+ self.moves -=1
+ self.nextlocation = self.location + self.increment
+ oldloc = (self.location/grain).roundtogrid()
+ newloc = (self.nextlocation/grain).roundtogrid()
+ self.location = self.nextlocation
+ if newloc != oldloc:
return True
else:
return False
+ def quadrant(self):
+ return (self.location / QUADSIZE).roundtogrid()
+ def sector(self):
+ return coord(int(round(self.location.i)) % QUADSIZE, int(round(self.location.j)) % QUADSIZE)
+ def power(self, warp):
+ return self.distance*(warp**3)*(game.shldup+1)
+ def time(self, warp):
+ return 10.0*self.distance/warp**2
def impulse():
"Move under impulse power."
# Make sure starship has enough energy for the trip
# Note: this formula is slightly different from the C version,
# and lets you skate a bit closer to the edge.
- if course.power() >= game.energy:
+ if course.power(game.warpfac) >= game.energy:
# Insufficient power for trip
game.ididit = False
skip(1)
prout(_("We haven't the energy to go that far with the shields up."))
return
# Make sure enough time is left for the trip
- game.optime = course.time()
+ game.optime = course.time(game.warpfac)
if game.optime >= 0.8*game.state.remtime:
skip(1)
prout(_("First Officer Spock- \"Captain, I compute that such"))
ix = x + 0.5
y += deltay
iy = y +0.5
- if not VALID_SECTOR(ix, iy):
+ if not coord(ix, iy).valid_sector():
break
if game.quad[ix][iy] != IHDOT:
blooey = False
imove(course, novapush=False)
if game.alldone:
return
- game.energy -= course.power()
+ game.energy -= course.power(game.warpfac)
if game.energy <= 0:
finish(FNRG)
- game.optime = course.time()
+ game.optime = course.time(game.warpfac)
if twarp:
timwrp()
if blooey:
distreq = randreal(math.sqrt(2))
if distreq < game.dist:
dist = distreq
- course = course(distance=dist, bearing=randreal(12)) # How dumb!
+ course = course(bearing=randreal(12), distance=dist) # How dumb!
game.optime = course.time()
game.justin = False
game.inorbit = False
game.sector.invalidate()
for m in range(1, 5+1):
w = game.base.scatter()
- if VALID_SECTOR(w.i,w.j) and game.quad[w.i][w.j]==IHDOT:
+ if w.valid_sector() and game.quad[w.i][w.j]==IHDOT:
# found one -- finish up
game.sector = w
break
game.quad[game.sector.i][game.sector.j] = IHDOT
for l in range(QUADSIZE):
game.sector = game.base.scatter()
- if VALID_SECTOR(game.sector.i, game.sector.j) and \
+ if game.sector.valid_sector() and \
game.quad[game.sector.i][game.sector.j] == IHDOT:
break
if l < QUADSIZE+1:
if not silent:
proutn(" ")
for y in range(game.quadrant.j-1, game.quadrant.j+2):
- if not VALID_QUADRANT(x, y):
+ if not coord(x, y).valid_quadrant():
if not silent:
proutn(" -1")
else:
"Damage report."
jdam = False
scanner.chew()
-
for i in range(NDEVICES):
if damaged(i):
if not jdam:
w2.j = 0
else:
w2.j=QUADSIZE-1
- if not VALID_QUADRANT(w1.i, w1.j) or not VALID_SECTOR(w2.i, w2.j):
+ if not w1.valid_quadrant() or not w2.valid_sector():
huh()
return
dist = math.sqrt((w1.j-game.quadrant.j+(w2.j-game.sector.j)/(QUADSIZE*1.0))**2+