From f594998dc35b1a616e88d72ff659654a93b70ab5 Mon Sep 17 00:00:00 2001 From: John McCardle Date: Wed, 12 Mar 2025 22:42:26 -0400 Subject: [PATCH] Final day of changes for 7DRL 2025 - Crypt of Sokoban game code --- src/scripts/cos_entities.py | 184 ++++++++++++++++++++++++++++++---- src/scripts/cos_itemdata.py | 62 ++++++++++++ src/scripts/cos_level.py | 33 ++++--- src/scripts/game.py | 191 +++++++++++++++++++++++++----------- 4 files changed, 378 insertions(+), 92 deletions(-) create mode 100644 src/scripts/cos_itemdata.py diff --git a/src/scripts/cos_entities.py b/src/scripts/cos_entities.py index 0643c00..6b8ff59 100644 --- a/src/scripts/cos_entities.py +++ b/src/scripts/cos_entities.py @@ -1,5 +1,6 @@ import mcrfpy import random +from cos_itemdata import itemdata #t = mcrfpy.Texture("assets/kenney_tinydungeon.png", 16, 16) t = mcrfpy.Texture("assets/kenney_TD_MR_IP.png", 16, 16) #def iterable_entities(grid): @@ -110,7 +111,7 @@ class COSEntity(): #mcrfpy.Entity): # Fake mcrfpy.Entity integration; engine bu self.do_move(tx, ty) class Equippable: - def __init__(self, hands = 0, hp_healing = 0, damage = 0, defense = 0, zap_damage = 1, zap_cooldown = 10, sprite = 129): + def __init__(self, hands = 0, hp_healing = 0, damage = 0, defense = 0, zap_damage = 1, zap_cooldown = 10, sprite = 129, boost=None, text="", text_color=(255, 255, 255), value=0): self.hands = hands self.hp_healing = hp_healing self.damage = damage @@ -118,8 +119,12 @@ class Equippable: self.zap_damage = zap_damage self.zap_cooldown = zap_cooldown self.zap_cooldown_remaining = 0 - self.sprite = self.sprite + self.sprite = sprite self.quality = 0 + self.text = text + self.text_color = text_color + self.boost = boost + self.value = value def tick(self): if self.zap_cooldown_remaining: @@ -128,7 +133,7 @@ class Equippable: def __repr__(self): cooldown_str = f'({self.zap_cooldown_remaining} rounds until ready)' - return f"" + return f"" def classify(self): categories = [] @@ -147,6 +152,54 @@ class Equippable: else: return "Erratic: " + ', '.join(categories) + def consume(self, consumer): + if self.boost == "green_pot": + consumer.base_damage += self.value + elif self.boost == "blue_pot": + b = self.value + while b: #split bonus between damage and faster cooldown + bonus = random.choice(["damage", "cooldown", "range"]) + if bonus == "damage": + consumer.base_zap_damage += 1 + elif bonus == "cooldown": + consumer.base_zap_cooldown += 1 + else: + consumer.base_zap_range += 1 + b -= 1 + elif self.boost == "grey_pot": + consumer.base_defense += self.value + elif self.boost == "sm_grey_pot": + consumer.luck += self.value + elif self.hp_healing: + consumer.hp += self.hp_healing + if consumer.hp > consumer.max_hp: consumer.hp = consumer.max_hp + + def do_zap(self, caster, entities): + if self.zap_damage == 0: + print("This item can't zap.") + return False + if self.zap_cooldown_remaining != 0: + print("zap is cooling down.") + return False + fx, fy = caster.draw_pos + x, y = int(fx), int (fy) + dist = lambda tx, ty: abs(int(tx) - x) + abs(int(ty) - y) + targets = [] + for e in entities: + if type(e) != EnemyEntity: continue + if dist(*e.draw_pos) > caster.base_zap_range: + continue + if e.hp <= 0: continue + targets.append(e) + if not targets: + print("No targets found in range.") + return False + target = random.choice(targets) + print(f"Zap! {target}") + target.get_zapped(self.zap_damage) + self.zap_cooldown_remaining = self.zap_cooldown + return True + #def compare(self, other): # my_class = self.classify() # o_class = other.classify() @@ -169,6 +222,9 @@ class PlayerEntity(COSEntity): self.archetype = None self.equipped = [] self.inventory = [] + self.base_zap_damage = 0 + self.base_zap_cooldown = 0 + self.base_zap_range = 4 def tick(self): for i in self.equipped: @@ -183,19 +239,48 @@ class PlayerEntity(COSEntity): def calc_defense(self): defense = self.base_defense for i in self.equipped: - defense += i.damage + defense += i.defense return defense def do_zap(self): - pass + for i in self.equipped: + if i.zap_damage and i.zap_cooldown_remaining == 0: + if i.do_zap(self, self.game.entities): + break + else: + print("Couldn't zap") def bump(self, other, dx, dy, test=False): if type(other) == BoulderEntity: print("Boulder hit w/ knockback!") return self.game.pull_boulder_move((-dx, -dy), other) - print(f"oof, ouch, {other} bumped the player - {other.base_damage} damage from {other}") + #print(f"oof, ouch, {other} bumped the player - {other.base_damage} damage from {other}") self.hp = max(self.hp - max(other.base_damage - self.calc_defense(), 0), 0) + def receive(self, equip): + print(equip) + if (equip.hands == 0): + if len([i for i in self.inventory if i is not None]) < 3: + if None in self.inventory: + self.inventory[self.inventory.index(None)] = equip + else: + self.inventory.append(equip) + return + else: + print("something something, consumable GUI") + elif (equip.hands == 1): + if len(self.equipped) < 2: + self.equipped.append(equip) + return + else: + print("Something something, 1h GUI") + else: # equip.hands == 2: + if len(self.equipped) == 0: + self.equipped.append(equip) + return + else: + print("Something something, 2h GUI") + def respawn(self, avoid=None): # find spawn point x_max, y_max = g.size @@ -287,7 +372,7 @@ class ExitEntity(COSEntity): #TODO - player go down a level logic if type(other) == PlayerEntity: self.game.depth += 1 - print(f"welcome to level {self.game.depth}") + #print(f"welcome to level {self.game.depth}") self.game.create_level(self.game.depth) self.game.swap_level(self.game.level, self.game.spawn_point) @@ -346,10 +431,12 @@ class EnemyEntity(COSEntity): return # slow movement (doesn't affect ability to attack) - if self.moved_last < 0: + if self.moved_last > 0: self.moved_last -= 1 + #print(f"Deducting move cooldown, now {self.moved_last} / {self.move_cooldown}") return else: + #print(f"Restaring move cooldown - {self.move_cooldown}") self.moved_last = self.move_cooldown # if player is not nearby, wander @@ -359,35 +446,94 @@ class EnemyEntity(COSEntity): # if can_push and player in a line: KICK if self.can_push: - if int(x) == int(px): - pass # vertical kick - elif int(y) == int(py): - pass # horizontal kick + if int(x) == int(px):# vertical kick + self.try_move(0, 1 if y < py else -1) + elif int(y) == int(py):# horizontal kick + self.try_move(1 if x < px else -1, 0) # else, nearby pursue towards = [] dist = lambda dx, dy: abs(px - (x + dx)) + abs(py - (y + dy)) - current_dist = dist(0, 0) - for d in ((1, 0), (0, 1), (-1, 0), (1, 0)): - if dist(*d) <= current_dist + 0.75: towards.append(d) - print(current_dist, towards) - target_dir = random.choice(towards) + #current_dist = dist(0, 0) + #for d in ((1, 0), (0, 1), (-1, 0), (1, 0)): + # if dist(*d) <= current_dist + 0.75: towards.append(d) + #print(current_dist, towards) + if px >= x: + towards.append((1, 0)) + if px <= x: + towards.append((-1, 0)) + if py >= y: + towards.append((0, 1)) + if py <= y: + towards.append((0, -1)) + towards = [p for p in towards if self.game.grid.at((int(x + p[0]), int(y + p[1]))).walkable] + towards.sort(key = lambda p: dist(*p)) + target_dir = towards[0] self.try_move(*target_dir) + def get_zapped(self, d): + self.hp -= d + self.hp = max(self.hp, 0) + if self.hp == 0: + self._entity.sprite_number = self.base_sprite + 246 + self.draw_order = 1 + print(f"Player zapped for {d}. HP = {self.hp}") + class TreasureEntity(COSEntity): def __init__(self, x, y, treasure_table=None, *, game): self.draw_order = 6 super().__init__(game.grid, x, y, 89, game=game) self.popped = False + self.treasure_table = treasure_table + + def generate(self): + items = list(self.treasure_table.keys()) + weights = [self.treasure_table[k] for k in items] + item = random.choices(items, weights=weights)[0] + bonus_stats_max = (self.game.depth + (self.game.player.luck*2)) * 0.66 + bonus_stats = random.randint(0, int(bonus_stats_max)) + bonus_colors = {1: (192, 255, 192), 2: (128, 128, 192), 3: (255, 192, 255), + 4: (255, 192, 192), 5: (255, 0, 0)} + + data = itemdata[item] + if item in ("sword", "sword2", "sword3", "axe", "axe2", "axe3"): + equip = Equippable(hands=data.handedness, sprite=data.sprite, damage=data.base_value+bonus_stats, text=data.base_name) + elif item in ("buckler", "shield"): + equip = Equippable(hands=data.handedness, sprite=data.sprite, defense=data.base_value+bonus_stats, text=data.base_name) + elif item in ("wand", "staff", "staff2"): + equip = Equippable(hands=data.handedness, sprite=data.sprite, zap_damage=data.base_value[0], zap_cooldown=data.base_value[1], text=data.base_name) + if bonus_stats: + b = bonus_stats + while b: # split bonus between damage and faster cooldown + if equip.zap_cooldown == 2 or random.random() > 0.66: + equip.zap_damage += 1 + else: + equip.zap_cooldown -= 1 + b -= 1 + elif item == "red_pot": + equip = Equippable(hands=data.handedness, sprite=data.sprite, hp_healing=data.base_value+bonus_stats, text=data.base_name) + elif item in ("blue_pot", "green_pot", "grey_pot", "sm_grey_pot"): + print(f"Permanent stat boost ({item})") + equip = Equippable(hands=data.handedness, sprite=data.sprite, text=data.base_name, boost=item, value=data.base_value + bonus_stats) + else: + print(f"Unfound item: {item}") + equip = Equippable() + + if bonus_stats: + equip.text = equip.text + f" (+{bonus_stats})" + equip.text_color = bonus_colors[bonus_stats if bonus_stats <=5 else 5] + return equip def bump(self, other, dx, dy, test=False): if type(other) != PlayerEntity: return False if self.popped: print("It's already open.") - return + return True print("Take me, I'm yours!") self._entity.sprite_number = 91 self.popped = True - + #print(self.treasure_table) + other.receive(self.generate()) + return False diff --git a/src/scripts/cos_itemdata.py b/src/scripts/cos_itemdata.py new file mode 100644 index 0000000..55349f0 --- /dev/null +++ b/src/scripts/cos_itemdata.py @@ -0,0 +1,62 @@ +from dataclasses import dataclass + +@dataclass +class ItemData: + min_lv: int + max_lv: int + base_wt: float + sprite: int + base_value: int + base_name: str + affinity: str # player archetype that makes it more common + handedness: int + +itemdata = { + "buckler": ItemData(min_lv = 1, max_lv = 10, base_wt = 0.25, sprite=101, base_value=1, + base_name="Buckler", affinity="knight", handedness=1), + + "shield": ItemData(min_lv = 2, max_lv = 99, base_wt = 0.15, sprite=102, base_value=2, + base_name="Shield", affinity="knight", handedness=1), + + "sword": ItemData(min_lv = 1, max_lv = 10, base_wt = 0.25, sprite=103, base_value=1, + base_name="Shortsword", affinity="knight", handedness=1), + + "sword2": ItemData(min_lv = 2, max_lv = 16, base_wt = 0.15, sprite=104, base_value=2, + base_name="Longsword", affinity="knight", handedness=1), + + "sword3": ItemData(min_lv = 5, max_lv = 99, base_wt = 0.08, sprite=105, base_value=5, + base_name="Claymore", affinity="knight", handedness=2), + + "axe": ItemData(min_lv = 1, max_lv = 10, base_wt = 0.25, sprite=119, base_value=1, + base_name="Hatchet", affinity="viking", handedness=1), + + "axe2": ItemData(min_lv = 2, max_lv = 16, base_wt = 0.15, sprite=120, base_value=4, + base_name="Broad Axe", affinity="viking", handedness=2), + + "axe3": ItemData(min_lv = 5, max_lv = 99, base_wt = 0.08, sprite=121, base_value=6, + base_name="Bearded Axe", affinity="viking", handedness=2), + + "wand": ItemData(min_lv = 1, max_lv = 10, base_wt = 0.25, sprite=132, base_value=(1, 10), + base_name="Wand", affinity="wizard", handedness=1), + + "staff": ItemData(min_lv = 2, max_lv = 16, base_wt = 0.15, sprite=130, base_value=(2, 8), + base_name="Sceptre", affinity="wizard", handedness=2), + + "staff2": ItemData(min_lv = 5, max_lv = 99, base_wt = 0.08, sprite=131, base_value=(3, 7), + base_name="Wizard's Staff", affinity="wizard", handedness=2), + + "red_pot": ItemData(min_lv = 1, max_lv = 99, base_wt = 0.25, sprite=115, base_value=1, + base_name="Health Potion", affinity=None, handedness=0), + + "blue_pot": ItemData(min_lv = 1, max_lv = 99, base_wt = 0.10, sprite=116, base_value=1, + base_name="Sorcery Potion", affinity="wizard", handedness=0), + + "green_pot": ItemData(min_lv = 1, max_lv = 99, base_wt = 0.10, sprite=114, base_value=1, + base_name="Strength Potion", affinity="viking", handedness=0), + + "grey_pot": ItemData(min_lv = 1, max_lv = 99, base_wt = 0.10, sprite=113, base_value=1, + base_name="Defense Potion", affinity="knight", handedness=0), + + "sm_grey_pot": ItemData(min_lv = 1, max_lv = 99, base_wt = 0.05, sprite=125, base_value=1, + base_name="Luck Potion", affinity=None, handedness=0), + } diff --git a/src/scripts/cos_level.py b/src/scripts/cos_level.py index b7509b9..5cb84dd 100644 --- a/src/scripts/cos_level.py +++ b/src/scripts/cos_level.py @@ -105,7 +105,7 @@ class Level: self.height = height #self.graph = [(0, 0, width, height)] self.graph = RoomGraph( (0, 0, width, height) ) - self.grid = mcrfpy.Grid(width, height, t, (10, 10), (1014, 758)) + self.grid = mcrfpy.Grid(width, height, t, (10, 5), (1014, 700)) self.highlighted = -1 #debug view feature self.walled_rooms = [] # for tracking "hallway rooms" vs "walled rooms" @@ -236,18 +236,25 @@ class Level: for f in room_plan: #feature_coords.append((f, room_coord(room, margin=4 if f in ("boulder",) else 1))) # boulders are breaking my brain. If I can't get boulders away from walls with margin, I'm just going to dig them out. - if f == "boulder": - x, y = room_coord(room, margin=0) - if x < 2: x += 1 - if y < 2: y += 1 - if x > self.grid.grid_size[0] - 2: x -= 1 - if y > self.grid.grid_size[1] - 2: y -= 1 - for _x in (1, 0, -1): - for _y in (1, 0, -1): - self.grid.at((x + _x, y + _y)).walkable = True - feature_coords.append((f, (x, y))) - else: - feature_coords.append((f, room_coord(room, margin=0))) + #if f == "boulder": + # x, y = room_coord(room, margin=0) + # if x < 2: x += 1 + # if y < 2: y += 1 + # if x > self.grid.grid_size[0] - 2: x -= 1 + # if y > self.grid.grid_size[1] - 2: y -= 1 + # for _x in (1, 0, -1): + # for _y in (1, 0, -1): + # self.grid.at((x + _x, y + _y)).walkable = True + # feature_coords.append((f, (x, y))) + #else: + # feature_coords.append((f, room_coord(room, margin=0))) + fcoord = None + while not fcoord: + fc = room_coord(room, margin=0) + if not self.grid.at(fc).walkable: continue + if fc in [_i[1] for _i in feature_coords]: continue + fcoord = fc + feature_coords.append((f, fcoord)) print(feature_coords[-1]) ## Hallway generation diff --git a/src/scripts/game.py b/src/scripts/game.py index 6b7fab5..8bee8c9 100644 --- a/src/scripts/game.py +++ b/src/scripts/game.py @@ -1,4 +1,6 @@ import mcrfpy +import code + #t = mcrfpy.Texture("assets/kenney_tinydungeon.png", 16, 16) # 12, 11) t = mcrfpy.Texture("assets/kenney_TD_MR_IP.png", 16, 16) # 12, 11) btn_tex = mcrfpy.Texture("assets/48px_ui_icons-KenneyNL.png", 48, 48) @@ -9,6 +11,7 @@ frame_color = (64, 64, 128) import random import cos_entities as ce import cos_level as cl +from cos_itemdata import itemdata #import cos_tiles as ct class Resources: @@ -53,7 +56,8 @@ class Crypt: self.level_plan = { 1: [("spawn", "button", "boulder"), ("exit")], - 2: [("spawn", "button", "boulder"), ("rat"), ("exit")], + 2: [("spawn", "button", "treasure", "treasure", "treasure", "rat", "rat", "boulder"), ("exit")], + #2: [("spawn", "button", "boulder"), ("rat"), ("exit")], 3: [("spawn", "button", "boulder"), ("rat"), ("exit")], 4: [("spawn", "button", "rat"), ("boulder", "rat", "treasure"), ("exit")], 5: [("spawn", "button", "rat"), ("boulder", "rat"), ("exit")], @@ -99,6 +103,7 @@ class Crypt: mcrfpy.Caption((25, 130 + 95 * i), "x", font, fill_color=(255, 255, 255)) for i in range(5) ] for i in self.inv_captions: + i.size = 16 self.sidebar.children.append(i) liminal_void = mcrfpy.Grid(1, 1, t, (0, 0), (16, 16)) @@ -177,7 +182,11 @@ class Crypt: self.inv_sprites[i].sprite_number = item.sprite if i > 1: self.key_captions[i - 2].sprite_number = 384 + (i - 2) - self.inv_captions[i].text = "Blah" + if item.zap_cooldown_remaining: + self.inv_captions[i].text = f"[{item.zap_cooldown_remaining}] {item.text})" + else: + self.inv_captions[i].text = item.text + self.inv_captions[i].fill_color = item.text_color def lv_planner(self, target_level): """Plan room sequence in levels > 9""" @@ -210,47 +219,27 @@ class Crypt: def treasure_planner(self, treasure_level): """Plan treasure contents at all levels""" - item_minlv = { - "buckler": 1, - "shield": 2, - "sword": 1, - "sword2": 2, - "sword3": 5, - "axe": 1, - "axe2": 2, - "axe3": 5, - "wand": 1, - "staff": 2, - "staff2": 5, - "red_pot": 3, - "blue_pot": 6, - "green_pot": 6, - "grey_pot": 6, - "sm_grey_pot": 1 - } - base_wts = { - ("buckler", "shield"): 0.25, # defensive items - ("sword", "sword2", "axe", "axe2"): 0.4, #1h weapons - ("sword3", "axe3"): 0.25, #2h weapons - ("wand", "staff", "staff2"): 0.15, #magic weapons - ("red_pot",): 0.25, #health - ("blue_pot", "green_pot", "grey_pot", "sm_grey_pot"): 0.2 #stat upgrade potions - } - + # find item name in base_wts key (base weight of the category) - base_weight = lambda s: base_wts[list([t for t in base_wts.keys() if s in t])[0]] - weights = {d[0]: base_weight(d[0]) for d in item_minlv.items() if treasure_level > d[1]} - if self.player.archetype is None: - prefs = [] - elif self.player.archetype == "viking": - prefs = ["axe2", "axe3", "green_pot"] - elif self.player.archetype == "knight": - prefs = ["sword2", "shield", "grey_pot"] - elif self.player.archetype == "wizard": - prefs = ["staff", "staff2", "blue_pot"] - for i in prefs: - if i in weights: weights[i] *= 3 - + #base_weight = lambda s: base_wts[list([t for t in base_wts.keys() if s in t])[0]] + #weights = {d[0]: base_weight(d[0]) for d in item_minlv.items() if treasure_level > d[1]} + #if self.player.archetype is None: + # prefs = [] + #elif self.player.archetype == "viking": + # prefs = ["axe2", "axe3", "green_pot"] + #elif self.player.archetype == "knight": + # prefs = ["sword2", "shield", "grey_pot"] + #elif self.player.archetype == "wizard": + # prefs = ["staff", "staff2", "blue_pot"] + #for i in prefs: + # if i in weights: weights[i] *= 3 + weights = {} + for item in itemdata: + data = itemdata[item] + if data.min_lv > treasure_level or treasure_level > data.max_lv: continue + weights[item] = data.base_wt + if self.player.archetype is not None and data.affinity == self.player.archetype: + weights[item] *= 3 return weights def start(self): @@ -317,10 +306,37 @@ class Crypt: def cos_keys(self, key, state): d = None if state == "end": return + elif key == "Grave": + code.InteractiveConsole(locals=globals()).interact() + return + elif key == "Z": + self.player.do_zap() + self.enemy_turn() + return elif key == "W": d = (0, -1) elif key == "A": d = (-1, 0) elif key == "S": d = (0, 1) elif key == "D": d = (1, 0) + elif key == "Num1": + if len(self.player.inventory) > 0: + self.player.inventory[0].consume(self.player) + self.player.inventory[0] = None + self.enemy_turn() + else: + print("No item") + elif key == "Num2": + if len(self.player.inventory) > 1: + self.player.inventory[1].consume(self.player) + self.player.inventory[1] = None + else: + print("No item") + elif key == "Num3": + if len(self.player.inventory) > 2: + self.player.inventory[2].consume(self.player) + self.player.inventory[2] = None + else: + print("No item") + #elif key == "M": self.level.generate() #elif key == "R": # self.level.reset() @@ -345,8 +361,8 @@ class Crypt: self.enemy_turn() elif key == "X": self.pull_boulder_search() - #else: - # print(key) + else: + print(key) if d: self.entities.sort(key = lambda e: e.draw_order, reverse=False) self.player.try_move(*d) @@ -356,8 +372,13 @@ class Crypt: self.entities.sort(key = lambda e: e.draw_order, reverse=False) for e in self.entities: e.act() + # end of enemy turn = player turn + for i in self.player.equipped: + i.tick() self.gui_update() + + def pull_boulder_search(self): for dx, dy in ( (0, -1), (-1, 0), (1, 0), (0, 1) ): for e in self.entities: @@ -405,9 +426,9 @@ class SweetButton: pos:"Tuple[int, int]", caption:str, font=font, font_size=24, font_color=(255,255,255), font_outline_color=(0, 0, 0), font_outline_width=2, shadow_offset = 8, box_width=200, box_height = 80, shadow_color=(64, 64, 86), box_color=(96, 96, 160), - icon=4, icon_scale=1.75, click=lambda *args: None): + icon=4, icon_scale=1.75, shadow=True, click=lambda *args: None): self.ui = ui - self.shadow_box = mcrfpy.Frame + #self.shadow_box = mcrfpy.Frame x, y = pos # box w/ drop shadow @@ -416,7 +437,8 @@ class SweetButton: self.base_frame.click = self.do_click # drop shadow won't need configured, append directly - self.base_frame.children.append(mcrfpy.Frame(0, 0, box_width, box_height, fill_color = shadow_color)) + if shadow: + self.base_frame.children.append(mcrfpy.Frame(0, 0, box_width, box_height, fill_color = shadow_color)) # main button is where the content lives self.main_button = mcrfpy.Frame(shadow_offset, shadow_offset, box_width, box_height, fill_color = box_color) @@ -472,8 +494,56 @@ class MainMenu: components = [] # demo grid - #components.append( - # ) + self.demo = cl.Level(20, 20) + self.grid = self.demo.grid + self.grid.zoom = 1.75 + coords = self.demo.generate( + [("boulder", "boulder", "rat", "cyclops", "boulder"), ("spawn"), ("rat", "big rat"), ("button", "boulder", "exit")] + ) + self.entities = [] + self.add_entity = lambda e: self.entities.append(e) + #self.create_level = lambda *args: None + buttons = [] + #self.depth = 20 + for k, v in sorted(coords, key=lambda i: i[0]): # "button" before "exit"; "button", "button", "door", "exit" -> alphabetical is correct sequence + if k == "spawn": + self.player = ce.PlayerEntity(game=self) + self.player.draw_pos = v + #if self.player: + # self.add_entity(self.player) + # #self.player.draw_pos = v + # self.spawn_point = v + elif k == "boulder": + ce.BoulderEntity(v[0], v[1], game=self) + elif k == "treasure": + ce.TreasureEntity(v[0], v[1], treasure_table = {}, game=self) + elif k == "button": + buttons.append(v) + elif k == "exit": + btn = buttons.pop(0) + ce.ExitEntity(v[0], v[1], btn[0], btn[1], game=self) + elif k == "rat": + ce.EnemyEntity(*v, game=self) + elif k == "big rat": + ce.EnemyEntity(*v, game=self, base_damage=2, hp=4, sprite=124) + elif k == "cyclops": + ce.EnemyEntity(*v, game=self, base_damage=3, hp=8, sprite=109, base_defense=2, can_push=True, move_cooldown=0) + #self.demo = cl.Level(20, 20) + #self.create_level(self.depth) + for e in self.entities: + self.grid.entities.append(e._entity) + def just_wiggle(*args): + try: + self.player.try_move(*random.choice(((1, 0),(-1, 0),(0, 1),(0, -1)))) + for e in self.entities: + e.act() + except: + pass + mcrfpy.setTimer("demo_motion", just_wiggle, 100) + components.append( + self.demo.grid + ) + # title text drop_shadow = mcrfpy.Caption((150, 10), "Crypt Of Sokoban", font, fill_color=(96, 96, 96), outline_color=(192, 0, 0)) @@ -499,7 +569,7 @@ class MainMenu: # button - PLAY #playbtn = mcrfpy.Frame(284, 548, 456, 120, fill_color = - play_btn = SweetButton(self.ui, (284, 548), "PLAY", box_width=456, box_height=110, icon=1, icon_scale=2.0, click=self.play) + play_btn = SweetButton(self.ui, (20, 248), "PLAY", box_width=200, box_height=110, icon=1, icon_scale=2.0, click=self.play) components.append(play_btn.base_frame) # button - config menu pane @@ -514,16 +584,17 @@ class MainMenu: # button - music toggle music_btn = SweetButton(self.ui, (10+256*2, 678), "Music\nON", icon=12, click=self.music_toggle) - self.music_enabled = True - self.music_volume = 40 + resources.music_enabled = True + resources.music_volume = 40 components.append(music_btn.base_frame) # button - sfx toggle sfx_btn = SweetButton(self.ui, (10+256*3, 678), "SFX\nON", icon=0, click=self.sfx_toggle) - self.sfx_enabled = True - self.sfx_volume = 40 + resources.sfx_enabled = True + resources.sfx_volume = 40 components.append(sfx_btn.base_frame) + [self.ui.append(e) for e in components] def toast_say(self, txt, delay=10): @@ -577,9 +648,9 @@ class MainMenu: def music_toggle(self, sweet_btn, args): if args[3] == "end": return - self.music_enabled = not self.music_enabled - print(f"music: {self.music_enabled}") - if self.music_enabled: + resources.music_enabled = not resources.music_enabled + print(f"music: {resources.music_enabled}") + if resources.music_enabled: mcrfpy.setMusicVolume(self.music_volume) sweet_btn.text = "Music is ON" sweet_btn.sprite_number = 12 @@ -591,9 +662,9 @@ class MainMenu: def sfx_toggle(self, sweet_btn, args): if args[3] == "end": return - self.sfx_enabled = not self.sfx_enabled - print(f"sfx: {self.sfx_enabled}") - if self.sfx_enabled: + resources.sfx_enabled = not resources.sfx_enabled + #print(f"sfx: {resources.sfx_enabled}") + if resources.sfx_enabled: mcrfpy.setSoundVolume(self.sfx_volume) sweet_btn.text = "SFX are ON" sweet_btn.sprite_number = 0