class ConfirmPayement(Window): def __init__(self, master): Window.__init__(self, master=master, bg_music=master.bg_music) self.bg = RectangleShape(*self.size, (0, 0, 0, 170)) self.frame = RectangleShape(0.50 * self.width, 0.50 * self.height, GREEN, outline=3) self.text = Text("Are you sure you want\nto buy this car ?", (RESOURCES.FONT["algerian"], 60), justify=Text.T_CENTER) self.button_yes = Button(self, "Yes", self.text.font, bg=GREEN, hover_bg=GREEN_LIGHT, active_bg=GREEN_DARK, hover_sound=RESOURCES.SFX["select"], on_click_sound=RESOURCES.SFX["validate"], highlight_color=YELLOW, callback=self.buy) self.button_red_cross = ImageButton( self, img=RESOURCES.IMG["red_cross"], active_img=RESOURCES.IMG["red_cross_hover"], hover_sound=RESOURCES.SFX["select"], on_click_sound=RESOURCES.SFX["back"], callback=self.stop, highlight_color=YELLOW) self.buyed = False self.bind_key(pygame.K_ESCAPE, lambda event: self.stop(sound=RESOURCES.SFX["back"])) self.bind_joystick( 0, "B", lambda event: self.stop(sound=RESOURCES.SFX["back"])) def place_objects(self): self.text.center = self.frame.center = self.center self.button_red_cross.move(left=self.frame.left + 5, top=self.frame.top + 5) self.button_yes.move(bottom=self.frame.bottom - 10, centerx=self.frame.centerx) def set_grid(self): self.button_red_cross.set_obj_on_side(on_bottom=self.button_yes) self.button_yes.set_obj_on_side(on_top=self.button_red_cross) def buy(self): self.buyed = True self.stop()
class LocalPlayingSection(Section): def __init__(self, master, gameplay: FourInARowGameplay): Section.__init__(self, master, "Local Multiplaying", gameplay) self.form = Form(self) self.form.add_entry("P1", Text("P1 Name:", theme="form"), Entry(self)) self.form.add_entry("P2", Text("P2 Name:", theme="form"), Entry(self)) self.button_play = Button(self, "Play", theme=["option", "section"], callback=self.play) def on_start_loop(self) -> None: super().on_start_loop() self.button_play.focus_set() def place_objects(self) -> None: Section.place_objects(self) self.form.move(left=self.frame.left + 10, top=self.title.bottom + 50) self.button_play.move(centerx=self.frame.centerx, bottom=self.frame.bottom - 10) def set_grid(self) -> None: self.button_back.set_obj_on_side(on_bottom=self.form[0], on_right=self.form[0]) self.form.set_obj_on_side(on_top=self.button_back, on_left=self.button_back, on_bottom=self.button_play) self.button_play.set_obj_on_side(on_top=self.form[-1]) def play(self) -> None: player_1_name = self.form.get("P1") or None player_2_name = self.form.get("P2") or None self.gameplay.start(LOCAL_PLAYER, player_name=player_1_name, enemy_name=player_2_name) self.stop()
class LANPlayingP2(Section): def __init__(self, master, gameplay: FourInARowGameplay): Section.__init__(self, master, "Play as P2", gameplay) self.form = Form(self) self.form.add_entry("name", Text("Your Name:", theme="form"), Entry(self)) self.form.add_entry("IP", Text("IP address:", theme="form"), Entry(self, width=15)) self.form.add_entry("port", Text("Port:", theme="form"), Entry(self, width=15)) self.button_connect = Button(self, "Connect to P1", theme=["option", "section"], callback=self.connection) self.text_game_status = Text(font=RESOURCES.font("heavy", 30), shadow_x=1, shadow_y=1) def place_objects(self) -> None: Section.place_objects(self) self.form.move(left=self.frame.left + 10, top=self.title.bottom + 50) self.text_game_status.move(centerx=self.frame.centerx, top=self.form.bottom + 10) self.button_connect.move(centerx=self.frame.centerx, bottom=self.frame.bottom - 10) def update(self) -> None: self.button_connect.state = Button.NORMAL if self.form.get( "name") else Button.DISABLED def on_start_loop(self) -> None: super().on_start_loop() self.form.get_entry("name").focus_set() self.form.get_entry("name").start_edit() self.text_game_status.hide() def on_quit(self) -> None: super().on_quit() self.stop_connection() def set_grid(self) -> None: self.button_back.set_obj_on_side(on_bottom=self.form[0], on_right=self.form[0]) self.form.set_obj_on_side(on_top=self.button_back, on_left=self.button_back, on_bottom=self.button_connect) self.button_connect.set_obj_on_side(on_top=self.form[-1]) def connection(self) -> None: self.text_game_status.show() self.text_game_status.message = "Connection..." self.draw_and_refresh() try: address = self.form.get("IP") port = int(self.form.get("port")) except ValueError: self.text_game_status.message = "The port of connection must be a number." return if not self.connect_to_server(address, port, 3): self.text_game_status.message = "Connection failed. Try again." else: self.gameplay.start(LAN_PLAYER, player=2, player_name=self.form.get("name")) self.stop()
class LANPlayingP1(Section): def __init__(self, master, gameplay: FourInARowGameplay): Section.__init__(self, master, "Play as P1", gameplay) self.form = Form(self) self.form.add_entry("P1", Text("Your Name:", theme="form"), Entry(self)) self.button_start_server = Button(self, theme=["option", "section"]) self.text_game_status = Text(font=RESOURCES.font("heavy", 20), shadow_x=1, shadow_y=1) self.text_server_ip = Text(font=RESOURCES.font("afterglow", 45), shadow_x=2, shadow_y=1) self.text_server_port = Text(font=RESOURCES.font("afterglow", 45), shadow_x=2, shadow_y=1) def place_objects(self) -> None: Section.place_objects(self) self.form.move(left=self.frame.left + 10, top=self.title.bottom + 50) self.text_game_status.move(centerx=self.frame.centerx, top=self.form.bottom + 10) self.button_start_server.move(centerx=self.frame.centerx, top=self.form.bottom + 50) self.text_server_ip.move(centerx=self.frame.centerx, top=self.button_start_server.bottom + 30) self.text_server_port.move(centerx=self.frame.centerx, top=self.text_server_ip.bottom + 10) def update(self) -> None: if not self.client_socket.connected(): self.button_start_server.state = Button.NORMAL if self.form.get( "P1") else Button.DISABLED self.form.get_entry("P1").state = Entry.NORMAL else: self.button_start_server.state = Button.NORMAL self.form.get_entry("P1").state = Entry.DISABLED if self.get_server_clients_count() == 2: self.set_server_listen(0) self.gameplay.start(LAN_PLAYER, player=1, player_name=self.form.get("P1")) self.stop() def on_start_loop(self) -> None: super().on_start_loop() self.form.get_entry("P1").focus_set() self.form.get_entry("P1").start_edit() self.stop_server() def on_quit(self) -> None: super().on_quit() self.stop_connection() def set_grid(self) -> None: self.button_back.set_obj_on_side(on_bottom=self.form[0], on_right=self.form[0]) self.form.set_obj_on_side(on_top=self.button_back, on_left=self.button_back, on_bottom=self.button_start_server) self.button_start_server.set_obj_on_side(on_top=self.form[-1], on_left=self.button_back) def start_server(self) -> None: try: ip, port = self.create_server(12800, 1) except OSError: self.text_game_status.message = "Cannot create server" else: self.text_game_status.message = "Waiting for player 2 to connect" self.text_server_ip.message = "IP: {}".format(ip) self.text_server_port.message = "Port: {}".format(port) self.text_server_ip.show() self.text_server_port.show() self.button_start_server.text = "Stop server" self.button_start_server.callback = self.stop_server self.text_game_status.show() self.place_objects() def stop_server(self) -> None: self.stop_connection() self.text_game_status.hide() self.text_server_ip.hide() self.text_server_port.hide() self.button_start_server.text = "Start server" self.button_start_server.callback = self.start_server
class Garage(Window): def __init__(self): Window.__init__(self, bg_color=GRAY, bg_music=RESOURCES.MUSIC["garage"]) params_for_all_buttons = { "bg": GREEN, "hover_bg": GREEN_LIGHT, "active_bg": GREEN_DARK, "highlight_color": YELLOW, "hover_sound": RESOURCES.SFX["select"], } params_for_button_except_back = { "on_click_sound": RESOURCES.SFX["validate"], "disabled_sound": RESOURCES.SFX["block"], "disabled_bg": GRAY_LIGHT, } params_for_button_except_back.update(params_for_all_buttons) params_for_car_viewer = { k: params_for_button_except_back[k] for k in ["hover_sound", "on_click_sound"] } self.button_back = ImageButton(self, RESOURCES.IMG["blue_arrow"], **params_for_all_buttons, on_click_sound=RESOURCES.SFX["back"], callback=self.stop) self.car_viewer = CarViewer(self, SAVE["car"], **params_for_car_viewer) size_progress_bar = (300, 30) self.speed_bar = ProgressBar(*size_progress_bar, TRANSPARENT, GREEN) self.maniability_bar = ProgressBar(*size_progress_bar, TRANSPARENT, GREEN) self.braking_bar = ProgressBar(*size_progress_bar, TRANSPARENT, GREEN) self.left_arrow = ImageButton( self, img=RESOURCES.IMG["left_arrow"], active_img=RESOURCES.IMG["left_arrow_hover"], **params_for_button_except_back, callback=self.car_viewer.decrease_id) self.right_arrow = ImageButton( self, img=RESOURCES.IMG["right_arrow"], active_img=RESOURCES.IMG["right_arrow_hover"], **params_for_button_except_back, callback=self.car_viewer.increase_id) for arrow in [self.left_arrow, self.right_arrow]: arrow.take_focus(False) self.button_price = Button(self, font=(RESOURCES.FONT["algerian"], 40), img=Image(RESOURCES.IMG["piece"], size=40), compound="right", callback=self.buy_car, **params_for_button_except_back) self.button_play = Button(self, "Play", font=(RESOURCES.FONT["algerian"], 70), callback=self.play, **params_for_button_except_back) self.text_money = Text(format_number(SAVE["money"]), (RESOURCES.FONT["algerian"], 50), YELLOW, img=Image(RESOURCES.IMG["piece"], height=40), compound="right") self.text_highscore = Text( "Highscore: {}".format(format_number(SAVE["highscore"])), (RESOURCES.FONT["algerian"], 50), YELLOW) self.padlock = Image(RESOURCES.IMG["padlock"]) self.bind_key(pygame.K_ESCAPE, lambda event: self.stop(sound=RESOURCES.SFX["back"])) self.bind_joystick( 0, "B", lambda event: self.stop(sound=RESOURCES.SFX["back"])) def update(self): self.left_arrow.set_visibility(self.car_viewer.id > 1) self.right_arrow.set_visibility( self.car_viewer.id < len(self.car_viewer)) if not SAVE["owned_cars"][self.car_viewer.id]: self.padlock.show() price = self.car_viewer["price"] if isinstance(price, int): self.button_price.show() self.button_price.text = format_number(price) self.button_price.state = Button.NORMAL if SAVE[ "money"] >= price else Button.DISABLED else: self.button_price.hide() self.button_play.state = Button.DISABLED else: self.padlock.hide() self.button_price.hide() self.button_play.state = Button.NORMAL SAVE["car"] = self.car_viewer.id max_s = self.car_viewer.max_speed min_a = self.car_viewer.min_acceleration max_m = self.car_viewer.max_maniability min_b = self.car_viewer.min_braking s = self.car_viewer["max_speed"] a = self.car_viewer["acceleration"] m = self.car_viewer["maniability"] b = self.car_viewer["braking"] self.speed_bar.percent = (s + min_a) / (max_s + a) self.maniability_bar.percent = m / max_m self.braking_bar.percent = min_b / b def place_objects(self): self.button_back.topleft = (5, 5) self.car_viewer.move(center=self.center) self.padlock.center = self.car_viewer.center self.braking_bar.move(bottom=self.car_viewer.top - 40, centerx=self.car_viewer.centerx + 100) self.maniability_bar.move(bottom=self.braking_bar.top - 10, centerx=self.car_viewer.centerx + 100) self.speed_bar.move(bottom=self.maniability_bar.top - 10, centerx=self.car_viewer.centerx + 100) self.speed_bar.show_label("Speed/Acc.", ProgressBar.S_LEFT, font=(RESOURCES.FONT["algerian"], 40)) self.maniability_bar.show_label("Maniability", ProgressBar.S_LEFT, font=(RESOURCES.FONT["algerian"], 40)) self.braking_bar.show_label("Braking", ProgressBar.S_LEFT, font=(RESOURCES.FONT["algerian"], 40)) self.left_arrow.move(left=self.left + 50, centery=self.centery) self.right_arrow.move(right=self.right - 50, centery=self.centery) self.button_price.move(centerx=self.centerx, top=self.car_viewer.bottom + 25) self.button_play.move(bottom=self.bottom - 50, right=self.right - 10) self.text_money.move(top=5, right=self.right - 10) self.text_highscore.move(bottom=self.bottom - 50, left=5) def set_grid(self): self.button_back.set_obj_on_side(on_bottom=self.car_viewer) self.car_viewer.set_obj_on_side(on_top=self.button_back, on_bottom=self.button_price) self.button_price.set_obj_on_side(on_top=self.car_viewer, on_bottom=self.button_play) self.button_play.set_obj_on_side(on_top=self.button_price) def buy_car(self): confirm_window = ConfirmPayement(self) confirm_window.mainloop() if confirm_window.buyed: SAVE["money"] -= self.car_viewer["price"] SAVE["owned_cars"][self.car_viewer.id] = True self.text_money.message = format_number(SAVE["money"]) if Clickable.MODE != Clickable.MODE_MOUSE: self.car_viewer.focus_set() def play(self): environment_chooser = EnvironmentChooser(self) environment_chooser.mainloop() self.text_money.message = format_number(SAVE["money"]) self.text_highscore.message = "Highscore: {}".format( format_number(SAVE["highscore"]))
class Options(Window): def __init__(self, master: Window): Window.__init__(self, master=master, bg_music=master.bg_music) self.frame = RectangleShape(0.60 * self.width, 0.60 * self.height, GREEN, outline=3) self.title = Text("Options", font=(RESOURCES.FONT["algerian"], 70)) self.options_font = (RESOURCES.FONT["algerian"], 40) self.case_font = (RESOURCES.FONT["algerian"], 30) self.control_font = ("calibri", 20) params_for_all_scales = { "width": 0.45 * self.frame.w, "color": TRANSPARENT, "scale_color": GREEN_DARK, "from_": 0, "to": 100, "outline": 3, } params_for_all_buttons = { "highlight_color": YELLOW, "hover_sound": RESOURCES.SFX["select"], "disabled_sound": RESOURCES.SFX["block"] } params_for_option_buttons = { "on_click_sound": RESOURCES.SFX["validate"] } params_for_buttons = { "bg": GRAY_DARK, "fg": WHITE, "hover_bg": GRAY, "active_bg": BLACK } params_for_reset_button = { "bg": RED, "fg": WHITE, "hover_bg": RED_LIGHT, "active_bg": RED_DARK, } self.button_back = ImageButton(self, img=RESOURCES.IMG["blue_arrow"], on_click_sound=RESOURCES.SFX["back"], callback=self.stop, **params_for_all_buttons) self.button_change_page = Button(self, ">>", font=self.case_font, callback=self.change_page, **params_for_all_buttons, **params_for_option_buttons, **params_for_buttons) self.nb_pages = 2 self.page = 1 ## PAGE 1 ## valid_img = Image(RESOURCES.IMG["green_valid"]) self.text_music = Text("Music:", self.options_font) self.cb_music = CheckBox(self, 30, 30, TRANSPARENT, image=valid_img, value=self.get_music_state(), callback=self.set_music_state, **params_for_all_buttons, **params_for_option_buttons) self.scale_music = Scale( self, **params_for_all_scales, **params_for_all_buttons, height=self.cb_music.height, default=Window.music_volume() * 100, callback=lambda value, percent: Window.set_music_volume(percent)) self.text_sound = Text("SFX:", self.options_font) self.cb_sound = CheckBox(self, 30, 30, TRANSPARENT, image=valid_img, value=self.get_sound_state(), callback=self.set_sound_state, **params_for_all_buttons, **params_for_option_buttons) self.scale_sound = Scale( self, **params_for_all_scales, **params_for_all_buttons, height=self.cb_sound.height, default=Window.sound_volume() * 100, callback=lambda value, percent: Window.set_sound_volume(percent)) self.text_fps = Text("FPS:", self.options_font) self.cb_show_fps = CheckBox(self, 30, 30, TRANSPARENT, image=valid_img, value=Window.fps_is_shown(), callback=self.show_fps, **params_for_all_buttons, **params_for_option_buttons) self.button_reset = Button(self, "Reset Save", font=(RESOURCES.FONT["algerian"], 30), callback=SAVE.reset, state=Button.DISABLED, **params_for_all_buttons, **params_for_option_buttons, **params_for_reset_button) ## PAGE 2 ## self.text_acceleration = Text("Accélérer:", self.options_font) self.button_auto_acceleration = Button( self, font=self.case_font, callback=lambda: SAVE.update(auto_acceleration=not SAVE[ "auto_acceleration"]), **params_for_all_buttons, **params_for_option_buttons, **params_for_buttons) self.button_acceleration = Button( self, font=self.control_font, callback=lambda: self.choose_key("speed_up"), **params_for_all_buttons, **params_for_option_buttons, **params_for_buttons) self.text_brake = Text("Freiner:", self.options_font) self.button_brake = Button(self, font=self.control_font, callback=lambda: self.choose_key("brake"), **params_for_all_buttons, **params_for_option_buttons, **params_for_buttons) self.text_move_up = Text("Aller en haut:", self.options_font) self.button_move_up = Button(self, font=self.control_font, callback=lambda: self.choose_key("up"), **params_for_all_buttons, **params_for_option_buttons, **params_for_buttons) self.text_move_down = Text("Aller en bas:", self.options_font) self.button_move_down = Button( self, font=self.control_font, callback=lambda: self.choose_key("down"), **params_for_all_buttons, **params_for_option_buttons, **params_for_buttons) self.bind_key(pygame.K_ESCAPE, lambda event: self.stop(sound=RESOURCES.SFX["back"])) self.bind_joystick( 0, "B", lambda event: self.stop(sound=RESOURCES.SFX["back"])) def on_quit(self): SAVE.dump() def change_page(self): self.page = (self.page % self.nb_pages) + 1 def update(self): self.hide_all(without=[ self.frame, self.title, self.button_back, self.button_change_page ]) if self.page == 1: self.text_music.show() self.text_sound.show() for checkbox, scale in [(self.cb_music, self.scale_music), (self.cb_sound, self.scale_sound)]: checkbox.show() if checkbox.value is True: scale.show() checkbox.set_obj_on_side(on_right=scale) else: checkbox.set_obj_on_side(on_right=self.button_change_page) self.text_fps.show() self.cb_show_fps.show() self.button_reset.show() self.button_back.set_obj_on_side(on_bottom=self.cb_music, on_right=self.cb_music) self.button_change_page.set_obj_on_side(on_top=self.cb_show_fps, on_left=self.button_reset) elif self.page == 2: self.text_acceleration.show() self.button_auto_acceleration.text = "Automatique" if SAVE[ "auto_acceleration"] else "Manuel" self.button_auto_acceleration.show() control_text_format = "Key: {key}\nJoystick: {joy}" if not SAVE["auto_acceleration"]: self.button_acceleration.text = control_text_format.format( **SAVE["controls"]["speed_up"]) self.button_acceleration.move( left=self.button_auto_acceleration.right + 10, centery=self.button_auto_acceleration.centery) self.button_acceleration.show() self.button_auto_acceleration.set_obj_on_side( on_right=self.button_acceleration) else: self.button_auto_acceleration.set_obj_on_side( on_right=self.button_back) fields = [ (self.text_brake, self.button_brake, "brake"), (self.text_move_up, self.button_move_up, "up"), (self.text_move_down, self.button_move_down, "down"), ] for text, button, action in fields: text.show() button.text = control_text_format.format( **SAVE["controls"][action]) button.show() self.button_back.set_obj_on_side( on_bottom=self.button_auto_acceleration, on_right=self.button_auto_acceleration) self.button_change_page.set_obj_on_side( on_top=self.button_move_down, on_left=self.button_move_down) def place_objects(self): self.frame.move(center=self.center) self.title.move(top=self.frame.top + 10, centerx=self.frame.centerx) self.button_back.move(top=self.frame.top + 5, left=self.frame.left + 5) self.button_change_page.move(bottom=self.frame.bottom - 5, right=self.frame.right - 5) ## PAGE 1 ## self.text_music.move(left=self.frame.left + 10, top=self.title.bottom + 10) self.text_sound.move(right=self.text_music.right, top=self.text_music.bottom + 5) self.cb_music.move(left=self.text_music.right + 10, centery=self.text_music.centery) self.cb_sound.move(left=self.text_music.right + 10, centery=self.text_sound.centery) self.scale_music.move(centerx=self.frame.centerx, centery=self.cb_music.centery) self.scale_music.show_value(Scale.S_RIGHT, font=self.case_font) self.scale_sound.move(centerx=self.frame.centerx, centery=self.cb_sound.centery) self.scale_sound.show_value(Scale.S_RIGHT, font=self.case_font) self.text_fps.move(right=self.text_music.right, top=self.text_sound.bottom + 50) self.cb_show_fps.move(left=self.text_fps.right + 10, centery=self.text_fps.centery) self.button_reset.move(bottom=self.frame.bottom - 5, left=self.frame.left + 5) ## PAGE 2 ## self.text_acceleration.move(left=self.frame.left + 10, top=self.title.bottom + 50) self.button_auto_acceleration.move( left=self.text_acceleration.right + 10, centery=self.text_acceleration.centery) self.text_brake.move(left=self.text_acceleration.left, top=self.text_acceleration.bottom + 50) self.button_brake.move(left=self.text_brake.right + 10, centery=self.text_brake.centery) self.text_move_up.move(left=self.text_acceleration.left, top=self.text_brake.bottom + 50) self.button_move_up.move(left=self.text_move_up.right + 10, centery=self.text_move_up.centery) self.text_move_down.move(left=self.text_acceleration.left, top=self.text_move_up.bottom + 50) self.button_move_down.move(left=self.text_move_down.right + 10, centery=self.text_move_down.centery) def set_grid(self): ## PAGE 1 ## self.cb_music.set_obj_on_side(on_top=self.button_back, on_left=self.button_back, on_bottom=self.cb_sound) self.scale_music.set_obj_on_side(on_top=self.button_back, on_left=self.cb_music, on_bottom=self.scale_sound, on_right=self.button_change_page) self.cb_sound.set_obj_on_side(on_top=self.cb_music, on_left=self.button_back, on_bottom=self.cb_show_fps) self.scale_sound.set_obj_on_side(on_top=self.scale_music, on_left=self.cb_sound, on_bottom=self.cb_show_fps, on_right=self.button_change_page) self.cb_show_fps.set_obj_on_side(on_left=self.button_back, on_top=self.cb_sound, on_bottom=self.button_reset, on_right=self.button_change_page) self.button_reset.set_obj_on_side(on_left=self.button_back, on_top=self.cb_show_fps, on_right=self.button_change_page) ## PAGE 2 ## self.button_auto_acceleration.set_obj_on_side( on_top=self.button_back, on_left=self.button_back, on_bottom=self.button_brake) self.button_acceleration.set_obj_on_side( on_top=self.button_back, on_left=self.button_auto_acceleration, on_bottom=self.button_brake, on_right=self.button_change_page) self.button_brake.set_obj_on_side(on_top=self.button_auto_acceleration, on_left=self.button_back, on_bottom=self.button_move_up, on_right=self.button_change_page) self.button_move_up.set_obj_on_side(on_top=self.button_brake, on_left=self.button_back, on_bottom=self.button_move_down, on_right=self.button_change_page) self.button_move_down.set_obj_on_side( on_top=self.button_move_up, on_left=self.button_back, on_bottom=self.button_change_page, on_right=self.button_change_page) def choose_key(self, action: str): AssignmentPrompt(self, action).mainloop()