#!/usr/bin/env python import curses, traceback, textwrap, random, copy, math, time def landShape(diff): if diff<1: return ' ' elif 1<=diff<2: return '.' elif 2<=diff<4: return "'" elif 4<=diff<6: return "," elif 6<=diff<8 : return ':' elif 8<=diff<10: return ';' elif 10<=diff<12 : return '%' elif 12<=diff<14 : return '$' else : return '&' def breaklines(s,length): start=0 while len(s)-start>length: start=s.rfind(" ",start,start+length) s=s[:start+1]+'\n'+s[start+1:] return s def listsquare(grid,x,y,diam,pos=0): retlist=0.0 rad=(diam-1)/2 for i in range(-rad,rad): for j in range(-rad,rad): if 0<=x+i<=300 and 0<=y+j<=300: retlist+=grid[x+i][y+j][0] return retlist def listsquare2(grid,x,y,diam): retlist=[] rad=(diam-1)/2 for i in range(-rad,rad): for j in range(-rad,rad): if 0<=x+i<=300 and 0<=y+j<=300: if grid[x+i][y+j]: retlist+=grid[x+i][y+j][0] return retlist def col(diff): if diff<3: return 2 elif 3<=diff<7: return 3 elif 7<=diff<11: return 4 else: return 5 def landitems(x,y): i=random.randint(0,340) if i in (0,1,2,3,4): return ['f'] elif i in (5,6): return ['m'] else: return [] class world: def __init__(self,mainbox,infobox,actionbox): self.mainbox=mainbox self.infobox=infobox self.actionbox=actionbox self.land=[[ [(-abs(x-130)-abs(y-90)+140)/2.0+random.randint(-9,10),] for y in range(300)] for x in range(300)] self.things=[[ landitems(x,y) for y in range(300)] for x in range(300)] self.offset=[4,71] self.px=25 self.py=80 self.things[self.px][self.py]=['@',] self.maxinfo=5 self.infoline=1 self.infowidth=48 self.waterlevel=-1.5 self.score=10 self.stamina=100 self.movetimer=1 self.monsters=0 self.resting=False self.smoothLand() self.smoothLand() for i in range(300): for j in range(300): if self.things[i][j] and 0<=self.land[i][j][0]<8 and self.things[i][j][0]=='f' and not random.randint(0,2+int(self.land[i][j][0])): self.things[i][j][0]='F' self.redrawAll() self.refreshAll() def redraw(self,x,y): diff= self.land[x][y][0] if self.things[x][y]: if self.land[x][y][0]>self.waterlevel: self.mainbox.addstr(y-self.offset[1],x-self.offset[0],str(self.things[x][y][0])[0],\ curses.color_pair(col(diff))|curses.A_BOLD|curses.A_UNDERLINE) else: if self.things[x][y][0]=='@': if self.stamina>-200: self.gameOver("You drowned. Quite impressive, really.") else: self.things[x][y]=[] else: if self.land[x][y][0]>self.waterlevel: if self.land[x][y][0]-self.waterlevel>0.5: landcol=col(diff) else: landcol=1 self.mainbox.addstr(y-self.offset[1],x-self.offset[0],landShape(diff),curses.color_pair(landcol)) else: self.mainbox.addstr(y-self.offset[1],x-self.offset[0],'~',curses.color_pair(1)) def redrawAll(self): for i in range(1,49): for j in range(1,16): self.redraw(*self.relToAbs(i,j)) def playerMove(self,x,y): if 4self.waterlevel: if self.stamina>0: self.px+=x self.py+=y px,py=self.px,self.py if self.things[px][py]: if self.things[px][py][0]=='f': self.score+=1 self.printInfo("Yay! Food.") elif self.things[px][py][0]=='F': self.score+=10 self.printInfo("A bountiful feast!") if self.things[px][py][0]=='m': self.stamina-=15 self.monsters+=1 self.printInfo("Ow. That monster took some energy to kill.") if self.stamina<0: self.gameOver("Apparently it was too much of a fight. You died.") ox,oy=px-x,py-y self.things[ox][oy],self.things[px][py]=[],self.things[ox][oy] if 10-200: self.printInfo("What, and drown?") else: self.printInfo("What, and drown?...oh wait.") else: self.printInfo("You can't go that way") def printInfo(self,message): if self.infoline>=self.maxinfo: self.infoline=2 self.infobox.clear() self.infobox.box() self.infobox.addstr(1,1,message) else: self.infobox.addstr(self.infoline,1,message) self.infoline+=1 def refreshAll(self): self.actionbox.addstr(5,4,"Score: "+str(self.score)+" ") if self.stamina>15: statcol=0 else: statcol=7 self.actionbox.addstr(6,4,"Stamina: "+str(self.stamina)+" ",curses.color_pair(statcol)) self.actionbox.addstr(7,4,"Monsters Killed: "+str(self.monsters)+" ") self.mainbox.box() self.infobox.box() self.actionbox.box() self.mainbox.refresh() self.infobox.refresh() self.actionbox.refresh() def absToRel(self,x,y): return x-self.offset[0],y-self.offset[1] def relToAbs(self,x,y): return x+self.offset[0],y+self.offset[1] def smoothLand(self): newland=copy.deepcopy(self.land) for i in range(0,299): for j in range(0,299): newland[i][j][0]=listsquare(self.land,i,j,3)/9.0 self.land=newland def everyAction(self): self.raiseWater() self.stamina-=1 self.movetimer+=1 if self.movetimer>=2: self.moveMonsters() self.movetimer=0 def gameOver(self,message): self.printInfo(message) self.stamina=-1000 def raiseWater(self): self.waterlevel+=0.025 self.waterlevel=min(self.waterlevel,12) def rest(self): self.resting=True for i in range(6): self.stamina+=1 self.everyAction() self.stamina=min(125,self.stamina+70) self.resting=False def moveMonsters(self): for i in range(5,290): for j in range(5,290): if self.things[i][j] and self.things[i][j][0]=='m': if '@' in listsquare2(self.things,i,j,11): #the monster sees you! if '@' in listsquare2(self.things,i,j,5): self.things[i][j]=[] if self.resting: self.stamina-=30 self.monsters+=1 else: self.monsters+=1 self.stamina-=15 self.printInfo("Ow! That thing attacked you!") if self.stamina<0: self.gameOver("Jeeze. It killed you!") else: if cmp(self.px,i) and cmp(self.py,j): dir=random.choice(((cmp(self.px,i),0),(0,cmp(self.py,j)))) elif cmp(self.px,i): dir=(cmp(self.px,i),0) else: dir=(0,cmp(self.py,j)) if not self.things[i+dir[0]][j+dir[1]]: self.things[i+dir[0]][j+dir[1]],self.things[i][j]=['M'],[] else: #move randomly dir=((-1,0),(0,-1),(1,0),(0,1))[random.randint(0,3)] if not self.things[i+dir[0]][j+dir[1]]: self.things[i+dir[0]][j+dir[1]],self.things[i][j]=['M'],[] else: #try again dir=((-1,0),(0,-1),(1,0),(0,1))[random.randint(0,3)] if not self.things[i+dir[0]][j+dir[1]]: self.things[i+dir[0]][j+dir[1]],self.things[i][j]=['M'],[] for i in range(5,290): for j in range(5,290): if self.things[i][j] and self.things[i][j][0]=='M': self.things[i][j][0]='m' def main(stdscr): curses.init_pair(1, curses.COLOR_BLACK, curses.COLOR_BLUE) curses.init_pair(2, curses.COLOR_GREEN, curses.COLOR_BLACK) curses.init_pair(3, curses.COLOR_BLACK, curses.COLOR_GREEN) curses.init_pair(4, curses.COLOR_WHITE, curses.COLOR_GREEN) curses.init_pair(5, curses.COLOR_BLACK, curses.COLOR_WHITE) curses.init_pair(6, curses.COLOR_BLUE, curses.COLOR_BLACK) curses.init_pair(7, curses.COLOR_RED, curses.COLOR_BLACK) stdscr.addstr(0,0,"Once upon a time...") stdscr.addstr(1,0,"AHHH FLOOD. Run!") stdscr.addstr(2,0,"Wait, grab some food. You don't want to starve!") stdscr.addstr(3,0,"Press a button if you don't mind.") stdscr.addstr(6,0,"By the way, you lose a lot of stamina if attacked when resting.") stdscr.addstr(7,0,"But if get low on stamina you'll rest automatically.") mainbox = curses.newwin(17, 50, 0, 0) infobox = curses.newwin(6,79,17,0) actionbox = curses.newwin(17,29,0,50) actionbox.addstr(2,7,"HILL CLIMBER:",curses.color_pair(3)) actionbox.addstr(3,6,"EXTREME EDITION",curses.color_pair(7)) actionbox.addstr(9,6,"s: Start Over") actionbox.addstr(11,6,"q: Quit") actionbox.addstr(13,6,"r: Rest") actionbox.addstr(15,6,"f: Funny") bravenew= world(mainbox,infobox,actionbox) bravenew.redrawAll() bravenew.printInfo("Grab some food and don't drown!") bravenew.printInfo("Press q to quit") bravenew.refreshAll() while True: c = stdscr.getch() if c in (ord('q'),curses.KEY_EXIT,curses.KEY_CLOSE): break elif c== ord('f'): mes=random.choice(( "It's hard to drown. Try it. It won't let you. It's like a feature.", "Bringing the funny since 1988.", "What? Are you bored?", "You want different monsters? Too bad!", "See if you can find an 'M'. That's a glitch.", "This counts as a roguelike right?", "It was either this or add more features. Aren't you lucky.", "You can play this over SSH. Why aren't you excited?", "Seeding funny generator................................................", "Please insert second floppy disk to continue.", "Hill Climber: NOW IN COLOR!", "Hill Climber: What a ridiculous name!", "Hill Climber: Graphics Shmaphics.")) bravenew.printInfo(mes) elif c== ord('r'): bravenew.rest() if bravenew.waterlevel!=12: bravenew.score-=3 bravenew.printInfo("Resting. Eating") else: bravenew.printInfo("You finished the game. Stop trying to take a nap!") if bravenew.score<0: bravenew.gameOver("You died of starvation.") elif c== ord('s'): bravenew.printInfo("THIS MIGHT TAKE A WHILE") bravenew.refreshAll() bravenew=world(mainbox,infobox,actionbox) bravenew.printInfo("Hyper-Realistic world created.") elif c == curses.KEY_RIGHT: bravenew.playerMove(1,0) elif c == curses.KEY_LEFT: bravenew.playerMove(-1,0) elif c == curses.KEY_DOWN: bravenew.playerMove(0,1) elif c == curses.KEY_UP: bravenew.playerMove(0,-1) bravenew.redrawAll() bravenew.refreshAll() if __name__=='__main__': try: import psyco psyco.full() except ImportError: pass try: # Initialize curses stdscr=curses.initscr() curses.start_color() # Turn off echoing of keys, and enter cbreak mode, # where no buffering is performed on keyboard input curses.noecho() curses.cbreak() # In keypad mode, escape sequences for special keys # (like the cursor keys) will be interpreted and # a special value like curses.KEY_LEFT will be returned stdscr.keypad(1) try: curses.curs_set(0) except Exception: pass main(stdscr) # Enter the main loop # Set everything back to normal stdscr.keypad(0) curses.echo() curses.nocbreak() curses.endwin() # Terminate curses except: # In event of error, restore terminal to sane state. stdscr.keypad(0) curses.echo() curses.nocbreak() curses.endwin() traceback.print_exc() # Print the exception # vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4