685 lines
28 KiB
Python
685 lines
28 KiB
Python
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)
|
|
font = mcrfpy.Font("assets/JetbrainsMono.ttf")
|
|
|
|
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:
|
|
def __init__(self):
|
|
self.music_enabled = True
|
|
self.music_volume = 40
|
|
self.sfx_enabled = True
|
|
self.sfx_volume = 100
|
|
self.master_volume = 100
|
|
|
|
# load the music/sfx files here
|
|
self.splats = []
|
|
for i in range(1, 10):
|
|
mcrfpy.createSoundBuffer(f"assets/sfx/splat{i}.ogg")
|
|
|
|
|
|
def play_sfx(self, sfx_id):
|
|
if self.sfx_enabled and self.sfx_volume and self.master_volume:
|
|
mcrfpy.setSoundVolume(self.master_volume/100 * self.sfx_volume)
|
|
mcrfpy.playSound(sfx_id)
|
|
|
|
def play_music(self, track_id):
|
|
if self.music_enabled and self.music_volume and self.master_volume:
|
|
mcrfpy.setMusicVolume(self.master_volume/100 * self.music_volume)
|
|
mcrfpy.playMusic(...)
|
|
|
|
resources = Resources()
|
|
|
|
class Crypt:
|
|
def __init__(self):
|
|
mcrfpy.createScene("play")
|
|
self.ui = mcrfpy.sceneUI("play")
|
|
|
|
entity_frame = mcrfpy.Frame(pos=(815, 10), size=(194, 595), fill_color=frame_color)
|
|
inventory_frame = mcrfpy.Frame(pos=(10, 610), size=(800, 143), fill_color=frame_color)
|
|
stats_frame = mcrfpy.Frame(pos=(815, 610), size=(194, 143), fill_color=frame_color)
|
|
|
|
#self.level = cl.Level(30, 23)
|
|
self.entities = []
|
|
self.depth=1
|
|
self.stuck_btn = SweetButton(self.ui, (810, 700), "Stuck", icon=19, box_width=150, box_height = 60, click=self.stuck)
|
|
|
|
self.level_plan = {
|
|
1: [("spawn", "button", "boulder"), ("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")],
|
|
6: {(("spawn", "button"), ("boulder", "treasure", "exit")),
|
|
(("spawn", "boulder"), ("button", "treasure", "exit"))},
|
|
7: {(("spawn", "button"), ("boulder", "treasure", "exit")),
|
|
(("spawn", "boulder"), ("button", "treasure", "exit"))},
|
|
8: {(("spawn", "treasure", "button"), ("boulder", "treasure", "exit")),
|
|
(("spawn", "treasure", "boulder"), ("button", "treasure", "exit"))}
|
|
#9: self.lv_planner
|
|
}
|
|
|
|
# empty void for the player to initialize into
|
|
self.headsup = mcrfpy.Frame(pos=(10, 684), size=(320, 64), fill_color=(0, 0, 0, 0))
|
|
self.sidebar = mcrfpy.Frame(pos=(860, 4), size=(160, 600), fill_color=(96, 96, 160))
|
|
|
|
# Heads Up (health bar, armor bar) config
|
|
self.health_bar = [mcrfpy.Sprite(x=32*i, y=2, texture=t, sprite_index=659, scale=2) for i in range(10)]
|
|
[self.headsup.children.append(i) for i in self.health_bar]
|
|
self.armor_bar = [mcrfpy.Sprite(x=32*i, y=42, texture=t, sprite_index=659, scale=2) for i in range(10)]
|
|
[self.headsup.children.append(i) for i in self.armor_bar]
|
|
# (40, 3), caption, font, fill_color=font_color
|
|
self.stat_captions = mcrfpy.Caption(text="HP:10\nDef:0(+0)", pos=(325,0), font=font, fill_color=(255, 255, 255))
|
|
self.stat_captions.outline = 3
|
|
self.stat_captions.outline_color = (0, 0, 0)
|
|
self.headsup.children.append(self.stat_captions)
|
|
|
|
# Side Bar (inventory, level info) config
|
|
self.level_caption = mcrfpy.Caption(text="Level: 1", pos=(5,5), font=font, fill_color=(255, 255, 255))
|
|
self.level_caption.font_size = 26
|
|
self.level_caption.outline = 3
|
|
self.level_caption.outline_color = (0, 0, 0)
|
|
self.sidebar.children.append(self.level_caption)
|
|
self.inv_sprites = [mcrfpy.Sprite(x=15, y=70 + 95*i, texture=t, sprite_index=659, scale=6.0) for i in range(5)]
|
|
for i in self.inv_sprites:
|
|
self.sidebar.children.append(i)
|
|
self.key_captions = [
|
|
mcrfpy.Sprite(x=75, y=130 + (95*2) + 95 * i, texture=t, sprite_index=384 + i, scale=3.0) for i in range(3)
|
|
]
|
|
for i in self.key_captions:
|
|
self.sidebar.children.append(i)
|
|
self.inv_captions = [
|
|
mcrfpy.Caption(text="x", pos=(25, 130 + 95 * i), font=font, fill_color=(255, 255, 255)) for i in range(5)
|
|
]
|
|
for i in self.inv_captions:
|
|
i.font_size = 16
|
|
self.sidebar.children.append(i)
|
|
|
|
liminal_void = mcrfpy.Grid(grid_size=(1, 1), texture=t, pos=(0, 0), size=(16, 16))
|
|
self.grid = liminal_void
|
|
self.player = ce.PlayerEntity(game=self)
|
|
self.spawn_point = (0, 0)
|
|
|
|
# level creation moves player to the game level at the generated spawn point
|
|
self.create_level(self.depth)
|
|
#self.grid = mcrfpy.Grid(20, 15, t, (10, 10), (1014, 758))
|
|
self.swap_level(self.level, self.spawn_point)
|
|
|
|
# Test Entities
|
|
#ce.BoulderEntity(9, 7, game=self)
|
|
#ce.BoulderEntity(9, 8, game=self)
|
|
#ce.ExitEntity(12, 6, 14, 4, game=self)
|
|
# scene setup
|
|
|
|
## might be done by self.swap_level
|
|
#[self.ui.append(e) for e in (self.grid, self.stuck_btn.base_frame)] # entity_frame, inventory_frame, stats_frame)]
|
|
|
|
self.possibilities = None # track WFC possibilities between rounds
|
|
self.enemies = []
|
|
#mcrfpy.setTimer("enemy_test", self.enemy_movement, 750)
|
|
|
|
#mcrfpy.Frame(x, y, box_width+shadow_offset, box_height, fill_color = (0, 0, 0, 255))
|
|
#Sprite(0, 3, btn_tex, icon, icon_scale)
|
|
|
|
#def enemy_movement(self, *args):
|
|
# for e in self.enemies: e.act()
|
|
|
|
#def spawn_test_rat(self):
|
|
# success = False
|
|
# while not success:
|
|
# x, y = [random.randint(0, i-1) for i in self.grid.grid_size]
|
|
# success = self.grid.at((x,y)).walkable
|
|
# self.enemies.append(ce.EnemyEntity(x, y, game=self))
|
|
|
|
def gui_update(self):
|
|
self.stat_captions.text = f"HP:{self.player.hp}\nDef:{self.player.calc_defense()}(+{self.player.calc_defense() - self.player.base_defense})"
|
|
for i, hs in enumerate(self.health_bar):
|
|
full_hearts = self.player.hp - (i*2)
|
|
empty_hearts = self.player.max_hp - (i*2)
|
|
hs.sprite_number = 659
|
|
if empty_hearts >= 2:
|
|
hs.sprite_number = 208
|
|
if full_hearts >= 2:
|
|
hs.sprite_number = 210
|
|
elif full_hearts == 1:
|
|
hs.sprite_number = 209
|
|
for i, arm_s in enumerate(self.armor_bar):
|
|
full_hearts = self.player.calc_defense() - (i*2)
|
|
arm_s.sprite_number = 659
|
|
if full_hearts >= 2:
|
|
arm_s.sprite_number = 211
|
|
elif full_hearts == 1:
|
|
arm_s.sprite_number = 212
|
|
|
|
#items = self.player.equipped[:] + self.player.inventory[:]
|
|
for i in range(5):
|
|
if i == 0:
|
|
item = self.player.equipped[0] if len(self.player.equipped) > 0 else None
|
|
elif i == 1:
|
|
item = self.player.equipped[1] if len(self.player.equipped) > 1 else None
|
|
elif i == 2:
|
|
item = self.player.inventory[0] if len(self.player.inventory) > 0 else None
|
|
elif i == 3:
|
|
item = self.player.inventory[1] if len(self.player.inventory) > 1 else None
|
|
elif i == 4:
|
|
item = self.player.inventory[2] if len(self.player.inventory) > 2 else None
|
|
if item is None:
|
|
self.inv_sprites[i].sprite_number = 659
|
|
if i > 1: self.key_captions[i - 2].sprite_number = 659
|
|
self.inv_captions[i].text = ""
|
|
continue
|
|
self.inv_sprites[i].sprite_number = item.sprite
|
|
if i > 1:
|
|
self.key_captions[i - 2].sprite_number = 384 + (i - 2)
|
|
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"""
|
|
monsters = (target_level - 6) // 2
|
|
target_rooms = min(int(target_level // 2), 6)
|
|
target_treasure = min(int(target_level // 3), 4)
|
|
rooms = []
|
|
for i in range(target_rooms):
|
|
rooms.append([])
|
|
for o in ("spawn", "boulder", "button", "exit"):
|
|
r = random.randint(0, target_rooms-1)
|
|
rooms[r].append(o)
|
|
monster_table = {
|
|
"rat": int(monsters * 0.8) + 2,
|
|
"big rat": max(int(monsters * 0.2) - 2, 0),
|
|
"cyclops": max(int(monsters * 0.1) - 3, 0)
|
|
}
|
|
monster_table = {k: v for k, v in monster_table.items() if v > 0}
|
|
monster_names = list(monster_table.keys())
|
|
monster_weights = [monster_table[k] for k in monster_names]
|
|
for m in range(monsters):
|
|
r = random.randint(0, target_rooms - 1)
|
|
rooms[r].append(random.choices(monster_names, weights = monster_weights)[0])
|
|
|
|
for t in range(target_treasure):
|
|
r = random.randint(0, target_rooms - 1)
|
|
rooms[r].append("treasure")
|
|
|
|
return rooms
|
|
|
|
def treasure_planner(self, treasure_level):
|
|
"""Plan treasure contents at all levels"""
|
|
|
|
# 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
|
|
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):
|
|
resources.play_sfx(1)
|
|
mcrfpy.setScene("play")
|
|
mcrfpy.keypressScene(self.cos_keys)
|
|
|
|
def add_entity(self, e:ce.COSEntity):
|
|
self.entities.append(e)
|
|
self.entities.sort(key = lambda e: e.draw_order, reverse=False)
|
|
# hack / workaround for grid.entities not interable
|
|
while len(self.grid.entities): # while there are entities on the grid,
|
|
self.grid.entities.pop(0) # remove the 1st ("0th")
|
|
for e in self.entities:
|
|
self.grid.entities.append(e._entity)
|
|
|
|
def create_level(self, depth, _luck = 0):
|
|
#if depth < 3:
|
|
# features = None
|
|
self.level = cl.Level(20, 20)
|
|
self.grid = self.level.grid
|
|
if depth in self.level_plan:
|
|
plan = self.level_plan[depth]
|
|
else:
|
|
plan = self.lv_planner(depth)
|
|
coords = self.level.generate(plan)
|
|
self.entities = []
|
|
if self.player:
|
|
luck = self.player.luck
|
|
else:
|
|
luck = 0
|
|
buttons = []
|
|
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":
|
|
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 = self.treasure_planner(depth + luck), 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=130)
|
|
elif k == "cyclops":
|
|
ce.EnemyEntity(*v, game=self, base_damage=3, hp=8, sprite=109, base_defense=2)
|
|
|
|
#if self.depth > 2:
|
|
#for i in range(10):
|
|
# self.spawn_test_rat()
|
|
|
|
def stuck(self, sweet_btn, args):
|
|
if args[3] == "end": return
|
|
self.create_level(self.depth)
|
|
self.swap_level(self.level, self.spawn_point)
|
|
|
|
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()
|
|
# self.possibilities = None
|
|
#elif key == "T":
|
|
# self.level.split()
|
|
# self.possibilities = None
|
|
#elif key == "Y": self.level.split(single=True)
|
|
#elif key == "U": self.level.highlight(+1)
|
|
#elif key == "I": self.level.highlight(-1)
|
|
#elif key == "O":
|
|
# self.level.wall_rooms()
|
|
# self.possibilities = None
|
|
#elif key == "P": ct.format_tiles(self.grid)
|
|
#elif key == "P":
|
|
#self.possibilities = ct.wfc_pass(self.grid, self.possibilities)
|
|
elif key == "P":
|
|
self.depth += 1
|
|
print(f"Descending: lv {self.depth}")
|
|
self.stuck(None, [1,2,3,4])
|
|
elif key == "Period":
|
|
self.enemy_turn()
|
|
elif key == "X":
|
|
self.pull_boulder_search()
|
|
else:
|
|
print(key)
|
|
if d:
|
|
self.entities.sort(key = lambda e: e.draw_order, reverse=False)
|
|
self.player.try_move(*d)
|
|
self.enemy_turn()
|
|
|
|
def enemy_turn(self):
|
|
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:
|
|
if e.draw_pos.x != self.player.draw_pos.x + dx or e.draw_pos.y != self.player.draw_pos.y + dy: continue
|
|
if type(e) == ce.BoulderEntity:
|
|
self.pull_boulder_move((dx, dy), e)
|
|
return self.enemy_turn()
|
|
else:
|
|
print("No boulder found to pull.")
|
|
|
|
def pull_boulder_move(self, p, target_boulder):
|
|
print(p, target_boulder)
|
|
self.entities.sort(key = lambda e: e.draw_order, reverse=False)
|
|
if self.player.try_move(-p[0], -p[1], test=True):
|
|
old_pos = self.player.draw_pos
|
|
self.player.try_move(-p[0], -p[1])
|
|
target_boulder.do_move(old_pos.x, old_pos.y)
|
|
|
|
def swap_level(self, new_level, spawn_point):
|
|
self.level = new_level
|
|
self.grid = self.level.grid
|
|
self.grid.zoom = 2.0
|
|
# Center the camera on the middle of the grid (pixel coordinates: cells * tile_size / 2)
|
|
gw, gh = self.grid.grid_size
|
|
self.grid.center = (gw * 16 / 2, gh * 16 / 2)
|
|
# TODO, make an entity mover function
|
|
#self.add_entity(self.player)
|
|
self.player.grid = self.grid
|
|
self.player.draw_pos = spawn_point
|
|
#self.grid.entities.append(self.player._entity)
|
|
|
|
# reform UI (workaround to ui collection iterators crashing)
|
|
while len(self.ui) > 0:
|
|
try:
|
|
self.ui.pop(0)
|
|
except:
|
|
pass
|
|
self.ui.append(self.grid)
|
|
self.ui.append(self.stuck_btn.base_frame)
|
|
self.ui.append(self.headsup)
|
|
|
|
self.level_caption.text = f"Level: {self.depth}"
|
|
self.ui.append(self.sidebar)
|
|
self.gui_update()
|
|
|
|
class SweetButton:
|
|
def __init__(self, ui:mcrfpy.UICollection,
|
|
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, shadow=True, click=lambda *args: None):
|
|
self.ui = ui
|
|
#self.shadow_box = mcrfpy.Frame
|
|
x, y = pos
|
|
|
|
# box w/ drop shadow
|
|
self.shadow_offset = shadow_offset
|
|
self.base_frame = mcrfpy.Frame(pos=(x, y), size=(box_width+shadow_offset, box_height), fill_color=(0, 0, 0, 255))
|
|
self.base_frame.click = self.do_click
|
|
|
|
# drop shadow won't need configured, append directly
|
|
if shadow:
|
|
self.base_frame.children.append(mcrfpy.Frame(pos=(0, 0), size=(box_width, box_height), fill_color=shadow_color))
|
|
|
|
# main button is where the content lives
|
|
self.main_button = mcrfpy.Frame(pos=(shadow_offset, shadow_offset), size=(box_width, box_height), fill_color=box_color)
|
|
self.click = click
|
|
self.base_frame.children.append(self.main_button)
|
|
|
|
# main button icon
|
|
self.icon = mcrfpy.Sprite(x=0, y=3, texture=btn_tex, sprite_index=icon, scale=icon_scale)
|
|
self.main_button.children.append(self.icon)
|
|
|
|
# main button caption
|
|
self.caption = mcrfpy.Caption(text=caption, pos=(40, 3), font=font, fill_color=font_color)
|
|
self.caption.font_size = font_size
|
|
self.caption.outline_color=font_outline_color
|
|
self.caption.outline=font_outline_width
|
|
self.main_button.children.append(self.caption)
|
|
|
|
def unpress(self):
|
|
"""Helper func for when graphics changes or glitches make the button stuck down"""
|
|
self.main_button.x, self.main_button.y = (self.shadow_offset, self.shadow_offset)
|
|
|
|
def do_click(self, x, y, mousebtn, event):
|
|
if event == "start":
|
|
self.main_button.x, self.main_button.y = (0, 0)
|
|
elif event == "end":
|
|
self.main_button.x, self.main_button.y = (self.shadow_offset, self.shadow_offset)
|
|
result = self.click(self, (x, y, mousebtn, event))
|
|
if result: # return True from event function to instantly un-pop
|
|
self.main_button.x, self.main_button.y = (self.shadow_offset, self.shadow_offset)
|
|
|
|
@property
|
|
def text(self):
|
|
return self.caption.text
|
|
|
|
@text.setter
|
|
def text(self, value):
|
|
self.caption.text = value
|
|
|
|
@property
|
|
def sprite_number(self):
|
|
return self.icon.sprite_number
|
|
|
|
@sprite_number.setter
|
|
def sprite_number(self, value):
|
|
self.icon.sprite_number = value
|
|
|
|
class MainMenu:
|
|
def __init__(self):
|
|
mcrfpy.createScene("menu")
|
|
self.ui = mcrfpy.sceneUI("menu")
|
|
mcrfpy.setScene("menu")
|
|
self.crypt = None
|
|
|
|
components = []
|
|
# demo grid
|
|
self.demo = cl.Level(20, 20)
|
|
self.grid = self.demo.grid
|
|
self.grid.zoom = 1.75
|
|
# Center the camera on the middle of the grid (pixel coordinates: cells * tile_size / 2)
|
|
gw, gh = self.grid.grid_size
|
|
self.grid.center = (gw * 16 / 2, gh * 16 / 2)
|
|
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(text="Crypt Of Sokoban", pos=(150, 10), font=font, fill_color=(96, 96, 96), outline_color=(192, 0, 0))
|
|
drop_shadow.outline = 3
|
|
drop_shadow.font_size = 64
|
|
components.append(
|
|
drop_shadow
|
|
)
|
|
|
|
title_txt = mcrfpy.Caption(text="Crypt Of Sokoban", pos=(158, 18), font=font, fill_color=(255, 255, 255))
|
|
title_txt.font_size = 64
|
|
components.append(
|
|
title_txt
|
|
)
|
|
|
|
# toast: text over the demo grid that fades out on a timer
|
|
self.toast = mcrfpy.Caption(text="", pos=(150, 400), font=font, fill_color=(0, 0, 0))
|
|
self.toast.font_size = 28
|
|
self.toast.outline = 2
|
|
self.toast.outline_color = (255, 255, 255)
|
|
self.toast_event = None
|
|
components.append(self.toast)
|
|
|
|
# button - PLAY
|
|
#playbtn = mcrfpy.Frame(284, 548, 456, 120, fill_color =
|
|
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
|
|
#self.config = lambda self, sweet_btn, *args: print(f"boop, sweet button {sweet_btn} config {args}")
|
|
config_btn = SweetButton(self.ui, (10, 678), "Settings", icon=2, click=self.show_config)
|
|
components.append(config_btn.base_frame)
|
|
|
|
# button - insta-1080p scaling
|
|
scale_btn = SweetButton(self.ui, (10+256, 678), "Scale up\nto 1080p", icon=15, click=self.scale)
|
|
self.scaled = False
|
|
components.append(scale_btn.base_frame)
|
|
|
|
# button - music toggle
|
|
music_btn = SweetButton(self.ui, (10+256*2, 678), "Music\nON", icon=12, click=self.music_toggle)
|
|
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)
|
|
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):
|
|
"kick off a toast event"
|
|
if self.toast_event is not None:
|
|
mcrfpy.delTimer("toast_timer")
|
|
self.toast.text = txt
|
|
self.toast_event = 350
|
|
self.toast.fill_color = (255, 255, 255, 255)
|
|
self.toast.outline = 2
|
|
self.toast.outline_color = (0, 0, 0, 255)
|
|
mcrfpy.setTimer("toast_timer", self.toast_callback, 100)
|
|
|
|
def toast_callback(self, *args):
|
|
"fade out the toast text"
|
|
self.toast_event -= 5
|
|
if self.toast_event < 0:
|
|
self.toast_event = None
|
|
mcrfpy.delTimer("toast_timer")
|
|
mcrfpy.text = ""
|
|
return
|
|
a = min(self.toast_event, 255)
|
|
self.toast.fill_color = (255, 255, 255, a)
|
|
self.toast.outline_color = (0, 0, 0, a)
|
|
|
|
def show_config(self, sweet_btn, args):
|
|
self.toast_say("Beep, Boop! Configurations will go here.")
|
|
|
|
def play(self, sweet_btn, args):
|
|
#if args[3] == "start": return # DRAMATIC on release action!
|
|
if args[3] == "end": return
|
|
mcrfpy.delTimer("demo_motion") # Clean up the demo timer
|
|
self.crypt = Crypt()
|
|
#mcrfpy.setScene("play")
|
|
self.crypt.start()
|
|
|
|
def scale(self, sweet_btn, args, window_scale=None):
|
|
if args[3] == "end": return
|
|
if not window_scale:
|
|
self.scaled = not self.scaled
|
|
window_scale = 1.3
|
|
else:
|
|
self.scaled = True
|
|
sweet_btn.unpress()
|
|
if self.scaled:
|
|
self.toast_say("Windowed mode only, sorry!\nCheck Settings for for fine-tuned controls.")
|
|
mcrfpy.setScale(window_scale)
|
|
sweet_btn.text = "Scale down\n to 1.0x"
|
|
else:
|
|
mcrfpy.setScale(1.0)
|
|
sweet_btn.text = "Scale up\nto 1080p"
|
|
|
|
def music_toggle(self, sweet_btn, args):
|
|
if args[3] == "end": return
|
|
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
|
|
else:
|
|
self.toast_say("Use your volume keys or\nlook in Settings for a volume meter.")
|
|
mcrfpy.setMusicVolume(0)
|
|
sweet_btn.text = "Music is OFF"
|
|
sweet_btn.sprite_number = 17
|
|
|
|
def sfx_toggle(self, sweet_btn, args):
|
|
if args[3] == "end": return
|
|
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
|
|
else:
|
|
self.toast_say("Use your volume keys or\nlook in Settings for a volume meter.")
|
|
mcrfpy.setSoundVolume(0)
|
|
sweet_btn.text = "SFX are OFF"
|
|
sweet_btn.sprite_number = 17
|
|
|
|
mainmenu = MainMenu()
|