class DoorSprite(pygame.sprite.Sprite, DoorObserver): def __init__(self, door_model: DoorModel, orientation: str, tile_sprite: TileSprite, tile_model: TileModel, id: Tuple[int, int, str]): super().__init__() self.orientation = orientation self._game: GameStateModel = GameStateModel.instance() self._current_player = self._game.players_turn self._button = None self.tile_model = tile_model self.id = id self.door_model = door_model self.door_model.add_observer(self) self.open = self.door_model.door_status == DoorStatusEnum.OPEN self.closed = self.door_model.door_status == DoorStatusEnum.CLOSED self.destroyed = self.door_model.door_status == DoorStatusEnum.DESTROYED self.marker = None self.tile_sprite = tile_sprite self._prev_x = self.tile_sprite.rect.x self._prev_y = self.tile_sprite.rect.y self.button_input = RectButton( self.tile_sprite.rect.x + 100, self.tile_sprite.rect.y + 100, 100, 25, Color.WOOD, 0, Text(pygame.font.SysFont('Agency FB', 15), "Interact", Color.GREEN2)) pygame.draw.rect(self.button_input.image, Color.YELLOW, [0, 0, 100, 25], 3) self.button_input.disable() self.menu_shown = False @property def direction(self) -> str: return self.id[2] @property def player(self) -> PlayerModel: return self._current_player @property def button(self): return self._button @button.setter def button(self, button): self._button = button def update(self, event_queue): diff_x = self.tile_sprite.rect.x - self._prev_x diff_y = self.tile_sprite.rect.y - self._prev_y self._button.rect.move_ip((diff_x, diff_y)) self._prev_x = self.tile_sprite.rect.x self._prev_y = self.tile_sprite.rect.y self.button_input.rect.x = self.tile_sprite.rect.x + 100 self.button_input.rect.y = self.tile_sprite.rect.y + 100 for event in event_queue: if event.type == pygame.MOUSEBUTTONUP: if not ((self.button_input.rect.x <= pygame.mouse.get_pos()[0] <= self.button_input.rect.x + 100) and (self.button_input.rect.y <= pygame.mouse.get_pos()[1] <= self.button_input.rect.y + 25)): self.button_input.disable() self._button.update(event_queue) self.button_input.update(event_queue) def door_status_changed(self, status: DoorStatusEnum): if status == DoorStatusEnum.DESTROYED: self.destroyed = True self.open = False self.closed = False elif status == DoorStatusEnum.CLOSED: self.closed = True self.open = False self.destroyed = False elif status == DoorStatusEnum.OPEN: self.open = True self.closed = False self.destroyed = False else: raise Exception("Door status ERROR") def draw(self, screen): self.button.draw(screen) x_offset1 = 0 y_offset1 = 0 if self.menu_shown: if self.button_input.enabled: screen.blit(self.button_input.image, self.button_input.rect) if self.orientation == "vertical": x_offset1 = -22 y_offset1 = 40 if self.orientation == "horizontal": x_offset1 = 34 y_offset1 = -18 if self.destroyed: self.marker = RectLabel(self.button.rect.x + x_offset1, self.button.rect.y + y_offset1, 50, 50, "media/Threat_Markers/damageMarker.png") self.marker.draw(screen) if self.open: self.marker = RectLabel(self.button.rect.x + x_offset1, self.button.rect.y + y_offset1, 50, 50, "media/Door_Markers/Open_Door.png") self.marker.draw(screen) if self.closed: self.marker = RectLabel(self.button.rect.x + x_offset1, self.button.rect.y + y_offset1, 50, 50, "media/Door_Markers/Closed_Door.png") self.marker.draw(screen)
class LobbyScene(GameStateObserver): def __init__(self, screen, current_player: PlayerModel): super().__init__() self._current_player = current_player self._game = GameStateModel.instance() self.player_boxes = [] if Networking.get_instance().is_host: self._current_player.color = Color.BLUE self._game.host.color = Color.BLUE self._current_player.status = PlayerStatusEnum.READY self._player_count = len(self._game.players) self.isReady = False self.resolution = (1280, 700) self.sprite_grp = pygame.sprite.Group() self.players_not_ready_prompt = None self._init_all() if self._game.rules == GameKindEnum.EXPERIENCED: self.buttonSelChar.on_click( EventQueue.post, CustomEvent(ChangeSceneEnum.CHARACTERSCENE)) if Networking.get_instance().is_host: self._current_player.status = PlayerStatusEnum.READY self.isReady = True self.start_button.on_click(self.start_game) self.start_button.disable() if self._game.rules == GameKindEnum.EXPERIENCED and self._current_player.role == PlayerRoleEnum.FAMILY: self._current_player.status = PlayerStatusEnum.NOT_READY else: self._current_player.status = PlayerStatusEnum.NOT_READY self.buttonReady.on_click(self.set_ready) self.buttonBack.on_click(self.go_back) @staticmethod def go_back(): if Networking.get_instance().is_host: next_scene = ChangeSceneEnum.SETMAXPLAYERSCENE else: next_scene = ChangeSceneEnum.JOINSCENE Networking.get_instance().disconnect() EventQueue.post(CustomEvent(next_scene)) def start_game(self): """Callback for when the host tries to start the game.""" game = GameStateModel.instance() players_ready = len([ player for player in game.players if player.status == PlayerStatusEnum.READY ]) if not self._game.rules == GameKindEnum.FAMILY: if any(player.role == PlayerRoleEnum.FAMILY for player in game.players): return if not players_ready == game.max_players: self.not_enough_players_ready_prompt() return # Perform the start game hook in Networking (ie. stop accepting new connections and kill broadcast) if Networking.get_instance().is_host: # Kill the broadcast for box in self.player_boxes: box.delete_class() Networking.get_instance().send_to_all_client(StartGameEvent()) def set_ready(self): """Set the status of the current player to ready.""" if not self.isReady: if not (self._game.rules == GameKindEnum.FAMILY and self._current_player.role == PlayerRoleEnum.FAMILY) \ or self._game.rules == GameKindEnum.FAMILY: self.isReady = True self.sprite_grp.remove(self.buttonReady) box_size = (130, 48) self.buttonReady = RectButton( 1050, 575, box_size[0], box_size[1], Color.BLACK, 0, Text(pygame.font.SysFont('Agency FB', 25), "Ready", Color.GREEN)) self.buttonReady.change_bg_image(MEDIA_CONSTS.WOOD) self.buttonReady.add_frame(MEDIA_CONSTS.FRAME) self.buttonReady.on_click(self.set_ready) self.sprite_grp.add(self.buttonReady) self._current_player.status = PlayerStatusEnum.READY event = ReadyEvent(self._current_player, True) if self._current_player.ip == GameStateModel.instance( ).host.ip: event.execute() Networking.get_instance().send_to_all_client(event) else: Networking.get_instance().send_to_server(event) else: self.isReady = False self.sprite_grp.remove(self.buttonReady) box_size = (130, 48) self.buttonReady = RectButton( 1050, 575, box_size[0], box_size[1], Color.BLACK, 0, Text(pygame.font.SysFont('Agency FB', 25), "Not Ready", Color.GREY)) self.buttonReady.change_bg_image(MEDIA_CONSTS.WOOD) self.buttonReady.add_frame(MEDIA_CONSTS.FRAME) self.buttonReady.on_click(self.set_ready) self.sprite_grp.add(self.buttonReady) self._current_player.status = PlayerStatusEnum.NOT_READY event = ReadyEvent(self._current_player, False) if self._current_player.ip == GameStateModel.instance().host.ip: event.execute() Networking.get_instance().send_to_all_client(event) else: Networking.get_instance().send_to_server(event) def _init_all(self, reuse=False): self._init_background() self._init_ip_addr() self.chat_box = ChatBox(self._current_player) if not reuse: self._init_btn_back(20, 20, "Exit", MEDIA_CONSTS.WOOD, Color.GREEN2) if self._current_player.ip == GameStateModel.instance().host.ip: self._init_start_game_button() else: # Ready button is grey at first self._init_ready(1050, 575, "Not Ready", Color.GREY, Color.BLACK) if not self._game.rules == GameKindEnum.FAMILY: self._init_selec_char(1050, 475, "Select Character", Color.STANDARDBTN, Color.GREEN2) else: if not self._game.rules == GameKindEnum.FAMILY: self.sprite_grp.add(self.buttonSelChar) if self._current_player.ip == GameStateModel.instance().host.ip: self.sprite_grp.add(self.start_button) else: self.sprite_grp.add(self.buttonReady, self.buttonBack) self.sprite_grp.add(self.buttonBack) self._init_sprites() def _init_start_game_button(self): """Button for starting the game once all players have clicked ready.""" box_size = (130, 48) self.start_button = RectButton( 1050, 575, box_size[0], box_size[1], Color.GREY, 0, Text(pygame.font.SysFont('Agency FB', 25), "Start", Color.RED)) self.start_button.change_bg_image(MEDIA_CONSTS.WOOD) self.start_button.add_frame(MEDIA_CONSTS.FRAME) self.sprite_grp.add(self.start_button) def _init_background(self): box_size = (self.resolution[0], self.resolution[1]) background_box = RectLabel(0, 0, box_size[0], box_size[1], MEDIA_CONSTS.FLASHPOINT_BACKGROUND) self.sprite_grp.add(background_box) def create_butn_img(self, x, y, width, height, path): box_size = (width, height) self.this_img = RectButton(x, y, box_size[0], box_size[1], path) self.sprite_grp.add(self.this_img) def _init_background_player(self, rect): if not self._game.rules == GameKindEnum.FAMILY and self._current_player.role: role_path = self.get_path_from_character_enum( self._current_player.role) user_box = RectLabel(rect[0], rect[1], rect[2], rect[3], role_path) else: user_box = RectLabel(rect[0], rect[1], rect[2], rect[3], MEDIA_CONSTS.FAMILY) return user_box def get_path_from_character_enum(self, enum: PlayerRoleEnum): if enum == PlayerRoleEnum.CAFS: return MEDIA_CONSTS.CAFS_FIREFIGHTER elif enum == PlayerRoleEnum.CAPTAIN: return MEDIA_CONSTS.FIRE_CAPTAIN elif enum == PlayerRoleEnum.GENERALIST: return MEDIA_CONSTS.GENERALIST elif enum == PlayerRoleEnum.DRIVER: return MEDIA_CONSTS.DRIVER_OPERATOR elif enum == PlayerRoleEnum.HAZMAT: return MEDIA_CONSTS.HAZMAT_TECHNICIAN elif enum == PlayerRoleEnum.IMAGING: return MEDIA_CONSTS.IMAGING_TECHNICIAN elif enum == PlayerRoleEnum.PARAMEDIC: return MEDIA_CONSTS.PARAMEDIC elif enum == PlayerRoleEnum.RESCUE: return MEDIA_CONSTS.RESCUE_SPECIALIST elif enum == PlayerRoleEnum.FAMILY: return MEDIA_CONSTS.FAMILY def _init_text_box(self, position, text, color): box_size = (position[2], position[3]) user_box = RectLabel( position[0], position[1], box_size[0], box_size[1], color, 0, Text(pygame.font.SysFont('Agency FB', 20), text, (0, 255, 0, 0))) return user_box def _init_selec_char(self, x_pos: int, y_pos: int, text: str, color: Color, color_text: Color): box_size = (170, 48) self.buttonSelChar = RectButton( x_pos, y_pos, box_size[0], box_size[1], color, 0, Text(pygame.font.SysFont('Agency FB', 25), text, color_text)) self.buttonSelChar.change_bg_image(MEDIA_CONSTS.WOOD) self.buttonSelChar.add_frame(MEDIA_CONSTS.FRAME) self.sprite_grp.add(self.buttonSelChar) def _init_ready(self, x_pos: int, y_pos: int, text: str, color: Color, color_text: Color): box_size = (130, 48) self.isReady = False self.buttonReady = RectButton( x_pos, y_pos, box_size[0], box_size[1], color, 0, Text(pygame.font.SysFont('Agency FB', 25), text, Color.GREY)) self.buttonReady.change_bg_image(MEDIA_CONSTS.WOOD) self.buttonReady.add_frame(MEDIA_CONSTS.FRAME) self.sprite_grp.add(self.buttonReady) def _init_btn_back(self, x_pos: int, y_pos: int, text: str, bg: str, color_text: Color): box_size = (130, 48) self.buttonBack = RectButton( x_pos, y_pos, box_size[0], box_size[1], bg, 0, Text(pygame.font.SysFont('Agency FB', 25), text, color_text)) self.buttonBack.add_frame(MEDIA_CONSTS.FRAME) self.sprite_grp.add(self.buttonBack) def _init_ip_addr(self): if Networking.get_instance().is_host: ip_addr = f"Your IP address: {Networking.get_instance().get_ip()}" label_width = 400 label_left = (pygame.display.get_surface().get_size()[0] / 2) - (label_width / 2) ip_addr_label = RectLabel(label_left, 20, label_width, 50, (255, 255, 255), txt_obj=(Text( pygame.font.SysFont('Agency FB', 26), ip_addr, Color.GREEN2))) ip_addr_label.change_bg_image(MEDIA_CONSTS.WOOD) ip_addr_label.add_frame(MEDIA_CONSTS.FRAME) #ip_addr_label.set_transparent_background(True) self.sprite_grp.add(ip_addr_label) def _init_sprites(self): text_pos = [(565, 625, 200, 32), (100, 364, 150, 32), (400, 289, 150, 32), (780, 289, 150, 32), (1080, 364, 150, 32)] background_pos = [(565, 375, 200, 250), (100, 164, 150, 200), (400, 89, 150, 200), (780, 89, 150, 200), (1080, 164, 150, 200)] self.player_boxes = [] current_player = [ player for player in GameStateModel.instance().players if player.ip == self._current_player.ip ][0] self.player_boxes.append( PlayerBox(text_pos[0], background_pos[0], self._current_player.nickname, current_player, current_player.color)) players = [ x for x in GameStateModel.instance().players if x.ip != self._current_player.ip ] i = 1 for player in players: self.player_boxes.append( PlayerBox(text_pos[i], background_pos[i], player.nickname, player, player.color)) # self.sprite_grp.add(self._init_text_box(text_pos[i], player.nickname, player.color)) # self.sprite_grp.add(self._init_background_player(background_pos[i])) i += 1 def not_enough_players_ready_prompt(self): """Prompt to the host that there are not enough players to join the game.""" label_width = 400 label_height = 30 label_left = 1050 - 100 label_top = (pygame.display.get_surface().get_size()[1] - 50) - (label_height / 2) message = f"Not all players are ready!" prompt_label = RectLabel(label_left, label_top, label_width, label_height, Color.WHITE, txt_obj=Text( pygame.font.SysFont('Agency FB', 24), message)) prompt_label.set_transparent_background(True) self.players_not_ready_prompt = prompt_label def draw(self, screen): self.sprite_grp.draw(screen) for box in self.player_boxes: box.draw(screen) self.chat_box.draw(screen) if self.players_not_ready_prompt: self.players_not_ready_prompt.draw(screen) def update(self, event_queue): if Networking.get_instance().is_host: game = GameStateModel.instance() players_ready = len([ player for player in game.players if player.status == PlayerStatusEnum.READY ]) if players_ready == game.max_players: self.sprite_grp.remove(self.start_button) self.start_button = RectButton( 1050, 575, 130, 48, Color.RED, 0, Text(pygame.font.SysFont('Agency FB', 25), "Start", Color.GREEN)) self.start_button.on_click(self.start_game) self.start_button.change_bg_image(MEDIA_CONSTS.WOOD) self.start_button.add_frame(MEDIA_CONSTS.FRAME) self.sprite_grp.add(self.start_button) # self.start_button.txt_obj.set_color(Color.GREEN) else: self.sprite_grp.remove(self.start_button) self.start_button = RectButton( 1050, 575, 130, 48, Color.GREEN, 0, Text(pygame.font.SysFont('Agency FB', 25), "Start", Color.RED)) self.start_button.disable() self.start_button.change_bg_image(MEDIA_CONSTS.WOOD) self.start_button.add_frame(MEDIA_CONSTS.FRAME) self.sprite_grp.add(self.start_button) self.chat_box.update(event_queue) # game is mutated by reference, BE CAREFUL!!! if len(GameStateModel.instance().players) != self._player_count: self._player_count = len(GameStateModel.instance().players) self.sprite_grp.empty() self._init_all(reuse=True) self.sprite_grp.update(event_queue) def notify_player_index(self, player_index: int): pass def notify_game_state(self, game_state: GameStateEnum): pass def damage_changed(self, new_damage: int): pass def saved_victims(self, victims_saved: int): pass def dead_victims(self, victims_dead: int): pass def player_added(self, player: PlayerModel): pass def player_removed(self, player: PlayerModel): pass def player_command(self, source: PlayerModel, target: PlayerModel): pass
class TileSprite(Interactable, TileObserver): """Graphical representation of a Tile and controls.""" def __init__(self, image: pygame.Surface, fire_image: pygame.Surface, smoke_image: pygame.Surface, x, y, x_offset, y_offset, row, column): self.index = 0 self.sprite_grp = pygame.sprite.Group() self.image = image self._highlight_color = None self.row = row self.column = column self._fire_image = fire_image self._smoke_image = smoke_image self._non_highlight_image = image.copy() self._blank_image = image.copy() self.counter = 80 self.explosion = False self.explosion_image = image.copy() self.explosion_image.blit(pygame.image.load(EXPLOSION), (0, 0, 128, 128)) self.explosion_image.get_rect().move_ip(x_offset, y_offset) self.fire_deck_gun = False self.fire_deck_gun_image = image.copy() self.fire_deck_gun_image.blit( pygame.transform.scale(pygame.image.load(WATER), (128, 128)), (0, 0, 128, 128)) self.fire_deck_gun_image.get_rect().move_ip(x_offset, y_offset) # Initialize if place is Fire, Smoke or Safe tile = GameStateModel.instance().game_board.get_tile_at(row, column) status = tile.space_status is_hotspot = tile.is_hotspot self.tile_status_changed(status, is_hotspot) Interactable.__init__(self, self.image.get_rect()) self.rect = self.image.get_rect().move(x_offset, y_offset) self.mouse_rect = pygame.Rect(self.rect).move(x, y) self._is_hovered = False self._mouse_pos = (0, 0) # For keeping track of previous location. self.is_scrolling = False # ------- POP-UP MENU -------- # self.identify_button = RectButton( self.rect.x, self.rect.y, 100, 25, Color.WOOD, 0, Text(pygame.font.SysFont('Agency FB', 15), "Identify", Color.GREEN2)) pygame.draw.rect(self.identify_button.image, Color.YELLOW, [0, 0, 100, 25], 3) self.move_button = RectButton( self.rect.x, self.rect.y, 100, 25, Color.WOOD, 0, Text(pygame.font.SysFont('Agency FB', 15), "Move Here", Color.GREEN2)) pygame.draw.rect(self.move_button.image, Color.YELLOW, [0, 0, 100, 25], 3) self.extinguish_button = RectButton( self.rect.x, self.rect.y, 100, 25, Color.WOOD, 0, Text(pygame.font.SysFont('Agency FB', 15), "Extinguish", Color.GREEN2)) pygame.draw.rect(self.extinguish_button.image, Color.YELLOW, [0, 0, 100, 25], 3) self.pickup_victim_button = RectButton( self.rect.x, self.rect.y, 100, 25, Color.WOOD, 0, Text(pygame.font.SysFont('Agency FB', 15), "Carry Victim", Color.GREEN2)) pygame.draw.rect(self.pickup_victim_button.image, Color.YELLOW, [0, 0, 100, 25], 3) self.drop_victim_button = RectButton( self.rect.x, self.rect.y, 100, 25, Color.WOOD, 0, Text(pygame.font.SysFont('Agency FB', 15), "Leave Victim", Color.GREEN2)) pygame.draw.rect(self.drop_victim_button.image, Color.YELLOW, [0, 0, 100, 25], 3) self.lead_button = RectButton( self.rect.x, self.rect.y, 100, 25, Color.WOOD, 0, Text(pygame.font.SysFont('Agency FB', 15), "Lead Victim", Color.GREEN2)) pygame.draw.rect(self.lead_button.image, Color.YELLOW, [0, 0, 100, 25], 3) self.change_crew_button = RectButton( self.rect.x, self.rect.y, 100, 25, Color.WOOD, 0, Text(pygame.font.SysFont('Agency FB', 15), "Change Crew", Color.GREEN2)) pygame.draw.rect(self.change_crew_button.image, Color.YELLOW, [0, 0, 100, 25], 3) self.stop_lead_button = RectButton( self.rect.x, self.rect.y, 100, 25, Color.WOOD, 0, Text(pygame.font.SysFont('Agency FB', 15), "Leave Victim", Color.GREEN2)) pygame.draw.rect(self.stop_lead_button.image, Color.YELLOW, [0, 0, 100, 25], 3) self.drive_ambulance_here_button = RectButton( self.rect.x, self.rect.y, 100, 25, Color.WOOD, 0, Text(pygame.font.SysFont('Agency FB', 15), "Drive Ambulance Here", Color.GREEN2)) pygame.draw.rect(self.drive_ambulance_here_button.image, Color.YELLOW, [0, 0, 100, 25], 3) self.drive_engine_here_button = RectButton( self.rect.x, self.rect.y, 100, 25, Color.WOOD, 0, Text(pygame.font.SysFont('Agency FB', 15), "Drive Engine Here", Color.GREEN2)) pygame.draw.rect(self.drive_engine_here_button.image, Color.YELLOW, [0, 0, 100, 25], 3) self.ride_vehicle_button = RectButton( self.rect.x, self.rect.y, 100, 25, Color.WOOD, 0, Text(pygame.font.SysFont('Agency FB', 15), "Ride Vehicle", Color.GREEN2)) pygame.draw.rect(self.ride_vehicle_button.image, Color.YELLOW, [0, 0, 100, 25], 3) self.remove_hazmat_button = RectButton( self.rect.x, self.rect.y, 100, 25, Color.WOOD, 0, Text(pygame.font.SysFont('Agency FB', 15), "Remove Hazmat", Color.GREEN2)) pygame.draw.rect(self.remove_hazmat_button.image, Color.YELLOW, [0, 0, 100, 25], 3) self.dismount_vehicle_button = RectButton( self.rect.x, self.rect.y, 100, 25, Color.WOOD, 0, Text(pygame.font.SysFont('Agency FB', 15), "Dismount Vehicle", Color.GREEN2)) pygame.draw.rect(self.dismount_vehicle_button.image, Color.YELLOW, [0, 0, 100, 25], 3) self.fire_deck_gun_button = RectButton( self.rect.x, self.rect.y, 100, 25, Color.WOOD, 0, Text(pygame.font.SysFont('Agency FB', 15), "Fire Deck Gun", Color.GREEN2)) pygame.draw.rect(self.fire_deck_gun_button.image, Color.YELLOW, [0, 0, 100, 25], 3) self.resuscitate_button = RectButton( self.rect.x, self.rect.y, 100, 25, Color.WOOD, 0, Text(pygame.font.SysFont('Agency FB', 15), "Resuscitate", Color.GREEN2)) pygame.draw.rect(self.resuscitate_button.image, Color.YELLOW, [0, 0, 100, 25], 3) self.command_button = RectButton( self.rect.x, self.rect.y, 100, 25, Color.WOOD, 0, Text(pygame.font.SysFont('Agency FB', 15), "Command", Color.GREEN2)) pygame.draw.rect(self.command_button.image, Color.YELLOW, [0, 0, 100, 25], 3) self.pickup_hazmat_button = RectButton( self.rect.x, self.rect.y, 100, 25, Color.WOOD, 0, Text(pygame.font.SysFont('Agency FB', 15), "Pickup Hazmat", Color.GREEN2)) pygame.draw.rect(self.pickup_hazmat_button.image, Color.YELLOW, [0, 0, 100, 25], 3) self.drop_hazmat_button = RectButton( self.rect.x, self.rect.y, 100, 25, Color.WOOD, 0, Text(pygame.font.SysFont('Agency FB', 15), "Drop Hazmat", Color.GREEN2)) pygame.draw.rect(self.drop_hazmat_button.image, Color.YELLOW, [0, 0, 100, 25], 3) self.disable_all() def __str__(self): return f"TileSprite at: {self.row},{self.column}" def _draw_hightlight(self): self.image.blit(self._non_highlight_image, (0, 0)) hover = pygame.Surface( (self._non_highlight_image.get_width(), self._non_highlight_image.get_height())).convert_alpha() if self._highlight_color: hover.fill(self._highlight_color) hover.set_alpha(10) self.image.blit(hover, (0, 0), special_flags=pygame.BLEND_RGBA_MULT) @property def highlight_color(self): return self._highlight_color @highlight_color.setter def highlight_color(self, color: Tuple[int, int, int]): self._highlight_color = color def hover(self): if self._is_enabled: mouse = pygame.mouse.get_pos() rect = self.rect x_max = rect.x + rect.w x_min = rect.x y_max = rect.y + rect.h y_min = rect.y return x_max > mouse[0] > x_min and y_max > mouse[1] > y_min else: return False def disable_all(self): # Disable all buttons self.identify_button.disable() self.move_button.disable() self.extinguish_button.disable() self.pickup_victim_button.disable() self.drop_victim_button.disable() self.drive_ambulance_here_button.disable() self.drive_engine_here_button.disable() self.ride_vehicle_button.disable() self.dismount_vehicle_button.disable() self.command_button.disable() self.remove_hazmat_button.disable() self.pickup_hazmat_button.disable() self.drop_hazmat_button.disable() self.resuscitate_button.disable() self.lead_button.disable() self.stop_lead_button.disable() self.fire_deck_gun_button.disable() self.change_crew_button.disable() # Important! Reset the on_clicks self.identify_button.on_click(None) self.move_button.on_click(None) self.extinguish_button.on_click(None) self.pickup_victim_button.on_click(None) self.drop_victim_button.on_click(None) self.drive_ambulance_here_button.on_click(None) self.drive_engine_here_button.on_click(None) self.ride_vehicle_button.on_click(None) self.dismount_vehicle_button.on_click(None) self.command_button.on_click(None) self.remove_hazmat_button.on_click(None) self.pickup_hazmat_button.on_click(None) self.drop_hazmat_button.on_click(None) self.resuscitate_button.on_click(None) self.lead_button.on_click(None) self.stop_lead_button.on_click(None) self.fire_deck_gun_button.on_click(None) self.change_crew_button.on_click(None) def is_clicked(self): if not self.hover(): return False for event in EventQueue.get_instance(): if event.type == pygame.MOUSEBUTTONUP and event.button == 1: return True return False def enable(self): """ Enables the event hook :return: """ self._is_enabled = True def disable(self): """ Disables the event hook :return: """ self._is_enabled = False def _scroll(self): """Move this Sprite in the direction of the scroll.""" current_mouse_pos = pygame.mouse.get_pos() pressed = pygame.mouse.get_pressed()[2] # right click movement = (current_mouse_pos[0] - self._mouse_pos[0], current_mouse_pos[1] - self._mouse_pos[1]) if pressed: grid = self.groups()[0] if (grid.rect.left < current_mouse_pos[0] < grid.rect.right and grid.rect.top < current_mouse_pos[1] < grid.rect.bottom): self.rect.move_ip(movement) self.mouse_rect.move_ip(movement) self._mouse_pos = current_mouse_pos def draw(self, screen: pygame.Surface): if self.explosion: screen.blit(self.explosion_image, self.rect) self.counter -= 1 if self.counter == 0: self.explosion = False self.counter = 80 screen.blit(self.image, self.rect) elif self.fire_deck_gun: screen.blit(self.fire_deck_gun_image, self.rect) self.counter -= 1 if self.counter == 0: self.fire_deck_gun = False self.counter = 80 screen.blit(self.image, self.rect) else: self._draw_hightlight() screen.blit(self.image, self.rect) def draw_menu(self, screen: pygame.Surface): offset = 0 inc = 30 if self.move_button.enabled: self.draw_btn(self.move_button, offset, screen) offset += inc if self.extinguish_button.enabled: self.draw_btn(self.extinguish_button, offset, screen) offset += inc if self.pickup_victim_button.enabled: self.draw_btn(self.pickup_victim_button, offset, screen) offset += inc elif self.drop_victim_button.enabled: self.draw_btn(self.drop_victim_button, offset, screen) offset += inc if self.drive_ambulance_here_button.enabled: self.draw_btn(self.drive_ambulance_here_button, offset, screen) offset += inc if self.drive_engine_here_button.enabled: self.draw_btn(self.drive_engine_here_button, offset, screen) offset += inc if self.identify_button.enabled: self.draw_btn(self.identify_button, offset, screen) offset += inc if self.ride_vehicle_button.enabled: self.draw_btn(self.ride_vehicle_button, offset, screen) offset += inc if self.dismount_vehicle_button.enabled: self.draw_btn(self.dismount_vehicle_button, offset, screen) offset += inc if self.remove_hazmat_button.enabled: self.draw_btn(self.remove_hazmat_button, offset, screen) offset += inc if self.pickup_hazmat_button.enabled: self.draw_btn(self.pickup_hazmat_button, offset, screen) offset += inc elif self.drop_hazmat_button.enabled: self.draw_btn(self.drop_hazmat_button, offset, screen) offset += inc if self.resuscitate_button.enabled: self.draw_btn(self.resuscitate_button, offset, screen) offset += inc if self.fire_deck_gun_button.enabled: screen.blit(self.fire_deck_gun_button.image, self.fire_deck_gun_button.rect) self.fire_deck_gun_button.rect.x = self.rect.x self.fire_deck_gun_button.rect.y = self.rect.y + offset offset += inc if self.change_crew_button.enabled: screen.blit(self.change_crew_button.image, self.change_crew_button.rect) self.change_crew_button.rect.x = self.rect.x self.change_crew_button.rect.y = self.rect.y + offset offset += inc if self.command_button.enabled: self.draw_btn(self.command_button, offset, screen) offset += inc if self.lead_button.enabled: self.draw_btn(self.lead_button, offset, screen) offset += inc if self.stop_lead_button.enabled: self.draw_btn(self.stop_lead_button, offset, screen) offset += inc def draw_btn(self, button: RectButton, offset: int, screen: pygame.Surface): screen.blit(button.image, button.rect) button.rect.x = self.rect.x button.rect.y = self.rect.y + offset def update(self, event_queue: EventQueue): self.sprite_grp.update(event_queue) self.drive_ambulance_here_button.update(event_queue) self.drop_victim_button.update(event_queue) self.extinguish_button.update(event_queue) self.pickup_victim_button.update(event_queue) self.move_button.update(event_queue) self.identify_button.update(event_queue) self.ride_vehicle_button.update(event_queue) self.dismount_vehicle_button.update(event_queue) self.drive_engine_here_button.update(event_queue) self.command_button.update(event_queue) self.remove_hazmat_button.update(event_queue) self.drop_hazmat_button.update(event_queue) self.pickup_hazmat_button.update(event_queue) self.resuscitate_button.update(event_queue) self.fire_deck_gun_button.update(event_queue) self.lead_button.update(event_queue) self.stop_lead_button.update(event_queue) self.change_crew_button.update(event_queue) self._scroll() if self.is_clicked(): self.click() def tile_status_changed(self, status: SpaceStatusEnum, is_hotspot: bool): new_surf = pygame.Surface([ self._non_highlight_image.get_width(), self._non_highlight_image.get_height() ]) self._non_highlight_image = self._blank_image.copy() new_surf = pygame.Surface.convert_alpha(new_surf) new_surf.fill((0, 0, 0, 0), None, pygame.BLEND_RGBA_MULT) if status == SpaceStatusEnum.FIRE: image_file = FileImporter.import_image( "media/All Markers/fire.png") new_surf.blit(image_file, (0, 0)) elif status == SpaceStatusEnum.SMOKE: image_file = FileImporter.import_image( "media/All Markers/smoke.png") new_surf.blit(image_file, (0, 0)) if is_hotspot: hs_img = FileImporter.import_image( "media/all_markers/hot_spot.png") new_surf.blit(hs_img, (0, 0)) self._non_highlight_image.blit(new_surf, (0, 0)) def tile_assoc_models_changed(self, assoc_models: List[Model]): pass
class DodgePrompt(object): """Prompt for the player deciding whether to dodge or not.""" def __init__(self): self.bg = pygame.image.load(WOOD) self.frame = pygame.image.load(FRAME) self.frame = pygame.transform.scale(self.frame, (400, 100)) self.accept_button = RectButton( 550 - 75, 310, 75, 50, Color.ORANGE, 0, Text(pygame.font.SysFont('Agency FB', 25), "Accept", Color.GREEN2)) self.accept_button.change_bg_image(WOOD) self.accept_button.add_frame(FRAME) self.deny_button = RectButton( 550 + 200, 310, 75, 50, Color.ORANGE, 0, Text(pygame.font.SysFont('Agency FB', 25), "Deny", Color.GREEN2)) self.deny_button.change_bg_image(WOOD) self.deny_button.add_frame(FRAME) self.accept_button.on_click(self._accept_on_click) self.deny_button.on_click(self._deny_on_click) self.background = RectLabel( 550, 300, 200, 75, Color.GREY, 0, Text(pygame.font.SysFont('Agency FB', 25), "Dodge?", Color.GREEN2)) self.background.change_bg_image(WOOD) self.background.add_frame(FRAME) self.enabled = False self.disable() def enable(self): self.deny_button.enable() self.accept_button.enable() self.accept_button.on_click(self._accept_on_click) self.deny_button.on_click(self._deny_on_click) self.enabled = True def disable(self): self.deny_button.disable() self.accept_button.disable() self.accept_button.on_click(None) self.deny_button.on_click(None) self.enabled = False def _send_reply_event(self, reply: bool): if Networking.get_instance().is_host: Networking.get_instance().send_to_all_client( DodgeReplyEvent(reply)) else: Networking.get_instance().send_to_server(DodgeReplyEvent(reply)) def _deny_on_click(self): self.disable() self._send_reply_event(False) def _accept_on_click(self): self.disable() self._send_reply_event(True) def update(self, event_queue: EventQueue): self.background.update(event_queue) self.accept_button.update(event_queue) self.deny_button.update(event_queue) def draw(self, screen): if self.enabled: self.background.draw(screen) self.accept_button.draw(screen) self.deny_button.draw(screen)
class WallSprite(pygame.sprite.Sprite, WallObserver): def __init__(self, wall_model: WallModel, orientation: str, tile_sprite: TileSprite, tile_model: TileModel, id: Tuple[int, int, str]): super().__init__() self.orientation = orientation self._game: GameStateModel = GameStateModel.instance() self._current_player = self._game.players_turn self._button = None self.tile_model = tile_model self.id = id self.wall_model = wall_model self.wall_model.add_observer(self) self.damaged = self.wall_model.wall_status == WallStatusEnum.DAMAGED self.destroyed = self.wall_model.wall_status == WallStatusEnum.DESTROYED self.tile_sprite = tile_sprite self._prev_x = self.tile_sprite.rect.x self._prev_y = self.tile_sprite.rect.y self.button_input = RectButton( self.tile_sprite.rect.x, self.tile_sprite.rect.y, 100, 25, Color.WOOD, 0, Text(pygame.font.SysFont('Agency FB', 20), "Chop Wall", Color.GREEN2)) pygame.draw.rect(self.button_input.image, Color.YELLOW, [0, 0, 100, 25], 3) self.button_input.disable() self.can_chop = False @property def direction(self) -> str: return self.id[2] @property def wall(self): return self.wall_model @property def player(self) -> PlayerModel: return self._current_player @property def button(self): return self._button @button.setter def button(self, button): self._button = button def update(self, event_queue): diff_x = self.tile_sprite.rect.x - self._prev_x diff_y = self.tile_sprite.rect.y - self._prev_y self._button.rect.move_ip((diff_x, diff_y)) self._prev_x = self.tile_sprite.rect.x self._prev_y = self.tile_sprite.rect.y self.button_input.rect.x = self.tile_sprite.rect.x + 14 self.button_input.rect.y = self.tile_sprite.rect.y + 50 for event in event_queue: if event.type == pygame.MOUSEBUTTONUP: if not ((self.button_input.rect.x <= pygame.mouse.get_pos()[0] <= self.button_input.rect.x + 100) and (self.button_input.rect.y <= pygame.mouse.get_pos()[1] <= self.button_input.rect.y + 25)): self.button_input.disable() self.can_chop = False self._button.update(event_queue) self.button_input.update(event_queue) def wall_status_changed(self, status: WallStatusEnum): if status == WallStatusEnum.DAMAGED: self.damaged = True elif status == WallStatusEnum.DESTROYED: self.damaged = False self.destroyed = True def draw_menu(self, screen): self.button.draw(screen) if self.can_chop: self.button_input.draw(screen) def draw(self, screen): x_offset1 = 0 if self.orientation == "vertical" else 25 y_offset1 = 0 if self.orientation == "horizontal" else 25 x_offset2 = 0 if self.orientation == "vertical" else 50 y_offset2 = 0 if self.orientation == "horizontal" else 50 if self.damaged: marker = RectLabel(self.button.rect.x + x_offset1, self.button.rect.y + y_offset1, 28, 28, "media/Threat_Markers/damageMarker.png") marker.draw(screen) elif self.destroyed: marker = RectLabel(self.button.rect.x + x_offset2, self.button.rect.y + y_offset2, 28, 28, "media/Threat_Markers/damageMarker.png") marker.draw(screen) marker = RectLabel(self.button.rect.x + x_offset1, self.button.rect.y + y_offset1, 28, 28, "media/Threat_Markers/damageMarker.png") marker.draw(screen) def disable_chop(self): self.can_chop = False def enable_chop(self): self.can_chop = True