class Mainmenu(): """Class that represents the main menu""" def __init__(self, window): """Constructor""" self.window = window pygame.font.init() self.buttonFont = pygame.font.Font("emulogic.ttf", 15) #Prepare fonts self.tutorialFont = pygame.font.Font("emulogic.ttf", 10) self.titleFont = pygame.font.Font("emulogic.ttf", 25) self.title = self.titleFont.render("Megaman Battles", False, (0, 0, 0)) self.playButton = Button( self.buttonFont.render("Play Game (2P)", False, (0, 0, 0)), self.window, 400, 150, 1) #Initialize player button self.tutorialButton = Button( self.buttonFont.render("Read Tutorial", False, (0, 0, 0)), self.window, 400, 300, 2) #Initialize tutorial button self.buttons = [self.playButton, self.tutorialButton] #List to hold buttons self.buttonIndex = 0 #Index to see which button is chosen. self.cursor = Cursor(self.buttons[self.buttonIndex].x + 256, self.buttons[self.buttonIndex].y, self.window) #Initialize cursor self.running = True def draw(self): """Draw main menu""" self.window.blit(bg, (0, 0)) #Draw background first self.window.blit(self.title, (350, 50)) #Draw title self.playButton.draw() #Draw buttons self.tutorialButton.draw() self.cursor.draw() #Draw cursor pygame.display.update() #Update display def run(self): """Run the main menu""" while self.running: pygame.time.delay(125) #Delay to not take multiple inputs at once self.cursor.move( self.buttons[self.buttonIndex].y) #Move the cursor for event in pygame.event.get(): #Loop to check for user exit. if event.type == pygame.QUIT: return 3 keys = pygame.key.get_pressed() #Get keys if keys[pygame.K_DOWN]: #If they pressed down if self.buttonIndex + 1 == len( self.buttons): #If the index exceeds the list length self.buttonIndex = 0 #Move the cursor to the first button else: self.buttonIndex += 1 #Move the cursor down. if keys[pygame.K_UP]: #If up is pressed if self.buttonIndex - 1 == -1: #If the index is less than 0 self.buttonIndex = len( self.buttons) - 1 #Move the cursor to the last button else: self.buttonIndex -= 1 #Move the cursor up if keys[pygame.K_RETURN]: #If Enter is pressed return self.buttons[self.buttonIndex].getDecision( ) #Return decision stored in selected button self.draw() #Draw def tutorial(self): run = True texts = [ self.tutorialFont.render("There are two players in this game.", False, (0, 0, 0)), self.tutorialFont.render( "Player one is on the left and player two is on the right.", False, (0, 0, 0)), self.tutorialFont.render( "Player one uses WASD to move and space to shoot.", False, (0, 0, 0)), self.tutorialFont.render( "Player two uses IJKL and Backslash (the button above enter) to shoot.", False, (0, 0, 0)), self.tutorialFont.render( "Both players cannot cross the middle of the arena.", False, (0, 0, 0)), self.tutorialFont.render("Good luck and Have Fun! Press", False, (0, 0, 0)), self.tutorialFont.render("Enter to go back to the main menu.", False, (0, 0, 0)) ] #Tutorial text split into lines self.window.blit(bg, (0, 0)) #Blit background once. i = 0 for text in texts: #Blit each line of text self.window.blit(text, (200, i)) i += 30 pygame.display.update() #Update display while run: #Main loop pygame.time.delay(100) #Delay for event in pygame.event.get(): #Loop to check for user exit. if event.type == pygame.QUIT: run = False keys = pygame.key.get_pressed() if keys[pygame.K_RETURN]: #If enter is pressed, exit run = False
class Engine(object): __world_objects = WeakKeyDictionary() def __init__(self): self.__message_queue = [] self.__cur_stat_surf = None self.__actors = [] self.__items = [] self.__gfx = None self.__quit_loop = False self.__last_id = 0 self.__id_gen = self.__gen_id() self.__actors_on_screen = [] self.__timer = 0 self.__world_time = 0 self.__load_fonts() self.__build_surf_cache() self.__set_game_instance() self.__player_actions = PlayerActions(self) self.__state_worker = StateWorker(self) self.__actor_grid = [] self.__item_grid = [] for y in xrange(200): aline = [] iline = [] for x in xrange(200): aline.append([]) iline.append([]) self.__actor_grid.append(aline) self.__item_grid.append(iline) self.map = None self.dungeon = dungeon.DungeonsOfGogadan() self.quit_mes = QUIT self.stats = [att.Att('Strength', 'Important for Melee-Fighter', 20), att.Att('Endurance', 'Important for Melee-Fighter'), att.Att('Mind', 'Important for Spellcaster'), att.Att('Health', 'How much can you take?', 45)] self.camera = Camera(20, 26) self.state = S_RUN self.__await_target = None Debug.init_debug(self) Debug.debug('init pygame') pygame.init() self.screen = pygame.display.set_mode((1024, 768)) self.__clock = pygame.time.Clock() self.item_to_throw = None self.cursor = Cursor(self) self._items_to_choose = {} self._symbols = [] c = 'abcdefghijklmonpqrstuvwxyz' for s in c: self._symbols.append(s) def call_pl_item_throw(self): self.__player_actions.throw_fire() def re_init(self): Debug.debug('re_init') self.__quit_loop = False self.quit_mes = QUIT self.__load_fonts() self.__build_surf_cache() self.__set_game_instance() self.__clock = pygame.time.Clock() self.__id_gen = self.__gen_id() for act in self.__actors: self.__world_objects[act] = True for item in self.__items: self.__world_objects[item] = True self.__world_objects[self.map] = True self.__clear_surfaces() if hasattr(self, 'map'): self.redraw_map() def get_symbol(self): s = self._symbols.pop(0) return s def free_symbol(self, s): if s == None: return self._symbols.append(s) self._symbols.sort() def get_actor_at(self, pos): x, y = pos act = self.__actor_grid[y][x] return act[0] if len(act) > 0 else None #for actor in self.__actors: # if actor.pos() == pos: # return actor #return None def get_all_srd_actors(self, pos, radius=1, null_pos=False): mo = [] for x in xrange(-radius, radius + 1): for y in xrange(-radius, radius + 1): mo.append((x, y)) if not null_pos: mo.remove((0, 0)) poss = [] for m in mo: poss.append((m[0] + pos[0], m[1] + pos[1])) actors = [] for p in poss: acts = self.get_actor_at(p) if not acts == None: actors.append(acts) return actors #for act in self.__actors: # if act.pos() in poss: # actors.append(act) #return actors def get_free_adj(self, pos): new_pos = None mo = [(-1, -1), (-1, 0), (-1, 1), (1, -1), (1, 0), (1, 1), (0, -1), (0, 1)] random.shuffle(mo) while new_pos == None and len(mo) > 0: t = mo.pop() new_pos = pos[0] + t[0], pos[1] + t[1] if not self.map.map_array[new_pos[1]][new_pos[0]][MT_FLAGS] & F_WALKABLE: new_pos = None else: for actor in self.__actors: if actor.pos() == new_pos: new_pos = None break return new_pos def get_sc_up_pos(self): y = 0 x = 0 pos = None for line in self.map.map_array: x = 0 for t in line: if t == MAP_TILE_up: pos = x, y x += 1 y += 1 return pos if pos != None else self.map.get_random_pos() def get_sc_down_pos(self): y = 0 x = 0 pos = None for line in self.map.map_array: x = 0 for t in line: if t == MAP_TILE_down: pos = x, y x += 1 y += 1 return pos if pos != None else self.map.get_random_pos() def get_actor_by_id(self, id): for act in self.__actors: if act.id == id: return act def shout(self, text): self.__message_queue.insert(0, text) print text def change_map(self, down=True): if self.map == None: level = 1 elif down: level = self.map.level + 1 self.__save_map() else: level = self.map.level - 1 self.__save_map() if self.__load_map(level): return if level == 0: self.game_over() self.__actors = [] self.__actors.append(self.player) self.__items = [] self.map = self.dungeon.get_map(level) for act in self.__actors: act.sc = sc(self.map.map_array) if down: pos = self.get_sc_up_pos() else: pos = self.get_sc_down_pos() self.player.set_pos(pos) r = self.camera.adjust(self.player.pos()) while r: r = self.camera.adjust(self.player.pos()) def create_gold(self, amount, pos): gold = dungeon.Populator.create_item('Gold', 'basic_stuff', 0) gold.amount = amount gold.set_pos(pos) self.add_item(gold) def summon_monster(self, caster, name, file, pos): mon = dungeon.Populator.create_creature(name, file) mon.ai = henchmanAI.HenchmanAI(mon) mon.ai.friends.add(caster.id) caster.ai.friends.add(mon.id) mon.set_pos(pos) mon.sc = sc(self.map.map_array) self.add_actor(mon, True) def create_humanoid(self): #man = races[1][3](True, 1) man = races[2][3](True, 1) #man.classkit = classkits[2][1](man) man.classkit = classkits[0][1](man) from ai import simpleai man.ai = henchmanAI.HenchmanAI(man) man.name = 'Nigg Yshur' pos = self.get_free_adj(self.player.pos()) man.set_pos(pos) man.ai.friends.add(self.player.id) self.player.ai.friends.add(man.id) man.sc = sc(self.map.map_array) #self.player = races[race][3](True, gender) #self.player.classkit = classkits[classkit][1](self.player) #self.player.classkit = classkits[classkit][1](self.player) #b = dungeon.Populator.create_item('TomeOfVileUmbrages','tovu',100) #self.player.pick_up(b) def create_character(self): c_res = Res('dc-pl.png', TILESIZE) g = 'female', 'male' gender = 1 race = 0 classkit = 0 OK = False name = '' title = 'He' title2 = 'His' story = ['This is the incredible story of our hero', 'Long time ago, there was a hero named', 'There once was a time, long ago, when'] s = random.choice(story) while not OK: self.screen.fill(BLACK) self.__render_text(self.screen, 'Build your character:', WHITE, ((35, 30)), 'big') self.screen.blit(self.__surf_cache['mes_block2'], (60, 65)) img = pygame.transform.smoothscale(c_res.get(races[race][1 + gender]), (TILESIZE * 2, TILESIZE * 2)) self.screen.blit(img , (75, 100)) self.__render_text(self.screen, name, WHITE, ((73, 170))) y = 100 self.__render_text(self.screen, s, WHITE, ((145, y))) self.__render_text(self.screen, name, GREEN, ((395, y))) y += 20 self.__render_text(self.screen, 'the' , WHITE, ((145, y))) self.__render_text(self.screen, g[gender] + ' ' + races[race][0] + ' ' + classkits[classkit][0] + '.', GREEN, ((167, y))) y += 20 self.__render_text(self.screen, title + ' ' + races[race][3].desc, WHITE, ((145, y))) y += 20 self.__render_text(self.screen, classkits[classkit][1].desc.replace('$$$', title.lower()).replace('%%%', title2.lower()), WHITE, ((145, y))) self.__render_text(self.screen, 'Type in your name', WHITE, ((600, 100))) self.__render_text(self.screen, 'press F1 / F2 to change race', WHITE, ((600, 120))) self.__render_text(self.screen, 'press F3 / F4 to change class', WHITE, ((600, 140))) self.__render_text(self.screen, 'press F5 to change gender', WHITE, ((600, 160))) self.__render_text(self.screen, 'press Enter to start', WHITE, ((600, 180))) pygame.display.flip() for e in pygame.event.get(): if e.type == pygame.QUIT: sys.exit() if e.type == pygame.KEYDOWN: if e.key == pygame.K_F5: if gender == 1: gender -= 1 title = 'She' title2 = 'Her' else: gender += 1 title = 'He' title2 = 'His' if e.key == pygame.K_F3: classkit += 1 if classkit >= len(classkits): classkit = 0 elif e.key == pygame.K_F4: classkit -= 1 if classkit < 0: classkit = len(classkits) - 1 elif e.key == pygame.K_F1: race += 1 if race >= len(races): race = 0 elif e.key == pygame.K_F2: race -= 1 if race < 0: race = len(races) - 1 elif e.key == pygame.K_RETURN: self.player = races[race][3](True, gender) self.player.classkit = classkits[classkit][1](self.player) b = dungeon.Populator.create_item('TomeOfVileUmbrages', 'tovu', 100) self.player.pick_up(b) self.player.clear_surfaces() self.player.timer = 0 OK = True elif e.key == pygame.K_BACKSPACE: if len(name) > 0: name = name[:-1] else: kn = pygame.key.name(e.key) if kn in 'abcdefghijklmnopqrstuvwxyz' and len(name) < 10: if len(name) > 0: name += pygame.key.name(e.key) else: name += pygame.key.name(e.key).upper() def start(self, ts): if ts: self.create_character() self.change_map() self.create_humanoid() Debug.debug('starting mainloop') return self._main_loop() def is_inside_map(self, pos): return not (pos[0] < 0 or pos[1] < 0 or pos[0] >= self.map.width or pos[1] >= self.map.height) def update_item_pos(self, item, new_pos): x, y = item.pos() nx, ny = new_pos if item in self.__item_grid[y][x]: self.__item_grid[y][x].remove(item) self.__item_grid[ny][nx].append(item) def update_actor_pos(self, act, new_pos): x, y = act.pos() nx, ny = new_pos if act in self.__actor_grid[y][x]: self.__actor_grid[y][x].remove(act) self.__actor_grid[ny][nx].append(act) def is_move_valid(self, actor, new_pos): if not self.is_inside_map(new_pos): return False nx, ny = new_pos act = self.__actor_grid[ny][nx] if len(act) > 0: return act[0] valid = self.map.can_enter(new_pos, actor.move_mode) if valid and actor == self.player: self.map.cur_surf = None items = self.get_items_at(new_pos) if len(items) == 1: self.shout('You see a %s' % (items[0].get_name())) if len(items) > 1: self.shout('You see several items here') return valid def get_range_target(self, cpos, tpos): return self.get_actor_at(tpos) # if cpos != tpos: # poss = line(cpos[0], cpos[1], tpos[0], tpos[1]) # poss.pop(0) # for pos in poss: # actor = self.get_actor_at(pos) # if actor != None: # return actor # else: # return self.caster # return None def throw_item(self, attacker, item, target_pos): t_pos = target_pos s_pos = attacker.pos() victim = self.get_range_target(attacker.pos(), target_pos) if victim != None: t_pos = victim.pos() dir = attacker.locateDirection(t_pos) gfx = throw.ThrowFX(dir, s_pos, t_pos, item) self.drawGFX(gfx) item.set_pos(t_pos) def range_attack(self, attacker, target_pos): t_pos = target_pos s_pos = attacker.pos() victim = self.get_range_target(attacker.pos(), target_pos) if victim != None: t_pos = victim.pos() dir = attacker.locateDirection(t_pos) gfx = projectile.ProjectileFX(dir, s_pos, t_pos) self.drawGFX(gfx) #while self.__gfx != None: # self._world_draw() if victim != None: self.attack(attacker, victim, True) def __c_end_friendship(self, attacker, victim): victim.ai.friends.discard(attacker.id) victim.ai.hostile.add(attacker.id) attacker.ai.friends.discard(victim.id) attacker.ai.hostile.add(victim.id) todel = [] for id in victim.ai.friends: act = self.get_actor_by_id(id) if act == None: todel.append(id) else: act.ai.friends.discard(attacker.id) act.ai.hostile.add(attacker.id) for id in todel: victim.ai.friends.discard(id) todel = [] for id in attacker.ai.friends: act = self.get_actor_by_id(id) if act == None: todel.append(id) else: act.ai.friends.discard(victim.id) act.ai.hostile.add(victim.id) for id in todel: attacker.ai.friends.discard(id) def __c_apply_effects(self, attacker, victim): for fx in attacker.get_av_fx(): if d(100) <= fx[1]: Debug.debug('Applied effect %s to %s by %s' % (fx[0], victim, attacker)) f = fx[0](victim, attacker) f.tick() for fx in victim.get_dv_fx(): skip = False for nt in fx[0].notrigger: if attacker.slot.weapon.flags & nt: skip = True if not skip and d(100) <= fx[1]: Debug.debug('Applied effect %s to %s by %s' % (fx[0], attacker, victim)) f = fx[0](attacker, victim) f.tick() def attack(self, attacker, victim, ranged=False): self.__c_end_friendship(attacker, victim) vi_adress = (victim == self.player and ['you'] or ['the ' + victim.name])[0] at_miss_adress = (attacker == self.player and ['You miss'] or [attacker.name + ' misses'])[0] at_hit_adress = (attacker == self.player and ['You hit'] or ['The ' + attacker.name + ' hits'])[0] at_kill_adress = (attacker == self.player and ['You killed'] or ['The ' + attacker.name + ' killed'])[0] wpn = attacker.weapon if wpn == None: wpn = attacker.unarmed_weapon highest_skill = None, 0 for s in wpn.skills: v = getattr(attacker.skills, s) if v > highest_skill[1]: highest_skill = s, v attack_roll = d(100) if attack_roll > highest_skill: self.shout('%s %s.' % (at_miss_adress, vi_adress)) Debug.debug('Miss!') return if victim.get_RA() > 0 and not victim.unconscious: victim.RA -= 1 dodge_skill = victim.skills.Dodge dodge_roll = d(100) if dodge_roll <= dodge_skill: self.shout('%s dodged the attack' % (vi_adress)) return self.__c_apply_effects(attacker, victim) hit_zone = victim.HP.get_random_zone() z = getattr(victim.HP, hit_zone)[2] if wpn.type != I_VOID: damage = wpn.damage[1]() + attacker.get_DM()[0]() else: damage = d(3) + attacker.get_DM()[0]() dam=self.do_damage(victim, damage, hit_zone, source=attacker) self.shout('%s %s at the %s for %i damage' % (at_hit_adress, vi_adress, z,dam)) def do_damage(self, act, dam, zone, type=D_GENERIC, source=None): return act.do_damage(dam, zone, type) def wait_for_target(self, point_of_entry): self.__await_target = point_of_entry self.__player_actions.cursor() def do_identify(self): self.__player_actions.identify() def target_choosen(self, pos): self.__await_target(pos) self.__await_target = None #self.player.fire(pos) def get_items_at(self, pos): x, y = pos #print self.__item_grid[y][x] return [item for item in self.__item_grid[y][x] if not item.picked_up] #return [item for item in self.__items if item.pos() == pos] def game_over(self): print 'You failed' self.__quit_loop = True self.__actors = [] def redraw_map(self): self.map.cur_surf = None def redraw_stats(self): self.__cur_stat_surf = None def add_to_world_objects(self, obj): self.__world_objects[obj] = True def add_actor(self, actor, add=True): if add: self.__actors.append(actor) if self.map != None: actor.sc = sc(self.map.map_array) self.__world_objects[actor] = True def add_item(self, item, add=True): if add: self.__items.append(item) self.__world_objects[item] = True def del_actor(self, actor): if actor in self.__actors: self.__actors.remove(actor) if actor in self.__actors_on_screen: self.__actors_on_screen.remove(actor) x, y = actor.pos() if actor in self.__actor_grid[y][x]: self.__actor_grid[y][x].remove(actor) def del_item(self, item): if item in self.__items: self.__items.remove(item) x, y = item.pos() if item in self.__item_grid[y][x]: self.__item_grid[y][x].remove(item) #if item.player_symbol != None: # self.free_symbol(item.player_symbol) def get_id(self): return self.__id_gen.next() def drawGFX(self, gfx): self.__gfx = gfx self.state = S_GFX # good or bad?? while self.__gfx != None: self._world_draw() def _main_loop(self): while not self.__quit_loop: self.__clock.tick(40) self._world_move() self._world_draw() self._world_input() # print self.clock.get_fps() self.std_font = None self.__clock = None self.__cur_stat_surf = None self.__last_id = self.__id_gen.next() self.__id_gen = None self.__clear_surfaces() return self.quit_mes def _world_input(self): for e in pygame.event.get(): self.__quit_loop = e.type == pygame.QUIT if e.type == pygame.KEYDOWN: if e.key == GAME_SAVE_QUIT: self.__quit_loop = True self.quit_mes = SAVE # --- cheat keys >>> if e.key == pygame.K_F1: for line in self.map.map_array: l = '' for s in line: l = l + str(s[0]) print l if e.key == pygame.K_F2: self.player.cur_health = 200 self.player.cur_endurance = 5000 self.player.cur_mind = 5000 self.player.cur_strength = 5000 if e.key == pygame.K_F3: for item in self.__items: print item.name, item.pos() if e.key == pygame.K_F4: for act in self.__actors: print act.name, act.timer if e.key == pygame.K_F5: for S in gc.get_referrers(Surface): if isinstance(S, Surface): print S print gc.get_referrers(Surface) if e.key == pygame.K_F6: self.create_humanoid() # <<< cheat keys --- if not self.state == S_GFX: self.__cur_stat_surf = None self.moved = True if self.state == S_RUN and not self.player.unconscious: if e.key in PLAYER_ACTIONS: self.__player_actions.__getattribute__(PLAYER_ACTIONS[e.key])() elif self.state in STATE_WORKER: self.__state_worker.__getattribute__(STATE_WORKER[self.state])(e.key) if self.state == S_PLAYER_CURSOR: pygame.event.pump() keys = pygame.key.get_pressed() for key in MOVES: if keys[key]: pygame.time.wait(150) if key == MOVE_WAIT: pos = self.__actors_on_screen[0].pos() if pos == self.cursor.pos(): self.__actors_on_screen.append(self.__actors_on_screen.pop(0)) pos = self.__actors_on_screen[0].pos() self.cursor.set_pos(pos) self.__actors_on_screen.append(self.__actors_on_screen.pop(0)) else: self.cursor.move(key) if self.state == S_RUN and not self.player.unconscious: pygame.event.pump() keys = pygame.key.get_pressed() [self.player.move(key) for key in MOVES if keys[key] and self.player.timer <= 0] def _world_move(self): if not self.__quit_loop: if self.state == S_RUN: self.__actors.sort(sort_by_time) #actors with lowest timer first diff = self.__actors[0].timer self.__timer += diff self.__world_time += diff if self.__timer > 500: #act-independent issues # one combat-round [act.tick() for act in self.__actors] self.__timer -= 500 for actor in self.__actors: if actor.timer > 0: actor.timer -= diff else: actor.act() elif self.state == S_GFX: if self.__gfx == None: self.state = S_RUN def _world_draw(self): if self.__gfx == None or self.__gfx.redraw: if self.camera.adjust(self.player.pos()): self.map.cur_surf = None self.screen.fill((0, 0, 0)) if not self.player.dazzled: self.screen.blit(self.__get_map_surface(), (-self.camera.x * TILESIZE, -self.camera.y * TILESIZE)) if not self.player.dazzled: for item in self.__items: if not item.picked_up and (self.player.sc.lit(item.x, item.y) or self.player.x == item.x and self.player.y == item.y): try: self.screen.blit(self.__get_item_surface(item), (item.x * TILESIZE - self.camera.x * TILESIZE, item.y * TILESIZE - self.camera.y * TILESIZE)) except: print sys.exc_info() print item.name, item.pos(), 'is invalid!!!!' for act in self.__actors: if act == self.player or self.player.sc.lit(act.x, act.y) and not self.player.dazzled: try: self.screen.blit(self.__get_actor_surface(act), (act.x * TILESIZE - self.camera.x * TILESIZE, act.y * TILESIZE - self.camera.y * TILESIZE)) if not act in self.__actors_on_screen: self.__actors_on_screen.append(act) except: print sys.exc_info() print act.name, act.pos(), 'is invalid!!!!' else: if act in self.__actors_on_screen: self.__actors_on_screen.remove(act) if self.state == S_PLAYER_CURSOR: self.screen.blit(self.cursor.get_surf(), (self.cursor.x * TILESIZE - self.camera.x * TILESIZE, self.cursor.y * TILESIZE - self.camera.y * TILESIZE)) self.screen.blit(self.__get_message_surface(), (0, 768 - 128)) self.screen.blit(self.__get_statblock_surface(), (1024 - 192, 0)) if self.__gfx != None: pos = self.__gfx.pos() if pos == None: self.__gfx = None self.__cur_stat_surf = None else: x, y = pos #tiles = __get_affected_tiles(x,y,self.__gfx.get_surf()) x = x / TILESIZE + self.camera.x y = y / TILESIZE + self.camera.y #print x,y,self.player.pos(),self.player.sc.lit(x, y) if self.player.sc.lit(x, y): self.screen.blit(self.__gfx.get_surf(), pos) self.__gfx.tick() pygame.display.flip() def __get_map_surface(self): if self.map.cur_surf == None: self.player.sc.do_fov(self.player.x, self.player.y, 15) surf_map = pygame.Surface((self.map.width * TILESIZE, self.map.height * TILESIZE)) cx, cy, cw, ch = self.camera.get_view_port() for x in xrange(max(cx, 0), min(self.map.width, cw + 1)): for y in xrange(max(cy, 0), min(self.map.height, ch + 1)): pos = (x, y) == self.player.pos() lit = self.player.sc.lit(x, y) memo = self.map.map_array[y][x][MT_FLAGS] & F_MEMO if pos or lit or memo: blit_position = ((x) * TILESIZE, (y) * TILESIZE) surf_map.blit(self.map.get_tile_at(x, y), blit_position) if not pos and not lit and memo: surf_map.blit(self.__surf_cache['FOW'], blit_position) if not self.map.map_array[y][x][MT_FLAGS] & F_MEMO: tile = self.map.map_array[y][x] new_tile = tile[0], tile[1], tile[2] ^ F_MEMO self.map.map_array[y][x] = new_tile self.map.cur_surf = surf_map return self.map.cur_surf def __get_actor_surface(self, act): if act.cur_surf == None: surf_act = pygame.Surface((TILESIZE, TILESIZE), pygame.SRCALPHA, 32) surf_act.blit(act.get_tile(), (0, 0)) act.cur_surf = surf_act return act.cur_surf def __get_item_surface(self, item): if item.cur_surf == None: surf_item = pygame.Surface((TILESIZE, TILESIZE), pygame.SRCALPHA, 32) surf_item.blit(item.get_dd_img(), (0, 0)) item.cur_surf = surf_item return item.cur_surf def __get_message_surface(self): surf = pygame.Surface((1024 - 192, 128)) surf.blit(self.__surf_cache['mes_block'], (0, 0)) y = 100 for mes in self.__message_queue: self.__render_text(surf, mes, WHITE, (20, y)) y -= 20 if y < 10: break return surf def __get_statblock_surface(self): if self.__cur_stat_surf == None: surf = pygame.Surface((192, 768)) surf.fill(BLACK) #surf.blit(self.__surf_cache['stat_block'], (0, 0)) if self.state in (S_RUN, S_GFX): self.__draw_stat_block(surf) if self.state in CHOOSE_STATES: self.__draw_item_choose(surf, CHOOSE_STATES[self.state]) self.__cur_stat_surf = surf return self.__cur_stat_surf def __set_game_instance(self): dungeon.Map.game = self Actor.game = self Item.game = self AI.game = self Camera.game = self dungeon.Populator.game = self magic.Spell.game = self GFX.game = self att.Att.game = self dungeon.SADungeon.game = self def __draw_item_choose(self, surf, message): self.__render_text(surf, message, WHITE, (16, 20)) y = 38 abc = self._items_to_choose.keys() #abc.sort(sort_by_type) s48 = pygame.Surface.copy(self.__surf_cache['stat_32']) for key in abc: item = self._items_to_choose[key] color = WHITE if hasattr(item, 'special'): if item.special: color = GREEN if hasattr(item, 'color'): color = item.color if hasattr(item, 'get_name'): name = item.get_name() else: name = item.name surf.blit(s48, (16, y)) if hasattr(item, 'cur_surf'): surf.blit(self.__get_item_surface(item), (16, y)) self.__render_text(surf, '%s' % (key), WHITE, (16, y)) #self.__render_text(surf, '%s -' % (key), WHITE, (16, y)) self.__render_text(surf, name, color, (64, y)); y += 18 info = item.info() for line in info: self.__render_text(surf, line, color, (64, y)); y += 18 if len(info) == 0: y += 18 y += 18 def __draw_stat_block(self, surf): bt = self.player.get_body_tile() bt = pygame.transform.smoothscale(bt, (96, 96)) bt.set_alpha(122) y = 50 surf.blit(bt, (32, y)) x = 77 y = 55 color = WHITE if self.player.HP.Head[0] == self.player.HP.Head[1]: color = GREEN if self.player.HP.Head[0] == 0: color = YELLOW if self.player.HP.Head[0] < 0: color = RED self.__render_text(surf, str(self.player.HP.Head[0]), color, (x, y)) y = 75 color = WHITE if self.player.HP.Chest[0] == self.player.HP.Chest[1]: color = GREEN if self.player.HP.Chest[0] == 0: color = YELLOW if self.player.HP.Chest[0] < 0: color = RED self.__render_text(surf, str(self.player.HP.Chest[0]), color, (x, y)) y = 95 color = WHITE if self.player.HP.Abdomen[0] == self.player.HP.Abdomen[1]: color = GREEN if self.player.HP.Abdomen[0] == 0: color = YELLOW if self.player.HP.Abdomen[0] < 0: color = RED self.__render_text(surf, str(self.player.HP.Abdomen[0]), color, (x, y)) x = 40 y = 85 color = WHITE if self.player.HP.L_Arm[0] == self.player.HP.L_Arm[1]: color = GREEN if self.player.HP.L_Arm[0] == 0: color = YELLOW if self.player.HP.L_Arm[0] < 0: color = RED self.__render_text(surf, str(self.player.HP.L_Arm[0]), color, (x, y)) x = 110 color = WHITE if self.player.HP.R_Arm[0] == self.player.HP.R_Arm[1]: color = GREEN if self.player.HP.R_Arm[0] == 0: color = YELLOW if self.player.HP.R_Arm[0] < 0: color = RED self.__render_text(surf, str(self.player.HP.R_Arm[0]), color, (x, y)) x = 55 y = 130 color = WHITE if self.player.HP.L_Leg[0] == self.player.HP.L_Leg[1]: color = GREEN if self.player.HP.L_Leg[0] == 0: color = YELLOW if self.player.HP.L_Leg[0] < 0: color = RED self.__render_text(surf, str(self.player.HP.L_Leg[0]), color, (x, y)) x = 95 color = WHITE if self.player.HP.R_Leg[0] == self.player.HP.R_Leg[1]: color = GREEN if self.player.HP.R_Leg[0] == 0: color = YELLOW if self.player.HP.R_Leg[0] < 0: color = RED self.__render_text(surf, str(self.player.HP.R_Leg[0]), color, (x, y)) stats = [('STR ', self.player.STR, self.player.get_STR()), ('CON ', self.player.CON, self.player.get_CON()), ('DEX ', self.player.DEX, self.player.get_DEX()), ('SIZ ', self.player.SIZ, self.player.get_SIZ()), ('INT ', self.player.INT, self.player.get_INT()), ('POW ', self.player.POW, self.player.get_POW()), ('CHA ', self.player.CHA, self.player.get_CHA()), ('DM ', self.player.DM[1], self.player.get_DM()[1])] y = 245 for line in stats: b = 0 if len(str(line[1])) > 3: b = 18 self.__render_text(surf, str(line[0]).rjust(2, ' '), WHITE, (16, y)); self.__render_text(surf, str(line[1]).rjust(2, ' '), GREEN, (55, y)); self.__render_text(surf, '/', WHITE, (70 + b, y)); self.__render_text(surf, str(line[2]).rjust(2, ' '), WHITE, (80 + b, y)); y += 18 #pygame.draw.circle(Surface, color, pos, radius, width=0): return Rect #r = pygame.Surface((100, 2)) #r.fill(RED) #surf.blit(r, (16, y + 20)) #size = float(line[2]) / float(line[1]) * 100 #if size > 0: # g = pygame.Surface((size, 2)) # if size > 100: # g.fill(BLUE) # else: # g.fill(GREEN) #surf.blit(g, (16, y + 20)) self.__render_text(surf, 'Gold:', WHITE, (16, 510)) self.__render_text(surf, str(self.player.gold), WHITE, (90, 510)) self.__render_text(surf, 'XP:', WHITE, (16, 528)) self.__render_text(surf, str(self.player.xp), WHITE, (90, 528)) i = 0 y = 600 count = len(self.player.items) s32 = pygame.Surface.copy(self.__surf_cache['stat_32']) sgreen = pygame.Surface.copy(self.__surf_cache['sgreen']) for h in xrange(3): for x in xrange(5): pos = (x * TILESIZE + x * 3 + 5, h * TILESIZE + y + h * 3) surf.blit(s32, pos) if i < count: item = self.player.items[i] if item.equipped: surf.blit(sgreen, pos) surf.blit(self.__get_item_surface(item), pos) self.__render_text(surf, self.player.items[i].get_ps(), WHITE, (pos)) i += 1 #print (x*TILESIZE,h*TILESIZE+y) self.__render_text(surf, self.dungeon.name, WHITE, (16, 710)) self.__render_text(surf, 'Level: %i' % (self.map.level), WHITE, (16, 728)) def __render_text(self, surf, text, color, pos, font='std'): t = self.__font_cache[font].render('%s' % (text), True, color) ts = self.__font_cache[font].render('%s' % (text), True, BLACK) surf.blit(ts, (pos[0] + 1, pos[1] + 1)) surf.blit(t, pos) def __load_fonts(self): #self.std_font = pygame.font.Font(os.path.join('font', 'jesaya.ttf'), 14) self.__font_cache = {'std':pygame.font.Font(os.path.join('font', 'alex.ttf'), 17), 'big':pygame.font.Font(os.path.join('font', 'alex.ttf'), 25)} def __save_map(self): self.__clear_surfaces() self.__actors.remove(self.player) data = self.map, self.__actors, self.__items , self.player.pos() if os.access('MAP%i.gz' % (self.map.level), os.F_OK): os.remove('MAP%i.gz' % (self.map.level)) FILE = gzip.open('MAP%i.gz' % (self.map.level), 'w') pickle.dump(data, FILE, 2) FILE.close() def __load_map(self, level): if os.access('MAP%i.gz' % (level), os.F_OK): FILE = gzip.open('MAP%i.gz' % (level), 'r') self.map, self.__actors, self.__items, pos = pickle.load(FILE) self.__set_game_instance() FILE.close() self.player.set_pos(pos) r = self.camera.adjust(self.player.pos()) while r: r = self.camera.adjust(self.player.pos()) self.__actors.append(self.player) for act in self.__actors: self.__world_objects[act] = True act.sc = sc(self.map.map_array) self.player.sc.do_fov(self.player.x, self.player.y, self.player.cur_mind / 20 + 5) for item in self.__items: self.__world_objects[item] = True self.__world_objects[self.map] = True self.__clear_surfaces() self._world_draw() return True return False self.__quit_loop = True self.quit_mes = SAVE def __build_surf_cache(self): fow_surf = pygame.Surface((TILESIZE, TILESIZE)) fow_surf.fill(BLACK) fow_surf.set_alpha(100) sgreen = pygame.Surface((TILESIZE, TILESIZE)) sgreen.fill(GREEN) sgreen.set_alpha(100) self.__surf_cache = {'sgreen':sgreen, 'FOW': fow_surf, 'stat_block': load_image('stat.png'), 'stat_48': load_image('48.png'), 'stat_32': pygame.transform.smoothscale(load_image('48.png'), (32, 32)), 'mes_block':load_image('mes_block.png'), 'mes_block2':load_image('mes_block2.png')} def __clear_surfaces(self): for obj in self.__world_objects.keys(): obj.clear_surfaces() self.cursor.cursor_surf = None def __gen_id(self): for x in xrange(self.__last_id, 9999999): yield x
class Board(): """ Entity that stores position and can render it to screen or to TeX string. """ def __init__(self, board=None, solutions=None): self._board = board or {} self._solution_idx = None self._solutions = solutions or [] self._cursor = Cursor() # Cursor {{{1 def move_cursor(self, where): """Move cursor left, right, up or down.""" self._cursor.move(where) def get_cursor(self): """Return cursor coordinates.""" return self._cursor.point # }}}1 # TeX support {{{1 def _get_psgo_prelude(self, solution_index=None): point = (self._get_dim(0, False, solution_index) + 1, self._get_dim(1, False, solution_index) + 1) return xp.psgo_prelude(point) def _objects_to_tex(self, objects, solution_index=None): result = [self._get_psgo_prelude(solution_index=solution_index)] for point, stone in objects.items(): result.append(xp.stone_to_tex(stone, point)) result.append(xp.psgo_postlude()) return '\n'.join(result) def to_tex(self, main_only=True): """Convert the board position to TeX code. If main_only is True, only the main position is used. Otherwise, the current solution branch is used.""" if main_only: objects = self._board else: objects = self.get_items() return self._objects_to_tex(objects) def solutions_to_tex(self): """Convert solutions to the list of TeX code strings.""" results = [] for idx in range(len(self._solutions)): objects = self.get_items(solution_index=idx) results.append(self._objects_to_tex(objects, idx)) return results # }}}1 # Geometry {{{1 def _get_dim(self, axis, use_cursor, idx): maxkey = itemgetter(axis) if self._board: res = max(self._board.keys(), key=maxkey)[axis] else: res = 0 if idx is not None: sol = self._solutions[idx] if sol: res = max(res, max(sol.keys(), key=maxkey)[axis]) if use_cursor: res = max(res, self._cursor.point[axis]) res = max(_MIN_CORNER_SIZE, res + _MIN_BORDER) return min(res, 19) def get_width(self, use_cursor=True): """Return the width of used part of the board.""" return self._get_dim(0, use_cursor, self._solution_idx) def get_height(self, use_cursor=True): """Return the height of used part of the board.""" return self._get_dim(1, use_cursor, self._solution_idx) # }}}1 # Manipulate stones in main position {{{1 def put(self, colour): """Put stone at cursor.""" self._board[self._cursor.point] = Stone(colour) def remove(self): """Remove stone at cursor.""" point = self._cursor.point if point in self._board: del self._board[point] def toggle(self, colour): """Put or remove stone at cursor.""" point = self._cursor.point if point in self._board: del self._board[point] else: self._board[point] = Stone(colour) def update_colour(self, colour): """Update colour of the stone under the cursor, if there is one.""" point = self._cursor.point if point in self._board: self._board[point].colour = colour # }}}1 # Manipulate stones in solution branch {{{1 def put_sol(self, colour, number): """Add a stone to solution.""" assert self._solution_idx is not None point = self._cursor.point self._solutions[self._solution_idx][point] = \ Stone(colour, label=number) def remove_sol(self): """Remove a stone from solution.""" assert self._solution_idx is not None point = self._cursor.point if point in self._solutions[self._solution_idx]: del self._solutions[self._solution_idx][point] def update_colour_sol(self, colour): """Update colour of the solution stone under the cursor, if there is one.""" assert self._solution_idx is not None sol = self._solutions[self._solution_idx] point = self._cursor.point if point in sol: sol[point].colour = colour def flip_sol(self): """Flip colour of the solution stone under the cursor, if there is one: white <-> black.""" assert self._solution_idx is not None sol = self._solutions[self._solution_idx] point = self._cursor.point if point in sol: sol[point].flip() # }}}1 # Solution branches management {{{1 def get_solution(self): """Return current solution branch.""" return self._solution_idx def add_solution(self): """Add solution branch and switch to it.""" self._solutions.append({}) self._solution_idx = len(self._solutions) - 1 def delete_solution(self): """Remove solution branch.""" del self._solutions[self._solution_idx] if self._solutions: self._solution_idx %= len(self._solutions) else: self._solution_idx = None def _shift_solution(self, delta): branches = len(self._solutions) if not branches: # no branches - nothing to do return if self._solution_idx is None: # if we are in a main line, move to one of the branches self._solution_idx = 0 if delta == 1 else branches - 1 return # we are not in a main line self._solution_idx += delta if self._solution_idx == branches: # To main line after the last self._solution_idx = None elif self._solution_idx == -1: # To main line before the first self._solution_idx = None else: self._solution_idx %= len(self._solutions) def next_solution(self): """Switch to the next solution.""" self._shift_solution(1) def prev_solution(self): """Switch to the previous solution.""" self._shift_solution(-1) # }}}1 # {{{1 Access to board items def get_items(self, solution_index=None): """Return board items.""" res = self._board.copy() if solution_index is not None: idx = solution_index else: idx = self._solution_idx if idx is not None: # Order matters, numbers should overwrite stones! res.update(deepcopy(self._solutions[idx])) return res
class PuyoGame(Widget): def __init__(self, **kwargs): super(PuyoGame, self).__init__(**kwargs) self.keyboard = Window.request_keyboard(self.keyboard_closed, self, 'text') self.keyboard.bind(on_key_down=self.on_key_down) self.board = Board() self.board.parse_cells(""" 000000 300000 444110 312440 331221 112441 """) self.deck = Deck() self.cursor = Cursor() self.erasing = False def update(self): self.render_board() self.render_cursor() self.render_hand() def render_board(self): for x in range(self.board.horizontal_cells): for y in range(self.board.vertical_cells): cell = self.board.cell(x, y) self.render_puyo_in_grid(pos=(x, y), cell=cell) def render_puyo(self, pos, cell): with self.canvas: if cell == 1: Color(1, 0, 0, 1, mode='rgba') elif cell == 2: Color(0, 1, 0, 1, mode='rgba') elif cell == 3: Color(0, 0, 1, 1, mode='rgba') elif cell == 4: Color(1, 1, 0, 1, mode='rgba') else: Color(0, 0, 0, 1, mode='rgba') Ellipse(pos=pos, size=(60, 40)) def clear_hand(self): with self.canvas: Color(0, 0, 0, 1, mode='rgba') Rectangle(pos=(0, self.board.vertical_cells * 50), size=(self.board.horizontal_cells * 60, 3 * 50)) def render_cursor(self): hand = self.deck.hand() axis = self.cursor.axis() self.clear_hand() self.render_puyo_in_grid(pos=(axis[0][0], axis[0][1] + self.board.vertical_cells), cell=hand[0]) self.render_puyo_in_grid(pos=(axis[1][0], axis[1][1] + self.board.vertical_cells), cell=hand[1]) def render_puyo_in_grid(self, pos, cell): self.render_puyo(pos=(pos[0] * 60, pos[1] * 50), cell=cell) def render_hand(self): hand = self.deck.hand() self.render_puyo_in_grid(pos=(self.board.horizontal_cells + 2, self.board.vertical_cells - 2), cell=hand[2]) self.render_puyo_in_grid(pos=(self.board.horizontal_cells + 2, self.board.vertical_cells - 1), cell=hand[3]) self.render_puyo_in_grid(pos=(self.board.horizontal_cells + 3, self.board.vertical_cells - 2), cell=hand[4]) self.render_puyo_in_grid(pos=(self.board.horizontal_cells + 3, self.board.vertical_cells - 1), cell=hand[5]) def keyboard_closed(self): print('My keyboard have been closed!') self.keyboard.unbind(on_key_down=self.on_key_down) self.keyboard = None def on_key_down(self, keyboard, keycode, text, modifiers): print('The key', keycode, 'have been pressed') print(' - text is %r' % text) print(' - modifiers are %r' % modifiers) # Keycode is composed of an integer + a string # If we hit escape, release the keyboard if keycode[1] == 'escape': keyboard.release() elif not self.erasing and keycode[1] == 'down': self.draw_hand() self.gravitize() self.render_board() self.render_cursor() elif keycode[1] == 'left': self.cursor.move(Direction.Left) self.render_cursor() elif keycode[1] == 'right': self.cursor.move(Direction.Right) self.render_cursor() elif keycode[1] == 'z': self.cursor.turn(Direction.Left) self.render_cursor() elif keycode[1] == 'x': self.cursor.turn(Direction.Right) self.render_cursor() # Return True to accept the key. Otherwise, it will be used by # the system. return True def draw_hand(self): hand = self.deck.draw() axis = self.cursor.axis() self.cursor.reset_position() self.board.set_cell(axis[0][0], axis[0][1] + self.board.vertical_cells - 3, hand[0]) self.board.set_cell(axis[1][0], axis[1][1] + self.board.vertical_cells - 3, hand[1]) self.render_hand() def gravitize(self, dt=0.0): if self.board.gravitize(): self.update() self.erasing = True Clock.schedule_once(self.erase, 0.5) else: self.erasing = False def erase(self, dt=0.0): if self.board.erase(): self.update() Clock.schedule_once(self.gravitize, 0.5) else: self.erasing = False
class Engine(object): __world_objects = WeakKeyDictionary() def __init__(self): self.__message_queue = [] self.__cur_stat_surf = None self.__actors = [] self.__items = [] self.__gfx = None self.__quit_loop = False self.__last_id = 0 self.__id_gen = self.__gen_id() self.__actors_on_screen = [] self.__timer = 0 self.__world_time = 0 self.__load_fonts() self.__build_surf_cache() self.__set_game_instance() self.__player_actions = PlayerActions(self) self.__state_worker = StateWorker(self) self.__actor_grid = [] self.__item_grid = [] for y in xrange(200): aline = [] iline = [] for x in xrange(200): aline.append([]) iline.append([]) self.__actor_grid.append(aline) self.__item_grid.append(iline) self.map = None self.dungeon = dungeon.DungeonsOfGogadan() self.quit_mes = QUIT self.stats = [ att.Att('Strength', 'Important for Melee-Fighter', 20), att.Att('Endurance', 'Important for Melee-Fighter'), att.Att('Mind', 'Important for Spellcaster'), att.Att('Health', 'How much can you take?', 45) ] self.camera = Camera(20, 26) self.state = S_RUN self.__await_target = None Debug.init_debug(self) Debug.debug('init pygame') pygame.init() self.screen = pygame.display.set_mode((1024, 768)) self.__clock = pygame.time.Clock() self.item_to_throw = None self.cursor = Cursor(self) self._items_to_choose = {} self._symbols = [] c = 'abcdefghijklmonpqrstuvwxyz' for s in c: self._symbols.append(s) def call_pl_item_throw(self): self.__player_actions.throw_fire() def re_init(self): Debug.debug('re_init') self.__quit_loop = False self.quit_mes = QUIT self.__load_fonts() self.__build_surf_cache() self.__set_game_instance() self.__clock = pygame.time.Clock() self.__id_gen = self.__gen_id() for act in self.__actors: self.__world_objects[act] = True for item in self.__items: self.__world_objects[item] = True self.__world_objects[self.map] = True self.__clear_surfaces() if hasattr(self, 'map'): self.redraw_map() def get_symbol(self): s = self._symbols.pop(0) return s def free_symbol(self, s): if s == None: return self._symbols.append(s) self._symbols.sort() def get_actor_at(self, pos): x, y = pos act = self.__actor_grid[y][x] return act[0] if len(act) > 0 else None #for actor in self.__actors: # if actor.pos() == pos: # return actor #return None def get_all_srd_actors(self, pos, radius=1, null_pos=False): mo = [] for x in xrange(-radius, radius + 1): for y in xrange(-radius, radius + 1): mo.append((x, y)) if not null_pos: mo.remove((0, 0)) poss = [] for m in mo: poss.append((m[0] + pos[0], m[1] + pos[1])) actors = [] for p in poss: acts = self.get_actor_at(p) if not acts == None: actors.append(acts) return actors #for act in self.__actors: # if act.pos() in poss: # actors.append(act) #return actors def get_free_adj(self, pos): new_pos = None mo = [(-1, -1), (-1, 0), (-1, 1), (1, -1), (1, 0), (1, 1), (0, -1), (0, 1)] random.shuffle(mo) while new_pos == None and len(mo) > 0: t = mo.pop() new_pos = pos[0] + t[0], pos[1] + t[1] if not self.map.map_array[new_pos[1]][ new_pos[0]][MT_FLAGS] & F_WALKABLE: new_pos = None else: for actor in self.__actors: if actor.pos() == new_pos: new_pos = None break return new_pos def get_sc_up_pos(self): y = 0 x = 0 pos = None for line in self.map.map_array: x = 0 for t in line: if t == MAP_TILE_up: pos = x, y x += 1 y += 1 return pos if pos != None else self.map.get_random_pos() def get_sc_down_pos(self): y = 0 x = 0 pos = None for line in self.map.map_array: x = 0 for t in line: if t == MAP_TILE_down: pos = x, y x += 1 y += 1 return pos if pos != None else self.map.get_random_pos() def get_actor_by_id(self, id): for act in self.__actors: if act.id == id: return act def shout(self, text): self.__message_queue.insert(0, text) print text def change_map(self, down=True): if self.map == None: level = 1 elif down: level = self.map.level + 1 self.__save_map() else: level = self.map.level - 1 self.__save_map() if self.__load_map(level): return if level == 0: self.game_over() self.__actors = [] self.__actors.append(self.player) self.__items = [] self.map = self.dungeon.get_map(level) for act in self.__actors: act.sc = sc(self.map.map_array) if down: pos = self.get_sc_up_pos() else: pos = self.get_sc_down_pos() self.player.set_pos(pos) r = self.camera.adjust(self.player.pos()) while r: r = self.camera.adjust(self.player.pos()) def create_gold(self, amount, pos): gold = dungeon.Populator.create_item('Gold', 'basic_stuff', 0) gold.amount = amount gold.set_pos(pos) self.add_item(gold) def summon_monster(self, caster, name, file, pos): mon = dungeon.Populator.create_creature(name, file) mon.ai = henchmanAI.HenchmanAI(mon) mon.ai.friends.add(caster.id) caster.ai.friends.add(mon.id) mon.set_pos(pos) mon.sc = sc(self.map.map_array) self.add_actor(mon, True) def create_humanoid(self): #man = races[1][3](True, 1) man = races[2][3](True, 1) #man.classkit = classkits[2][1](man) man.classkit = classkits[0][1](man) from ai import simpleai man.ai = henchmanAI.HenchmanAI(man) man.name = 'Nigg Yshur' pos = self.get_free_adj(self.player.pos()) man.set_pos(pos) man.ai.friends.add(self.player.id) self.player.ai.friends.add(man.id) man.sc = sc(self.map.map_array) #self.player = races[race][3](True, gender) #self.player.classkit = classkits[classkit][1](self.player) #self.player.classkit = classkits[classkit][1](self.player) #b = dungeon.Populator.create_item('TomeOfVileUmbrages','tovu',100) #self.player.pick_up(b) def create_character(self): c_res = Res('dc-pl.png', TILESIZE) g = 'female', 'male' gender = 1 race = 0 classkit = 0 OK = False name = '' title = 'He' title2 = 'His' story = [ 'This is the incredible story of our hero', 'Long time ago, there was a hero named', 'There once was a time, long ago, when' ] s = random.choice(story) while not OK: self.screen.fill(BLACK) self.__render_text(self.screen, 'Build your character:', WHITE, ((35, 30)), 'big') self.screen.blit(self.__surf_cache['mes_block2'], (60, 65)) img = pygame.transform.smoothscale( c_res.get(races[race][1 + gender]), (TILESIZE * 2, TILESIZE * 2)) self.screen.blit(img, (75, 100)) self.__render_text(self.screen, name, WHITE, ((73, 170))) y = 100 self.__render_text(self.screen, s, WHITE, ((145, y))) self.__render_text(self.screen, name, GREEN, ((395, y))) y += 20 self.__render_text(self.screen, 'the', WHITE, ((145, y))) self.__render_text( self.screen, g[gender] + ' ' + races[race][0] + ' ' + classkits[classkit][0] + '.', GREEN, ((167, y))) y += 20 self.__render_text(self.screen, title + ' ' + races[race][3].desc, WHITE, ((145, y))) y += 20 self.__render_text( self.screen, classkits[classkit][1].desc.replace( '$$$', title.lower()).replace('%%%', title2.lower()), WHITE, ((145, y))) self.__render_text(self.screen, 'Type in your name', WHITE, ((600, 100))) self.__render_text(self.screen, 'press F1 / F2 to change race', WHITE, ((600, 120))) self.__render_text(self.screen, 'press F3 / F4 to change class', WHITE, ((600, 140))) self.__render_text(self.screen, 'press F5 to change gender', WHITE, ((600, 160))) self.__render_text(self.screen, 'press Enter to start', WHITE, ((600, 180))) pygame.display.flip() for e in pygame.event.get(): if e.type == pygame.QUIT: sys.exit() if e.type == pygame.KEYDOWN: if e.key == pygame.K_F5: if gender == 1: gender -= 1 title = 'She' title2 = 'Her' else: gender += 1 title = 'He' title2 = 'His' if e.key == pygame.K_F3: classkit += 1 if classkit >= len(classkits): classkit = 0 elif e.key == pygame.K_F4: classkit -= 1 if classkit < 0: classkit = len(classkits) - 1 elif e.key == pygame.K_F1: race += 1 if race >= len(races): race = 0 elif e.key == pygame.K_F2: race -= 1 if race < 0: race = len(races) - 1 elif e.key == pygame.K_RETURN: self.player = races[race][3](True, gender) self.player.classkit = classkits[classkit][1]( self.player) b = dungeon.Populator.create_item( 'TomeOfVileUmbrages', 'tovu', 100) self.player.pick_up(b) self.player.clear_surfaces() self.player.timer = 0 OK = True elif e.key == pygame.K_BACKSPACE: if len(name) > 0: name = name[:-1] else: kn = pygame.key.name(e.key) if kn in 'abcdefghijklmnopqrstuvwxyz' and len( name) < 10: if len(name) > 0: name += pygame.key.name(e.key) else: name += pygame.key.name(e.key).upper() def start(self, ts): if ts: self.create_character() self.change_map() self.create_humanoid() Debug.debug('starting mainloop') return self._main_loop() def is_inside_map(self, pos): return not (pos[0] < 0 or pos[1] < 0 or pos[0] >= self.map.width or pos[1] >= self.map.height) def update_item_pos(self, item, new_pos): x, y = item.pos() nx, ny = new_pos if item in self.__item_grid[y][x]: self.__item_grid[y][x].remove(item) self.__item_grid[ny][nx].append(item) def update_actor_pos(self, act, new_pos): x, y = act.pos() nx, ny = new_pos if act in self.__actor_grid[y][x]: self.__actor_grid[y][x].remove(act) self.__actor_grid[ny][nx].append(act) def is_move_valid(self, actor, new_pos): if not self.is_inside_map(new_pos): return False nx, ny = new_pos act = self.__actor_grid[ny][nx] if len(act) > 0: return act[0] valid = self.map.can_enter(new_pos, actor.move_mode) if valid and actor == self.player: self.map.cur_surf = None items = self.get_items_at(new_pos) if len(items) == 1: self.shout('You see a %s' % (items[0].get_name())) if len(items) > 1: self.shout('You see several items here') return valid def get_range_target(self, cpos, tpos): return self.get_actor_at(tpos) # if cpos != tpos: # poss = line(cpos[0], cpos[1], tpos[0], tpos[1]) # poss.pop(0) # for pos in poss: # actor = self.get_actor_at(pos) # if actor != None: # return actor # else: # return self.caster # return None def throw_item(self, attacker, item, target_pos): t_pos = target_pos s_pos = attacker.pos() victim = self.get_range_target(attacker.pos(), target_pos) if victim != None: t_pos = victim.pos() dir = attacker.locateDirection(t_pos) gfx = throw.ThrowFX(dir, s_pos, t_pos, item) self.drawGFX(gfx) item.set_pos(t_pos) def range_attack(self, attacker, target_pos): t_pos = target_pos s_pos = attacker.pos() victim = self.get_range_target(attacker.pos(), target_pos) if victim != None: t_pos = victim.pos() dir = attacker.locateDirection(t_pos) gfx = projectile.ProjectileFX(dir, s_pos, t_pos) self.drawGFX(gfx) #while self.__gfx != None: # self._world_draw() if victim != None: self.attack(attacker, victim, True) def __c_end_friendship(self, attacker, victim): victim.ai.friends.discard(attacker.id) victim.ai.hostile.add(attacker.id) attacker.ai.friends.discard(victim.id) attacker.ai.hostile.add(victim.id) todel = [] for id in victim.ai.friends: act = self.get_actor_by_id(id) if act == None: todel.append(id) else: act.ai.friends.discard(attacker.id) act.ai.hostile.add(attacker.id) for id in todel: victim.ai.friends.discard(id) todel = [] for id in attacker.ai.friends: act = self.get_actor_by_id(id) if act == None: todel.append(id) else: act.ai.friends.discard(victim.id) act.ai.hostile.add(victim.id) for id in todel: attacker.ai.friends.discard(id) def __c_apply_effects(self, attacker, victim): for fx in attacker.get_av_fx(): if d(100) <= fx[1]: Debug.debug('Applied effect %s to %s by %s' % (fx[0], victim, attacker)) f = fx[0](victim, attacker) f.tick() for fx in victim.get_dv_fx(): skip = False for nt in fx[0].notrigger: if attacker.slot.weapon.flags & nt: skip = True if not skip and d(100) <= fx[1]: Debug.debug('Applied effect %s to %s by %s' % (fx[0], attacker, victim)) f = fx[0](attacker, victim) f.tick() def attack(self, attacker, victim, ranged=False): self.__c_end_friendship(attacker, victim) vi_adress = (victim == self.player and ['you'] or ['the ' + victim.name])[0] at_miss_adress = (attacker == self.player and ['You miss'] or [attacker.name + ' misses'])[0] at_hit_adress = (attacker == self.player and ['You hit'] or ['The ' + attacker.name + ' hits'])[0] at_kill_adress = (attacker == self.player and ['You killed'] or ['The ' + attacker.name + ' killed'])[0] wpn = attacker.weapon if wpn == None: wpn = attacker.unarmed_weapon highest_skill = None, 0 for s in wpn.skills: v = getattr(attacker.skills, s) if v > highest_skill[1]: highest_skill = s, v attack_roll = d(100) if attack_roll > highest_skill: self.shout('%s %s.' % (at_miss_adress, vi_adress)) Debug.debug('Miss!') return if victim.get_RA() > 0 and not victim.unconscious: victim.RA -= 1 dodge_skill = victim.skills.Dodge dodge_roll = d(100) if dodge_roll <= dodge_skill: self.shout('%s dodged the attack' % (vi_adress)) return self.__c_apply_effects(attacker, victim) hit_zone = victim.HP.get_random_zone() z = getattr(victim.HP, hit_zone)[2] if wpn.type != I_VOID: damage = wpn.damage[1]() + attacker.get_DM()[0]() else: damage = d(3) + attacker.get_DM()[0]() dam = self.do_damage(victim, damage, hit_zone, source=attacker) self.shout('%s %s at the %s for %i damage' % (at_hit_adress, vi_adress, z, dam)) def do_damage(self, act, dam, zone, type=D_GENERIC, source=None): return act.do_damage(dam, zone, type) def wait_for_target(self, point_of_entry): self.__await_target = point_of_entry self.__player_actions.cursor() def do_identify(self): self.__player_actions.identify() def target_choosen(self, pos): self.__await_target(pos) self.__await_target = None #self.player.fire(pos) def get_items_at(self, pos): x, y = pos #print self.__item_grid[y][x] return [item for item in self.__item_grid[y][x] if not item.picked_up] #return [item for item in self.__items if item.pos() == pos] def game_over(self): print 'You failed' self.__quit_loop = True self.__actors = [] def redraw_map(self): self.map.cur_surf = None def redraw_stats(self): self.__cur_stat_surf = None def add_to_world_objects(self, obj): self.__world_objects[obj] = True def add_actor(self, actor, add=True): if add: self.__actors.append(actor) if self.map != None: actor.sc = sc(self.map.map_array) self.__world_objects[actor] = True def add_item(self, item, add=True): if add: self.__items.append(item) self.__world_objects[item] = True def del_actor(self, actor): if actor in self.__actors: self.__actors.remove(actor) if actor in self.__actors_on_screen: self.__actors_on_screen.remove(actor) x, y = actor.pos() if actor in self.__actor_grid[y][x]: self.__actor_grid[y][x].remove(actor) def del_item(self, item): if item in self.__items: self.__items.remove(item) x, y = item.pos() if item in self.__item_grid[y][x]: self.__item_grid[y][x].remove(item) #if item.player_symbol != None: # self.free_symbol(item.player_symbol) def get_id(self): return self.__id_gen.next() def drawGFX(self, gfx): self.__gfx = gfx self.state = S_GFX # good or bad?? while self.__gfx != None: self._world_draw() def _main_loop(self): while not self.__quit_loop: self.__clock.tick(40) self._world_move() self._world_draw() self._world_input() # print self.clock.get_fps() self.std_font = None self.__clock = None self.__cur_stat_surf = None self.__last_id = self.__id_gen.next() self.__id_gen = None self.__clear_surfaces() return self.quit_mes def _world_input(self): for e in pygame.event.get(): self.__quit_loop = e.type == pygame.QUIT if e.type == pygame.KEYDOWN: if e.key == GAME_SAVE_QUIT: self.__quit_loop = True self.quit_mes = SAVE # --- cheat keys >>> if e.key == pygame.K_F1: for line in self.map.map_array: l = '' for s in line: l = l + str(s[0]) print l if e.key == pygame.K_F2: self.player.cur_health = 200 self.player.cur_endurance = 5000 self.player.cur_mind = 5000 self.player.cur_strength = 5000 if e.key == pygame.K_F3: for item in self.__items: print item.name, item.pos() if e.key == pygame.K_F4: for act in self.__actors: print act.name, act.timer if e.key == pygame.K_F5: for S in gc.get_referrers(Surface): if isinstance(S, Surface): print S print gc.get_referrers(Surface) if e.key == pygame.K_F6: self.create_humanoid() # <<< cheat keys --- if not self.state == S_GFX: self.__cur_stat_surf = None self.moved = True if self.state == S_RUN and not self.player.unconscious: if e.key in PLAYER_ACTIONS: self.__player_actions.__getattribute__( PLAYER_ACTIONS[e.key])() elif self.state in STATE_WORKER: self.__state_worker.__getattribute__( STATE_WORKER[self.state])(e.key) if self.state == S_PLAYER_CURSOR: pygame.event.pump() keys = pygame.key.get_pressed() for key in MOVES: if keys[key]: pygame.time.wait(150) if key == MOVE_WAIT: pos = self.__actors_on_screen[0].pos() if pos == self.cursor.pos(): self.__actors_on_screen.append( self.__actors_on_screen.pop(0)) pos = self.__actors_on_screen[0].pos() self.cursor.set_pos(pos) self.__actors_on_screen.append( self.__actors_on_screen.pop(0)) else: self.cursor.move(key) if self.state == S_RUN and not self.player.unconscious: pygame.event.pump() keys = pygame.key.get_pressed() [ self.player.move(key) for key in MOVES if keys[key] and self.player.timer <= 0 ] def _world_move(self): if not self.__quit_loop: if self.state == S_RUN: self.__actors.sort( sort_by_time) #actors with lowest timer first diff = self.__actors[0].timer self.__timer += diff self.__world_time += diff if self.__timer > 500: #act-independent issues # one combat-round [act.tick() for act in self.__actors] self.__timer -= 500 for actor in self.__actors: if actor.timer > 0: actor.timer -= diff else: actor.act() elif self.state == S_GFX: if self.__gfx == None: self.state = S_RUN def _world_draw(self): if self.__gfx == None or self.__gfx.redraw: if self.camera.adjust(self.player.pos()): self.map.cur_surf = None self.screen.fill((0, 0, 0)) if not self.player.dazzled: self.screen.blit( self.__get_map_surface(), (-self.camera.x * TILESIZE, -self.camera.y * TILESIZE)) if not self.player.dazzled: for item in self.__items: if not item.picked_up and (self.player.sc.lit( item.x, item.y) or self.player.x == item.x and self.player.y == item.y): try: self.screen.blit( self.__get_item_surface(item), (item.x * TILESIZE - self.camera.x * TILESIZE, item.y * TILESIZE - self.camera.y * TILESIZE)) except: print sys.exc_info() print item.name, item.pos(), 'is invalid!!!!' for act in self.__actors: if act == self.player or self.player.sc.lit( act.x, act.y) and not self.player.dazzled: try: self.screen.blit( self.__get_actor_surface(act), (act.x * TILESIZE - self.camera.x * TILESIZE, act.y * TILESIZE - self.camera.y * TILESIZE)) if not act in self.__actors_on_screen: self.__actors_on_screen.append(act) except: print sys.exc_info() print act.name, act.pos(), 'is invalid!!!!' else: if act in self.__actors_on_screen: self.__actors_on_screen.remove(act) if self.state == S_PLAYER_CURSOR: self.screen.blit( self.cursor.get_surf(), (self.cursor.x * TILESIZE - self.camera.x * TILESIZE, self.cursor.y * TILESIZE - self.camera.y * TILESIZE)) self.screen.blit(self.__get_message_surface(), (0, 768 - 128)) self.screen.blit(self.__get_statblock_surface(), (1024 - 192, 0)) if self.__gfx != None: pos = self.__gfx.pos() if pos == None: self.__gfx = None self.__cur_stat_surf = None else: x, y = pos #tiles = __get_affected_tiles(x,y,self.__gfx.get_surf()) x = x / TILESIZE + self.camera.x y = y / TILESIZE + self.camera.y #print x,y,self.player.pos(),self.player.sc.lit(x, y) if self.player.sc.lit(x, y): self.screen.blit(self.__gfx.get_surf(), pos) self.__gfx.tick() pygame.display.flip() def __get_map_surface(self): if self.map.cur_surf == None: self.player.sc.do_fov(self.player.x, self.player.y, 15) surf_map = pygame.Surface( (self.map.width * TILESIZE, self.map.height * TILESIZE)) cx, cy, cw, ch = self.camera.get_view_port() for x in xrange(max(cx, 0), min(self.map.width, cw + 1)): for y in xrange(max(cy, 0), min(self.map.height, ch + 1)): pos = (x, y) == self.player.pos() lit = self.player.sc.lit(x, y) memo = self.map.map_array[y][x][MT_FLAGS] & F_MEMO if pos or lit or memo: blit_position = ((x) * TILESIZE, (y) * TILESIZE) surf_map.blit(self.map.get_tile_at(x, y), blit_position) if not pos and not lit and memo: surf_map.blit(self.__surf_cache['FOW'], blit_position) if not self.map.map_array[y][x][MT_FLAGS] & F_MEMO: tile = self.map.map_array[y][x] new_tile = tile[0], tile[1], tile[2] ^ F_MEMO self.map.map_array[y][x] = new_tile self.map.cur_surf = surf_map return self.map.cur_surf def __get_actor_surface(self, act): if act.cur_surf == None: surf_act = pygame.Surface((TILESIZE, TILESIZE), pygame.SRCALPHA, 32) surf_act.blit(act.get_tile(), (0, 0)) act.cur_surf = surf_act return act.cur_surf def __get_item_surface(self, item): if item.cur_surf == None: surf_item = pygame.Surface((TILESIZE, TILESIZE), pygame.SRCALPHA, 32) surf_item.blit(item.get_dd_img(), (0, 0)) item.cur_surf = surf_item return item.cur_surf def __get_message_surface(self): surf = pygame.Surface((1024 - 192, 128)) surf.blit(self.__surf_cache['mes_block'], (0, 0)) y = 100 for mes in self.__message_queue: self.__render_text(surf, mes, WHITE, (20, y)) y -= 20 if y < 10: break return surf def __get_statblock_surface(self): if self.__cur_stat_surf == None: surf = pygame.Surface((192, 768)) surf.fill(BLACK) #surf.blit(self.__surf_cache['stat_block'], (0, 0)) if self.state in (S_RUN, S_GFX): self.__draw_stat_block(surf) if self.state in CHOOSE_STATES: self.__draw_item_choose(surf, CHOOSE_STATES[self.state]) self.__cur_stat_surf = surf return self.__cur_stat_surf def __set_game_instance(self): dungeon.Map.game = self Actor.game = self Item.game = self AI.game = self Camera.game = self dungeon.Populator.game = self magic.Spell.game = self GFX.game = self att.Att.game = self dungeon.SADungeon.game = self def __draw_item_choose(self, surf, message): self.__render_text(surf, message, WHITE, (16, 20)) y = 38 abc = self._items_to_choose.keys() #abc.sort(sort_by_type) s48 = pygame.Surface.copy(self.__surf_cache['stat_32']) for key in abc: item = self._items_to_choose[key] color = WHITE if hasattr(item, 'special'): if item.special: color = GREEN if hasattr(item, 'color'): color = item.color if hasattr(item, 'get_name'): name = item.get_name() else: name = item.name surf.blit(s48, (16, y)) if hasattr(item, 'cur_surf'): surf.blit(self.__get_item_surface(item), (16, y)) self.__render_text(surf, '%s' % (key), WHITE, (16, y)) #self.__render_text(surf, '%s -' % (key), WHITE, (16, y)) self.__render_text(surf, name, color, (64, y)) y += 18 info = item.info() for line in info: self.__render_text(surf, line, color, (64, y)) y += 18 if len(info) == 0: y += 18 y += 18 def __draw_stat_block(self, surf): bt = self.player.get_body_tile() bt = pygame.transform.smoothscale(bt, (96, 96)) bt.set_alpha(122) y = 50 surf.blit(bt, (32, y)) x = 77 y = 55 color = WHITE if self.player.HP.Head[0] == self.player.HP.Head[1]: color = GREEN if self.player.HP.Head[0] == 0: color = YELLOW if self.player.HP.Head[0] < 0: color = RED self.__render_text(surf, str(self.player.HP.Head[0]), color, (x, y)) y = 75 color = WHITE if self.player.HP.Chest[0] == self.player.HP.Chest[1]: color = GREEN if self.player.HP.Chest[0] == 0: color = YELLOW if self.player.HP.Chest[0] < 0: color = RED self.__render_text(surf, str(self.player.HP.Chest[0]), color, (x, y)) y = 95 color = WHITE if self.player.HP.Abdomen[0] == self.player.HP.Abdomen[1]: color = GREEN if self.player.HP.Abdomen[0] == 0: color = YELLOW if self.player.HP.Abdomen[0] < 0: color = RED self.__render_text(surf, str(self.player.HP.Abdomen[0]), color, (x, y)) x = 40 y = 85 color = WHITE if self.player.HP.L_Arm[0] == self.player.HP.L_Arm[1]: color = GREEN if self.player.HP.L_Arm[0] == 0: color = YELLOW if self.player.HP.L_Arm[0] < 0: color = RED self.__render_text(surf, str(self.player.HP.L_Arm[0]), color, (x, y)) x = 110 color = WHITE if self.player.HP.R_Arm[0] == self.player.HP.R_Arm[1]: color = GREEN if self.player.HP.R_Arm[0] == 0: color = YELLOW if self.player.HP.R_Arm[0] < 0: color = RED self.__render_text(surf, str(self.player.HP.R_Arm[0]), color, (x, y)) x = 55 y = 130 color = WHITE if self.player.HP.L_Leg[0] == self.player.HP.L_Leg[1]: color = GREEN if self.player.HP.L_Leg[0] == 0: color = YELLOW if self.player.HP.L_Leg[0] < 0: color = RED self.__render_text(surf, str(self.player.HP.L_Leg[0]), color, (x, y)) x = 95 color = WHITE if self.player.HP.R_Leg[0] == self.player.HP.R_Leg[1]: color = GREEN if self.player.HP.R_Leg[0] == 0: color = YELLOW if self.player.HP.R_Leg[0] < 0: color = RED self.__render_text(surf, str(self.player.HP.R_Leg[0]), color, (x, y)) stats = [('STR ', self.player.STR, self.player.get_STR()), ('CON ', self.player.CON, self.player.get_CON()), ('DEX ', self.player.DEX, self.player.get_DEX()), ('SIZ ', self.player.SIZ, self.player.get_SIZ()), ('INT ', self.player.INT, self.player.get_INT()), ('POW ', self.player.POW, self.player.get_POW()), ('CHA ', self.player.CHA, self.player.get_CHA()), ('DM ', self.player.DM[1], self.player.get_DM()[1])] y = 245 for line in stats: b = 0 if len(str(line[1])) > 3: b = 18 self.__render_text(surf, str(line[0]).rjust(2, ' '), WHITE, (16, y)) self.__render_text(surf, str(line[1]).rjust(2, ' '), GREEN, (55, y)) self.__render_text(surf, '/', WHITE, (70 + b, y)) self.__render_text(surf, str(line[2]).rjust(2, ' '), WHITE, (80 + b, y)) y += 18 #pygame.draw.circle(Surface, color, pos, radius, width=0): return Rect #r = pygame.Surface((100, 2)) #r.fill(RED) #surf.blit(r, (16, y + 20)) #size = float(line[2]) / float(line[1]) * 100 #if size > 0: # g = pygame.Surface((size, 2)) # if size > 100: # g.fill(BLUE) # else: # g.fill(GREEN) #surf.blit(g, (16, y + 20)) self.__render_text(surf, 'Gold:', WHITE, (16, 510)) self.__render_text(surf, str(self.player.gold), WHITE, (90, 510)) self.__render_text(surf, 'XP:', WHITE, (16, 528)) self.__render_text(surf, str(self.player.xp), WHITE, (90, 528)) i = 0 y = 600 count = len(self.player.items) s32 = pygame.Surface.copy(self.__surf_cache['stat_32']) sgreen = pygame.Surface.copy(self.__surf_cache['sgreen']) for h in xrange(3): for x in xrange(5): pos = (x * TILESIZE + x * 3 + 5, h * TILESIZE + y + h * 3) surf.blit(s32, pos) if i < count: item = self.player.items[i] if item.equipped: surf.blit(sgreen, pos) surf.blit(self.__get_item_surface(item), pos) self.__render_text(surf, self.player.items[i].get_ps(), WHITE, (pos)) i += 1 #print (x*TILESIZE,h*TILESIZE+y) self.__render_text(surf, self.dungeon.name, WHITE, (16, 710)) self.__render_text(surf, 'Level: %i' % (self.map.level), WHITE, (16, 728)) def __render_text(self, surf, text, color, pos, font='std'): t = self.__font_cache[font].render('%s' % (text), True, color) ts = self.__font_cache[font].render('%s' % (text), True, BLACK) surf.blit(ts, (pos[0] + 1, pos[1] + 1)) surf.blit(t, pos) def __load_fonts(self): #self.std_font = pygame.font.Font(os.path.join('font', 'jesaya.ttf'), 14) self.__font_cache = { 'std': pygame.font.Font(os.path.join('font', 'alex.ttf'), 17), 'big': pygame.font.Font(os.path.join('font', 'alex.ttf'), 25) } def __save_map(self): self.__clear_surfaces() self.__actors.remove(self.player) data = self.map, self.__actors, self.__items, self.player.pos() if os.access('MAP%i.gz' % (self.map.level), os.F_OK): os.remove('MAP%i.gz' % (self.map.level)) FILE = gzip.open('MAP%i.gz' % (self.map.level), 'w') pickle.dump(data, FILE, 2) FILE.close() def __load_map(self, level): if os.access('MAP%i.gz' % (level), os.F_OK): FILE = gzip.open('MAP%i.gz' % (level), 'r') self.map, self.__actors, self.__items, pos = pickle.load(FILE) self.__set_game_instance() FILE.close() self.player.set_pos(pos) r = self.camera.adjust(self.player.pos()) while r: r = self.camera.adjust(self.player.pos()) self.__actors.append(self.player) for act in self.__actors: self.__world_objects[act] = True act.sc = sc(self.map.map_array) self.player.sc.do_fov(self.player.x, self.player.y, self.player.cur_mind / 20 + 5) for item in self.__items: self.__world_objects[item] = True self.__world_objects[self.map] = True self.__clear_surfaces() self._world_draw() return True return False self.__quit_loop = True self.quit_mes = SAVE def __build_surf_cache(self): fow_surf = pygame.Surface((TILESIZE, TILESIZE)) fow_surf.fill(BLACK) fow_surf.set_alpha(100) sgreen = pygame.Surface((TILESIZE, TILESIZE)) sgreen.fill(GREEN) sgreen.set_alpha(100) self.__surf_cache = { 'sgreen': sgreen, 'FOW': fow_surf, 'stat_block': load_image('stat.png'), 'stat_48': load_image('48.png'), 'stat_32': pygame.transform.smoothscale(load_image('48.png'), (32, 32)), 'mes_block': load_image('mes_block.png'), 'mes_block2': load_image('mes_block2.png') } def __clear_surfaces(self): for obj in self.__world_objects.keys(): obj.clear_surfaces() self.cursor.cursor_surf = None def __gen_id(self): for x in xrange(self.__last_id, 9999999): yield x
def play_game(player, entities, game_map, message_log, game_state, con, panel, constants, priority_queue, global_variables, world): fov_recompute = True fov_map = initialize_fov(game_map) key = libtcod.Key() mouse = libtcod.Mouse() # Variables used to make decisions during the game. targeting_item = None previous_game_state = game_state # Turn on camera. camera = Camera(constants['camera_width'], constants['camera_height'], player.x, player.y, constants['map_width'], constants['map_height']) # Actviate cursor. cursor = Cursor() while not libtcod.console_is_window_closed(): libtcod.sys_check_for_event(libtcod.EVENT_KEY_PRESS | libtcod.EVENT_MOUSE, key, mouse) if fov_recompute: recompute_fov(fov_map, player.x, player.y, constants['fov_radius'], constants['fov_light_walls'], constants['fov_algorithm']) # Only render and recompute FOV while on the player's turn. if not game_state == GameStates.ENEMY_TURN: render_all(con, panel, entities, player, game_map, fov_map, fov_recompute, message_log, constants['screen_width'], constants['screen_height'], constants['bar_width'], constants['panel_height'], constants['panel_y'], mouse, constants['colors'], game_state, camera, cursor) fov_recompute = False libtcod.console_flush() # The console is cleared, but it will only be flushed on the player's turn. clear_all(con, entities, camera.x, camera.y, cursor) action = handle_keys(key, game_state) mouse_action = handle_mouse(mouse) enemy = None # If it's not the player's turn, it's _this_ enemy's turn. # Decide the entity's turn. if not priority_queue.empty() and game_state == GameStates.ENEMY_TURN: queue_ID = priority_queue.get_ID() # This removes the topmost ID from the queue. for entity in entities: if queue_ID == entity.ID and not entity.is_dead(): # If the entity is dead, do nothing. It has already been removed from the queue. if entity.ai == None: #it's the player # The player gets reinserted into the queue after their action. game_state = GameStates.PLAYERS_TURN break else: # The enemy gets reinserted into the queue after their action. enemy = entity break """ List of possible actions taken by the player. TODO: Cut things up via GameState more clearly. """ move = action.get('move') wait = action.get('wait') pickup = action.get('pickup') show_inventory = action.get('show_inventory') drop_inventory = action.get('drop_inventory') inventory_index = action.get('inventory_index') exit = action.get('exit') fullscreen = action.get('fullscreen') level_up = action.get('level_up') show_character_screen = action.get('show_character_screen') show_extract_materia_menu = action.get('show_extract_materia_menu') # Prompt the player to extra materia from creature. extraction_index = action.get('extraction_index') # Select this entry from the extraction menu. look = action.get('look') # Enter the LOOK GameState. select = action.get('select') # A target has been selected via keyboard. left_click = mouse_action.get('left_click') right_click = mouse_action.get('right_click') player_turn_results = [] if move and game_state == GameStates.PLAYERS_TURN: # TODO: Prevent player from moving outside the map. dx, dy = move destination_x = player.x + dx destination_y = player.y + dy if not game_map.is_blocked(destination_x, destination_y): target = get_blocking_entities_at_location(entities, destination_x, destination_y) if target: attack_results = player.fighter.attack(target) player_turn_results.extend(attack_results) else: # Check to see if the player is lined up with the center. # If so, move the camera with the player. camera_x, camera_y = camera.absolute_center() if player.x == camera_x: camera.move(dx, 0) if player.y == camera_y: camera.move(0, dy) player.move(dx, dy) fov_recompute = True priority_queue.put(player.fighter.speed, player.ID) # The player spends their turn to move/attack. game_state = GameStates.ENEMY_TURN elif move and game_state == GameStates.LOOK: # Move the cursor. dx, dy = move cursor.move(dx, dy, constants['camera_width'], constants['camera_height'], camera.x, camera.y) elif wait and game_state == GameStates.PLAYERS_TURN: # Puts the player second in queue. priority_queue.put_next(player.ID) game_state = GameStates.ENEMY_TURN elif pickup and game_state == GameStates.PLAYERS_TURN: for entity in entities: if entity.item and entity.x == player.x and entity.y == player.y: pickup_results = player.inventory.add_item(entity) player_turn_results.extend(pickup_results) priority_queue.put(player.fighter.speed, player.ID) # The player spends their turn picking up stuff. game_state = GameStates.ENEMY_TURN break else: message_log.add_message(Message('There is nothing here to pick up.', libtcod.yellow)) if show_inventory and game_state == GameStates.PLAYERS_TURN: previous_game_state = game_state game_state = GameStates.SHOW_INVENTORY if drop_inventory and game_state == GameStates.PLAYERS_TURN: previous_game_state = game_state game_state = GameStates.DROP_INVENTORY if inventory_index is not None and previous_game_state != GameStates.PLAYER_DEAD and inventory_index < len(player.inventory.items): item = player.inventory.items[inventory_index] if game_state == GameStates.SHOW_INVENTORY: player_turn_results.extend(player.inventory.use(item)) elif game_state == GameStates.DROP_INVENTORY: player_turn_results.extend(player.inventory.drop_item(item)) if game_state == GameStates.TARGETING: # Mouse targeting if left_click: target_x, target_y = left_click target_x += camera.x target_y += camera.y item_use_results = player.inventory.use(targeting_item, entities=entities, fov_map=fov_map, target_x=target_x, target_y=target_y) player_turn_results.extend(item_use_results) elif right_click: player_turn_results.append({'targeting_cancelled': True}) # Keyboard targeting if move: # Move the cursor. dx, dy = move cursor.move(dx, dy, constants['camera_width'], constants['camera_height'], camera.x, camera.y) if select: # Hit the chosen target. target_x, target_y = cursor.x, cursor.y item_use_results = player.inventory.use(targeting_item, entities=entities, fov_map=fov_map, target_x=target_x, target_y=target_y) player_turn_results.extend(item_use_results) if exit: if game_state in (GameStates.SHOW_INVENTORY, GameStates.DROP_INVENTORY, GameStates.CHARACTER_SCREEN, GameStates.MATERIA_SCREEN, GameStates.LOOK): game_state = previous_game_state elif game_state == GameStates.TARGETING: player_turn_results.append({'targeting_cancelled': True}) else: save_game(player, entities, game_map, message_log, game_state, priority_queue, global_variables, world) return True if fullscreen: libtcod.console_set_fullscreen(not libtcod.console_is_fullscreen()) if level_up: if level_up == 'hp': player.fighter.max_hp += 20 player.fighter.hp += 20 elif level_up == 'str': player.fighter.power += 1 elif level_up == 'def': player.fighter.defense += 1 game_state = previous_game_state if show_character_screen and game_state == GameStates.PLAYERS_TURN: previous_game_state = game_state game_state = GameStates.CHARACTER_SCREEN if show_extract_materia_menu and game_state == GameStates.PLAYERS_TURN: previous_game_state = game_state game_state = GameStates.MATERIA_SCREEN if extraction_index is not None and previous_game_state != GameStates.PLAYER_DEAD: # Create the list of items that have materia item_list = player.inventory.item_list_with_property('materia') # Check to see the index is inside this list if extraction_index < len(item_list): # Create an item called "type Materia (lvl n)" extracting_item = item_list[extraction_index] # This is the pokeball entity. materia_type = extracting_item.item.caught_entity.materia[0] materia_level = extracting_item.item.caught_entity.materia[1] materia_name = materia_type.capitalize() + ' Materia (lvl ' + str(materia_level) + ')' item_component = Item(use_function=item_functions.materia, type=materia_type, level=materia_level) materia_item = Entity(0, 0, '*', libtcod.white, materia_name, global_variables.get_new_ID(), RenderOrder.ITEM, item=item_component) # Add it to the inventory player.inventory.add_item(materia_item) entities.append(materia_item) # Remove the entity from which it came from the parent entity holding it extracting_item.item.caught_entity = None # Return the pokeball to a "catch" mode instead of release. # TODO: There are now two instances of switching the pokeball from one function to another. Consider moving this inside the Item class. extracting_item.item.swap_messages() extracting_item.item.use_function = item_functions.catch if look: previous_game_state = game_state cursor.x, cursor.y = player.x, player.y game_state = GameStates.LOOK """ List of possible results from actions taken by the player. """ for player_turn_result in player_turn_results: message = player_turn_result.get('message') dead_entity = player_turn_result.get('dead') item_added = player_turn_result.get('item_added') item_consumed = player_turn_result.get('consumed') item_dropped = player_turn_result.get('item_dropped') targeting = player_turn_result.get('targeting') targeting_cancelled = player_turn_result.get('targeting_cancelled') thrown = player_turn_result.get('thrown') # This item was thrown. Returns the item entity. catch = player_turn_result.get('catch') # This item catches pokemon. Returns the caught entity. release = player_turn_result.get('release') # This item released pokemon. Returns the released entity. xp = player_turn_result.get('xp') if message: message_log.add_message(message) if dead_entity: if dead_entity == player: message, game_state = kill_player(dead_entity) else: message = kill_monster(dead_entity) message_log.add_message(message) if item_added: entities.remove(item_added) if item_consumed: # Removed from inventory in inventory.py pass if item_dropped: entities.append(item_dropped) if targeting: previous_game_state = GameStates.PLAYERS_TURN game_state = GameStates.TARGETING cursor.x, cursor.y = player.x, player.y targeting_item = targeting message_log.add_message(targeting_item.item.targeting_message) if targeting_cancelled: game_state = previous_game_state message_log.add_message(Message('Targeting cancelled')) if thrown: # Removed from inventory in inventory.py thrown.x, thrown.y = player_turn_result.get('target_xy') entities.append(thrown) game_state = GameStates.PLAYERS_TURN if catch: entities.remove(catch) if release: release.x, release.y = player_turn_result.get('target_xy') entities.append(release) priority_queue.put(release.fighter.speed, release.ID) if xp: leveled_up = player.level.add_xp(xp) message_log.add_message(Message('You gain {0} experience points.'.format(xp))) if leveled_up: message_log.add_message(Message( 'Your battle skills grow stronger! You reached level {0}'.format(player.level.current_level) + '!', libtcod.yellow)) previous_game_state = game_state game_state = GameStates.LEVEL_UP if game_state == GameStates.ENEMY_TURN and enemy: enemy_turn_results = enemy.ai.take_turn(player, fov_map, game_map, entities) for enemy_turn_result in enemy_turn_results: message = enemy_turn_result.get('message') dead_entity = enemy_turn_result.get('dead') if message: message_log.add_message(message) if dead_entity: if dead_entity == player: message, game_state = kill_player(dead_entity) else: message = kill_monster(dead_entity) message_log.add_message(message) if game_state == GameStates.PLAYER_DEAD: break if game_state == GameStates.PLAYER_DEAD: break elif not enemy.ai == None: priority_queue.put(enemy.fighter.speed, enemy.ID)