#!/usr/bin/env python -tt from __future__ import absolute_import import sys, os verbose = (__name__ == '__main__') __version__ = '1.2' from th import g if os.path.exists('tunnelhack.sav'): if verbose: print '. Loading saved game...' import bz2 from th.Serialization import Unserializer fobj = bz2.BZ2File('tunnelhack.sav', 'r') u = Unserializer(fobj) try: u.load() except IOError: if verbose: print '! Your saved game file is corrupted!' sys.exit() finally: os.remove('tunnelhack.sav') del u, fobj from th.data import Items, Species, Nodes from th import Datafile, Map, Ifc, Monster, Hsn, Utl def do_traceback(): import traceback Ifc.msg('\n%sError!%s' % (Ifc.color(Ifc.BRIGHT_RED), Ifc.color())) sys.last_type, sys.last_value, sys.last_traceback = ( type, value, tb) = sys.exc_info() errorlog = open('errorlog', 'a') for s in traceback.format_exception(type, value, tb): Ifc.msg(s.rstrip()) errorlog.write(s) errorlog.close() Ifc.msg('---\n') except_hook = None def do_glide(): if g.glidetrigger: g.glide = None if g.glide: _dir = Utl.nsew(g.player.here, g.glide) Ifc.you('proceed %s.' % _dir) dir = Map._DIRS.index(_dir) if _dir in Map._DIRS else -1 g.glidetrigger = False g.player.here.mons.remove(g.player) g.player.here = g.glide g.glide.add(g.player) if len(g.glide.mons) > 1 or len(g.glide.items) > 0 or g.glide.countexits() != 2: g.glide = None else: if g.player.here.north and not g.player.here.north.special_symbol and dir != 2: g.glide = g.player.here.north elif g.player.here.south and not g.player.here.south.special_symbol and dir != 0: g.glide = g.player.here.south elif g.player.here.east and not g.player.here.east.special_symbol and dir != 3: g.glide = g.player.here.east elif g.player.here.west and not g.player.here.west.special_symbol and dir != 1: g.glide = g.player.here.west else: g.glide = None return True return False def main_loop(): loop = g.main_loop() while True: try: ap = loop.next() if g.lines > 1 and not g.unpk_only and g.show_pk: Ifc.pk() g.lines = 0 g.unpk_only = True if (not g.glide or g.glidetrigger) and not g.player.stunned: Map.show_map() if g.player.hp < g.player.mhp and g.turns % g.player.species.regeneration == 1: g.player.hp += 1 print '\n' print 'T:%s AP: %s/%s HP:%s%s/%s%s -- %s the %s (%s/%s)' % ( g.turns, ap, g.player.ap, Ifc.hpcolor(g.player), g.player.hp, g.player.mhp, Ifc.color(), g.player.name, g.player.species.name, g.player.level, g.player.xp ) print g.player.here.describe() if g.player.stunned > 0: Ifc.you("are helplessly %s and unable to move!" % g.player.stunner) Ifc.pk() g.player.stunned -= 1 else: while not player_turn(): pass if g.do_win: win() print "\t---" except StopIteration: break except except_hook: do_traceback() continue return True def player_turn(): if g.player.hp <= 0: return True g.player.here.visited = True if do_glide(): g.player.here.seen = True return True x = Ifc.getch("> ") if x == '\x03': print '^C (type q to exit)' return False elif x and ord(x) < 32: print '^%s' % chr(64 + ord(x)) else: print x #if not x: return False #x = x[0] if x == 'n': if g.player.here.north: Ifc.you("proceed north.") g.player.move(0) return True else: Ifc.you("look for a northern passage, but find none.") return False elif x == 's': if g.player.here.south: Ifc.you("proceed south.") g.player.move(2) return True else: Ifc.you("look for a southern passage, but find none.") return False elif x == 'e': if g.player.here.east: Ifc.you("proceed east.") g.player.move(1) return True else: Ifc.you("look for a eastern passage, but find none.") return False elif x == 'w': if g.player.here.west: Ifc.you("proceed west.") g.player.move(3) return True else: Ifc.you("look for a western passage, but find none.") return False elif x == 'l': Ifc.you('look around.') Ifc.msg(g.player.here.describe()) return False elif x == 'i': if not g.player.inventory: Ifc.you('are without material possessions.') return False Ifc.you('have these items:') Ifc.msg(Ifc.show(g.player.inventory)) return False elif x == 'g': if not g.player.here.items: Ifc.you('see no items here.') return False itm = Ifc.choice('Pick up what? ', g.player.here.items) if not itm: return False g.player.pick_up(itm) return True elif x == 'd': if not g.player.inventory: Ifc.you('are without material possessions.') return False itm = Ifc.choice('Drop what? ', g.player.inventory) if not itm: return False g.player.drop(itm) return False elif x == 'a': mons = [m for m in g.player.here.mons if m is not g.player] if not mons: Ifc.you('are alone.') return False who = Ifc.choice('Attack what creature? ', mons) if not who or who is g.player: return False if who.owner is g.player: Ifc.you("wouldn't dare hurt your %s!" % ('friend' if who.species.smart else 'pet')) return False if who.i_like(g.player) and who.target is not g.player: t = Ifc.the_mon(who) if Ifc.yn('Really? %s%s means you no harm. ' % (t[0].upper(), t[1:])): g.peacefuls += 1 else: return False g.player.target = who Ifc.you('attack the %s!' % who.species.name) if not g.player.do_attack(who): Ifc.you('miss %s!' % Ifc.format('|youm|', who)) if g.player.species.usable_special and not who.dead and g.player.species.useSpecial(g.player, who): g.player.species.doSpecial(g.player, who) if who.hp <= 0 and g.player.species.human and who.species.human and not who.rabid: if (g.player.wielded and g.player.wielded.kind.deadly_weapon) or not g.player.wielded: g.murders += 1 Ifc.you('worry that someone might find out about this...') return True elif x == 'u': if not g.player.inventory: Ifc.you('are without material possessions.') return False which = Ifc.choice('Use which object? ', g.player.inventory) if not which: return False return g.player.use(which) elif x == 'r': inv = [(e, x) for e, x in enumerate(g.player.inventory) if x.kind.damage] if not g.player.inventory: Ifc.you('are without material possessions.') return False if not inv: Ifc.you('have nothing worth wielding.') return False which = Ifc.prenumbered_choice('Wield which item as a weapon? ', inv) if not which: return False g.player.wield(which) return True elif x == 'p': inv = [(e, x) for e, x in enumerate(g.player.inventory) if (x.kind.armor and not x.worn)] if not inv: Ifc.you('have no armor to wear.') return False which = Ifc.prenumbered_choice('Wear which item as armor? ', inv) if not which: return False g.player.wear(which) return True elif x == 'R': inv = [(e, x) for e, x in enumerate(g.player.inventory) if x.worn] if not inv: Ifc.you("aren't wearing any armor.") return False which = Ifc.prenumbered_choice('Take off what armor? ', inv) if not which: return False g.player.unwear(which) return True elif x == 'c': inv = [(e, x) for e, x in enumerate(g.player.inventory) if x.kind.heal] if not g.player.inventory: Ifc.you('are without material possessions.') return False if not inv: Ifc.you('have nothing worth eating.') return False which = Ifc.prenumbered_choice('Eat which item? ', inv) if not which: return False if which.kind is g.player.species.corpse: Ifc.you(Utl.rn_seq(Monster.CANNIBAL)) g.cannibal += 1 return g.player.eat(which) elif x == 'I': who = Ifc.choice('Which creature? ', g.player.here.mons) if not who: return False if who is g.player: if Ifc.yn('Do you wish to rename yourself? '): g.player.name = Ifc.gstring('And what do you desire to be called? ') return False elif who.owner is not g.player: if Ifc.yn('Do you wish to rename %s? ' % Ifc.the_mon(who)): who.name = Ifc.gstring('And what sort of a name do you want for %s? ' % Ifc.the_mon(who)) return False the = Ifc.the_mon(who) choices = ['Name %s.', 'Give an item to %s.', 'Take an item from %s.', 'Feed %s.'] if who.name: choices[0] = 'Rename %s.' choices = [s % the for s in choices] choices.append('Examine %s inventory.' % Ifc.the_mon(who, possessive=1)) mode = Ifc.choice_str('Do what? ', choices, cancel=1) if mode == -1: return False elif mode == 0: who.name = Ifc.gstring('What is the new name for %s? ' % the) elif mode == 1: if not g.player.inventory: Ifc.you('have nothing to give.') return False elif len(who.inventory) >= who.str: Ifc.you('look|s| burdened enough already.', who) return False else: itm = Ifc.choice('Give which item? ', g.player.inventory) if not itm: return False if itm.wielded: itm.wielded = 0 g.player.wielded = None Ifc.you('|are| no longer wielding the %s.' % itm.kind.name) if itm.worn: if not self.unwear(itm): return False if not itm.kind.drop(itm, g.player, g.player.here): return False Ifc.you('hand %s to %s.' % (itm.kind.adesc, the)) g.player.inventory.remove(itm) who.add(itm) return True elif mode == 2: inv = [i for i in who.inventory if not i.wielded and not i.worn] if not inv: Ifc.you('ha|ve| nothing to give.', who) return False elif len(g.player.inventory) >= g.player.str: Ifc.you('|are| burdened enough already.') return False else: itm = Ifc.choice('Take which item? ', inv) if not itm: return False if not itm.kind.drop(itm, who, who.here): return False Ifc.you('take|s| %s from %s.' % (itm.kind.adesc, the)) who.inventory.remove(itm) g.player.add(itm) return True elif mode == 3: inv = [(e, x) for e, x in enumerate(g.player.inventory) if x.kind.heal] if not inv: Ifc.you('have nothing worth eating.') return False itm = Ifc.prenumbered_choice('Feed what to %s? ' % the, inv) if not itm: return False if who.species.smart and itm.kind is who.species.corpse: Ifc.you('reject|s| your offer.', who) return False if not itm.kind.drop(itm, who, who.here): return False Ifc.you('feed the %s to %s.' % (itm.kind.name, the)) return who.eat(itm) elif mode == 4: if not who.inventory: Ifc.you('ha|ve| no material possessions.', who) return False Ifc.you('ha|ve| these items:', who) Ifc.msg(Ifc.show(who.inventory)) return False elif x == 'N': if not g.player.inventory: Ifc.you('are without material possessions.') return False which = Ifc.choice('Name which object? ', g.player.inventory) if not which: return False which.name = Ifc.gstring('What name do you have for your %s? ' % which.kind.name) return False elif x == '.' or x == ' ' or x == '_': Ifc.you('stand around uselessly.') return True elif x == 'x' and g.config['debug']: import code gl = locals() gl.update(globals()) code.interact(local=gl) elif x == 'm': Map.showseen(g.grid) return False elif x == 'G': tmp = Ifc.gnsew('Glide in which direction?', g.player.here) if tmp: g.glide = tmp g.glidetrigger = False return do_glide() else: return False elif x == 'S' and g.config['allow_save']: if not Ifc.yn('Are you sure you want to save? '): return False Ifc.msg('This will only take a moment.') import bz2 from th.Serialization import Serializer st = bz2.BZ2File('tunnelhack.sav', 'w') s = Serializer(st) g.loaded = True s.dump(g) Ifc.msg('Be seeing you...') sys.exit() elif x == 'z' and g.config['debug']: execfile('deb') elif x == 'P': g.show_pk = not g.show_pk if g.show_pk: Ifc.msg('Now showing "press any key" messages.') else: Ifc.msg('Now hiding "press any key" messages.') return False elif x == 'q' and Ifc.yn('Are you sure you want to quit? '): Ifc.msg("Goodbye, %s!" % g.player.name) g.player.last_damage = 'fled from the tunnels like a coward' Hsn.writeout() sys.exit() elif x == '?': Ifc.msg("""Commands indicated by letters in parentheses. move (n)orth, move (s)outh, move (e)ast, move (w)est, (l)ook around. show (i)nventory, (g)et an item from the room, (d)rop an item of yours. (a)ttack a creature, (r)eady a weapon, (p)ut on armor, (R)emove armor. (c)onsume food, (u)se an item, (N)ame an item, view your (m)ap, (G)lide along a long corridor, (I)nteract with your pets. toggle (P)ress any key messages. (q)uit. """) return False else: return False def win(): g.player.xp += g.player.vanquished * 100 g.incscore(25000, 'You returned from the steam tunnels alive.') if g.player.xp < 0: g.player.xp = 0 Ifc.msg("""Congratulations, %s! You've completed TunnelHack! You have survived... Goodbye %s, the great level %d %s, possessor of the legendary %s!""" % ( g.player.name, g.player.name, g.player.level, g.player.species.name, g.artifact.kind.name )) g.player.last_damage = 'exited the tunnels victoriously' if g.murders > 0: if g.murders <= g.allow_murder: Ifc.msg('You murdered %d people, but you got away with it.' % g.murders) else: Ifc.msg('Upon leaving the tunnels, you were arrested and sentenced to %d years in prison for your %d murders.' % (Utl.d(1, 50) * (g.cannibal + g.murders), g.murders)) g.player.last_damage = 'emerged, only to be arrested for murder' Hsn.writeout() sys.exit() def main(): if not g.loaded: print '. Loading configuration file...' Datafile.load_config() print '. Generating map...' en = Map.genmap() print '. Generating regions...' Map.genregions() en.dijkstra = Map.Dijkstra(en) accessible = len(en.dijkstra[0]) if accessible != len(g.nodes): print 'Pathological map! (%s unreachable nodes)' % (len(g.nodes) - accessible) if not g.config['debug']: print "(This means the map is possibly unplayable. Sorry, try again! We're working on it.)" sys.exit() else: for x in g.nodes: if x not in en.dijkstra[0]: print x, print if g.config['pet_pathfinding'] == 2: print '. Calculating shortest paths between nodes... ', m = Map.PathMole(g.nodes[0]) m.tunnel() print print "Welcome to TunnelHack!" g.major = Ifc.choice_str('What is your major? ', ('Science', 'Liberal Arts', 'Physical Education')) g.player = Species.starters[g.major].make(pc=True, ai=Monster.WANDERING) pet = Species.pets[g.major].make(ai=Monster.PET, owner=g.player, rabid=False) g.player.gender = Ifc.choice_str('Which gender are you? ', ('Male', 'Female')) + 1 g.player.name = Ifc.gstring('What is your name? ') pet.name = Ifc.gstring('What is the name of your pet %s? ' % pet.species.name) en.add(g.player) en.add(pet) del pet g.player.fmt = { 's': '', 'es': '', 'do': 'do', 'you': 'you', 'youm': 'you', 'your': 'your', 'are': 'are', 've': 've' } g.artifact = Items.artifacts[g.major].make() g.allow_murder = Utl.rn(6) print "- Aaron Gallagher's python port (v%s) of:" % __version__ print " Bryce Schroeder's Steam Tunnel Hack, v1.3" print """ Long have strange tales been told of the things that lurk in the dark recesses of the steam tunnels, a maze of forgotten catacombs underneath this very institution. Some say they conceal fabulous riches. Others say that they offer only instant death to those who dare enter them. You, however, have not come for treasure, but for a more noble goal: You seek the legendary |artifact|, said to have been stolen by the evil technician Suzie. Even now, Suzie plots to overthrow the government and, by use of the mighty artifact's power, rule Earth from her lair in the steam tunnels. Hailed by the faculty and your fellow students as the last hope for humankind in the face of this impending disaster, you have been escorted to an abandoned entrance to the tunnels and pushed in, instructed not to return without the |artifact|! May the random number generator be with you, adventurer! """.replace('|artifact|', g.artifact.kind.name) Ifc.pk() g.phase += 1 else: print 'Welcome back!' if g.config['catch_exceptions']: global except_hook except_hook = Exception print 'Press ? for help.' Hsn.install_handlers() while main_loop(): if g.player.hp <= 0 or g.player.dead: Ifc.msg('\nYou were killed by %s.' % g.player.last_damage) Ifc.msg('The soul of %s drifts off into the ether.' % g.player.species.adesc) Hsn.writeout() break if __name__ == '__main__': main()