adding files

cc
This commit is contained in:
Benjamín 2020-12-16 20:47:09 +01:00
commit fa3353c471
62 changed files with 3384 additions and 0 deletions

864
Hashi.py Normal file

@ -0,0 +1,864 @@
from hashi_functions import *
import hashi_generator as hg
import hashi_game
import assets.palettes.palette_manager as pm
from menu_effect import Circle_effect
from game_effect import Rectangle_effect
from widget_engine import *
from s_engine import *
import sounds
import pygame
import sys
import json
from pygame.locals import *
# basic config
pygame.mixer.pre_init(48000, -16, 2, 512)
pygame.init()
pygame.mixer.set_num_channels(16)
available = pygame.font.get_fonts()
monitor_size = [pygame.display.Info().current_w, pygame.display.Info().current_h]
font = pygame.font.SysFont('calibri', 60, True)
small_font = pygame.font.SysFont('calibri', 40, True)
tiny_font = pygame.font.SysFont('calibri', 20, True)
Window_size = [600, 650]
Default_size = Window_size
screen = pygame.display.set_mode(Window_size)
display = pygame.Surface((600, 650))
pygame.display.set_caption("Hashi")
pygame.display.set_icon(pygame.image.load("assets/images/general/hashi_logo.png").convert())
clock = pygame.time.Clock()
soundsX = sounds.get_sounds()
def main_menu(screenX, Win_size):
# PREP WORK
# getting setup
with open("assets/saves/setup.json", "r") as f:
setup = json.load(f)
# game variables
game = Game()
game.game_flow["ac"] = True
game.game_flow["custom_string"] = setup["custom_num"]
# next 3 lines for arrow buttons
game.game_flow["dfs"] = ["easy", "medium", "hard", "extreme", "custom"]
game.game_flow["df"] = setup["difficulty"]
game.game_flow["df_change"] = False
game.game_flow["dp"] = [0, 0]
game.game_flow["back_from_game"] = False
game.game_flow["Win_size"] = Win_size
game.game_flow["cut_click"] = False
game.game_flow["change_fs"] = False
# mouse
mouse = Mouse(pygame.mouse.get_pos())
mouse.update(Win_size, Default_size)
# dealing with palettes
palette = pm.Palettes("assets/palettes")
palette.current_palette = setup["palette"]
palette.palette = palette.get_palette()
menu_objects = []
# loading images
play_images = {"idle": pygame.image.load("assets/images/menu/play.png").convert(),
"hover": pygame.image.load("assets/images/menu/play_hover.png").convert()}
# size 200
palette_images = {"idle": pygame.image.load("assets/images/menu/palette.png").convert(),
"hover": pygame.image.load("assets/images/menu/palette_hover.png").convert()}
# size 140
new_game_images = {"idle": pygame.image.load("assets/images/menu/new_game.png").convert(),
"hover": pygame.image.load("assets/images/menu/new_game_hover.png").convert()}
# size 300 150
difficulty_images = {"idle": pygame.image.load("assets/images/menu/template.png").convert(),
"hover": pygame.image.load("assets/images/menu/template_hover.png").convert()}
# size 250 100
right_arrow_images = {"idle": pygame.image.load("assets/images/menu/arrow.png").convert(),
"hover": pygame.image.load("assets/images/menu/arrow_hover.png").convert()}
left_arrow_images = {"idle": pygame.transform.flip(pygame.image.load("assets/images/menu/arrow.png").convert(),
True, False),
"hover": pygame.transform.flip(
pygame.image.load("assets/images/menu/arrow_hover.png").convert(),
True, False)}
# size 100 100
custom_size_images = {"idle": pygame.image.load("assets/images/menu/custom.png").convert(),
"hover": pygame.image.load("assets/images/menu/custom_pressed.png").convert()}
# size 100 100
fs_images = {"idle": pygame.image.load("assets/images/menu/fs.png").convert(),
"hover": pygame.image.load("assets/images/menu/fs_hover.png").convert()}
ms_images = {"idle": pygame.image.load("assets/images/menu/ms.png").convert(),
"hover": pygame.image.load("assets/images/menu/ms_hover.png").convert()}
# size 60 60
menu_objects.append(CircleButton(200, [200, 220], play_images, play, [game, palette, mouse]))
menu_objects.append(CircleButton(200, [440, 20], palette_images, next_palette, [palette]))
menu_objects.append(Button([150, 450], [300, 150], new_game_images, new_game, [game, palette, mouse]))
menu_objects.append(Button([20, 20], [250, 100], difficulty_images, play_click_sound, []))
menu_objects.append(Button([440, 270], [100, 100], right_arrow_images, right_arrow, [game]))
menu_objects.append(Button([60, 270], [100, 100], left_arrow_images, left_arrow, [game]))
menu_objects.append(Button([480, 400], [100, 100], custom_size_images, activate_edit_text, [game], False))
menu_objects.append(Button([20, 570], [60, 60], fs_images, change_fs, [game]))
menu_objects[-1].name = "fs"
menu_objects.append(Button([20, 570], [60, 60], ms_images, change_fs, [game], False))
menu_objects[-1].name = "ms"
difficulty_text = font.render(setup["difficulty"].capitalize(), False, palette.palette["outline-dark"])
# setting up custom text
custom_text = font.render(game.game_flow["custom_string"], False, palette.palette["outline-dark"])
custom_text_hover = font.render(game.game_flow["custom_string"], False, palette.palette["background"])
ct_images = {"idle": create_text_sur(custom_text, [20, 20], [100, 100]),
"hover": create_text_sur(custom_text_hover, [20, 20], [100, 100])}
menu_objects.append(Button([480, 400], [100, 100], ct_images, activate_edit_text, [game], False))
menu_objects[-1].name = "custom_text"
custom_pointer = palette.swap_image(pygame.image.load("assets/images/menu/writing.png").convert(),
"emerald", setup["palette"])
custom_pointer.set_colorkey((0, 0, 0))
# setting up custom
if setup["difficulty"] == "custom":
for item in menu_objects:
if item.on_click == activate_edit_text:
item.active = True
# circle effect
cE = Circle_effect
cE.generate_circles(50, [-50, 50])
cE.generate_circles(50, [480, 600])
# last config
menu_objects, setup = set_palette(setup, palette, setup["palette"], menu_objects, True)
palette.create_cycle()
game.game_flow["setup"] = setup
game.game_flow["screen"] = screenX
# checking tutorial
if setup["tutorial"]:
run_tutorial(screenX, setup, game, palette, mouse)
# game loop
while game.alive:
# checking if returned
if game.game_flow["back_from_game"]:
game.game_flow["back_from_game"] = False
Win_size = game.game_flow["Win_size"]
with open("assets/saves/setup.json", "r") as f:
setup = json.load(f)
game.game_flow["setup"] = setup
# background
display.fill(palette.palette["background"])
pygame.draw.rect(display, palette.palette["outline-shade"], pygame.Rect(180, 0, 240, 650))
pygame.draw.rect(display, palette.palette["outline"], pygame.Rect(200, 0, 200, 650))
# displaying effect
for circle in cE.circles:
circle.move(display, palette)
if cE.timer == 0:
cE.generate_circles(4, [-50, 50])
cE.generate_circles(4, [480, 600])
cE.timer += 10
else:
cE.timer -= 1
# displaying widgets
for widget in menu_objects:
widget.blit(display)
# dealing with difficulty
if game.game_flow["df_change"]:
game.game_flow["df_change"] = False
# dealing with json
setup["difficulty"] = game.game_flow["df"]
with open("assets/saves/setup.json", "w") as f:
json.dump(setup, f, indent=4)
difficulty_text = font.render(setup["difficulty"].capitalize(), False, palette.palette["outline-dark"])
# changing custom edit text
if setup["difficulty"] == "custom":
for item in menu_objects:
if item.on_click == activate_edit_text:
item.active = True
else:
for item in menu_objects:
if item.on_click == activate_edit_text:
item.active = False
display.blit(difficulty_text, [40, 40])
# checking palette
if palette.changed:
palette.changed = False
menu_objects, setup = set_palette(setup, palette, palette.current_palette, menu_objects)
difficulty_text = font.render(setup["difficulty"].capitalize(), False, palette.palette["outline-dark"])
custom_pointer = palette.swap_image(pygame.image.load("assets/images/menu/writing.png").convert(),
"emerald", setup["palette"])
custom_pointer.set_colorkey((0, 0, 0))
game.game_flow["setup"] = setup
# custom pointer
if game.game_flow["ac"] is False:
display.blit(custom_pointer, [480, 350])
# event loop
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit(0)
# keydown
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
pygame.quit()
sys.exit(0)
elif event.key == K_f:
game.fs = not game.fs
if game.fs is False:
Win_size = Default_size
screenX = pygame.display.set_mode(Win_size)
game.game_flow["dp"] = [0, 0]
mouse.mouse_scroll = game.game_flow["dp"]
game.game_flow["Win_size"] = Win_size
game.game_flow["screen"] = screenX
else:
screenX = pygame.display.set_mode(monitor_size, pygame.FULLSCREEN)
d = screenX
ratio = [Default_size[1] / Default_size[0], Default_size[0] / Default_size[1]]
# u chose width or height here
if Default_size[0] > Default_size[1]:
Win_size = [d.get_width(), int(d.get_width() * ratio[0])]
d = d.get_height()
dd = Win_size[1]
game.game_flow["dp"][1] = (d - dd) / 2
mouse.mouse_scroll = game.game_flow["dp"]
else:
Win_size = [int(d.get_height() * ratio[1]), d.get_height()]
d = pygame.display.get_surface().get_width()
dd = Win_size[0]
game.game_flow["dp"][0] = (d - dd) / 2
mouse.mouse_scroll = game.game_flow["dp"]
game.game_flow["Win_size"] = Win_size
game.game_flow["screen"] = screenX
if game.game_flow["ac"]:
# mouse stuff
if event.type == MOUSEMOTION:
mouse.update(Win_size, Default_size)
for widget in menu_objects:
widget.hover_check(mouse.mouse_pos)
# click
if event.type == MOUSEBUTTONDOWN:
for widget in menu_objects:
widget.click_check(mouse.mouse_pos)
if game.game_flow["cut_click"]:
game.game_flow["cut_click"] = False
break
else:
if event.type == MOUSEBUTTONDOWN:
mouse.update(Win_size, Default_size)
game.game_flow["ac"] = True
for widget in menu_objects:
widget.hover_check(mouse.mouse_pos)
soundsX["click"].play()
# checking if num big enough
try:
if int(game.game_flow["custom_string"]) < 2 or len(
game.game_flow["custom_string"]) == 0:
game.game_flow["custom_string"] = "2"
except:
game.game_flow["custom_string"] = "2"
menu_objects, setup = update_text(menu_objects, setup, game, palette)
if event.type == KEYDOWN:
if event.key == K_BACKSPACE:
try:
game.game_flow["custom_string"] = game.game_flow["custom_string"][:-1]
menu_objects, setup = update_text(menu_objects, setup, game, palette)
except:
pass
elif event.key == K_RETURN:
mouse.update(Win_size, Default_size)
game.game_flow["ac"] = True
for widget in menu_objects:
widget.hover_check(mouse.mouse_pos)
soundsX["click"].play()
# checking if num big enough
try:
if int(game.game_flow["custom_string"]) < 2 or len(game.game_flow["custom_string"]) == 0:
game.game_flow["custom_string"] = "2"
except:
game.game_flow["custom_string"] = "2"
menu_objects, setup = update_text(menu_objects, setup, game, palette)
else:
if len(game.game_flow["custom_string"]) < 2:
try:
int(event.unicode)
game.game_flow["custom_string"] += event.unicode
menu_objects, setup = update_text(menu_objects, setup, game, palette)
except:
pass
# checking fs change
if game.game_flow["change_fs"]:
game.game_flow["change_fs"] = False
for obj in menu_objects:
if obj.name in ["fs", "ms"]:
obj.active = not obj.active
game.fs = not game.fs
if game.fs is False:
Win_size = Default_size
screenX = pygame.display.set_mode(Win_size)
game.game_flow["dp"] = [0, 0]
mouse.mouse_scroll = game.game_flow["dp"]
game.game_flow["Win_size"] = Win_size
game.game_flow["screen"] = screenX
else:
screenX = pygame.display.set_mode(monitor_size, pygame.FULLSCREEN)
d = screenX
ratio = [Default_size[1] / Default_size[0], Default_size[0] / Default_size[1]]
# u chose width or height here
if Default_size[0] > Default_size[1]:
Win_size = [d.get_width(), int(d.get_width() * ratio[0])]
d = d.get_height()
dd = Win_size[1]
game.game_flow["dp"][1] = (d - dd) / 2
mouse.mouse_scroll = game.game_flow["dp"]
else:
Win_size = [int(d.get_height() * ratio[1]), d.get_height()]
d = pygame.display.get_surface().get_width()
dd = Win_size[0]
game.game_flow["dp"][0] = (d - dd) / 2
mouse.mouse_scroll = game.game_flow["dp"]
game.game_flow["Win_size"] = Win_size
game.game_flow["screen"] = screenX
# basic loop config
screenX.blit(pygame.transform.scale(display, Win_size), game.game_flow["dp"])
pygame.display.update()
clock.tick(60)
# new_game_btn
def new_game(args):
game = args[0]
palette = args[1]
mouse = args[2]
setup = game.game_flow["setup"]
screenX = game.game_flow["screen"]
setup[setup["difficulty"]] = True
if setup["difficulty"] == "easy":
hashi = hg.Hashi(5)
elif setup["difficulty"] == "medium":
hashi = hg.Hashi(10)
elif setup["difficulty"] == "hard":
hashi = hg.Hashi(15)
elif setup["difficulty"] == "extreme":
hashi = hg.Hashi(20)
elif setup["difficulty"] == "custom":
hashi = hg.Hashi(int(setup["custom_num"]))
else:
sys.exit(55)
hashi.generate_map()
hashi.save(f"assets/maps/{setup['difficulty']}.txt")
soundsX["click"].play()
run_game(screenX, setup, game, palette, mouse, "new")
game.game_flow["cut_click"] = True
# play_btn
def play(args):
game = args[0]
palette = args[1]
mouse = args[2]
setup = game.game_flow["setup"]
screenX = game.game_flow["screen"]
if setup[setup["difficulty"]] is False:
new_game(args)
else:
soundsX["click"].play()
run_game(screenX, setup, game, palette, mouse, "continue")
game.game_flow["cut_click"] = True
# at this point the whole menu is done and the game is ready to be run so here we go
def run_game(screenX, setup, gameMenu, palette, mouse, state):
game = Game()
game.game_flow["dp"] = gameMenu.game_flow["dp"]
game.fs = gameMenu.fs
hashi = None
Win_size = gameMenu.game_flow["Win_size"]
game.game_flow["scroll_length"] = (Win_size[0] - 60) / 2
game.game_flow["quit"] = False
scroll = Scroll([-20, -20])
mid_point_scroll_mouse = [game.game_flow["dp"][0] + (Win_size[0] / 2),
game.game_flow["dp"][1] + (Win_size[1] / 2)]
back_btn = Button([200, 350], [200, 100], get_back_images(palette), go_back, [game])
win_image = get_win_image()
# initing rectangle effect
rE = Rectangle_effect
rE.generate_rects()
# initializing game by state
if state == "new":
hashi = hashi_game.HashiG("file.txt", f"assets/maps/{setup['difficulty']}.txt", palette, mouse)
elif state == "continue":
hashi = hashi_game.HashiG("file.json", f"assets/saves/game_saves/{setup['difficulty']}.json", palette, mouse)
hashi_top_lim = [(hashi.get_length() + 40) - 600, (hashi.get_length() + 40) - 650]
# pre scrolling
scroll.move_scroll_based_on_pos(mouse.get_scrolled(scroll), [600, 650], "both", 40)
scroll.scroll_lim(scroll, [-40, -40], hashi_top_lim)
while game.alive:
# dealing with hashi locked
if hashi.locked:
hashi.on_locked(mouse, scroll)
# background
display.fill(palette.palette["background"])
# dealing with bg effect
for item in rE.rects:
item.move(display, palette)
if rE.timer == 0:
rE.generate_rects(5, [1, 3])
rE.timer = 10
else:
rE.timer -= 1
# dealing with scroll
# not using mouse.mouse_pos because screen size affects
if distance_indicator(pygame.mouse.get_pos(), mid_point_scroll_mouse) > game.game_flow["scroll_length"]:
scroll.move_scroll_based_on_pos(mouse.get_scrolled(scroll), [600, 650], "both", 40)
scroll.scroll_lim(scroll, [-40, -40], hashi_top_lim)
# game
hashi.blit(display, palette, scroll)
# win screen
if hashi.win:
display.blit(win_image, [50, 50])
back_btn.blit(display)
setup[setup["difficulty"]] = False
# event loop
for event in pygame.event.get():
if event.type == QUIT:
# saving before quiting
with open("assets/saves/setup.json", "w") as f:
json.dump(setup, f, indent=4)
if hashi.win is False:
hashi.save(setup)
pygame.quit()
sys.exit(0)
# keydown
if event.type == KEYDOWN:
if hashi.locked is False:
if event.key == K_ESCAPE:
gameMenu.fs = game.fs
gameMenu.game_flow["dp"] = game.game_flow["dp"]
gameMenu.game_flow["back_from_game"] = True
gameMenu.game_flow["Win_size"] = Win_size
game.alive = False
with open("assets/saves/setup.json", "w") as f:
json.dump(setup, f, indent=4)
if hashi.win is False:
hashi.save(setup)
else:
if event.key == K_ESCAPE:
hashi.locked = False
hashi.clear_temp()
hashi.clear_temp_remove()
mouse.update(Win_size, Default_size)
hashi.hover(mouse, scroll)
if event.key == K_f:
game.fs = not game.fs
if game.fs is False:
Win_size = Default_size
screenX = pygame.display.set_mode(Win_size)
game.game_flow["dp"] = [0, 0]
mouse.mouse_scroll = game.game_flow["dp"]
# specifics
mid_point_scroll_mouse = [game.game_flow["dp"][0] + (Win_size[0] / 2),
game.game_flow["dp"][1] + (Win_size[1] / 2)]
game.game_flow["scroll_length"] = (Win_size[0] - 100) / 2
else:
screenX = pygame.display.set_mode(monitor_size, pygame.FULLSCREEN)
d = screenX
ratio = [Default_size[1] / Default_size[0], Default_size[0] / Default_size[1]]
# u chose width or height here
if Default_size[0] > Default_size[1]:
Win_size = [d.get_width(), int(d.get_width() * ratio[0])]
d = d.get_height()
dd = Win_size[1]
game.game_flow["dp"][1] = (d - dd) / 2
else:
Win_size = [int(d.get_height() * ratio[1]), d.get_height()]
d = pygame.display.get_surface().get_width()
dd = Win_size[0]
game.game_flow["dp"][0] = (d - dd) / 2
mouse.mouse_scroll = game.game_flow["dp"]
# specifics
mid_point_scroll_mouse = [game.game_flow["dp"][0] + (Win_size[0] / 2),
game.game_flow["dp"][1] + (Win_size[1] / 2)]
game.game_flow["scroll_length"] = (Win_size[0] - 60) / 2
if hashi.win is False:
if hashi.locked is False:
# mouse stuff
if event.type == MOUSEMOTION:
mouse.update(Win_size, Default_size)
hashi.hover(mouse, scroll)
# click
elif event.type == MOUSEBUTTONDOWN:
hashi.click(mouse, scroll)
if hashi.locked:
soundsX["click"].play()
else:
if event.type == MOUSEMOTION:
mouse.update(Win_size, Default_size)
elif event.type == MOUSEBUTTONDOWN:
hashi.locked = False
hashi.click_on_locked(mouse, scroll)
hashi.check_win()
mouse.update(Win_size, Default_size)
hashi.hover(mouse, scroll)
else:
if event.type == MOUSEMOTION:
mouse.update(Win_size, Default_size)
back_btn.hover_check(mouse.mouse_pos)
elif event.type == MOUSEBUTTONDOWN:
back_btn.click_check(mouse.mouse_pos)
# quiting on back button (same as esc)
if game.game_flow["quit"]:
gameMenu.fs = game.fs
gameMenu.game_flow["dp"] = game.game_flow["dp"]
gameMenu.game_flow["back_from_game"] = True
gameMenu.game_flow["Win_size"] = Win_size
game.alive = False
with open("assets/saves/setup.json", "w") as f:
json.dump(setup, f, indent=4)
# basic loop config
screenX.blit(pygame.transform.scale(display, Win_size), game.game_flow["dp"])
pygame.display.update()
clock.tick(60)
# tutorial
def run_tutorial(screenX, setup, gameMenu, palette, mouse):
game = Game()
game.game_flow["dp"] = gameMenu.game_flow["dp"]
game.fs = gameMenu.fs
Win_size = gameMenu.game_flow["Win_size"]
game.game_flow["scroll_length"] = (Win_size[0] - 60) / 2
game.game_flow["quit"] = False
game.game_flow["tf"] = False # tutorial forward
game.game_flow["t_step"] = 0
scroll = Scroll([-20, -20])
mid_point_scroll_mouse = [game.game_flow["dp"][0] + (Win_size[0] / 2),
game.game_flow["dp"][1] + (Win_size[1] / 2)]
back_btn = Button([200, 350], [200, 100], get_back_images(palette), go_back, [game])
win_image = get_win_image()
# initing rectangle effect
rE = Rectangle_effect
rE.generate_rects()
# initializing tutorial
hashi = hashi_game.HashiG("file.json", f"assets/tutorial/tutorial.json", palette, mouse)
hashi_top_lim = [(hashi.get_length() + 40) - 600, (hashi.get_length() + 40) - 650]
# preparing tutorial circle
tutorial_circle_images, size = get_tutorial_circle_images(math.sqrt(hashi.indent/hashi.indent_default)**1.5)
tutorial_circle = CircleButton(size, [120 - (size/2), 120 - (size/2)],
tutorial_circle_images, move_in_tutorial, [game])
# pre scrolling
scroll.move_scroll_based_on_pos(mouse.get_scrolled(scroll), [600, 650], "both", 40)
scroll.scroll_lim(scroll, [-40, -40], hashi_top_lim)
while game.alive:
# dealing with tutorial
if game.game_flow['tf']:
game.game_flow["tf"] = False
if game.game_flow["t_step"] == 0:
game.game_flow["t_step"] += 1
hashi.click(mouse, scroll)
tutorial_circle.move([0, 240])
tutorial_circle.hover_check(mouse.get_scrolled(scroll))
soundsX["click"].play()
elif game.game_flow["t_step"] == 1:
game.game_flow["t_step"] += 1
hashi.locked = False
hashi.click_on_locked(mouse, scroll)
hashi.check_win()
mouse.update(Win_size, Default_size)
hashi.hover(mouse, scroll)
tutorial_circle.move([240, -240])
tutorial_circle.hover_check(mouse.get_scrolled(scroll))
soundsX["join"].play()
elif game.game_flow["t_step"] == 2:
game.game_flow["t_step"] += 1
hashi.click(mouse, scroll)
tutorial_circle.move([0, -60])
tutorial_circle.hover_check(mouse.get_scrolled(scroll))
soundsX["click"].play()
elif game.game_flow["t_step"] == 3:
game.game_flow["t_step"] += 1
hashi.locked = False
hashi.click_on_locked(mouse, scroll)
hashi.check_win()
mouse.update(Win_size, Default_size)
hashi.hover(mouse, scroll)
tutorial_circle.move([0, -60])
tutorial_circle.hover_check(mouse.get_scrolled(scroll))
soundsX["join"].play()
elif game.game_flow["t_step"] == 4:
game.game_flow["t_step"] += 1
hashi.click(mouse, scroll)
tutorial_circle.move([-240, 0])
tutorial_circle.hover_check(mouse.get_scrolled(scroll))
soundsX["click"].play()
elif game.game_flow["t_step"] == 5:
hashi.locked = False
hashi.click_on_locked(mouse, scroll)
hashi.check_win()
mouse.update(Win_size, Default_size)
hashi.hover(mouse, scroll)
soundsX["join"].play()
tutorial_circle.active = False
# dealing with hashi locked
if hashi.locked:
hashi.on_locked(mouse, scroll)
# background
display.fill(palette.palette["background"])
# dealing with bg effect
for item in rE.rects:
item.move(display, palette)
if rE.timer == 0:
rE.generate_rects(5, [1, 3])
rE.timer = 10
else:
rE.timer -= 1
# dealing with scroll
# not using mouse.mouse_pos because screen size affects
if distance_indicator(pygame.mouse.get_pos(), mid_point_scroll_mouse) > game.game_flow["scroll_length"]:
scroll.move_scroll_based_on_pos(mouse.get_scrolled(scroll), [600, 650], "both", 40)
scroll.scroll_lim(scroll, [-40, -40], hashi_top_lim)
# game
hashi.blit(display, palette, scroll)
# tutorial
tutorial_circle.blit(display, scroll)
# win screen
if hashi.win:
display.blit(win_image, [50, 50])
back_btn.blit(display)
setup["tutorial"] = False
# event loop
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit(0)
# keydown
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
gameMenu.fs = game.fs
gameMenu.game_flow["dp"] = game.game_flow["dp"]
gameMenu.game_flow["back_from_game"] = True
gameMenu.game_flow["Win_size"] = Win_size
game.alive = False
with open("assets/saves/setup.json", "w") as f:
json.dump(setup, f, indent=4)
if event.key == K_f:
game.fs = not game.fs
if game.fs is False:
Win_size = Default_size
screenX = pygame.display.set_mode(Win_size)
game.game_flow["dp"] = [0, 0]
mouse.mouse_scroll = game.game_flow["dp"]
# specifics
mid_point_scroll_mouse = [game.game_flow["dp"][0] + (Win_size[0] / 2),
game.game_flow["dp"][1] + (Win_size[1] / 2)]
game.game_flow["scroll_length"] = (Win_size[0] - 100) / 2
else:
screenX = pygame.display.set_mode(monitor_size, pygame.FULLSCREEN)
d = screenX
ratio = [Default_size[1] / Default_size[0], Default_size[0] / Default_size[1]]
# u chose width or height here
if Default_size[0] > Default_size[1]:
Win_size = [d.get_width(), int(d.get_width() * ratio[0])]
d = d.get_height()
dd = Win_size[1]
game.game_flow["dp"][1] = (d - dd) / 2
else:
Win_size = [int(d.get_height() * ratio[1]), d.get_height()]
d = pygame.display.get_surface().get_width()
dd = Win_size[0]
game.game_flow["dp"][0] = (d - dd) / 2
mouse.mouse_scroll = game.game_flow["dp"]
# specifics
mid_point_scroll_mouse = [game.game_flow["dp"][0] + (Win_size[0] / 2),
game.game_flow["dp"][1] + (Win_size[1] / 2)]
game.game_flow["scroll_length"] = (Win_size[0] - 60) / 2
if hashi.win is False:
if hashi.locked is False:
# mouse stuff
if event.type == MOUSEMOTION:
mouse.update(Win_size, Default_size)
hashi.hover(mouse, scroll)
tutorial_circle.hover_check(mouse.get_scrolled(scroll))
# click
elif event.type == MOUSEBUTTONDOWN:
tutorial_circle.click_check(mouse.get_scrolled(scroll))
else:
if event.type == MOUSEMOTION:
mouse.update(Win_size, Default_size)
tutorial_circle.hover_check(mouse.get_scrolled(scroll))
elif event.type == MOUSEBUTTONDOWN:
tutorial_circle.click_check(mouse.get_scrolled(scroll))
else:
if event.type == MOUSEMOTION:
mouse.update(Win_size, Default_size)
back_btn.hover_check(mouse.mouse_pos)
elif event.type == MOUSEBUTTONDOWN:
back_btn.click_check(mouse.mouse_pos)
# quiting on back button (same as esc)
if game.game_flow["quit"]:
gameMenu.fs = game.fs
gameMenu.game_flow["dp"] = game.game_flow["dp"]
gameMenu.game_flow["back_from_game"] = True
gameMenu.game_flow["Win_size"] = Win_size
game.alive = False
with open("assets/saves/setup.json", "w") as f:
json.dump(setup, f, indent=4)
# basic loop config
screenX.blit(pygame.transform.scale(display, Win_size), game.game_flow["dp"])
pygame.display.update()
clock.tick(60)
main_menu(screen, Window_size)

BIN
assets/images/game/back.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 731 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 352 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 280 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 968 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 805 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 918 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 522 B

BIN
assets/images/menu/fs.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 586 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 509 B

BIN
assets/images/menu/ms.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 590 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 521 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
assets/images/menu/play.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 560 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 370 B

0
assets/maps/custom.txt Normal file

0
assets/maps/easy.txt Normal file

0
assets/maps/extreme.txt Normal file

0
assets/maps/hard.txt Normal file

0
assets/maps/medium.txt Normal file

5
assets/maps/tutorial.txt Normal file

@ -0,0 +1,5 @@
0 1 0 0 0
0 0 0 1 0
0 0 0 0 0
0 3 0 5 1
2 0 0 3 0

@ -0,0 +1,6 @@
{"background": "#59bdf7",
"backgroundShade": "#81ccf7",
"outline": "#268cc7",
"outline-shade": "#2ba0e3",
"addition": "#1575ad",
"outline-dark": "#09517a"}

@ -0,0 +1,6 @@
{"background": "#75ebc2",
"backgroundShade": "#4debb4",
"outline": "#9baba5",
"outline-shade": "#81a195",
"addition": "#07db91",
"outline-dark": "#60716a"}

@ -0,0 +1,6 @@
{"background": "#8818c9",
"backgroundShade": "#8425ba",
"outline": "#dd26e0",
"outline-shade": "#7e38a6",
"addition": "#a716fa",
"outline-dark": "#5b1485"}

@ -0,0 +1,71 @@
import os
import json
import pygame
from itertools import cycle
pygame.init()
class Palettes:
def __init__(self, path):
self.path = path
self.palettes = {}
self.current_palette = "emerald" # set starting palette here
self.load_palettes()
self.palette = self.get_palette()
self.cycle = None
self.changed = False
def load_palettes(self):
current_dir = os.getcwd()
os.chdir(self.path)
files = os.listdir()
files.remove('palette_manager.py')
try:
files.remove("__pycache__")
except:
pass
for file in files:
with open(file, "r") as f:
fileX = json.load(f)
for color in fileX.keys():
fileX[color] = self.rgb(fileX[color])
file = "".join(list(file)[:-5])
self.palettes[file] = fileX
os.chdir(current_dir)
def get_palette(self):
return self.palettes[self.current_palette]
def swap_image(self, image, old_p, new_p):
for color in self.palettes[old_p].keys():
image = swap_color(image, self.palettes[old_p][color], self.palettes[new_p][color])
return image
def create_cycle(self):
names = self.palettes.keys()
self.cycle = cycle(names)
while next(self.cycle) != self.current_palette:
pass
@staticmethod
def rgb(color):
color = color.strip("#")
color = [int(color[i:i+2], 16) for i in range(0, 5, 2)]
return color
def swap_color(imageX, old, new):
image_copy = pygame.Surface(imageX.copy().get_size())
image_copy.fill(new)
imageX.set_colorkey(old)
image_copy.blit(imageX, [0, 0])
return image_copy

@ -0,0 +1,6 @@
{"background": "#c9c5c5",
"backgroundShade": "#a3a0a0",
"outline": "#9e2929",
"outline-shade": "#8f6565",
"addition": "#a83939",
"outline-dark": "#610e0e"}

@ -0,0 +1,6 @@
{"background": "#ff87df",
"backgroundShade": "#f7b2e5",
"outline": "#d94db4",
"outline-shade": "#fe75db",
"addition": "#eb3bbc",
"outline-dark": "#97316b"}

@ -0,0 +1,6 @@
{"background": "#faf9de",
"backgroundShade": "#f2f2df",
"outline": "#c7c689",
"outline-shade": "#ccca5e",
"addition": "#fffd6e",
"outline-dark": "#474731"}

11
assets/saves/default.json Normal file

@ -0,0 +1,11 @@
{
"difficulty": "easy",
"palette": "emerald",
"tutorial": true,
"easy": false,
"medium": false,
"hard": false,
"extreme": false,
"custom": false,
"custom_num": "22"
}

@ -0,0 +1 @@
{}

@ -0,0 +1 @@
{}

@ -0,0 +1 @@
{}

@ -0,0 +1 @@
{}

@ -0,0 +1 @@
{}

11
assets/saves/setup.json Normal file

@ -0,0 +1,11 @@
{
"difficulty": "easy",
"palette": "emerald",
"tutorial": true,
"easy": false,
"medium": false,
"hard": false,
"extreme": false,
"custom": false,
"custom_num": "22"
}

BIN
assets/sounds/click.wav Normal file

Binary file not shown.

BIN
assets/sounds/join.wav Normal file

Binary file not shown.

BIN
assets/sounds/remove.wav Normal file

Binary file not shown.

@ -0,0 +1,239 @@
{
"difficulty": "tutorial",
"connections": [
{
"pos": [
0,
0
],
"bridges": [
{
"bridge_num": 0,
"connection": null
},
{
"bridge_num": 0,
"connection": null
},
{
"bridge_num": 1,
"connection": [
3,
0
]
},
{
"bridge_num": 0,
"connection": null
}
],
"bridge_occupied": 1,
"locked": true
},
{
"pos": [
1,
0
],
"locked": true
},
{
"pos": [
1,
1
],
"bridges": [
{
"bridge_num": 0,
"connection": null
},
{
"bridge_num": 0,
"connection": null
},
{
"bridge_num": 2,
"connection": [
3,
1
]
},
{
"bridge_num": 0,
"connection": null
}
],
"bridge_occupied": 2,
"locked": true
},
{
"pos": [
1,
4
],
"bridges": [
{
"bridge_num": 0,
"connection": null
},
{
"bridge_num": 0,
"connection": null
},
{
"bridge_num": 0,
"connection": null
},
{
"bridge_num": 0,
"connection": null
}
],
"bridge_occupied": 0,
"locked": true
},
{
"pos": [
2,
0
],
"locked": true
},
{
"pos": [
2,
1
],
"locked": true
},
{
"pos": [
3,
0
],
"bridges": [
{
"bridge_num": 0,
"connection": null
},
{
"bridge_num": 0,
"connection": null
},
{
"bridge_num": 0,
"connection": null
},
{
"bridge_num": 1,
"connection": [
0,
0
]
}
],
"bridge_occupied": 1,
"locked": true
},
{
"pos": [
3,
1
],
"bridges": [
{
"bridge_num": 0,
"connection": null
},
{
"bridge_num": 1,
"connection": [
3,
3
]
},
{
"bridge_num": 1,
"connection": [
4,
1
]
},
{
"bridge_num": 2,
"connection": [
1,
1
]
}
],
"bridge_occupied": 4,
"locked": true
},
{
"pos": [
3,
2
],
"locked": true
},
{
"pos": [
3,
3
],
"bridges": [
{
"bridge_num": 1,
"connection": [
3,
1
]
},
{
"bridge_num": 0,
"connection": null
},
{
"bridge_num": 0,
"connection": null
},
{
"bridge_num": 0,
"connection": null
}
],
"bridge_occupied": 1,
"locked": true
},
{
"pos": [
4,
1
],
"bridges": [
{
"bridge_num": 0,
"connection": null
},
{
"bridge_num": 0,
"connection": null
},
{
"bridge_num": 0,
"connection": null
},
{
"bridge_num": 1,
"connection": [
3,
1
]
}
],
"bridge_occupied": 1,
"locked": true
}
]
}

51
game_effect.py Normal file

@ -0,0 +1,51 @@
import pygame
import random
import pygame
import random
class Rectangle_effect:
rects = []
timer = 0
def __init__(self, pos, size, speed, dirs):
self.pos = pos
self.size = size
self.speed = speed
self.dirs = dirs # True for going up False for down
def move(self, display, palette):
sur = pygame.Surface(self.size)
sur.fill(palette.palette["backgroundShade"])
sur.set_alpha(random.randint(100, 200))
display.blit(sur, self.pos)
if self.dirs[0]:
self.pos[1] -= self.speed
elif self.dirs[1]:
self.pos[1] += self.speed
elif self.dirs[2]:
self.pos[0] += self.speed
elif self.dirs[3]:
self.pos[0] -= self.speed
if self.pos[1] < -120 or self.pos[0] > 600 or self.pos[1] > 650 or self.pos[0] < -120:
self.delete(self)
@classmethod
def generate_rects(cls, amount=100, speed_range=None):
if speed_range is None:
speed_range = [1, 4]
for _ in range(amount):
dirs = [0, 0, 0, 0]
dirs[random.randint(0, 3)] = 1
cls.rects.append(Rectangle_effect([random.randint(0, 600), random.randint(0, 650)],
[random.randint(40, 120), random.randint(40, 120)],
random.randint(speed_range[0], speed_range[1]),
dirs))
@classmethod
def delete(cls, circle):
cls.rects.remove(circle)

9
garbage.py Normal file

@ -0,0 +1,9 @@
def get_result(size):
size += 1 # increasing to get away from 0
x = [1 for _ in range(size)]
for i in range(size - 1): # getting original size
x = [sum(x[:i+1]) for i in range(size)]
print(x[-1])
get_result(20)

229
hashi_functions.py Normal file

@ -0,0 +1,229 @@
import json
import pygame
import sounds
# basic config
pygame.mixer.pre_init(48000, -16, 2, 512)
pygame.init()
pygame.mixer.set_num_channels(16)
font = pygame.font.SysFont('calibri', 60, True)
small_font = pygame.font.SysFont('calibri', 40, True)
tiny_font = pygame.font.SysFont('calibri', 20, True)
soundsX = sounds.get_sounds()
def set_palette(setup, palette, name_of_new_palette, menu_objects, first=False):
if first:
old_palette = "emerald"
else:
old_palette = setup["palette"]
palette.current_palette = name_of_new_palette
palette.palette = palette.get_palette()
# saving new json
setup["palette"] = name_of_new_palette
with open("assets/saves/setup.json", "w") as f:
json.dump(setup, f, indent=4)
# iterates over images and sets new palette
for obj in range(len(menu_objects)):
for img in menu_objects[obj].images.keys():
menu_objects[obj].images[img] = palette.swap_image(menu_objects[obj].images[img],
old_palette, name_of_new_palette)
menu_objects[obj].images[img].set_colorkey((0, 0, 0))
menu_objects[obj].display_image = palette.swap_image(menu_objects[obj].display_image,
old_palette, name_of_new_palette)
menu_objects[obj].display_image.set_colorkey((0, 0, 0))
return menu_objects, setup
# function for palette btn
def next_palette(palette):
palette = palette[0]
palette.current_palette = next(palette.cycle)
palette.changed = True
soundsX["click"].play()
# function for right arrow
def right_arrow(game):
game = game[0]
index = game.game_flow["dfs"].index(game.game_flow["df"])
if index != len(game.game_flow["dfs"]) - 1:
game.game_flow["df"] = game.game_flow["dfs"][index + 1]
game.game_flow["df_change"] = True
soundsX["click"].play()
# function for left arrow
def left_arrow(game):
game = game[0]
index = game.game_flow["dfs"].index(game.game_flow["df"])
if index != 0:
game.game_flow["df"] = game.game_flow["dfs"][index - 1]
game.game_flow["df_change"] = True
soundsX["click"].play()
# input
def activate_edit_text(game):
game[0].game_flow["ac"] = False
soundsX["click"].play()
def update_text(menu_objects, setup, game, palette):
custom_text = font.render(game.game_flow["custom_string"], False,
palette.palette["outline-dark"])
custom_text_hover = font.render(game.game_flow["custom_string"], False,
palette.palette["background"])
ct_images = {"idle": create_text_sur(custom_text, [20, 20], [100, 100]),
"hover": create_text_sur(custom_text_hover, [20, 20], [100, 100])}
for image in ct_images.keys():
ct_images[image].set_colorkey((0, 0, 0))
for item in range(len(menu_objects)):
if menu_objects[item].on_click == activate_edit_text:
if menu_objects[item].name == "custom_text":
menu_objects[item].images = ct_images
menu_objects[item].display_image = ct_images["hover"]
# saving json
setup["custom_num"] = game.game_flow["custom_string"]
with open("assets/saves/setup.json", "w") as f:
json.dump(setup, f, indent=4)
return menu_objects, setup
def create_text_sur(text, pos, size):
sur = pygame.Surface(size)
sur.fill((0, 0, 0))
sur.blit(text, pos)
return sur
def get_num_circles(palette, size_multiplier=1):
circle_num = pygame.image.load("assets/images/game/num_circle.png").convert()
circle_num_hover = pygame.image.load("assets/images/game/num_circle_hover.png").convert()
circle_num = palette.swap_image(circle_num, "emerald", palette.current_palette)
circle_num_hover = palette.swap_image(circle_num_hover, "emerald", palette.current_palette)
nums = [tiny_font.render(str(num), False, palette.palette["outline-dark"]) for num in range(1, 9)]
for i in range(len(nums)):
nums[i] = create_text_sur(nums[i], [10, 6], [30, 30])
nums[i].set_colorkey((0, 0, 0))
num_dict = {}
size = 0
for i in range(len(nums)):
cn = circle_num.copy()
cnh = circle_num_hover.copy()
cn.blit(nums[i], [0, 0])
cnh.blit(nums[i], [0, 0])
cn.set_colorkey((0, 0, 0))
cnh.set_colorkey((0, 0, 0))
size = int(30 * size_multiplier)
cn = pygame.transform.scale(cn, [size for _ in range(2)])
cnh = pygame.transform.scale(cnh, [size for _ in range(2)])
num_dict[str(i + 1)] = {"idle": cn,
"hover": cnh}
return num_dict, size
def get_images(palette, size):
circle_num = pygame.image.load("assets/images/game/num_circle.png").convert()
circle_num_hover = pygame.image.load("assets/images/game/num_circle_hover.png").convert()
circle_num = palette.swap_image(circle_num, "emerald", palette.current_palette)
circle_num_hover = palette.swap_image(circle_num_hover, "emerald", palette.current_palette)
nums = [tiny_font.render(str(num), False, palette.palette["backgroundShade"]) for num in range(1, 9)]
for i in range(len(nums)):
nums[i] = create_text_sur(nums[i], [10, 6], [30, 30])
nums[i].set_colorkey((0, 0, 0))
num_dict = {}
for i in range(len(nums)):
cn = circle_num.copy()
cnh = circle_num_hover.copy()
cn.blit(nums[i], [0, 0])
cnh.blit(nums[i], [0, 0])
cn.set_colorkey((0, 0, 0))
cnh.set_colorkey((0, 0, 0))
cn = pygame.transform.scale(cn, [size for _ in range(2)])
cnh = pygame.transform.scale(cnh, [size for _ in range(2)])
num_dict[str(i + 1)] = {"idle": cn,
"hover": cnh}
return num_dict
def get_back_images(palette):
back_images = {"idle": pygame.image.load("assets/images/game/back.png").convert(),
"hover": pygame.image.load("assets/images/game/back_hover.png").convert()}
for image in back_images.keys():
back_images[image] = palette.swap_image(back_images[image], "emerald", palette.current_palette)
back_images[image].set_colorkey((0, 0, 0))
return back_images
def get_win_image():
surf = pygame.Surface([500, 550])
surf.fill((80, 80, 80))
surf.set_alpha(180)
text = font.render("Congratulations!", False, (10, 10, 10))
surf.blit(text, [60, 120])
return surf
def go_back(args):
game = args[0]
game.game_flow["quit"] = True
soundsX["click"].play()
def change_fs(args):
args[0].game_flow["change_fs"] = True
soundsX["click"].play()
def get_tutorial_circle_images(size_multiplier):
tutorial_circle_images = {"idle": pygame.image.load("assets/images/game/tutorial_circle.png").convert(),
"hover": pygame.image.load("assets/images/game/tutorial_circle_hover.png").convert()}
size = int(30 * size_multiplier)
for image in tutorial_circle_images.keys():
tutorial_circle_images[image].set_alpha(120)
tutorial_circle_images[image].set_colorkey((0, 0, 0))
tutorial_circle_images[image] = pygame.transform.scale(tutorial_circle_images[image], [size for _ in range(2)])
return tutorial_circle_images, size
def move_in_tutorial(args):
args[0].game_flow["tf"] = True
def play_click_sound(args):
soundsX["click"].play()

933
hashi_game.py Normal file

@ -0,0 +1,933 @@
import json
import sounds
import widget_engine as wg
from hashi_functions import get_num_circles
from hashi_functions import get_images
import pygame
import math
import copy
pygame.init()
soundsX = sounds.get_sounds()
class HashiG:
def __init__(self, load_from_where, load_path, palette, mouse):
# creating variables
self.map = []
self.size = None
self.indent = 40
self.indent_default = 40
self.node_count = 0
self.win = False
# for nodes
self.locked = False
self.c_node = None
self.temp_done = [0, 0, 0, 0]
self.temp_removed = [0, 0, 0, 0]
self.s_node = None
# loading game
if load_from_where == "file.txt":
self.load_from_file(load_path, palette)
elif load_from_where == "file.json":
self.load_game(load_path, palette, mouse)
self.set_size()
self.line_width = int(self.indent / 12) + 1
def load_from_file(self, path, palette):
with open(path, "r") as f:
file = f.read()
f.close()
file = file.split("\n")
del file[-1]
# init blank map
self.size = len(file)
self.map = [[NodeG([x, y]) for y in range(len(file))] for x in range(len(file))]
self.set_size()
# getting images
images, widget_size = get_num_circles(palette, math.sqrt(self.indent/self.indent_default)**1.5)
switch_images = get_images(palette, widget_size)
# reversing to get back into our format
file = file[::-1]
file = [x.split() for x in file]
for y in range(len(file)):
for x in range(len(file[y])):
node = self.map[x][y]
node.bridge_num = int(file[y][x])
if int(file[y][x]) != 0:
# if its node and not blank
node.locked = True
node.widget = wg.CircleButton(widget_size, [0, 0],
images[file[y][x]], self.lock, [node])
node.widget.switch_images = switch_images[file[y][x]]
self.node_count += 1
def load_game(self, path, palette, mouse):
with open(path, "r") as f:
save = json.load(f)
self.load_from_file(f"assets/maps/{save['difficulty']}.txt", palette)
for connection in save["connections"]:
# also bridge_occupied
if self.map[connection["pos"][0]][connection["pos"][1]].bridge_num != 0:
self.map[connection["pos"][0]][connection["pos"][1]].bridges = connection["bridges"]
self.map[connection["pos"][0]][connection["pos"][1]].bridge_occupied = connection["bridge_occupied"]
self.map[connection["pos"][0]][connection["pos"][1]].locked = connection["locked"]
if self.map[connection["pos"][0]][connection["pos"][1]].bridge_occupied == self.map[connection["pos"][0]][connection["pos"][1]].bridge_num:
if self.map[connection["pos"][0]][connection["pos"][1]].widget is not None:
self.map[connection["pos"][0]][connection["pos"][1]].widget.switch(mouse.mouse_pos)
else:
self.map[connection["pos"][0]][connection["pos"][1]].locked = connection["locked"]
def blit(self, display, palette, scroll):
# grid
for lines in range(self.size):
pygame.draw.line(display, palette.palette["outline-shade"],
[(lines * self.indent) - scroll.scroll[0],
0 - scroll.scroll[1]],
[(lines * self.indent) - scroll.scroll[0],
((self.size - 1) * self.indent) - scroll.scroll[1]], self.line_width)
pygame.draw.line(display, palette.palette["outline-shade"],
[0 - scroll.scroll[0],
(lines * self.indent) - scroll.scroll[1]],
[((self.size - 1) * self.indent) - scroll.scroll[0],
(lines * self.indent) - scroll.scroll[1]], self.line_width)
# connections
for x in range(self.size):
for y in range(self.size):
for connection in self.map[x][y].bridges:
if connection["connection"] is not None:
if connection["bridge_num"] == 1:
node = self.map[x][y]
target = self.map[connection["connection"][0]][connection["connection"][1]]
pygame.draw.line(display, palette.palette["addition"],
[(node.pos[0] * self.indent) - scroll.scroll[0],
(node.pos[1] * self.indent) - scroll.scroll[1]],
[(target.pos[0] * self.indent) - scroll.scroll[0],
(target.pos[1] * self.indent) - scroll.scroll[1]],
self.line_width + 1)
elif connection["bridge_num"] == 2:
node = self.map[x][y]
target = self.map[connection["connection"][0]][connection["connection"][1]]
pygame.draw.line(display, palette.palette["outline-dark"],
[(node.pos[0] * self.indent) - scroll.scroll[0],
(node.pos[1] * self.indent) - scroll.scroll[1]],
[(target.pos[0] * self.indent) - scroll.scroll[0],
(target.pos[1] * self.indent) - scroll.scroll[1]],
int((self.line_width * 1.4) + 1))
# dealing with nodes
for x in range(self.size):
for y in range(self.size):
if self.map[x][y].widget is not None:
node = self.map[x][y]
node.widget.pos = [(node.pos[0] * self.indent) - node.widget.radius,
(node.pos[1] * self.indent) - node.widget.radius]
node.widget.center = [node.widget.pos[0] + node.widget.radius,
node.widget.pos[1] + node.widget.radius]
node.widget.blit(display, scroll)
def hover(self, mouse, scroll):
ms = mouse.get_scrolled(scroll)
for y in range(self.size):
for x in range(self.size):
if self.map[x][y].widget is not None:
self.map[x][y].widget.hover_check(ms)
def click(self, mouse, scroll):
ms = mouse.get_scrolled(scroll)
for y in range(self.size):
for x in range(self.size):
if self.map[x][y].widget is not None:
self.map[x][y].widget.click_check(ms)
def on_locked(self, mouse, scroll):
ms = mouse.get_scrolled(scroll)
cords = self.c_node.pos
dists = [ms[0] - self.c_node.widget.center[0],
ms[1] - self.c_node.widget.center[1]]
da = list(map(abs, dists))
self.clear_temp()
self.clear_temp_remove()
# if we still can add bridges
if self.c_node.bridge_occupied < self.c_node.bridge_num:
# if we move out mouse more on x
if da[0] > da[1]:
if dists[0] > 0:
# here we do in case we move right
self.__right(cords)
else:
# here we do in case we move left
self.__left(cords)
else:
if dists[1] > 0:
# here we do in case we move down
self.__down(cords)
else:
# here we do in case we go up
self.__up(cords)
# removing bridges here
else:
if da[0] > da[1]:
if dists[0] > 0:
# here we do in case we move right
if self.c_node.bridges[2]["bridge_num"] != 2:
for i in range(1, self.size):
if cords[0] + i < self.size:
if self.map[cords[0] + i][cords[1]].locked is False:
pass
else:
if self.map[cords[0] + i][cords[1]].pos == self.c_node.bridges[2]["connection"]:
# connect
self.s_node = self.map[cords[0] + i][cords[1]]
self.c_node.bridges[2]["bridge_num"] -= 1
self.s_node.bridges[3]["bridge_num"] -= 1
if self.c_node.bridges[2]["bridge_num"] == -1:
self.c_node.bridges[2]["bridge_num"] = 0
self.s_node.bridges[3]["bridge_num"] = 0
break
self.temp_removed[2] = 1
if self.c_node.bridges[2]["bridge_num"] == 0:
self.c_node.bridges[2] = {"bridge_num": 0, "connection": True}
self.s_node.bridges[3] = {"bridge_num": 0, "connection": True}
break
else:
if self.c_node.bridges[2]["connection"] is not None and self.map[cords[0] + i][cords[1]].bridge_occupied == 0:
pass
else:
break
else:
break
else:
self.__right(cords)
else:
# here we do in case we move left
if self.c_node.bridges[3]["bridge_num"] != 2:
for i in range(1, self.size):
if cords[0] - i > -1:
if self.map[cords[0] - i][cords[1]].locked is False:
pass
else:
if self.map[cords[0] - i][cords[1]].pos == self.c_node.bridges[3]["connection"]:
# connect
self.s_node = self.map[cords[0] - i][cords[1]]
self.c_node.bridges[3]["bridge_num"] -= 1
self.s_node.bridges[2]["bridge_num"] -= 1
if self.c_node.bridges[3]["bridge_num"] == -1:
self.c_node.bridges[3]["bridge_num"] = 0
self.s_node.bridges[2]["bridge_num"] = 0
break
self.temp_removed[3] = 1
if self.c_node.bridges[3]["bridge_num"] == 0:
self.c_node.bridges[3] = {"bridge_num": 0, "connection": True}
self.s_node.bridges[2] = {"bridge_num": 0, "connection": True}
break
else:
if self.c_node.bridges[3]["connection"] is not None and self.map[cords[0] - i][cords[1]].bridge_occupied == 0:
pass
else:
break
else:
break
else:
self.__left(cords)
else:
if dists[1] > 0:
# here we do in case we move down
if self.c_node.bridges[1]["bridge_num"] != 2:
for i in range(1, self.size):
if cords[1] + i < self.size:
if self.map[cords[0]][cords[1] + i].locked is False:
pass
else:
if self.map[cords[0]][cords[1] + i].pos == self.c_node.bridges[1]["connection"]:
# connect
self.s_node = self.map[cords[0]][cords[1] + i]
self.c_node.bridges[1]["bridge_num"] -= 1
self.s_node.bridges[0]["bridge_num"] -= 1
if self.c_node.bridges[1]["bridge_num"] == -1:
self.c_node.bridges[1]["bridge_num"] = 0
self.s_node.bridges[0]["bridge_num"] = 0
break
self.temp_removed[1] = 1
if self.c_node.bridges[1]["bridge_num"] == 0:
self.c_node.bridges[1] = {"bridge_num": 0, "connection": True}
self.s_node.bridges[0] = {"bridge_num": 0, "connection": True}
break
else:
if self.c_node.bridges[1]["connection"] is not None and self.map[cords[0]][cords[1] + i].bridge_occupied == 0:
pass
else:
break
else:
break
else:
self.__down(cords)
else:
# here we do in case we go up
if self.c_node.bridges[0]["bridge_num"] != 2:
for i in range(1, self.size):
if cords[1] - i > -1:
if self.map[cords[0]][cords[1] - i].locked is False:
pass
else:
if self.map[cords[0]][cords[1] - i].pos == self.c_node.bridges[0]["connection"]:
# connect
self.s_node = self.map[cords[0]][cords[1] - i]
self.c_node.bridges[0]["bridge_num"] -= 1
self.s_node.bridges[1]["bridge_num"] -= 1
if self.c_node.bridges[0]["bridge_num"] == -1:
self.c_node.bridges[0]["bridge_num"] -= 1
self.s_node.bridges[1]["bridge_num"] -= 1
break
self.temp_removed[0] = 1
if self.c_node.bridges[0]["bridge_num"] == 0:
self.c_node.bridges[0] = {"bridge_num": 0, "connection": True}
self.s_node.bridges[1] = {"bridge_num": 0, "connection": True}
break
else:
if self.c_node.bridges[0]["connection"] is not None and self.map[cords[0]][cords[1] - i].bridge_occupied == 0:
pass
else:
break
else:
break
else:
self.__up(cords)
def clear_temp(self):
if self.temp_done.count(1) != 0:
i = self.temp_done.index(1)
self.temp_done[i] = 0
if i == 0:
self.c_node.bridges[0]["bridge_num"] -= 1
self.s_node.bridges[1]["bridge_num"] -= 1
if self.c_node.bridges[0]["bridge_num"] == 0:
self.c_node.bridges[0] = {"bridge_num": 0, "connection": None}
self.s_node.bridges[1] = {"bridge_num": 0, "connection": None}
elif self.c_node.bridges[0]["bridge_num"] == -1:
self.c_node.bridges[0]["bridge_num"] = 2
self.s_node.bridges[1]["bridge_num"] = 2
self.c_node.bridges[0]["connection"] = self.s_node.pos
self.s_node.bridges[1]["connection"] = self.c_node.pos
elif i == 1:
self.c_node.bridges[1]["bridge_num"] -= 1
self.s_node.bridges[0]["bridge_num"] -= 1
if self.c_node.bridges[1]["bridge_num"] == 0:
self.c_node.bridges[1] = {"bridge_num": 0, "connection": None}
self.s_node.bridges[0] = {"bridge_num": 0, "connection": None}
elif self.c_node.bridges[1]["bridge_num"] == -1:
self.c_node.bridges[1]["bridge_num"] = 2
self.s_node.bridges[0]["bridge_num"] = 2
self.c_node.bridges[1]["connection"] = self.s_node.pos
self.s_node.bridges[0]["connection"] = self.c_node.pos
elif i == 2:
self.c_node.bridges[2]["bridge_num"] -= 1
self.s_node.bridges[3]["bridge_num"] -= 1
if self.c_node.bridges[2]["bridge_num"] == 0:
self.c_node.bridges[2] = {"bridge_num": 0, "connection": None}
self.s_node.bridges[3] = {"bridge_num": 0, "connection": None}
elif self.c_node.bridges[2]["bridge_num"] == -1:
self.c_node.bridges[2]["bridge_num"] = 2
self.s_node.bridges[3]["bridge_num"] = 2
self.c_node.bridges[2]["connection"] = self.s_node.pos
self.s_node.bridges[3]["connection"] = self.c_node.pos
elif i == 3:
self.c_node.bridges[3]["bridge_num"] -= 1
self.s_node.bridges[2]["bridge_num"] -= 1
if self.c_node.bridges[3]["bridge_num"] == 0:
self.c_node.bridges[3] = {"bridge_num": 0, "connection": None}
self.s_node.bridges[2] = {"bridge_num": 0, "connection": None}
elif self.c_node.bridges[3]["bridge_num"] == -1:
self.c_node.bridges[3]["bridge_num"] = 2
self.s_node.bridges[2]["bridge_num"] = 2
self.c_node.bridges[3]["connection"] = self.s_node.pos
self.s_node.bridges[2]["connection"] = self.c_node.pos
def clear_temp_remove(self):
if self.temp_removed.count(1) != 0:
i = self.temp_removed.index(1)
self.temp_removed[i] = 0
cords = self.c_node.pos
if i == 0:
for i in range(1, self.size):
if cords[1] - i > -1:
if self.map[cords[0]][cords[1] - i].locked is False:
pass
else:
if self.map[cords[0]][cords[1] - i].pos == self.s_node.pos:
# connect
self.s_node = self.map[cords[0]][cords[1] - i]
self.c_node.bridges[0]["bridge_num"] += 1
self.s_node.bridges[1]["bridge_num"] += 1
if self.c_node.bridges[0]["bridge_num"] == 3:
self.c_node.bridges[0] = {"bridge_num": 0, "connection": None}
self.s_node.bridges[1] = {"bridge_num": 0, "connection": None}
else:
self.c_node.bridges[0]["connection"] = self.s_node.pos
self.s_node.bridges[1]["connection"] = self.c_node.pos
break
else:
if self.c_node.bridges[0]["connection"] is not None and self.map[cords[0]][cords[1] - i].bridge_occupied == 0:
pass
else:
break
else:
break
elif i == 1:
for i in range(1, self.size):
if cords[1] + i < self.size:
if self.map[cords[0]][cords[1] + i].locked is False:
pass
else:
if self.map[cords[0]][cords[1] + i].pos == self.s_node.pos:
# connect
self.s_node = self.map[cords[0]][cords[1] + i]
self.c_node.bridges[1]["bridge_num"] += 1
self.s_node.bridges[0]["bridge_num"] += 1
if self.c_node.bridges[1]["bridge_num"] == 3:
self.c_node.bridges[1] = {"bridge_num": 0, "connection": None}
self.s_node.bridges[0] = {"bridge_num": 0, "connection": None}
else:
self.c_node.bridges[1]["connection"] = self.s_node.pos
self.s_node.bridges[0]["connection"] = self.c_node.pos
break
else:
if self.c_node.bridges[1]["connection"] is not None and self.map[cords[0]][cords[1] + i].bridge_occupied == 0:
pass
else:
break
else:
break
elif i == 2:
for i in range(1, self.size):
if cords[0] + i < self.size:
if self.map[cords[0] + i][cords[1]].locked is False:
pass
else:
if self.map[cords[0] + i][cords[1]].pos == self.s_node.pos:
# connect
self.s_node = self.map[cords[0] + i][cords[1]]
self.c_node.bridges[2]["bridge_num"] += 1
self.s_node.bridges[3]["bridge_num"] += 1
if self.c_node.bridges[2]["bridge_num"] == 3:
self.c_node.bridges[2] = {"bridge_num": 0, "connection": None}
self.s_node.bridges[3] = {"bridge_num": 0, "connection": None}
else:
self.c_node.bridges[2]["connection"] = self.s_node.pos
self.s_node.bridges[3]["connection"] = self.c_node.pos
break
else:
if self.c_node.bridges[2]["connection"] is not None and self.map[cords[0] + i][cords[1]].bridge_occupied == 0:
pass
else:
break
else:
break
elif i == 3:
for i in range(1, self.size):
if cords[0] - i > -1:
if self.map[cords[0] - i][cords[1]].locked is False:
pass
else:
if self.map[cords[0] - i][cords[1]].pos == self.s_node.pos:
# connect
self.s_node = self.map[cords[0] - i][cords[1]]
self.c_node.bridges[3]["bridge_num"] += 1
self.s_node.bridges[2]["bridge_num"] += 1
if self.c_node.bridges[3]["bridge_num"] == 3:
self.c_node.bridges[3] = {"bridge_num": 0, "connection": None}
self.s_node.bridges[2] = {"bridge_num": 0, "connection": None}
else:
self.c_node.bridges[3]["connection"] = self.s_node.pos
self.s_node.bridges[2]["connection"] = self.c_node.pos
break
else:
if self.c_node.bridges[3]["connection"] is not None and self.map[cords[0] - i][cords[1]].bridge_occupied == 0:
pass
else:
break
else:
break
def click_on_locked(self, mouse, scroll):
c = self.c_node
s = self.s_node
temp_done = copy.copy(self.temp_done)
temp_removed = copy.copy(self.temp_removed)
other_removed = self.get_other(temp_removed)
other_done = self.get_other(temp_done)
self.clear_temp()
self.clear_temp_remove()
if temp_done.count(1) != 0:
# connecting
i1 = temp_done.index(1)
i2 = other_done.index(1)
switch = {"c": False,
"s": False}
if c.bridge_occupied == c.bridge_num:
switch["c"] = True
if s.bridge_occupied == s.bridge_num:
switch["s"] = True
c.bridges[i1]["bridge_num"] += 1
s.bridges[i2]["bridge_num"] += 1
c.bridge_occupied += 1
s.bridge_occupied += 1
c.bridges[i1]["connection"] = s.pos
s.bridges[i2]["connection"] = c.pos
if c.bridges[i1]["bridge_num"] > 2:
c.bridges[i1] = {"bridge_num": 0, "connection": None}
s.bridges[i2] = {"bridge_num": 0, "connection": None}
c.bridge_occupied -= 3
s.bridge_occupied -= 3
# playing sound
soundsX["remove"].play()
else:
soundsX["join"].play()
if c.bridge_occupied == c.bridge_num or switch["c"]:
c.widget.switch(mouse.get_scrolled(scroll))
if s.bridge_occupied == s.bridge_num or switch["s"]:
s.widget.switch(mouse.get_scrolled(scroll))
# locking
if temp_done[1]:
for i in range(c.pos[1] + 1, s.pos[1]):
if c.bridges[1]["connection"] is not None:
self.map[c.pos[0]][i].locked = True
else:
self.map[c.pos[0]][i].locked = False
elif temp_done[0]:
for i in range(s.pos[1] + 1, c.pos[1]):
if c.bridges[0]["connection"] is not None:
self.map[s.pos[0]][i].locked = True
else:
self.map[s.pos[0]][i].locked = False
elif temp_done[2]:
for i in range(c.pos[0] + 1, s.pos[0]):
if c.bridges[2]["connection"] is not None:
self.map[i][c.pos[1]].locked = True
else:
self.map[i][c.pos[1]].locked = False
elif temp_done[3]:
for i in range(s.pos[0] + 1, c.pos[0]):
if c.bridges[3]["connection"] is not None:
self.map[i][s.pos[1]].locked = True
else:
self.map[i][s.pos[1]].locked = False
elif temp_removed.count(1) != 0:
# connecting
i1 = temp_removed.index(1)
i2 = other_removed.index(1)
switch = {"c": False,
"s": False}
if c.bridge_occupied == c.bridge_num:
switch["c"] = True
if s.bridge_occupied == s.bridge_num:
switch["s"] = True
c.bridges[i1]["bridge_num"] -= 1
s.bridges[i2]["bridge_num"] -= 1
c.bridge_occupied -= 1
s.bridge_occupied -= 1
c.bridges[i1]["connection"] = s.pos
s.bridges[i2]["connection"] = c.pos
if c.bridges[i1]["bridge_num"] == 0:
c.bridges[i1]["connection"] = None
s.bridges[i2]["connection"] = None
if switch["c"]:
c.widget.switch(mouse.get_scrolled(scroll))
if switch["s"]:
s.widget.switch(mouse.get_scrolled(scroll))
# locking
if temp_removed[1]:
for i in range(c.pos[1] + 1, s.pos[1]):
if c.bridges[1]["connection"] is not None:
self.map[c.pos[0]][i].locked = True
else:
self.map[c.pos[0]][i].locked = False
elif temp_removed[0]:
for i in range(s.pos[1] + 1, c.pos[1]):
if c.bridges[0]["connection"] is not None:
self.map[s.pos[0]][i].locked = True
else:
self.map[s.pos[0]][i].locked = False
elif temp_removed[2]:
for i in range(c.pos[0] + 1, s.pos[0]):
if c.bridges[2]["connection"] is not None:
self.map[i][c.pos[1]].locked = True
else:
self.map[i][c.pos[1]].locked = False
elif temp_removed[3]:
for i in range(s.pos[0] + 1, c.pos[0]):
if c.bridges[3]["connection"] is not None:
self.map[i][s.pos[1]].locked = True
else:
self.map[i][s.pos[1]].locked = False
# playing sound
soundsX["remove"].play()
def check_win(self):
node_done_count = 0
test_node = None
for line in self.map:
for item in line:
if item.bridge_num > 0:
if item.bridge_num == item.bridge_occupied:
node_done_count += 1
test_node = item
if node_done_count == self.node_count:
# checking if all connected
nodes_to_do = [test_node]
nodes_to_remove = []
appending = []
while len(nodes_to_do) != 0:
# making them done
for node in nodes_to_do:
node.check_for_win = True
for node in nodes_to_do:
for connection in node.bridges:
if connection["connection"] is not None:
if self.map[connection["connection"][0]][connection["connection"][1]].check_for_win is False:
appending.append(self.map[connection["connection"][0]][connection["connection"][1]])
nodes_to_remove.append(node)
for node in appending:
nodes_to_do.append(node)
appending = []
for node in nodes_to_remove:
nodes_to_do.remove(node)
nodes_to_remove = []
win = True
for line in self.map:
for item in line:
if item.bridge_num > 0:
if item.check_for_win is False:
win = False
if win:
self.win = True
else:
for line in self.map:
for item in line:
item.check_for_win = False
def save(self, setup):
save = {"difficulty": setup["difficulty"]}
connections = []
for line in self.map:
for node in line:
if node.locked is True:
if node.bridge_num != 0:
connections.append({"pos": node.pos,
"bridges": node.bridges,
"bridge_occupied": node.bridge_occupied,
"locked": node.locked})
else:
connections.append({"pos": node.pos,
"locked": node.locked})
save["connections"] = connections
with open(f"assets/saves/game_saves/{setup['difficulty']}.json", "w") as f:
json.dump(save, f, indent=4)
def print_nodes(self):
print("_" * 20)
for line in self.map:
for item in line:
if item.bridge_num > 0:
print(f"| Node at pos {item.widget.pos}, map pos {item.pos}, bridge_num {item.bridge_num}"
f" with {item.bridge_occupied} occupied bridges. |")
print("_" * 20)
# technical stuff not used inside class
def set_size(self):
if self.size <= 15:
self.indent = (15 / self.size) * 40
def get_length(self):
return self.indent * (self.size - 1)
def lock(self, args):
self.locked = True
self.c_node = args[0]
# technical stuff used inside class
def __down(self, cords):
for i in range(1, self.size):
if cords[1] + i < self.size:
if self.map[cords[0]][cords[1] + i].locked is False:
pass
else:
if self.map[cords[0]][cords[1] + i].bridge_occupied < self.map[cords[0]][
cords[1] + i].bridge_num or (
self.c_node.bridges[1]["bridge_num"] == 2 and self.map[cords[0]][cords[1] + i].pos ==
self.c_node.bridges[1]["connection"]):
# connect
self.s_node = self.map[cords[0]][cords[1] + i]
self.c_node.bridges[1]["bridge_num"] += 1
self.s_node.bridges[0]["bridge_num"] += 1
self.temp_done[1] = 1
if self.c_node.bridges[1]["bridge_num"] == 3:
self.c_node.bridges[1] = {"bridge_num": 0, "connection": None}
self.s_node.bridges[0] = {"bridge_num": 0, "connection": None}
else:
self.c_node.bridges[1]["connection"] = self.s_node.pos
self.s_node.bridges[0]["connection"] = self.c_node.pos
break
else:
if self.c_node.bridges[1]["connection"] is not None and self.map[cords[0]][
cords[1] + i].bridge_occupied == 0:
pass
else:
break
else:
break
def __up(self, cords):
for i in range(1, self.size):
if cords[1] - i > -1:
if self.map[cords[0]][cords[1] - i].locked is False:
pass
else:
if self.map[cords[0]][cords[1] - i].bridge_occupied < self.map[cords[0]][
cords[1] - i].bridge_num or (
self.c_node.bridges[0]["bridge_num"] == 2 and self.map[cords[0]][cords[1] - i].pos ==
self.c_node.bridges[0]["connection"]):
# connect
self.s_node = self.map[cords[0]][cords[1] - i]
self.c_node.bridges[0]["bridge_num"] += 1
self.s_node.bridges[1]["bridge_num"] += 1
self.temp_done[0] = 1
if self.c_node.bridges[0]["bridge_num"] == 3:
self.c_node.bridges[0] = {"bridge_num": 0, "connection": None}
self.s_node.bridges[1] = {"bridge_num": 0, "connection": None}
else:
self.c_node.bridges[0]["connection"] = self.s_node.pos
self.s_node.bridges[1]["connection"] = self.c_node.pos
break
else:
if self.c_node.bridges[0]["connection"] is not None and self.map[cords[0]][
cords[1] - i].bridge_occupied == 0:
pass
else:
break
else:
break
def __right(self, cords):
for i in range(1, self.size):
if cords[0] + i < self.size:
if self.map[cords[0] + i][cords[1]].locked is False:
pass
else:
if self.map[cords[0] + i][cords[1]].bridge_occupied < self.map[cords[0] + i][
cords[1]].bridge_num or (
self.c_node.bridges[2]["bridge_num"] == 2 and self.map[cords[0] + i][cords[1]].pos ==
self.c_node.bridges[2]["connection"]):
# connect
self.s_node = self.map[cords[0] + i][cords[1]]
self.c_node.bridges[2]["bridge_num"] += 1
self.s_node.bridges[3]["bridge_num"] += 1
self.temp_done[2] = 1
if self.c_node.bridges[2]["bridge_num"] == 3:
self.c_node.bridges[2] = {"bridge_num": 0, "connection": None}
self.s_node.bridges[3] = {"bridge_num": 0, "connection": None}
else:
self.c_node.bridges[2]["connection"] = self.s_node.pos
self.s_node.bridges[3]["connection"] = self.c_node.pos
break
else:
if self.c_node.bridges[2]["connection"] is not None and self.map[cords[0] + i][
cords[1]].bridge_occupied == 0:
pass
else:
break
else:
break
def __left(self, cords):
for i in range(1, self.size):
if cords[0] - i > -1:
if self.map[cords[0] - i][cords[1]].locked is False:
pass
else:
if self.map[cords[0] - i][cords[1]].bridge_occupied < self.map[cords[0] - i][
cords[1]].bridge_num or (
self.c_node.bridges[3]["bridge_num"] == 2 and self.map[cords[0] - i][cords[1]].pos ==
self.c_node.bridges[3]["connection"]):
# connect
self.s_node = self.map[cords[0] - i][cords[1]]
self.c_node.bridges[3]["bridge_num"] += 1
self.s_node.bridges[2]["bridge_num"] += 1
self.temp_done[3] = 1
if self.c_node.bridges[3]["bridge_num"] == 3:
self.c_node.bridges[3] = {"bridge_num": 0, "connection": None}
self.s_node.bridges[2] = {"bridge_num": 0, "connection": None}
else:
self.c_node.bridges[3]["connection"] = self.s_node.pos
self.s_node.bridges[2]["connection"] = self.c_node.pos
break
else:
if self.c_node.bridges[3]["connection"] is not None and self.map[cords[0] - i][
cords[1]].bridge_occupied == 0:
pass
else:
break
else:
break
@staticmethod
def get_other(temp):
second = [0, 0, 0, 0]
if temp[0]:
second[1] = 1
elif temp[1]:
second[0] = 1
elif temp[2]:
second[3] = 1
elif temp[3]:
second[2] = 1
return second
class NodeG:
def __init__(self, pos, bridge_num=0):
self.pos = pos
self.bridge_occupied = 0
self.bridge_num = bridge_num
self.locked = False
self.widget = None
self.check_for_win = False
self.bridges = [{"bridge_num": 0, "connection": None} for _ in range(4)] # down, up, right, left

232
hashi_generator.py Normal file

@ -0,0 +1,232 @@
import random
class Hashi:
def __init__(self, size):
if size < 2:
size = 2
print("Size cant be 1 or lower.")
self.size = size
self.node_limit_lower = size # lower limit
self.node_upper_limit = int(size ** 1.4) + 1 # upper limit
self.node_count = 0
self.low_lim = 0
self.high_lim = size
self.map = [[Node([x, y]) for y in range(size)] for x in range(size)]
def generate_map(self):
# down, up, right, left
first = [random.randint(0, self.size-1), random.randint(0, self.size-1)]
self.node_count += 1
node = self.get_node(first)
self.write_node(node)
nodes_to_do = self.get_new_nodes(node)
while len(nodes_to_do) != 0:
for n in nodes_to_do:
node = self.get_node(n)
self.write_node(node)
nodes_to_do = nodes_to_do + self.get_new_nodes(node)
nodes_to_do.remove(n)
def get_node(self, cords):
ways = [0, 0, 0, 0] # down, up, right, left
possibilities = 0
if self.node_count >= self.node_upper_limit:
node = {"ways": [0, 0, 0, 0],
"num_of_bridges": [random.randint(1, 2) for _ in range(4)],
"pos": cords}
return node
if cords[1] - 1 > -1 and self.map[cords[0]][cords[1] - 1].locked is False:
ways[0] += 1
possibilities += 1
if cords[1] + 1 < self.size and self.map[cords[0]][cords[1] + 1].locked is False:
ways[1] += 1
possibilities += 1
if cords[0] + 1 < self.size and self.map[cords[0] + 1][cords[1]].locked is False:
ways[2] += 1
possibilities += 1
if cords[0] - 1 > -1 and self.map[cords[0] - 1][cords[1]].locked is False:
ways[3] += 1
possibilities += 1
if possibilities:
attempts = [x+1 if random.randint(0, 1) == 0 else x for x in ways]
# making the puzzle forcefully bigger
if self.node_count < self.node_limit_lower:
while 2 not in attempts:
attempts = [x + 1 if random.randint(0, 1) == 0 else x for x in ways]
# getting the starting distances
distances = [1 if x > 1 else 0 for x in attempts]
# getting possible distance up to 6
if attempts[0] > 1:
for i in range(2, self.size):
if cords[1] - i > -1 and self.map[cords[0]][cords[1] - i].locked is False:
distances[0] += 1
else:
break
if attempts[1] > 1:
for i in range(2, self.size):
if cords[1]+i < self.size and self.map[cords[0]][cords[1]+i].locked is False:
distances[1] += 1
else:
break
if attempts[2] > 1:
for i in range(2, self.size):
if cords[0] + i < self.size and self.map[cords[0]+i][cords[1]].locked is False:
distances[2] += 1
else:
break
if attempts[3] > 1:
for i in range(2, self.size):
if cords[0] - i > -1 and self.map[cords[0] - i][cords[1]].locked is False:
distances[3] += 1
else:
break
final_decision = [random.randint(1, x)if x != 0 else 0 for x in distances]
node = {"ways": final_decision,
"num_of_bridges": [random.randint(1, 2) for _ in range(4)],
"pos": cords}
return node
else:
node = {"ways": [0, 0, 0, 0],
"num_of_bridges": [random.randint(1, 2) for _ in range(4)],
"pos": cords}
return node
def write_node(self, node):
pos = node["pos"]
i = 0
sum_of_bridges = 0
for item in node["ways"]:
if item != 0:
sum_of_bridges += node["num_of_bridges"][i]
# adding the bridges to new nodes
if i == 0:
self.map[pos[0]][pos[1] - item].bridge_num += node["num_of_bridges"][i]
elif i == 1:
self.map[pos[0]][pos[1] + item].bridge_num += node["num_of_bridges"][i]
elif i == 2:
self.map[pos[0] + item][pos[1]].bridge_num += node["num_of_bridges"][i]
elif i == 3:
self.map[pos[0] - item][pos[1]].bridge_num += node["num_of_bridges"][i]
i += 1
self.map[pos[0]][pos[1]].locked = True
self.map[pos[0]][pos[1]].bridge_num += sum_of_bridges
def get_new_nodes(self, node):
pos = node["pos"]
# down, up, right, left
nodes_to_send = []
for nodeX in range(1, node["ways"][0]+1):
self.map[pos[0]][pos[1] - nodeX].locked = True
if nodeX == node["ways"][0]:
nodes_to_send.append(self.map[pos[0]][pos[1] - nodeX].pos)
for nodeX in range(1, node["ways"][1]+1):
self.map[pos[0]][pos[1] + nodeX].locked = True
if nodeX == node["ways"][1]:
nodes_to_send.append(self.map[pos[0]][pos[1] + nodeX].pos)
for nodeX in range(1, node["ways"][2]+1):
self.map[pos[0] + nodeX][pos[1]].locked = True
if nodeX == node["ways"][2]:
nodes_to_send.append(self.map[pos[0] + nodeX][pos[1]].pos)
for nodeX in range(1, node["ways"][3]+1):
self.map[pos[0] - nodeX][pos[1]].locked = True
if nodeX == node["ways"][3]:
nodes_to_send.append(self.map[pos[0] - nodeX][pos[1]].pos)
self.node_count += len(nodes_to_send)
return nodes_to_send
def save(self, path):
final_string = ""
for y in range(self.size):
for x in range(self.size):
final_string += str(self.map[x][y].bridge_num) + " "
final_string += "\n"
with open(path, "w") as f:
f.write(final_string)
f.close()
def print(self, bridges=False):
final_string = "_" * ((self.size * 2) + 3) + "\n"
for y in range(self.size):
final_string += "| "
for x in range(self.size):
if bridges is False:
final_string += str(self.map[x][y].bridge_num) + " "
else:
final_string += f" |* {self.map[x][y].bridge_num} *,{str(self.map[x][y].locked)[0]}| "
final_string += "|\n"
final_string += "¯" * ((self.size * 2) + 3)
print(final_string)
def __len__(self):
return self.node_count
def __str__(self):
final_string = "_" * ((self.size*2)+3) + "\n"
for y in range(self.size):
final_string += "| "
for x in range(self.size):
final_string += str(self.map[x][y].bridge_num) + " "
final_string += "|\n"
final_string += "¯" * ((self.size*2)+3)
return final_string
def __add__(self, other):
return self.node_count + other.node_count
class Node:
def __init__(self, pos, bridge_num=0):
self.pos = pos
self.bridge_num = bridge_num
self.locked = False

50
menu_effect.py Normal file

@ -0,0 +1,50 @@
import pygame
import random
class Circle_effect:
circles = []
timer = 0
def __init__(self, pos, radius, speed, vertical):
self.pos = pos
self.radius = radius
self.speed = speed
self.vertical = vertical # True for going up False for down
def move(self, display, palette, horizontal=False):
sur = pygame.Surface((self.radius * 2, self.radius * 2))
pygame.draw.circle(sur, palette.palette["addition"], [self.radius, self.radius], self.radius)
sur.set_alpha(random.randint(100, 200))
sur.set_colorkey((0, 0, 0))
display.blit(sur, self.pos)
if self.vertical:
if horizontal:
self.pos[0] -= self.speed
else:
self.pos[1] -= self.speed
else:
if horizontal:
self.pos[0] += self.speed
else:
self.pos[1] += self.speed
if self.pos[1] < -100 or self.pos[0] > 700 or self.pos[1] > 700 or self.pos[0] < -100:
self.delete(self)
@classmethod
def generate_circles(cls, amount=100, y_lim=None):
if y_lim is None:
y_lim = [0, 100]
for _ in range(amount):
cls.circles.append(Circle_effect([random.randint(y_lim[0], y_lim[1]), random.randint(0, 650)],
random.randint(20, 50), random.randint(1, 4),
[True if x == 1 else False for x in [random.randint(0, 1)]][0]))
@classmethod
def delete(cls, circle):
cls.circles.remove(circle)

527
s_engine.py Normal file

@ -0,0 +1,527 @@
import pygame
import sys
import time
import random
import math
import copy
from pygame.locals import *
pygame.init()
# has attributes for basic thing in game
class Game:
def __init__(self, game_maps=None):
self.alive = True
# fs = fullscreen
self.fs = False
self.custom_id_giver = 0
self.game_flow = {}
self.game_maps = None
# checks if there are any maps if there are puts them in self.game_maps
if game_maps is not None:
self.game_maps = game_maps
# stores objects in a sorted way
class Objects:
def __init__(self):
self.game_objects = []
self.collision_objects = []
self.moving_objects = []
# dunno if next att will be useful
# u add ids of objects u want to delete there is no func to delete for now
self.objects_to_delete = []
self.values = {
"pos_to_del": []
}
def do_collisions(self, objects):
for obj in self.collision_objects:
collision(obj, objects)
def take_out_trash(self, ids):
for trash in self.objects_to_delete:
ids.ids_to_remove.append(trash)
self.objects_to_delete = []
# Id class just stores all ids of all objects
class Id:
all_ids = []
ids_to_remove = []
def remove_by_id(self, objects):
for item in self.ids_to_remove:
for obj in objects.game_objects:
if obj.object_id == item:
g_index = objects.game_objects.index(obj)
if obj.moving:
m_index = objects.moving_objects.index(obj)
if obj.move.collisions:
c_index = objects.collision_objects.index(obj)
del objects.collision_objects[c_index]
del objects.moving_objects[m_index]
del objects.game_objects[g_index]
self.ids_to_remove = []
class Scroll:
def __init__(self, scroll):
self.scroll = scroll
self.fade = 20
self.safe_fade = 20
self.in_progress = False
self.save_scroll = self.scroll
def move_scroll(self, player, screen, which, space=20):
if which == "y" or which == "both":
self.scroll[1] += (player.rect.y - self.scroll[1] - (screen[1] / 2) + (player.size[1] / 2)) / space
self.scroll[1] = int(self.scroll[1])
if which == "x" or which == "both":
self.scroll[0] += (player.rect.x - self.scroll[0] - (screen[0] / 2) + (player.size[0] / 2)) / space
self.scroll[0] = int(self.scroll[0])
def add_scroll(self, which, how_much, fade=None):
if fade is not None:
self.safe_fade = fade
if self.in_progress is False:
self.load_safe_fade()
self.save_scroll = self.scroll
self.in_progress = True
how_much[0] /= self.fade
how_much[1] /= self.fade
self.fade += 0.01 * self.fade
if which == "x" or which == "both":
self.scroll[0] += how_much[0]
self.scroll[0] = round(self.scroll[0])
if which == "y" or which == "both":
self.scroll[1] += how_much[1]
self.scroll[1] = round(self.scroll[1])
def load_safe_fade(self):
self.fade = self.safe_fade
self.in_progress = False
# next function is used for mouse scrolling mainly
def move_scroll_based_on_pos(self, pos, screen, which, space=20):
# id used for mouse u can first check mouse pos from mid to create non moving bubble in middle
if which == "y" or which == "both":
self.scroll[1] += (pos[1] - self.scroll[1] - (screen[1] / 2)) / space
self.scroll[1] = int(self.scroll[1])
if which == "x" or which == "both":
self.scroll[0] += (pos[0] - self.scroll[0] - (screen[0] / 2)) / space
self.scroll[0] = int(self.scroll[0])
# for limiting scroll
@staticmethod
def scroll_lim(scroll, lim_min, lim_max):
# min lim has priority
if lim_min[0] < lim_max[0]:
if scroll.scroll[0] < lim_min[0]:
scroll.scroll[0] = lim_min[0]
if scroll.scroll[0] > lim_max[0]:
scroll.scroll[0] = lim_max[0]
else:
scroll.scroll[0] = lim_min[0]
if lim_min[1] < lim_max[1]:
if scroll.scroll[1] < lim_min[1]:
scroll.scroll[1] = lim_min[1]
if scroll.scroll[1] > lim_max[1]:
scroll.scroll[1] = lim_max[1]
else:
scroll.scroll[1] = lim_min[1]
class Special:
def __init__(self, object_id):
self.object_id = object_id
self.stage = ""
self.attribute = ""
self.images = []
self.attribute_0 = 0
self.attribute_1 = 0
self.attribute_2 = 0
self.color_r = [0, 0, 0]
self.boolean_attribute = False
self.height = 0
self.power = 0
self.flip = False
self.scroll = False
self.fixed = False
# collisions class take care of collision funcs
# !!!!!!!!!! holds init for Object !!!!!!!!!!!!!!!!!!!
# class purely for inheritance
class Collisions(Id):
def __init__(self, typeX, object_id, x_y, movement, direction, moving, size, special=None):
self.type = typeX
self.object_id = object_id
self.object_pos = x_y
self.movement = movement
self.direction = direction
self.moving = moving
self.size = size
self.dir_movement = [0.0, 0.0]
self.memory = []
self.special = special
if self.object_id != self.all_ids:
self.all_ids.append(self.object_id)
else:
print("duplicate/ linked object")
# giving it bonus classes
if self.moving:
self.move = Moving_Object()
if self.special:
self.specific = Special(self.object_id)
self.rect = pygame.Rect(self.object_pos[0], self.object_pos[1], self.size[0], self.size[1])
# theres a function for every type of collisions
# edit collisions here (I added some basic ones just so u can see)
# self if objects that it hit and obj is the object that hit smt
# always add both side of collisions (ask who collided with whom)
def hit_bottom(self, obj, objects):
if self.type == "solid":
if obj.type == "player":
obj.rect.bottom = self.rect.top
obj.object_pos = [obj.rect.x, obj.rect.y]
self.memory[0] -= 1
if self.memory[0] == 0:
objects.objects_to_delete.append(self.object_id)
opposite = obj.move.get_final_vector()
opp = [-opposite[0] * 0.4, -opposite[1] * 0.8]
obj.move.vectors.append(opp)
def hit_top(self, obj, objects):
if self.type == "solid":
if obj.type == "player":
obj.rect.top = self.rect.bottom
obj.object_pos = [obj.rect.x, obj.rect.y]
self.memory[0] -= 1
if self.memory[0] == 0:
objects.objects_to_delete.append(self.object_id)
opposite = obj.move.get_final_vector()
opp = [-opposite[0] * 0.4, -opposite[1] * 0.8]
obj.move.vectors.append(opp)
def hit_left(self, obj, objects):
if self.type == "solid":
if obj.type == "player":
obj.rect.left = self.rect.right
obj.object_pos = [obj.rect.x, obj.rect.y]
self.memory[0] -= 1
if self.memory[0] == 0:
objects.objects_to_delete.append(self.object_id)
opposite = obj.move.get_final_vector()
opp = [-opposite[0] * 0.4, -opposite[1] * 0.8]
obj.move.vectors.append(opp)
def hit_right(self, obj, objects):
if self.type == "solid":
if obj.type == "player":
obj.rect.right = self.rect.left
obj.object_pos = [obj.rect.x, obj.rect.y]
self.memory[0] -= 1
if self.memory[0] == 0:
objects.objects_to_delete.append(self.object_id)
opposite = obj.move.get_final_vector()
opp = [-opposite[0] * 0.4, -opposite[1] * 0.8]
obj.move.vectors.append(opp)
# next 2 classes are for object class
class Moving_Object:
def __init__(self):
# consts
self.degree = 0.0174533
self.pi = math.pi
self.half_pi = round(math.pi / 2, 6)
self.two_pi = round(math.pi * 2, 6)
self.three_halves_pi = round(3 * (math.pi / 2), 6)
self.speed = 1
self.force = 3
self.offset = 0
self.vectors = []
self.forward = False
self.backwards = False
self.left = False
self.right = False
self.collisions = False
def move(self, dir_movement):
movement = dir_movement
return movement
# dir is the angle the player is facing
def change_dir(self, direction, angle):
new_vector = [0, 0]
if self.left:
direction -= angle
if direction < 0:
direction += self.two_pi
new_vector[0] = round(math.cos(direction) * self.speed, 2)
new_vector[1] = round(math.sin(direction) * self.speed, 2)
self.vectors.append(new_vector)
elif self.right:
direction += angle
if direction > self.two_pi:
direction -= self.two_pi
new_vector[0] = round(math.cos(direction) * self.speed, 2)
new_vector[1] = round(math.sin(direction) * self.speed, 2)
self.vectors.append(new_vector)
elif self.forward:
new_vector[0] = round(math.cos(direction) * self.speed, 2)
new_vector[1] = round(math.sin(direction) * self.speed, 2)
self.vectors.append(new_vector)
return direction, self.get_final_vector()
# used for setting things before game loop
def set_start_dir_movement(self, direction, dir_movement):
dir_movement[0] = round(math.cos(direction + (self.offset * self.degree)) * self.speed, 2)
dir_movement[1] = round(math.sin(direction + (self.offset * self.degree)) * self.speed, 2)
return dir_movement
def get_final_vector(self):
to_remove = []
for i in range(len(self.vectors)-1):
self.vectors[i][0] *= 0.96
self.vectors[i][1] *= 0.96
if abs(self.vectors[i][0]) < 0.2 and abs(self.vectors[i][1]) < 0.2:
to_remove.append(self.vectors[i])
for item in to_remove:
self.vectors.remove(item)
final_vector = [0, 0]
for vector in self.vectors:
final_vector[0] += vector[0]
final_vector[1] += vector[1]
return final_vector
class Object(Collisions):
def __init__(self, typeX, object_id, x_y, movement, direction, moving, size, special=None):
super().__init__(typeX, object_id, x_y, movement, direction, moving, size, special)
def __str__(self):
return self.type
# changes position along with the rect
def change_pos(self, x_y):
self.object_pos = x_y
self.rect = pygame.Rect(self.object_pos[0], self.object_pos[1], self.size[0], self.size[1])
class Mouse:
points = 0
def __init__(self, mouse_pos):
self.mouse_pos = mouse_pos
self.mouse_scroll = [0, 0]
def update(self, Win_size, Default_size):
self.mouse_pos = pygame.mouse.get_pos()
self.mouse_pos = [((self.mouse_pos[0] - self.mouse_scroll[0]) * (Default_size[0] / Win_size[0])),
((self.mouse_pos[1] - self.mouse_scroll[1]) * (Default_size[1] / Win_size[1]))]
def get_scrolled(self, scroll):
scrolled_pos = [self.mouse_pos[0] + scroll.scroll[0],
self.mouse_pos[1] + scroll.scroll[1]]
return scrolled_pos
def distance_indicator(coords1, coords2):
x_distance = abs(coords1[0] - coords2[0])
y_distance = abs(coords1[1] - coords2[1])
distance = math.sqrt((x_distance ** 2) + (y_distance ** 2))
return round(distance, 4)
def load_images(path, name, number_of_images, file_type=".png"):
images = []
for i in range(number_of_images):
images.append(pygame.image.load("{}/{}{}{}".format(path, name, i, file_type)).convert())
return images
def load_map(path):
f = open(path, "r")
data = f.read()
f.close()
data = data.split('\n')
product = []
for line in data:
product.append(list(line))
return product
# next func sorts object into objects class so the objects is stored where it should be
def sort(obj, objects):
objects.game_objects.append(obj)
if obj.moving:
objects.moving_objects.append(obj)
if obj.move.collisions:
objects.collision_objects.append(obj)
def find_collisions(obj, objects):
hit_list = []
for element in objects.game_objects:
if element.object_id != obj.object_id:
if element.rect.colliderect(obj.rect):
hit_list.append(element)
return hit_list
def collision(obj, objects):
# collisions for left/right
obj.change_pos([obj.object_pos[0] + obj.movement[0], obj.object_pos[1]])
hit_list = find_collisions(obj, objects)
for item in hit_list:
if obj.movement[0] > 0:
item.hit_right(obj, objects)
elif obj.movement[0] < 0:
item.hit_left(obj, objects)
# collisions for top/bottom
obj.change_pos([obj.object_pos[0], obj.object_pos[1] + obj.movement[1]])
hit_list = find_collisions(obj, objects)
for item in hit_list:
if obj.movement[1] > 0:
item.hit_bottom(obj, objects)
elif obj.movement[1] < 0:
item.hit_top(obj, objects)
# !!!!!!!!!!! config this function for every program !!!!!!!!!!
def load_objects(game_map, width, height, objects, game):
x, y = 0, 0
for line in game_map:
for obj in line:
# this is just to be efficient normaly u can use elif and put another obj to another num
if obj == "1":
obj = Object("solid", game.custom_id_giver, [x, y], [0, 0], 0, False, [width, height])
obj.memory.append(3)
sort(obj, objects)
game.custom_id_giver += 1
x += width
y += height
x = 0
def load_textures(objects, dictionary, display, scroll):
for object in objects.game_objects:
if object.special:
display.blit(object.specific.images[object.specific.attribute_0],
[object.object_pos[0] - scroll.scroll[0], object.object_pos[1] - scroll.scroll[1]])
else:
display.blit(dictionary["{}".format(object.type)],
[object.object_pos[0] - scroll.scroll[0], object.object_pos[1] - scroll.scroll[1]])
def load_sp_texture(objects, type_x, image):
for object in objects.special_objects:
if object.type == type_x:
object.attributes.images.append(image)
def load_bg(image, y_x, width, height, display):
pos = [0, 0]
for i in range(y_x[0]):
for j in range(y_x[1]):
display.blit(image, pos)
pos[0] += width
pos[0] = 0
pos[1] += height
def find_angle_between_points(center, point):
dists = distances(center, point)
try:
angle = math.atan(dists[1] / dists[0])
if point[0] < center[0]:
if point[1] < center[1]:
return angle + math.pi
else:
return (math.pi / 2 - angle) + (math.pi / 2)
else:
if point[1] < center[1]:
return (math.pi / 2 - angle) + 3 * (math.pi / 2)
else:
return angle
except ZeroDivisionError:
return False
def distances(cords1, cords2):
return [abs(cords1[0] - cords2[0]), abs(cords1[1] - cords2[1])]
def average(*args):
sumX = 0
for item in args:
sumX += item
return sumX/len(args)
def area_intersection_of_circles(points, radius_list):
try:
dist = distance_indicator(points[0], points[1])
alpha_cos = (pow(radius_list[1], 2) + pow(dist, 2) - pow(radius_list[0], 2)) / (2 * radius_list[1] * dist)
alpha = math.acos(alpha_cos)
beta_cos = (dist - alpha_cos * radius_list[1]) / radius_list[0]
beta = math.acos(beta_cos)
triangles = (alpha_cos * pow(radius_list[1], 2) * math.sin(alpha)) + (
beta_cos * pow(radius_list[0], 2) * math.sin(beta))
arcs = ((math.pi * pow(radius_list[0], 2) * beta * 2) / math.tau) + (
(math.pi * pow(radius_list[1], 2) * alpha * 2) / math.tau)
return arcs - triangles
except:
return False

12
sounds.py Normal file

@ -0,0 +1,12 @@
import pygame
from pygame.locals import *
pygame.init()
def get_sounds():
sounds = {"click": pygame.mixer.Sound("assets/sounds/click.wav"),
"remove": pygame.mixer.Sound("assets/sounds/remove.wav"),
"join": pygame.mixer.Sound("assets/sounds/join.wav")}
return sounds

99
widget_engine.py Normal file

@ -0,0 +1,99 @@
import pygame
import math
class Button:
def __init__(self, pos, size, images, onclick=None, onclick_args=None, active=True):
self.pos = pos
self.size = size
self.rect = pygame.Rect(pos[0], pos[1], size[0], size[1])
self.images = images
self.display_image = images["idle"]
self.on_click = onclick
self.oc_args = onclick_args
self.active = active
self.switch_images = None
self.name = ""
def hover_check(self, mouse_pos):
if self.active:
if self.rect.collidepoint(mouse_pos):
self.display_image = self.images["hover"]
else:
self.display_image = self.images["idle"]
def click_check(self, mouse_pos):
if self.active:
if self.rect.collidepoint(mouse_pos):
if self.on_click is not None:
self.on_click(self.oc_args)
def blit(self, display, scroll=None):
if self.active:
if scroll is None:
display.blit(self.display_image, self.pos)
else:
display.blit(self.display_image, [self.pos[0] - scroll.scroll[0],
self.pos[1] - scroll.scroll[1]])
def switch(self, mouse_pos):
self.switch_images, self.images = self.images, self.switch_images
self.hover_check(mouse_pos)
def move(self, movement):
self.pos = [self.pos[0] + movement[0],
self.pos[1] + movement[1]]
self.rect = pygame.Rect(self.pos[0], self.pos[1], self.size[0], self.size[1])
class CircleButton:
def __init__(self, size, pos, images, onclick=None, onclick_args=None, active=True):
self.pos = pos
self.size = size
self.center = [pos[0] + (size/2), pos[1] + (size/2)]
self.radius = size/2
self.images = images
self.display_image = images["idle"]
self.on_click = onclick
self.oc_args = onclick_args
self.active = active
self.switch_images = None
self.name = ""
def hover_check(self, mouse_pos):
if self.active:
if distance_indicator(self.center, mouse_pos) <= self.radius:
self.display_image = self.images["hover"]
else:
self.display_image = self.images["idle"]
def click_check(self, mouse_pos):
if self.active:
if distance_indicator(self.center, mouse_pos) <= self.radius:
if self.on_click is not None:
self.on_click(self.oc_args)
def blit(self, display, scroll=None):
if self.active:
if scroll is None:
display.blit(self.display_image, self.pos)
else:
display.blit(self.display_image, [self.pos[0] - scroll.scroll[0],
self.pos[1] - scroll.scroll[1]])
def switch(self, mouse_pos):
self.switch_images, self.images = self.images, self.switch_images
self.hover_check(mouse_pos)
def move(self, movement):
self.pos = [self.pos[0] + movement[0],
self.pos[1] + movement[1]]
self.center = [self.pos[0] + (self.size / 2), self.pos[1] + (self.size / 2)]
def distance_indicator(cords1, cords2):
x_distance = abs(cords1[0] - cords2[0])
y_distance = abs(cords1[1] - cords2[1])
distance = round(math.sqrt((x_distance**2) + (y_distance**2)))
return distance