Toggle Navigation
Hatchery
Eggs
emj testing
__init__.py
Users
Badges
Login
Register
MCH2022 badge?
go to mch2022.badge.team
__init__.py
raw
Content
### Author: Mattsi Jansky, Anthony Thomas, Michael Hunter ### Heavily modified from Sam Delaney and Sebastius' Game of Life app. ### Also uses James Spencer's Python dungeon generator from Roguebasin.com ### Description: A dungeon crawler for SHA 2017's badge ### Category: Games ### License: MIT ### Appname: GoL ### Built-in: no import badge import ugfx import urandom import deepsleep import random from random import randint import utime import sys ### BEGIN block of third party code ### The following code by James Spencer taken from Rogue Basin: http://www.roguebasin.com/index.php?title=A_Simple_Dungeon_Generator_for_Python_2_or_3 ### (With slight adaptions) # generator-1.py, a simple python dungeon generator by # James Spencer <jamessp [at] gmail.com>. # To the extent possible under law, the person who associated CC0 with # pathfinder.py has waived all copyright and related or neighboring rights # to pathfinder.py. # You should have received a copy of the CC0 legalcode along with this # work. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>. CHARACTER_TILES = {'stone': ' ', 'floor': '.', 'wall': '#'} class Generator(): def __init__(self, width=36, height=16, max_rooms=4, min_room_xy=3, max_room_xy=6, rooms_overlap=False, random_connections=1, random_spurs=3, tiles=CHARACTER_TILES): self.width = width self.height = height self.max_rooms = max_rooms self.min_room_xy = min_room_xy self.max_room_xy = max_room_xy self.rooms_overlap = rooms_overlap self.random_connections = random_connections self.random_spurs = random_spurs self.tiles = CHARACTER_TILES self.level = [] self.room_list = [] self.corridor_list = [] self.tiles_level = [] def gen_room(self): x, y, w, h = 0, 0, 0, 0 w = random.randint(self.min_room_xy, self.max_room_xy) h = random.randint(self.min_room_xy, self.max_room_xy) x = random.randint(1, (self.width - w - 1)) y = random.randint(1, (self.height - h - 1)) return [x, y, w, h] def room_overlapping(self, room, room_list): x = room[0] y = room[1] w = room[2] h = room[3] for current_room in room_list: # The rectangles don't overlap if # one rectangle's minimum in some dimension # is greater than the other's maximum in # that dimension. if (x < (current_room[0] + current_room[2]) and current_room[0] < (x + w) and y < (current_room[1] + current_room[3]) and current_room[1] < (y + h)): return True return False def corridor_between_points(self, x1, y1, x2, y2, join_type='either'): if x1 == x2 and y1 == y2 or x1 == x2 or y1 == y2: return [(x1, y1), (x2, y2)] else: # 2 Corridors # NOTE: Never randomly choose a join that will go out of bounds # when the walls are added. join = None if join_type is 'either' and set([0, 1]).intersection( set([x1, x2, y1, y2])): join = 'bottom' elif join_type is 'either' and set([self.width - 1, self.width - 2]).intersection(set([x1, x2])) or set( [self.height - 1, self.height - 2]).intersection( set([y1, y2])): join = 'top' elif join_type is 'either': join = random.choice(['top', 'bottom']) else: join = join_type if join is 'top': return [(x1, y1), (x1, y2), (x2, y2)] elif join is 'bottom': return [(x1, y1), (x2, y1), (x2, y2)] def join_rooms(self, room_1, room_2, join_type='either'): # sort by the value of x sorted_room = [room_1, room_2] sorted_room.sort(key=lambda x_y: x_y[0]) x1 = sorted_room[0][0] y1 = sorted_room[0][1] w1 = sorted_room[0][2] h1 = sorted_room[0][3] x1_2 = x1 + w1 - 1 y1_2 = y1 + h1 - 1 x2 = sorted_room[1][0] y2 = sorted_room[1][1] w2 = sorted_room[1][2] h2 = sorted_room[1][3] x2_2 = x2 + w2 - 1 y2_2 = y2 + h2 - 1 # overlapping on x if x1 < (x2 + w2) and x2 < (x1 + w1): jx1 = random.randint(x2, x1_2) jx2 = jx1 tmp_y = [y1, y2, y1_2, y2_2] tmp_y.sort() jy1 = tmp_y[1] + 1 jy2 = tmp_y[2] - 1 corridors = self.corridor_between_points(jx1, jy1, jx2, jy2) self.corridor_list.append(corridors) # overlapping on y elif y1 < (y2 + h2) and y2 < (y1 + h1): if y2 > y1: jy1 = random.randint(y2, y1_2) jy2 = jy1 else: jy1 = random.randint(y1, y2_2) jy2 = jy1 tmp_x = [x1, x2, x1_2, x2_2] tmp_x.sort() jx1 = tmp_x[1] + 1 jx2 = tmp_x[2] - 1 corridors = self.corridor_between_points(jx1, jy1, jx2, jy2) self.corridor_list.append(corridors) # no overlap else: join = None if join_type is 'either': join = random.choice(['top', 'bottom']) else: join = join_type if join is 'top': if y2 > y1: jx1 = x1_2 + 1 jy1 = random.randint(y1, y1_2) jx2 = random.randint(x2, x2_2) jy2 = y2 - 1 corridors = self.corridor_between_points( jx1, jy1, jx2, jy2, 'bottom') self.corridor_list.append(corridors) else: jx1 = random.randint(x1, x1_2) jy1 = y1 - 1 jx2 = x2 - 1 jy2 = random.randint(y2, y2_2) corridors = self.corridor_between_points( jx1, jy1, jx2, jy2, 'top') self.corridor_list.append(corridors) elif join is 'bottom': if y2 > y1: jx1 = random.randint(x1, x1_2) jy1 = y1_2 + 1 jx2 = x2 - 1 jy2 = random.randint(y2, y2_2) corridors = self.corridor_between_points( jx1, jy1, jx2, jy2, 'top') self.corridor_list.append(corridors) else: jx1 = x1_2 + 1 jy1 = random.randint(y1, y1_2) jx2 = random.randint(x2, x2_2) jy2 = y2_2 + 1 corridors = self.corridor_between_points( jx1, jy1, jx2, jy2, 'bottom') self.corridor_list.append(corridors) def gen_level(self): # build an empty dungeon, blank the room and corridor lists for i in range(self.height): self.level.append(['stone'] * self.width) self.room_list = [] self.corridor_list = [] max_iters = self.max_rooms * 5 for a in range(max_iters): tmp_room = self.gen_room() if self.rooms_overlap or not self.room_list: self.room_list.append(tmp_room) else: tmp_room = self.gen_room() tmp_room_list = self.room_list[:] if self.room_overlapping(tmp_room, tmp_room_list) is False: self.room_list.append(tmp_room) if len(self.room_list) >= self.max_rooms: break # connect the rooms for a in range(len(self.room_list) - 1): self.join_rooms(self.room_list[a], self.room_list[a + 1]) # do the random joins for a in range(self.random_connections): room_1 = self.room_list[random.randint(0, len(self.room_list) - 1)] room_2 = self.room_list[random.randint(0, len(self.room_list) - 1)] self.join_rooms(room_1, room_2) # do the spurs for a in range(self.random_spurs): room_1 = [random.randint(2, self.width - 2), random.randint( 2, self.height - 2), 1, 1] room_2 = self.room_list[random.randint(0, len(self.room_list) - 1)] self.join_rooms(room_1, room_2) # fill the map # paint rooms for room_num, room in enumerate(self.room_list): for b in range(room[2]): for c in range(room[3]): self.level[room[1] + c][room[0] + b] = 'floor' # paint corridors for corridor in self.corridor_list: x1, y1 = corridor[0] x2, y2 = corridor[1] for width in range(abs(x1 - x2) + 1): for height in range(abs(y1 - y2) + 1): self.level[min(y1, y2) + height][ min(x1, x2) + width] = 'floor' if len(corridor) == 3: x3, y3 = corridor[2] for width in range(abs(x2 - x3) + 1): for height in range(abs(y2 - y3) + 1): self.level[min(y2, y3) + height][ min(x2, x3) + width] = 'floor' # paint the walls for row in range(1, self.height - 1): for col in range(1, self.width - 1): if self.level[row][col] == 'floor': if self.level[row - 1][col - 1] == 'stone': self.level[row - 1][col - 1] = 'wall' if self.level[row - 1][col] == 'stone': self.level[row - 1][col] = 'wall' if self.level[row - 1][col + 1] == 'stone': self.level[row - 1][col + 1] = 'wall' if self.level[row][col - 1] == 'stone': self.level[row][col - 1] = 'wall' if self.level[row][col + 1] == 'stone': self.level[row][col + 1] = 'wall' if self.level[row + 1][col - 1] == 'stone': self.level[row + 1][col - 1] = 'wall' if self.level[row + 1][col] == 'stone': self.level[row + 1][col] = 'wall' if self.level[row + 1][col + 1] == 'stone': self.level[row + 1][col + 1] = 'wall' def gen_tiles_level(self): for row_num, row in enumerate(self.level): tmp_tiles = [] for col_num, col in enumerate(row): if col == 'stone': tmp_tiles.append(self.tiles['stone']) if col == 'floor': tmp_tiles.append(self.tiles['floor']) if col == 'wall': tmp_tiles.append(self.tiles['wall']) self.tiles_level.append(''.join(tmp_tiles)) return self.tiles_level ### END OF GENERATOR ### constants MSG_INTERACT = "interact" MSG_DAMAGE = "damage" MSG_ATTACK = "attack" MSG_DEFEND = "defend" MSG_REPORT_HP = "report hp" STUFF_SOURCE = "source" STUFF_TARGET = "target" STUFF_VALUE = "value" STUFF_ATTACK = "attack" STUFF_DAMAGE = "damage" STUFF_DEFEND = "defend" #render, name, strength, defense, HP mobTypes = [ ['h','harpy',3,5,4], ['s','skeleton',1,1,20], ['d','dickbutt',2,2,10], ['n','ninja',1,7,1] ] adverbs = ["lightly", "deeply", "feebly", "firmly", "sloppily", "brutally"] verbs = ["bemoans", "harasses", "molests", "manhandles", "slaps", "caresses", "aggrieves"] class Position: def __init__(self, x, y): self.x = x self.y = y def add(self,x,y): return Position(self.x + x, self.y + y) class Message: def __init__(self, name): self.name = name self.stuff = {} class Entity: def __init__(self, render, name, position): self.render = render self.name = name self.position = position self.components = [] def recieve(self, msg): for component in self.components: component.recieve(msg) class Component: def recieve(self, msg) : raise NotImplementedError class CharacterComponent(Component): def __init__(self, str, defn, hp): self.str = str self.defn = defn self.hp = hp def recieve(self, msg): if(msg.name == MSG_ATTACK): msg.stuff[STUFF_ATTACK] = randint(1,20) + self.str msg.stuff[STUFF_DAMAGE] = randint(1,6) + self.str if(msg.name == MSG_DEFEND): msg.stuff[STUFF_DEFEND] = 10 + self.defn if(msg.name == MSG_INTERACT): fight(msg.stuff[STUFF_SOURCE], msg.stuff[STUFF_TARGET]) if(msg.name == MSG_DAMAGE): self.hp -= msg.stuff[STUFF_VALUE] if(msg.name == MSG_REPORT_HP): msg.stuff[STUFF_VALUE] = self.hp class Tile: def __init__(self, render): self.render = render self.entity = None def __str__(self): if(self.entity is not None): return self.entity.render else: return self.render #### globals width = 36 height = 16 screenHeight = 7 cell_width = 8 cell_height = 12 grid = [[Tile('.') for x in range(height)] for y in range(width)] playername = badge.nvs_get_str("owner", "name", "player") player = Entity('@',playername[0:5], Position(1,1)) player.components.append(CharacterComponent(2,2,20)) grid[1][1].entity = player camera = Position(0,0) mobs = [] console = [] # rooms = [] walls = [' ','#'] hasPlayerActed = False def interact(source,target): msg = Message(MSG_INTERACT) msg.stuff[STUFF_SOURCE] = source msg.stuff[STUFF_TARGET] = target source.recieve(msg) class Manipulator: def move(self,entity,position): origin = grid[entity.position.x][entity.position.y] target = grid[position.x][position.y] if(target.entity is None and target.render not in walls): origin.entity = None target.entity = entity entity.position = position elif(target.entity is not None): interact(entity, target.entity) manipulator = Manipulator() def log(message): if(len(message) < 36): console.append(message) if(len(console) > 3): del console[0] def makemob(position): mobtype = mobTypes[randint(0,len(mobTypes)-1)] mob = Entity(mobtype[0], mobtype[1], position) mob.components.append(CharacterComponent(mobtype[2],mobtype[3],mobtype[4])) mobs.append(mob) return mob def attackDescription(): return "%s %s" % (adverbs[randint(0,len(adverbs)-1)], verbs[randint(0,len(verbs)-1)]) def fight(attacker, defender): attackMsg = Message(MSG_ATTACK) defendMsg = Message(MSG_DEFEND) attacker.recieve(attackMsg) defender.recieve(defendMsg) if(attackMsg.stuff[MSG_ATTACK] > defendMsg.stuff[MSG_DEFEND]): log("%s %s %s, %s DMG" % (attacker.name, attackDescription(), defender.name, attackMsg.stuff[STUFF_DAMAGE])) damageMsg = Message(MSG_DAMAGE) damageMsg.stuff[STUFF_VALUE] = attackMsg.stuff[STUFF_DAMAGE] defender.recieve(damageMsg) else: log("%s blocked %s's ATK!" % (defender.name, attacker.name)) def randomise(rooms): for i in range(randint(5,15)): i = 0 room = rooms[randint(0,len(rooms)-1)] pos = Position(randint(room[0],room[0]+room[2]),randint(room[1],room[1]+room[3])) if(grid[pos.x][pos.y].entity is None): grid[pos.x][pos.y].entity = makemob(pos) def moveMob(entity): direction = 1 if(randint(0,1) == 0): direction = -direction if(randint(0,1) == 0): manipulator.move(entity,entity.position.add(direction,0)) else: manipulator.move(entity,entity.position.add(0,direction)) def updateGame(): for mob in mobs: msg = Message(MSG_REPORT_HP) mob.recieve(msg) if(msg.stuff[STUFF_VALUE] > 0): moveMob(mob) else: mobs.remove(mob) grid[mob.position.x][mob.position.y].entity = None log("%s has died" % (mob.name)) def left(pressed): global hasPlayerActed if(pressed): manipulator.move(player,player.position.add(-1,0)) hasPlayerActed = True def right(pressed): global hasPlayerActed if(pressed): manipulator.move(player,player.position.add(1,0)) hasPlayerActed = True def up(pressed): global hasPlayerActed if(pressed): manipulator.move(player,player.position.add(0,-1)) hasPlayerActed = True def down(pressed): global hasPlayerActed if(pressed): manipulator.move(player,player.position.add(0,1)) hasPlayerActed = True def select(pressed): log("in select") def getPlayerHealth(): msg = Message(MSG_REPORT_HP) player.recieve(msg) return msg.stuff[STUFF_VALUE] def placePlayer(rooms): playerPlaced = False for room in rooms: for x in range(room[0],room[0]+room[2]): for y in range(room[1],room[1]+room[3]): if(grid[x][y].entity is None and grid[x][y].render not in walls): grid[player.position.x][player.position.y].entity = None player.position = Position(x,y) grid[x][y].entity = player playerPlaced = True break; if(playerPlaced): break; def emj_test(): global hasPlayerActed random.seed(utime.time()) badge.eink_init() ugfx.init() ugfx.input_init() ugfx.input_attach(ugfx.JOY_RIGHT, right) ugfx.input_attach(ugfx.JOY_LEFT, left) ugfx.input_attach(ugfx.JOY_UP, up) ugfx.input_attach(ugfx.JOY_DOWN, down) #ugfx.input_attach(ugfx.BTN_A, reboot) #ugfx.input_attach(ugfx.BTN_B, reboot) ugfx.input_attach(ugfx.BTN_START, reboot) ugfx.input_attach(ugfx.BTN_SELECT, select) ugfx.clear(ugfx.WHITE) ugfx.flush() gen = Generator() gen.gen_level() print("Room List") print(gen.room_list) for y, row in enumerate(gen.gen_tiles_level()): for x, c in enumerate(row): grid[x][y].render = c print("Rooms now") print(gen.room_list) these_rooms = gen.room_list gen = None randomise(these_rooms) placePlayer(these_rooms) def display(): camera = player.position.add(-18,-3) #main screen ugfx.clear(ugfx.WHITE) for x in range(0, width): for y in range(0, screenHeight): char = ' ' if(x + camera.x > 0 and y + camera.y > 0 and x + camera.x < len(grid) and y + camera.y < len(grid[0])): char = str(grid[x + camera.x][y + camera.y]) ugfx.text(x * cell_width, y * cell_height, char, ugfx.BLACK) #console ugfx.line(0,screenHeight * cell_height + 1, width * cell_width, screenHeight * cell_height + 1, ugfx.BLACK) for index, msg in enumerate(console): ugfx.text(0,screenHeight * cell_height + 1 + index * cell_height, msg, ugfx.BLACK) badge.eink_busy_wait() ugfx.flush() while (getPlayerHealth() > 0): if(hasPlayerActed): updateGame() hasPlayerActed = False display() ugfx.clear(ugfx.WHITE) ugfx.flush() ugfx.clear(ugfx.WHITE) ugfx.flush() ugfx.text(50,100,"YOU DIED",ugfx.BLACK) ugfx.flush() def reboot(wut): deepsleep.reboot() emj_test()