def _put_loot_on_ground(self, enemy_death_position: Tuple[int, int], loot: List[LootEntry]): for loot_entry in loot: if len(loot) > 1: position_offset = (random.randint(-20, 20), random.randint(-20, 20)) else: position_offset = (0, 0) loot_position = sum_of_vectors(enemy_death_position, position_offset) if loot_entry.money_amount: money_pile_on_ground = create_money_pile_on_ground( loot_entry.money_amount, loot_position) self.game_state.money_piles_on_ground.append( money_pile_on_ground) elif loot_entry.item_type: item_on_ground = create_item_on_ground(loot_entry.item_type, loot_position) self.game_state.items_on_ground.append(item_on_ground) elif loot_entry.consumable_type: consumable_on_ground = create_consumable_on_ground( loot_entry.consumable_type, loot_position) self.game_state.consumables_on_ground.append( consumable_on_ground)
def _put_loot_on_ground(self, enemy_death_position: Tuple[int, int], loot: List[LootEntry]): for loot_entry in loot: if len(loot) > 1: position_offset = (random.randint(-20, 20), random.randint(-20, 20)) else: position_offset = (0, 0) loot_position = sum_of_vectors(enemy_death_position, position_offset) if isinstance(loot_entry, MoneyLootEntry): money_pile_on_ground = create_money_pile_on_ground( loot_entry.amount, loot_position) self.game_state.money_piles_on_ground.append( money_pile_on_ground) elif isinstance(loot_entry, ItemLootEntry): item_id = randomized_item_id(loot_entry.item_type) item_on_ground = create_item_on_ground(item_id, loot_position) self.game_state.items_on_ground.append(item_on_ground) elif isinstance(loot_entry, SuffixedItemLootEntry): item_id = randomized_suffixed_item_id(loot_entry.item_type, loot_entry.suffix_id) item_on_ground = create_item_on_ground(item_id, loot_position) self.game_state.items_on_ground.append(item_on_ground) elif isinstance(loot_entry, ConsumableLootEntry): consumable_on_ground = create_consumable_on_ground( loot_entry.consumable_type, loot_position) self.game_state.consumables_on_ground.append( consumable_on_ground)
def _add_smart_floor_tiles(self, tiles: List[Tuple[int, int, int, int]]): floor_cells = [ ((r[0] - self.game_state.game_world.entire_world_area.x) // GRID_CELL_SIZE, (r[1] - self.game_state.game_world.entire_world_area.y) // GRID_CELL_SIZE) for r in tiles ] self.grid.add_floor_cells(floor_cells) xmin = min([cell[0] for cell in floor_cells]) - 1 xmax = max([cell[0] for cell in floor_cells]) + 2 ymin = min([cell[1] for cell in floor_cells]) - 1 ymax = max([cell[1] for cell in floor_cells]) + 2 for y in range(ymin, ymax): for x in range(xmin, xmax): pos = sum_of_vectors( self.game_state.game_world.entire_world_area.topleft, (x * GRID_CELL_SIZE, y * GRID_CELL_SIZE)) is_even_cell = x % 2 == 0 and y % 2 == 0 # ground sprite covers 4 cells, so we only need them on even cells if is_even_cell and any([ self.grid.is_floor(c) for c in [(x, y), (x + 1, y), (x, y + 1), (x + 1, y + 1)] ]): _add_decoration(Sprite.DECORATION_GROUND_STONE, self.game_state, pos) if self.grid.is_wall((x, y)): wall_type = DungeonGenerator.determine_wall_type( self.grid, (x, y)) self._set_wall(pos, wall_type) if self.grid.is_floor((x, y)): # print("deleting wall from cell (%i,%i)" % (pos)) self._delete_wall(pos)
def handle_mouse_movement( self, mouse_screen_pos: Tuple[int, int]) -> Optional[MapEditorAction]: self._set_currently_hovered_component_not_hovered() self._mouse_screen_pos = mouse_screen_pos self._entity_icon_hovered_by_mouse = None self._snapped_mouse_screen_pos = ( (mouse_screen_pos[0] // self.grid_cell_size) * self.grid_cell_size, (mouse_screen_pos[1] // self.grid_cell_size) * self.grid_cell_size) self._snapped_mouse_world_pos = sum_of_vectors( self._snapped_mouse_screen_pos, self.camera_world_area.topleft) self._is_snapped_mouse_within_world = self.world_area.collidepoint( self._snapped_mouse_world_pos[0], self._snapped_mouse_world_pos[1]) self._is_snapped_mouse_over_ui = self._is_screen_position_within_ui( self._snapped_mouse_screen_pos) mouse_ui_pos = self._translate_screen_position_to_ui(mouse_screen_pos) for icon in self.entity_icons_by_type[self._shown_tab]: if icon.contains(mouse_ui_pos): self._on_hover_component(icon) entity = self._get_map_editor_entity_by_id( icon.map_editor_entity_id) self._entity_icon_hovered_by_mouse = entity return for component in self._checkboxes + self._buttons + self._tab_buttons: if component.contains(mouse_ui_pos): self._on_hover_component(component) return if self._minimap.contains(mouse_ui_pos): self._on_hover_component(self._minimap) if self._is_mouse_button_down: position_ratio = self._minimap.get_position_ratio(mouse_ui_pos) return SetCameraPosition(position_ratio) return if self._is_mouse_button_down and self._is_snapped_mouse_within_world and not self._is_snapped_mouse_over_ui: if self._user_state.placing_entity: if self._user_state.placing_entity.wall_type or self._user_state.placing_entity.decoration_sprite: return AddEntity(self._snapped_mouse_world_pos, self._user_state.placing_entity) elif self._user_state.placing_entity.is_smart_floor_tile: return self._add_smart_floor_tiles() elif self._user_state.deleting_entities: return DeleteEntities(self._snapped_mouse_world_pos) elif self._user_state.deleting_decorations: return DeleteDecorations(self._snapped_mouse_world_pos) elif self._user_state.deleting_smart_floor_tiles: return self._delete_smart_floor_tiles() else: raise Exception("Unhandled user state: " + str(self._user_state))
def render_map_editor_world_entity_at_position(self, sprite: Sprite, entity_size: Tuple[int, int], position: Tuple[int, int]): image_with_relative_position = self._get_image_for_sprite( sprite, Direction.DOWN, 0) sprite_position = sum_of_vectors( position, image_with_relative_position.position_relative_to_entity) self.screen_render.image(image_with_relative_position.image, sprite_position) self.screen_render.rect((50, 250, 0), Rect(position[0], position[1], entity_size[0], entity_size[1]), 3)
def update(self, npc: NonPlayerCharacter, game_state: GameState, time_passed: Millis): self._time_since_summoning += time_passed if self._time_since_summoning > self._summoning_cooldown: necro_center_pos = npc.world_entity.get_center_position() self._time_since_summoning = 0 self._alive_summons = [ summon for summon in self._alive_summons if summon in game_state.game_world.non_player_characters ] if len(self._alive_summons) < self._max_summons: relative_pos_from_summoner = (random.randint(-150, 150), random.randint(-150, 150)) summon_center_pos = sum_of_vectors(necro_center_pos, relative_pos_from_summoner) summon_type = random.choice(self._summon_npc_types) summon_size = NON_PLAYER_CHARACTERS[summon_type].size summon_pos = game_state.game_world.get_within_world( get_position_from_center_position(summon_center_pos, summon_size), summon_size) summon_enemy = self._create_npc(summon_type, summon_pos) is_wall_blocking = game_state.game_world.walls_state.does_rect_intersect_with_wall( rect_from_corners(necro_center_pos, summon_center_pos)) is_position_blocked = game_state.game_world.would_entity_collide_if_new_pos( summon_enemy.world_entity, summon_pos) if not is_wall_blocking and not is_position_blocked: self._summoning_cooldown = self._random_summoning_cooldown( ) game_state.game_world.add_non_player_character( summon_enemy) self._alive_summons.append(summon_enemy) game_state.game_world.visual_effects.append( VisualCircle((80, 150, 100), necro_center_pos, 40, 70, Millis(120), 3)) game_state.game_world.visual_effects.append( VisualCircle((80, 150, 100), summon_center_pos, 40, 70, Millis(120), 3)) play_sound(SoundId.ENEMY_NECROMANCER_SUMMON) else: # Failed to summon, so try again without waiting full duration self._summoning_cooldown = 500 else: self._summoning_cooldown = self._random_summoning_cooldown()
def _put_loot_on_ground(self, enemy_death_position: Tuple[int, int], loot: List[LootEntry]): for loot_entry in loot: if len(loot) > 1: position_offset = (random.randint(-20, 20), random.randint(-20, 20)) else: position_offset = (0, 0) loot_position = sum_of_vectors(enemy_death_position, position_offset) if isinstance(loot_entry, MoneyLootEntry): money_pile_on_ground = create_money_pile_on_ground( loot_entry.amount, loot_position) self.game_state.game_world.money_piles_on_ground.append( money_pile_on_ground) elif isinstance(loot_entry, ItemLootEntry): item_id = randomized_item_id(loot_entry.item_type) item_on_ground = create_item_on_ground(item_id, loot_position) self.game_state.game_world.items_on_ground.append( item_on_ground) elif isinstance(loot_entry, AffixedItemLootEntry): item_id = loot_entry.item_id item_on_ground = create_item_on_ground(item_id, loot_position) self.game_state.game_world.items_on_ground.append( item_on_ground) loot_center_pos = (loot_position[0] + ITEM_ENTITY_SIZE[0] // 2, loot_position[1] + ITEM_ENTITY_SIZE[1] // 2) self.game_state.game_world.visual_effects.append( VisualCircle((170, 200, 170), loot_center_pos, 30, 40, Millis(500), 2)) self.game_state.game_world.visual_effects.append( VisualCircle((70, 100, 70), loot_center_pos, 25, 35, Millis(500), 2)) elif isinstance(loot_entry, ConsumableLootEntry): consumable_on_ground = create_consumable_on_ground( loot_entry.consumable_type, loot_position) self.game_state.game_world.consumables_on_ground.append( consumable_on_ground)
def _render_map_editor_world_entity_at_position(self, sprite: Sprite, position: Tuple[int, int]): image_with_relative_position = self._get_image_for_sprite(sprite, Direction.DOWN, 0) sprite_position = sum_of_vectors(position, image_with_relative_position.position_relative_to_entity) self._screen_render.image(image_with_relative_position.image, sprite_position)
def control_npc(self, game_state: GameState, npc: NonPlayerCharacter, player_entity: WorldEntity, _is_player_invisible: bool, time_passed: Millis): self._time_since_decision += time_passed self._time_since_summoning += time_passed self._time_since_healing += time_passed self._time_since_shoot += time_passed if self._time_since_summoning > self._summoning_cooldown: necro_center_pos = npc.world_entity.get_center_position() self._time_since_summoning = 0 self._alive_summons = [summon for summon in self._alive_summons if summon in game_state.non_player_characters] if len(self._alive_summons) < 3: relative_pos_from_summoner = (random.randint(-150, 150), random.randint(-150, 150)) summon_center_pos = sum_of_vectors(necro_center_pos, relative_pos_from_summoner) summon_type = random.choice([NpcType.ZOMBIE, NpcType.MUMMY]) summon_size = NON_PLAYER_CHARACTERS[summon_type].size summon_pos = game_state.get_within_world( get_position_from_center_position(summon_center_pos, summon_size), summon_size) summon_enemy = create_npc(summon_type, summon_pos) is_wall_blocking = game_state.walls_state.does_rect_intersect_with_wall( rect_from_corners(necro_center_pos, summon_center_pos)) is_position_blocked = game_state.would_entity_collide_if_new_pos(summon_enemy.world_entity, summon_pos) if not is_wall_blocking and not is_position_blocked: self._summoning_cooldown = self._random_summoning_cooldown() game_state.add_non_player_character(summon_enemy) self._alive_summons.append(summon_enemy) game_state.visual_effects.append( VisualCircle((80, 150, 100), necro_center_pos, 40, 70, Millis(120), 3)) game_state.visual_effects.append( VisualCircle((80, 150, 100), summon_center_pos, 40, 70, Millis(120), 3)) play_sound(SoundId.ENEMY_NECROMANCER_SUMMON) else: # Failed to summon, so try again without waiting full duration self._summoning_cooldown = 500 else: self._summoning_cooldown = self._random_summoning_cooldown() if self._time_since_healing > self._healing_cooldown: self._time_since_healing = 0 self._healing_cooldown = self._random_healing_cooldown() necro_center_pos = npc.world_entity.get_center_position() nearby_hurt_enemies = [ e for e in game_state.non_player_characters if e.is_enemy and is_x_and_y_within_distance(necro_center_pos, e.world_entity.get_center_position(), 200) and e != npc and not e.health_resource.is_at_max() ] if nearby_hurt_enemies: healing_target = nearby_hurt_enemies[0] healing_target.health_resource.gain(5) healing_target_pos = healing_target.world_entity.get_center_position() visual_line = VisualLine((80, 200, 150), necro_center_pos, healing_target_pos, Millis(350), 3) game_state.visual_effects.append(visual_line) play_sound(SoundId.ENEMY_NECROMANCER_HEAL) if self._time_since_shoot > self._shoot_cooldown: self._time_since_shoot = 0 self._shoot_cooldown = self._random_shoot_cooldown() npc.world_entity.direction = get_directions_to_position(npc.world_entity, player_entity.get_position())[0] npc.world_entity.set_not_moving() center_position = npc.world_entity.get_center_position() distance_from_enemy = 35 projectile_pos = translate_in_direction( get_position_from_center_position(center_position, PROJECTILE_SIZE), npc.world_entity.direction, distance_from_enemy) projectile_speed = 0.2 projectile_entity = WorldEntity(projectile_pos, PROJECTILE_SIZE, Sprite.NONE, npc.world_entity.direction, projectile_speed) projectile = Projectile(projectile_entity, create_projectile_controller(PROJECTILE_TYPE)) game_state.projectile_entities.append(projectile) play_sound(SoundId.ENEMY_ATTACK_NECRO) if self._time_since_decision > self._decision_interval: self._time_since_decision = 0 if random.random() < 0.2: direction = random_direction() npc.world_entity.set_moving_in_dir(direction) else: npc.world_entity.set_not_moving()
def image_with_relative_pos( self, image_with_relative_position: ImageWithRelativePosition, pos: Tuple[int, int]): translated_pos = sum_of_vectors( pos, image_with_relative_position.position_relative_to_entity) self.image(image_with_relative_position.image, translated_pos)
def main(map_file_name: Optional[str]): map_file_path = MAP_DIR + (map_file_name or "map1.json") if Path(map_file_path).exists(): game_state = create_game_state_from_json_file(CAMERA_SIZE, map_file_path, HERO_ID) else: player_entity = create_hero_world_entity(HERO_ID, (0, 0)) player_state = create_player_state(HERO_ID) game_state = GameState(player_entity, [], [], [], [], [], CAMERA_SIZE, Rect(-250, -250, 500, 500), player_state, [], [], []) pygame.init() pygame_screen = pygame.display.set_mode(SCREEN_SIZE) images_by_sprite = load_images_by_sprite(ENTITY_SPRITE_INITIALIZERS) images_by_ui_sprite = load_images_by_ui_sprite(UI_ICON_SPRITE_PATHS, MAP_EDITOR_UI_ICON_SIZE) images_by_portrait_sprite = load_images_by_portrait_sprite( PORTRAIT_ICON_SPRITE_PATHS, PORTRAIT_ICON_SIZE) world_view = GameWorldView(pygame_screen, CAMERA_SIZE, SCREEN_SIZE, images_by_sprite) ui_view = MapEditorView(pygame_screen, CAMERA_SIZE, SCREEN_SIZE, images_by_sprite, images_by_ui_sprite, images_by_portrait_sprite) user_state = UserState.deleting_entities() is_mouse_button_down = False possible_grid_cell_sizes = [25, 50] grid_cell_size_index = 0 grid_cell_size = possible_grid_cell_sizes[grid_cell_size_index] camera_move_distance = 75 # must be a multiple of the grid size snapped_mouse_screen_position = (0, 0) snapped_mouse_world_position = (0, 0) exact_mouse_screen_position = (0, 0) is_snapped_mouse_within_world = True is_snapped_mouse_over_ui = False game_state.center_camera_on_player() game_state.camera_world_area.topleft = ( (game_state.camera_world_area.x // grid_cell_size) * grid_cell_size, (game_state.camera_world_area.y // grid_cell_size) * grid_cell_size) held_down_arrow_keys = set([]) clock = pygame.time.Clock() camera_pan_timer = PeriodicTimer(Millis(50)) shown_tab = EntityTab.ITEMS while True: for event in pygame.event.get(): if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE): pygame.quit() sys.exit() if event.type == pygame.MOUSEMOTION: exact_mouse_screen_position: Tuple[int, int] = event.pos ui_view.handle_mouse_movement(exact_mouse_screen_position) snapped_mouse_screen_position = ( (exact_mouse_screen_position[0] // grid_cell_size) * grid_cell_size, (exact_mouse_screen_position[1] // grid_cell_size) * grid_cell_size) snapped_mouse_world_position = sum_of_vectors( snapped_mouse_screen_position, game_state.camera_world_area.topleft) is_snapped_mouse_within_world = game_state.is_position_within_game_world( snapped_mouse_world_position) is_snapped_mouse_over_ui = ui_view.is_screen_position_within_ui( snapped_mouse_screen_position) if is_mouse_button_down and is_snapped_mouse_within_world and not is_snapped_mouse_over_ui: if user_state.placing_entity: if user_state.placing_entity.wall_type: _add_wall(game_state, snapped_mouse_world_position, user_state.placing_entity.wall_type) elif user_state.placing_entity.decoration_sprite: _add_decoration( user_state.placing_entity.decoration_sprite, game_state, snapped_mouse_world_position) elif user_state.deleting_entities: _delete_map_entities_from_position( game_state, snapped_mouse_world_position) else: _delete_map_decorations_from_position( game_state, snapped_mouse_world_position) if event.type == pygame.KEYDOWN: if event.key == pygame.K_s: save_file = map_file_path save_game_state_to_json_file(game_state, save_file) print("Saved state to " + save_file) elif event.key in [ pygame.K_RIGHT, pygame.K_DOWN, pygame.K_LEFT, pygame.K_UP ]: held_down_arrow_keys.add(event.key) elif event.key == pygame.K_q: user_state = UserState.deleting_entities() elif event.key == pygame.K_z: user_state = UserState.deleting_decorations() elif event.key == pygame.K_PLUS: grid_cell_size_index = (grid_cell_size_index + 1) % len(possible_grid_cell_sizes) grid_cell_size = possible_grid_cell_sizes[ grid_cell_size_index] elif event.key == pygame.K_v: shown_tab = EntityTab.ITEMS elif event.key == pygame.K_b: shown_tab = EntityTab.NPCS elif event.key == pygame.K_n: shown_tab = EntityTab.WALLS elif event.key == pygame.K_m: shown_tab = EntityTab.MISC if event.type == pygame.KEYUP: if event.key in held_down_arrow_keys: held_down_arrow_keys.remove(event.key) if event.type == pygame.MOUSEBUTTONDOWN: ui_view.handle_mouse_click() is_mouse_button_down = True if user_state.placing_entity: entity_being_placed = user_state.placing_entity if is_snapped_mouse_within_world and not is_snapped_mouse_over_ui: if entity_being_placed.is_player: game_state.player_entity.set_position( snapped_mouse_world_position) elif entity_being_placed.npc_type: _add_npc(entity_being_placed.npc_type, game_state, snapped_mouse_world_position) elif entity_being_placed.wall_type: _add_wall(game_state, snapped_mouse_world_position, entity_being_placed.wall_type) elif entity_being_placed.consumable_type: _add_consumable( entity_being_placed.consumable_type, game_state, snapped_mouse_world_position) elif entity_being_placed.item_type: _add_item(entity_being_placed.item_type, game_state, snapped_mouse_world_position) elif entity_being_placed.decoration_sprite: _add_decoration( entity_being_placed.decoration_sprite, game_state, snapped_mouse_world_position) elif entity_being_placed.money_amount: _add_money(entity_being_placed.money_amount, game_state, snapped_mouse_world_position) elif entity_being_placed.portal_id: _add_portal(entity_being_placed.portal_id, game_state, snapped_mouse_world_position) elif entity_being_placed.is_chest: _add_chest(game_state, snapped_mouse_world_position) else: raise Exception("Unknown entity: " + str(entity_being_placed)) elif user_state.deleting_entities: _delete_map_entities_from_position( game_state, snapped_mouse_world_position) else: _delete_map_decorations_from_position( game_state, snapped_mouse_world_position) if event.type == pygame.MOUSEBUTTONUP: is_mouse_button_down = False clock.tick() time_passed = clock.get_time() if camera_pan_timer.update_and_check_if_ready(time_passed): if pygame.K_RIGHT in held_down_arrow_keys: game_state.translate_camera_position((camera_move_distance, 0)) if pygame.K_LEFT in held_down_arrow_keys: game_state.translate_camera_position( (-camera_move_distance, 0)) if pygame.K_DOWN in held_down_arrow_keys: game_state.translate_camera_position((0, camera_move_distance)) if pygame.K_UP in held_down_arrow_keys: game_state.translate_camera_position( (0, -camera_move_distance)) entities_to_render = game_state.get_all_entities_to_render() decorations_to_render = game_state.get_decorations_to_render() world_view.render_world( all_entities_to_render=entities_to_render, decorations_to_render=decorations_to_render, player_entity=game_state.player_entity, is_player_invisible=game_state.player_state.is_invisible, player_active_buffs=game_state.player_state.active_buffs, camera_world_area=game_state.camera_world_area, non_player_characters=game_state.non_player_characters, visual_effects=game_state.visual_effects, render_hit_and_collision_boxes=ui_view. checkbox_show_entity_outlines.checked, player_health=game_state.player_state.health_resource.value, player_max_health=game_state.player_state.health_resource. max_value, entire_world_area=game_state.entire_world_area, entity_action_text=None) camera_world_area = game_state.camera_world_area world_area = game_state.entire_world_area camera_rect_ratio = ((camera_world_area.x - world_area.x) / world_area.w, (camera_world_area.y - world_area.y) / world_area.h, camera_world_area.w / world_area.w, camera_world_area.h / world_area.h) npc_positions_ratio = [ ((npc.world_entity.x - world_area.x) / world_area.w, (npc.world_entity.y - world_area.y) / world_area.h) for npc in game_state.non_player_characters ] wall_positions_ratio = [ ((wall.world_entity.x - world_area.x) / world_area.w, (wall.world_entity.y - world_area.y) / world_area.h) for wall in game_state.walls_state.walls ] if shown_tab == EntityTab.ITEMS: shown_entities = ITEM_ENTITIES elif shown_tab == EntityTab.NPCS: shown_entities = NPC_ENTITIES elif shown_tab == EntityTab.WALLS: shown_entities = WALL_ENTITIES elif shown_tab == EntityTab.MISC: shown_entities = MISC_ENTITIES else: raise Exception("Unknown entity tab: " + str(shown_tab)) ui_view.set_shown_tab(shown_tab) entity_icon_hovered_by_mouse = ui_view.render( entities=shown_entities, placing_entity=user_state.placing_entity, deleting_entities=user_state.deleting_entities, deleting_decorations=user_state.deleting_decorations, num_enemies=len(game_state.non_player_characters), num_walls=len(game_state.walls_state.walls), num_decorations=len( game_state.decorations_state.decoration_entities), grid_cell_size=grid_cell_size, mouse_screen_position=exact_mouse_screen_position, camera_rect_ratio=camera_rect_ratio, npc_positions_ratio=npc_positions_ratio, wall_positions_ratio=wall_positions_ratio) if is_mouse_button_down and entity_icon_hovered_by_mouse: user_state = UserState.placing_entity(entity_icon_hovered_by_mouse) if is_snapped_mouse_over_ui: pass # render nothing over UI elif not is_snapped_mouse_within_world: snapped_mouse_rect = Rect(snapped_mouse_screen_position[0], snapped_mouse_screen_position[1], grid_cell_size, grid_cell_size) ui_view.render_map_editor_mouse_rect((250, 50, 0), snapped_mouse_rect) elif user_state.placing_entity: entity_being_placed = user_state.placing_entity ui_view.render_map_editor_world_entity_at_position( entity_being_placed.sprite, entity_being_placed.entity_size, snapped_mouse_screen_position) elif user_state.deleting_entities: snapped_mouse_rect = Rect(snapped_mouse_screen_position[0], snapped_mouse_screen_position[1], grid_cell_size, grid_cell_size) ui_view.render_map_editor_mouse_rect((250, 250, 0), snapped_mouse_rect) elif user_state.deleting_decorations: snapped_mouse_rect = Rect(snapped_mouse_screen_position[0], snapped_mouse_screen_position[1], grid_cell_size, grid_cell_size) ui_view.render_map_editor_mouse_rect((0, 250, 250), snapped_mouse_rect) else: raise Exception("Unhandled user_state: " + str(user_state)) pygame.display.update()