diff --git a/assets/temp_logo.png b/assets/temp_logo.png new file mode 100644 index 0000000..9d6501a Binary files /dev/null and b/assets/temp_logo.png differ diff --git a/src/scripts/cos_play.py b/src/scripts/cos_play.py new file mode 100644 index 0000000..fef09c1 --- /dev/null +++ b/src/scripts/cos_play.py @@ -0,0 +1,300 @@ +import mcrfpy +mcrfpy.createScene("play") +ui = mcrfpy.sceneUI("play") +t = mcrfpy.Texture("assets/kenney_tinydungeon.png", 16, 12, 11) +font = mcrfpy.Font("assets/JetbrainsMono.ttf") + +frame_color = (64, 64, 128) + +grid = mcrfpy.Grid(20, 15, t, 10, 10, 800, 595) +grid.zoom = 2.0 +entity_frame = mcrfpy.Frame(815, 10, 194, 595, fill_color = frame_color) +inventory_frame = mcrfpy.Frame(10, 610, 800, 143, fill_color = frame_color) +stats_frame = mcrfpy.Frame(815, 610, 194, 143, fill_color = frame_color) + +begin_btn = mcrfpy.Frame(350,250,100,100, fill_color = (255,0,0)) +begin_btn.children.append(mcrfpy.Caption(5, 5, "Begin", font)) +def cos_keys(key, state): + if key == 'M' and state == 'start': + mapgen() + elif state == "end": return + elif key == "W": + player.move("N") + elif key == "A": + player.move("W") + elif key == "S": + player.move("S") + elif key == "D": + player.move("E") + + +def cos_init(*args): + if args[3] != "start": return + mcrfpy.keypressScene(cos_keys) + ui.remove(4) + +begin_btn.click = cos_init + +[ui.append(e) for e in (grid, entity_frame, inventory_frame, stats_frame, begin_btn)] + +import random +def rcolor(): + return tuple([random.randint(0, 255) for i in range(3)]) # TODO list won't work with GridPoint.color, so had to cast to tuple + +x_max, y_max = grid.grid_size +for x in range(x_max): + for y in range(y_max): + grid.at((x,y)).color = rcolor() + +from math import pi, cos, sin +def mapgen(room_size_max = 7, room_size_min = 3, room_count = 4): + # reset map + for x in range(x_max): + for y in range(y_max): + grid.at((x, y)).walkable = False + grid.at((x, y)).transparent= False + grid.at((x,y)).tilesprite = random.choices([40, 28], weights=[.8, .2])[0] + global cos_entities + for e in cos_entities: + e.e.position = (999,999) # TODO + e.die() + cos_entities = [] + + #Dungeon generation + centers = [] + attempts = 0 + while len(centers) < room_count: + # Leaving this attempt here for later comparison. These rooms sucked. + # overlapping, uninteresting hallways, crowded into the corners sometimes, etc. + attempts += 1 + if attempts > room_count * 15: break + # room_left = random.randint(1, x_max) + # room_top = random.randint(1, y_max) + + # Take 2 - circular distribution of rooms + angle_mid = (len(centers) / room_count) * 2 * pi + 0.785 + angle = random.uniform(angle_mid - 0.25, angle_mid + 0.25) + radius = random.uniform(3, 14) + room_left = int(radius * cos(angle)) + int(x_max/2) + if room_left <= 1: room_left = 1 + if room_left > x_max - 1: room_left = x_max - 2 + room_top = int(radius * sin(angle)) + int(y_max/2) + if room_top <= 1: room_top = 1 + if room_top > y_max - 1: room_top = y_max - 2 + room_w = random.randint(room_size_min, room_size_max) + if room_w + room_left >= x_max: room_w = x_max - room_left - 2 + room_h = random.randint(room_size_min, room_size_max) + if room_h + room_top >= y_max: room_h = y_max - room_top - 2 + #print(room_left, room_top, room_left + room_w, room_top + room_h) + if any( # centers contained in this randomly generated room + [c[0] >= room_left and c[0] <= room_left + room_w and c[1] >= room_top and c[1] <= room_top + room_h for c in centers] + ): + continue # re-randomize the room position + centers.append( + (int(room_left + (room_w/2)), int(room_top + (room_h/2))) + ) + + for x in range(room_w): + for y in range(room_h): + grid.at((room_left+x, room_top+y)).walkable=True + grid.at((room_left+x, room_top+y)).transparent=True + grid.at((room_left+x, room_top+y)).tilesprite = random.choice([48, 49, 50, 51, 52, 53]) + + # generate a boulder + if (room_w > 2 and room_h > 2): + room_boulder_x, room_boulder_y = random.randint(room_left+1, room_left+room_w-1), random.randint(room_top+1, room_top+room_h-1) + cos_entities.append(BoulderEntity(room_boulder_x, room_boulder_y)) + + print(f"{room_count} rooms generated after {attempts} attempts.") + #print(centers) + # hallways + pairs = [] + for c1 in centers: + for c2 in centers: + if c1 == c2: continue + if (c2, c1) in pairs or (c1, c2) in pairs: continue + left = min(c1[0], c2[0]) + right = max(c1[0], c2[0]) + top = min(c1[1], c2[1]) + bottom = max(c1[1], c2[1]) + + corners = [(left, top), (left, bottom), (right, top), (right, bottom)] + corners.remove(c1) + corners.remove(c2) + random.shuffle(corners) + target, other = corners + for x in range(target[0], other[0], -1 if target[0] > other[0] else 1): + was_walkable = grid.at((x, target[1])).walkable + grid.at((x, target[1])).walkable=True + grid.at((x, target[1])).transparent=True + if not was_walkable: + grid.at((x, target[1])).tilesprite = random.choices([0, 12, 24], weights=[.6, .3, .1])[0] + for y in range(target[1], other[1], -1 if target[1] > other[1] else 1): + was_walkable = grid.at((target[0], y)).walkable + grid.at((target[0], y)).walkable=True + grid.at((target[0], y)).transparent=True + if not was_walkable: + grid.at((target[0], y)).tilesprite = random.choices([0, 12, 24], weights=[0.4, 0.3, 0.3])[0] + pairs.append((c1, c2)) + + + # spawn exit and button + spawn_points = [] + for x in range(x_max): + for y in range(y_max): + if grid.at((x, y)).walkable: + spawn_points.append((x, y)) + random.shuffle(spawn_points) + door_spawn, button_spawn = spawn_points[:2] + cos_entities.append(ExitEntity(*door_spawn, *button_spawn)) + + # respawn player + global player + if player: + player.position = (999,999) # TODO - die() is broken and I don't know why + player = PlayerEntity() + + + #for x in range(x_max): + # for y in range(y_max): + # if grid.at((x, y)).walkable: + # #grid.at((x,y)).tilesprite = random.choice([48, 49, 50, 51, 52, 53]) + # pass + # else: + # #grid.at((x,y)).tilesprite = random.choices([40, 28], weights=[.8, .2])[0] + +#131 - last sprite +#123, 124 - brown, grey rats +#121 - ghost +#114, 115, 116 - green, red, blue potion +#102 - shield +#98 - low armor guy, #97 - high armor guy +#89 - chest, #91 - empty chest +#84 - wizard +#82 - barrel +#66 - boulder +#64, 65 - graves +#48 - 53: ground (not going to figure out how they fit together tonight) +#42 - button-looking ground +#40 - basic solid wall +#36, 37, 38 - wall (left, middle, right) +#28 solid wall but with a grate +#21 - wide open door, 33 medium open, 45 closed door +#0 - basic dirt +class MyEntity: + def __init__(self, x=0, y=0, sprite_num=86): + self.e = mcrfpy.Entity(x, y, t, sprite_num) + grid.entities.append(self.e) + def die(self): + for i in range(len(grid.entities)): + e = grid.entities[i] + if e == self.e: + grid.entities.remove(i) + break + def bump(self, other, dx, dy): + raise NotImplementedError + + def try_move(self, dx, dy): + tx, ty = int(self.e.position[0] + dx), int(self.e.position[1] + dy) + for e in cos_entities: + if e.e.position == (tx, ty): + #print(f"bumping {e}") + return e.bump(self, dx, dy) + if tx < 0 or tx >= x_max: + #print("out of bounds horizontally") + return False + if ty < 0 or ty >= y_max: + #print("out of bounds vertically") + return False + if grid.at((tx, ty)).walkable == True: + #print("Motion!") + self.e.position = (tx, ty) + return True + else: + #print("Bonk") + return False + + def _relative_move(self, dx, dy): + tx, ty = int(self.e.position[0] + dx), int(self.e.position[1] + dy) + self.e.position = (tx, ty) + + + def move(self, direction): + if direction == "N": + self.try_move(0, -1) + elif direction == "E": + self.try_move(1, 0) + elif direction == "S": + self.try_move(0, 1) + elif direction == "W": + self.try_move(-1, 0) + +cos_entities = [] + +class PlayerEntity(MyEntity): + def __init__(self): + # find spawn point + spawn_points = [] + for x in range(x_max): + for y in range(y_max): + if grid.at((x, y)).walkable: + spawn_points.append((x, y)) + random.shuffle(spawn_points) + for spawn in spawn_points: + for e in cos_entities: + if e.e.position == spawn: break + else: + break + + #print(f"spawn at {spawn}") + super().__init__(spawn[0], spawn[1], sprite_num=84) + +class BoulderEntity(MyEntity): + def __init__(self, x, y): + super().__init__(x, y, 66) + + def bump(self, other, dx, dy): + if type(other) == BoulderEntity: + #print("Boulders can't push boulders") + return False + tx, ty = int(self.e.position[0] + dx), int(self.e.position[1] + dy) + # Is the boulder blocked the same direction as the bumper? If not, let's both move + old_pos = int(self.e.position[0]), int(self.e.position[1]) + if self.try_move(dx, dy): + other.e.position = old_pos + return True + +class ButtonEntity(MyEntity): + def __init__(self, x, y, exit): + super().__init__(x, y, 42) + self.exit = exit + + def bump(self, other, dx, dy): + if type(other) == BoulderEntity: + self.exit.unlock() + other._relative_move(dx, dy) + return True + +class ExitEntity(MyEntity): + def __init__(self, x, y, bx, by): + super().__init__(x, y, 45) + self.my_button = ButtonEntity(bx, by, self) + self.unlocked = False + global cos_entities + cos_entities.append(self.my_button) + + def unlock(self): + self.e.sprite_number = 21 + self.unlocked = True + + def lock(self): + self.e.sprite_number = 45 + self.unlocked = True + + def bump(self, other, dx, dy): + if type(other) == BoulderEntity: + return False + if self.unlocked: + other._relative_move(dx, dy) + +player = None diff --git a/src/scripts/game.py b/src/scripts/game.py index 81222dc..15cc524 100644 --- a/src/scripts/game.py +++ b/src/scripts/game.py @@ -1,2 +1,136 @@ -print("Hello mcrogueface") +#print("Hello mcrogueface") +import mcrfpy +import cos_play +# Universal stuff +font = mcrfpy.Font("assets/JetbrainsMono.ttf") +texture = mcrfpy.Texture("assets/kenney_tinydungeon.png", 16, 12, 11) +texture_cold = mcrfpy.Texture("assets/kenney_ice.png", 16, 12, 11) +texture_hot = mcrfpy.Texture("assets/kenney_lava.png", 16, 12, 11) +# Test stuff +mcrfpy.createScene("boom") +#mcrfpy.setScene("boom") +ui = mcrfpy.sceneUI("boom") +box = mcrfpy.Frame(40, 60, 200, 300, fill_color=(255,128,0), outline=4.0, outline_color=(64,64,255,96)) +ui.append(box) + +#caption = mcrfpy.Caption(10, 10, "Clicky", font, (255, 255, 255, 255), (0, 0, 0, 255)) +#box.click = lambda x, y, btn, type: print("Hello callback: ", x, y, btn, type) +#box.children.append(caption) + +test_sprite_number = 86 +sprite = mcrfpy.Sprite(20, 60, texture, test_sprite_number, 4.0) +spritecap = mcrfpy.Caption(5, 5, "60", font) +def click_sprite(x, y, btn, action): + global test_sprite_number + if action != "start": return + if btn in ("left", "wheel_up"): + test_sprite_number -= 1 + elif btn in ("right", "wheel_down"): + test_sprite_number += 1 + sprite.sprite_number = test_sprite_number # TODO - inconsistent naming for __init__, __repr__ and getsetter: sprite_number vs sprite_index + spritecap.text = test_sprite_number + +sprite.click = click_sprite # TODO - sprites don't seem to correct for screen position or scale when clicking +box.children.append(sprite) +box.children.append(spritecap) +box.click = click_sprite + +# Loading Screen +mcrfpy.createScene("loading") +ui = mcrfpy.sceneUI("loading") +mcrfpy.setScene("loading") +logo_texture = mcrfpy.Texture("assets/temp_logo.png", 1024, 1, 1) +logo_sprite = mcrfpy.Sprite(50, 50, logo_texture, 0, 0.5) +ui.append(logo_sprite) +logo_sprite.click = lambda *args: mcrfpy.setScene("menu") +logo_caption = mcrfpy.Caption(70, 600, "Click to Proceed", font, (255, 0, 0, 255), (0, 0, 0, 255)) +logo_caption.fill_color =(255, 0, 0, 255) +ui.append(logo_caption) + + +# menu screen +mcrfpy.createScene("menu") + +for e in [ + mcrfpy.Caption(10, 10, "Crypt of Sokoban", font, (255, 255, 255), (0, 0, 0)), + mcrfpy.Caption(20, 55, "a McRogueFace demo project", font, (192, 192, 192), (0, 0, 0)), + mcrfpy.Frame(15, 70, 150, 60, fill_color=(64, 64, 128)), + mcrfpy.Frame(15, 145, 150, 60, fill_color=(64, 64, 128)), + mcrfpy.Frame(15, 220, 150, 60, fill_color=(64, 64, 128)), + mcrfpy.Frame(15, 295, 150, 60, fill_color=(64, 64, 128)), + #mcrfpy.Frame(900, 10, 100, 100, fill_color=(255, 0, 0)), + ]: + mcrfpy.sceneUI("menu").append(e) + +def click_once(fn): + def wraps(*args, **kwargs): + #print(args) + action = args[3] + if action != "start": return + return fn(*args, **kwargs) + return wraps + +@click_once +def asdf(x, y, btn, action): + print(f"clicky @({x},{y}) {action}->{btn}") + +@click_once +def clicked_exit(*args): + mcrfpy.exit() + +menu_btns = [ + ("Boom", lambda *args: 1 / 0), + ("Exit", clicked_exit), + ("About", lambda *args: mcrfpy.setScene("about")), + ("Settings", lambda *args: mcrfpy.setScene("settings")), + ("Start", lambda *args: mcrfpy.setScene("play")) + ] +for i in range(len(mcrfpy.sceneUI("menu"))): + e = mcrfpy.sceneUI("menu")[i] # TODO - fix iterator + #print(e, type(e)) + if type(e) is not mcrfpy.Frame: continue + label, fn = menu_btns.pop() + #print(label) + e.children.append(mcrfpy.Caption(5, 5, label, font, (192, 192, 255), (0,0,0))) + e.click = fn + + +# settings screen +mcrfpy.createScene("settings") +window_scaling = 1.0 + +scale_caption = mcrfpy.Caption(180, 70, "1.0x", font, (255, 255, 255), (0, 0, 0)) +scale_caption.fill_color = (255, 255, 255) # TODO - mcrfpy.Caption.__init__ is not setting colors +for e in [ + mcrfpy.Caption(10, 10, "Settings", font, (255, 255, 255), (0, 0, 0)), + mcrfpy.Frame(15, 70, 150, 60, fill_color=(64, 64, 128)), # + + mcrfpy.Frame(300, 70, 150, 60, fill_color=(64, 64, 128)), # - + mcrfpy.Frame(15, 295, 150, 60, fill_color=(64, 64, 128)), + scale_caption, + ]: + mcrfpy.sceneUI("settings").append(e) + +@click_once +def game_scale(x, y, btn, action, delta): + global window_scaling + print(f"WIP - scale the window from {window_scaling:.1f} to {window_scaling+delta:.1f}") + window_scaling += delta + scale_caption.text = f"{window_scaling:.1f}x" + mcrfpy.setScale(window_scaling) + #mcrfpy.setScale(2) + +settings_btns = [ + ("back", lambda *args: mcrfpy.setScene("menu")), + ("-", lambda x, y, btn, action: game_scale(x, y, btn, action, -0.1)), + ("+", lambda x, y, btn, action: game_scale(x, y, btn, action, +0.1)) + ] + +for i in range(len(mcrfpy.sceneUI("settings"))): + e = mcrfpy.sceneUI("settings")[i] # TODO - fix iterator + #print(e, type(e)) + if type(e) is not mcrfpy.Frame: continue + label, fn = settings_btns.pop() + #print(label, fn) + e.children.append(mcrfpy.Caption(5, 5, label, font, (192, 192, 255), (0,0,0))) + e.click = fn