def pool_release_handle(arr, handle: int, last_in_use_handle_ptr: int): last_in_use_handle = deref(last_in_use_handle_ptr) item = arr.at(handle) if not (item.in_use_in_pool): print( "pool_release_handle - tried to release an inactive item. Item must be active to be released." ) exit(1) item.in_use_in_pool = False # if the handle released is the last in use handle, then find the new last in use # handle. If you do a batch release, make sure the indices are in ascending order so that # only the last delete triggers this scan, i.e indices [0, 1, 2, 3, 4, 5] if 5 is the last # in use handle it only triggers this branch on the last index in the list. # unit_handles in map for enemies follows this pattern. if handle == last_in_use_handle: set(deref(last_in_use_handle_ptr), pool_get_last_in_use_handle(arr))
def get_bgm_audio(self, bgm_audio_name: BGMAudioName) -> BGMAudio: for audio in self.bgm_audio: if audio.audio_name == bgm_audio_name: return deref(audio) exit(1) return self.bgm_audio[0]
def pool_get_handle(arr, last_in_use_handle_ptr: int, debug_pool_name_char_ptr) -> int: last_in_use_handle = deref(last_in_use_handle_ptr) for i, item in enumerate(arr): if not (item.in_use_in_pool): item.in_use_in_pool = True # update last_in_use_handle_ptr if the handle returned # is greater than the last_in_use_handle_ptr value if i > last_in_use_handle: set(deref(last_in_use_handle_ptr), i) return i capacity = array_capacity(arr) print("pool_get_handle - all elements are in use.") print("pool name:", debug_pool_name_char_ptr, "\npool size: ", arr.size, "\npool capacity:", capacity) exit(1)
def get_se_audio(self, se_audio_name: SEAudioName) -> SEAudio: for audio in self.se_audio: if audio.audio_name == se_audio_name: return deref(audio) exit(1) return self.se_audio[0]
def get_image(self, image_name: ImageName) -> Image: for image in self.images: if image.image_name == image_name: return deref(image) exit(1) return self.images[0]
def push(arr, value_ptr): capacity = array_capacity(arr) if arr.size > capacity - 1: print("push - array size is > than capacity - 1.", "size:", arr.size, "capacity:", capacity) exit(1) arr[arr.size] = deref(value_ptr) arr.size += 1
def text_set(self, game: Game, text_str, dst: SDL_Point, font_style: FontStyle, _text_alignment: TextAlignment, _text_word_wrap: TextWordWrap, _width: int, font_size: int, color: SDL_Color, outline: int, outline_color: SDL_Color, use_drop_shadow: bool): self.render_dst.dst = create_rect(dst.x, dst.y, 0, 0) self.render_dst.scaled_dst = self.render_dst.dst self.font_style = font_style self.text_alignment = _text_alignment self.text_word_wrap = _text_word_wrap self.width = _width self.font_size = font_size * game.engine.scale self.color = deref(color) self.outline = outline self.outline_color = deref(outline_color) self.use_drop_shadow = use_drop_shadow self.str.string_set_literal(text_str) self.font = engine_get_font(game.engine, self.font_style, self.font_size, self.color, self.outline, self.outline_color, self.use_drop_shadow) self.render_dst.is_camera_rendered = False
def text_set_without_str(self, game: Game, dst: SDL_Point, font_style: FontStyle, _text_alignment: TextAlignment, _text_word_wrap: TextWordWrap, _width: int, font_size: int, color: SDL_Color, outline: int, outline_color: SDL_Color, use_drop_shadow: bool): # if the str was set before calling this function (such as in the case of damage text in world) self.render_dst.dst = create_rect(dst.x, dst.y, 0, 0) self.render_dst.scaled_dst = self.render_dst.dst self.font_style = font_style self.text_alignment = _text_alignment self.text_word_wrap = _text_word_wrap self.width = _width self.font_size = font_size * game.engine.scale self.color = deref(color) self.outline = outline self.outline_color = deref(outline_color) self.use_drop_shadow = use_drop_shadow self.font = engine_get_font(game.engine, self.font_style, self.font_size, self.color, self.outline, self.outline_color, self.use_drop_shadow) self.render_dst.is_camera_rendered = False
def set(self, game: Game, warp_point_name: WarpPointName, tile_point: SDL_Point, warp_to_tile_point: SDL_Point, warp_to_map_handle: int): self.warp_point_name = warp_point_name self.tile_point = deref(tile_point) self.tile_point_move_grid.x = self.tile_point.x * game.move_grid_ratio self.tile_point_move_grid.y = self.tile_point.y * game.move_grid_ratio self.warp_to_tile_point = deref(warp_to_tile_point) self.warp_to_tile_point_move_grid.x = self.warp_to_tile_point.x self.warp_to_tile_point_move_grid.y = self.warp_to_tile_point.y self.warp_to_tile_point_move_grid.x *= game.move_grid_ratio self.warp_to_tile_point_move_grid.y *= game.move_grid_ratio self.warp_to_map_handle = warp_to_map_handle world_point = tile_point_to_world_point(self.tile_point_move_grid, game.move_grid_tile_size) self.sprite.render_dst.dst.x = world_point.x self.sprite.render_dst.dst.y = world_point.y if warp_point_name == WarpPointName.Standard: src = create_rect(0, 20, 40, 40) self.sprite.shared_srcs = game.sprite_db.find( game, ImageName.Tiles, src) self.sprite.anim_speed = 100 self.sprite.render_dst.is_camera_rendered = True elif warp_point_name == WarpPointName.Town: src = create_rect(20, 0, 20, 20) self.sprite.shared_srcs = game.sprite_db.find( game, ImageName.Tiles, src) self.sprite.anim_speed = 100 self.sprite.render_dst.is_camera_rendered = True elif warp_point_name == WarpPointName.Forest: src = create_rect(40, 0, 20, 20) self.sprite.shared_srcs = game.sprite_db.find( game, ImageName.Tiles, src) self.sprite.anim_speed = 100 self.sprite.render_dst.is_camera_rendered = True
def get_random_unoccupied_move_grid_tile_point(self, game: Game, tile_point_hit_box: SDL_Rect) -> SDL_Point: iters = 0 max_iters = 500 hit_box_cpy = deref(tile_point_hit_box) p = create_point(hit_box_cpy.x, hit_box_cpy.y) while iters < max_iters: iters += 1 p.x = game.engine.get_rand_int(0, self.move_grid_rows - 1) p.y = game.engine.get_rand_int(0, self.move_grid_cols - 1) hit_box_cpy.x = p.x hit_box_cpy.y = p.y if not(self.unit_occupies_tile_point_move_grid(game, hit_box_cpy, -1)): # print("Point found") return p print("Could not find random unoccupied point.") return create_point(0, 0)
def set_path(self, game: Game, map: Map, acting_unit: Unit, p1: SDL_Point, p2: SDL_Point, check_unit_collissions: bool): # inc call number, doens't matter if it overflows just needs to be unique for each call self.call_number += 1 # if the call number if 0 it means it overflowed, clear the tables so that previous # call numbers won't be treated as valid. Imagine call number 5 is set in a cell from the # previous 0 - MAX_SIZE iteration, if the current call number is 5 it will treat it as valid, # even though it is from the previous 0 - MAX_SIZE iteration if self.call_number == 0: memset(addr(self.g_arr), 0, 1) memset(addr(self.came_from), 0, 1) # reset size as it was just zero'd out self.g_arr.size = array_capacity(self.g_arr) self.came_from.size = array_capacity(self.came_from) # finally inc call number to 1 so that 0 call number values from memset are not # treated as valid from this call number (that would mean every cell was valid) self.call_number = 1 # clear previous path data self.clear_prev_path_data() # make copies of p1 and p2 because there was a weird mutation bug start = deref(p1) target = deref(p2) # closest point to target - is only valid if find_closest_target param is true self.closest_point_to_target = start self.closest_dist_to_target = manhattan_distance(start, target) tile_point_hit_box_cpy = acting_unit.tile_point_hit_box if not(map.in_bounds_move_grid(target)): print("PathFinder.set path - target_point is not in bounds.") exit(1) if points_are_equal(start, target): print("Pathfinder.set_path - start and target points are equal.") return iters = 0 reconstruct_path_iters = 0 # max iters for now is the path capacity, though iters can be greater than # the number of tiles in the map if it gets stuck and needs go around obstacles. # a good starting point though, change later if people struggle to find paths. max_iters = array_capacity(self.path) # not sure if this is true but keeping it for now if max_iters > array_capacity(self.path): print("PathFinder.set_path max_iters must be <= path capacity") exit(1) neighbors = Array[SDL_Point](4) # set size directly because it will be manipulated with random access below neighbors.size = 4 path_node = PathNode() path_node.p = start path_node.g = 0 # self.g_arr.push(path_node) insert_point(self.g_arr, path_node.p, path_node, map.rows, self.call_number) pq_node = PQNode() pq_node.p = start pq_node.f = manhattan_distance(start, target) self.pq_arr.push(pq_node) came_from = CameFrom() # don't exit if iters fails, it just means a path couldn't be found. # it is not likely an error condition (althought it could be) while iters < max_iters and self.pq_arr.size > 0: iters += 1 # pop last idx from pq_arr. It is sorted so it is the # node with the min f value. pq_last_idx = self.pq_arr.size - 1 current = self.pq_arr[pq_last_idx] self.pq_arr.size -= 1 if points_are_equal(current.p, target): # print("Found target in", iters, "iters") self.path.push(target) while arr_contains_key(self.came_from, current.p, map.rows, self.call_number): reconstruct_path_iters += 1 if reconstruct_path_iters > max_iters: print( "PathFinder.set_path - reconstruct_path iters > max_iters.") exit(1) came_from_handle = get_1d_from_2d_idx(current.p, map.rows) came_from_ptr = self.came_from.at(came_from_handle) current.p = came_from_ptr.to_point if not(points_are_equal(current.p, start)): self.path.push(current.p) # reverse the array as it is currently backwards self.path.reverse() return n0 = neighbors.at(0) n1 = neighbors.at(1) n2 = neighbors.at(2) n3 = neighbors.at(3) n0.x = current.p.x + 1 n0.y = current.p.y n1.x = current.p.x - 1 n1.y = current.p.y n2.x = current.p.x n2.y = current.p.y + 1 n3.x = current.p.x n3.y = current.p.y - 1 for n in neighbors: if not(map.in_bounds_move_grid(n)): continue tile_point_hit_box_cpy.x = n.x tile_point_hit_box_cpy.y = n.y if check_unit_collissions and map.unit_occupies_tile_point_move_grid(game, tile_point_hit_box_cpy, acting_unit.handle): continue g_handle = get_1d_from_2d_idx(current.p, map.rows) g_node = self.g_arr.at(g_handle) new_g_cost = g_node.g + 1 neighbor_g_contains_handle = arr_contains_key( self.g_arr, n, map.rows, self.call_number) neighbor_g_handle = get_1d_from_2d_idx(n, map.rows) neighbor_g = -1 if neighbor_g_contains_handle: neighbor_g_node = self.g_arr.at(neighbor_g_handle) neighbor_g = neighbor_g_node.g if not(neighbor_g_contains_handle) or new_g_cost < neighbor_g: f = manhattan_distance(n, target) # update or push g_arr for the neighbor path_node.g = new_g_cost path_node.p = deref(n) insert_point(self.g_arr, path_node.p, path_node, map.rows, self.call_number) # push pq node and sort the pq pq_node.f = f pq_node.p = deref(n) self.pq_arr.push(pq_node) pq_insertion_sort(self.pq_arr) # update or push a new came from to came from arr came_from.from_point = deref(n) came_from.to_point = current.p insert_point(self.came_from, n, came_from, map.rows, self.call_number) # possibly update closest point to target dist = manhattan_distance(current.p, target) if dist > 0 and dist < self.closest_dist_to_target: self.closest_dist_to_target = dist self.closest_point_to_target = current.p
def insert_point(arr, point: SDL_Point, value, rows: int, call_number: Uint32): idx = get_1d_from_2d_idx(point, rows) value.contains_key = True # set call number to this call so that contains key will treat the cell as valid value.call_number = call_number arr[idx] = deref(value)
def world_point_to_index_with_camera(world_point: SDL_Point, camera_point: SDL_Point, tile_size: SDL_Point): p = deref(world_point) p.x += camera_point.x p.y += camera_point.y return world_point_to_tile_point(p, tile_size)
def pool_init(game: Game, arr, last_in_use_handle_ptr: int): arr.size = array_capacity(arr) set(deref(last_in_use_handle_ptr), -1) for i, item in enumerate(arr): item.init(game, i)
def audio_play_bgm(self, bgm_audio: BGMAudio): # just using self for now so that unused var warnings go away self.current_bgm_audio = deref(bgm_audio) Mix_PlayMusic(bgm_audio.audio, -1)
def text_set_color(self, game: Game, color: SDL_Color): self.color = deref(color) self.font = engine_get_font(game.engine, self.font_style, self.font_size, self.color, self.outline, self.outline_color, self.use_drop_shadow)
def pool_of_text_init(game: Game, arr, last_in_use_handle_ptr: int): # text uses text_init because there are many texts for each string size. arr.size = array_capacity(arr) set(deref(last_in_use_handle_ptr), -1) for i, item in enumerate(arr): item.text_init(game, i)
def set_to(self, game: Game, building_name: BuildingName, move_grid_tile_point: SDL_Point): self.tile_point_hit_box.x = move_grid_tile_point.x self.tile_point_hit_box.y = move_grid_tile_point.y world_point = tile_point_to_world_point(move_grid_tile_point, game.move_grid_tile_size) self.sprite.render_dst.dst.x = world_point.x self.sprite.render_dst.dst.y = world_point.y # clear previous ability data self.sprite.srcs.clear() # set new data self.building_name = building_name self.sprite.spawn_time = game.engine.current_time self.sprite.render_dst.is_camera_rendered = True self.is_shop = False self.building_type = BuildingType.NA self.door_tile_point = deref(move_grid_tile_point) if building_name == BuildingName.NA: print("Building.set_to - attempted to call with AbilityName.NA.") exit(1) elif building_name == BuildingName.PlayerLeague: self.building_type = BuildingType.League self.sprite.image = game.engine.get_image(ImageName.Buildings) self.sprite.anim_speed = 100 src_w = 140 src_h = 200 move_grid_hit_box_size_dims = get_move_grid_size_dims( src_w, src_h, game.move_grid_tile_size) self.tile_point_hit_box.w = move_grid_hit_box_size_dims.x self.tile_point_hit_box.h = move_grid_hit_box_size_dims.y src0 = create_rect(0, 0, src_w, src_h) self.sprite.srcs.push(src0) self.door_tile_point.x = move_grid_tile_point.x + 30 self.door_tile_point.y = move_grid_tile_point.y + 80 elif building_name == BuildingName.Shop0: self.building_type = BuildingType.PotionShop self.is_shop = True self.sprite.image = game.engine.get_image(ImageName.Buildings) self.sprite.anim_speed = 100 src_w = 140 src_h = 200 move_grid_hit_box_size_dims = get_move_grid_size_dims( src_w, src_h, game.move_grid_tile_size) self.tile_point_hit_box.w = move_grid_hit_box_size_dims.x self.tile_point_hit_box.h = move_grid_hit_box_size_dims.y src0 = create_rect(140, 0, src_w, src_h) self.sprite.srcs.push(src0) self.door_tile_point.x = move_grid_tile_point.x + 30 self.door_tile_point.y = move_grid_tile_point.y + 80 elif building_name == BuildingName.RecruitmentCenter0: self.building_type = BuildingType.RecruitmentShop self.sprite.image = game.engine.get_image(ImageName.Buildings) self.sprite.anim_speed = 100 src_w = 140 src_h = 200 move_grid_hit_box_size_dims = get_move_grid_size_dims( src_w, src_h, game.move_grid_tile_size) self.tile_point_hit_box.w = move_grid_hit_box_size_dims.x self.tile_point_hit_box.h = move_grid_hit_box_size_dims.y src0 = create_rect(280, 0, src_w, src_h) self.sprite.srcs.push(src0) self.door_tile_point.x = move_grid_tile_point.x + 30 self.door_tile_point.y = move_grid_tile_point.y + 80 elif building_name == BuildingName.TeleportationStone: self.sprite.image = game.engine.get_image(ImageName.Buildings) self.sprite.anim_speed = 150 src_w = 80 src_h = 160 move_grid_hit_box_size_dims = get_move_grid_size_dims( src_w, src_h, game.move_grid_tile_size) self.tile_point_hit_box.w = move_grid_hit_box_size_dims.x self.tile_point_hit_box.h = move_grid_hit_box_size_dims.y src = create_rect(0, 864, src_w, src_h) self.sprite.srcs.push(src) for i in range(6): src = create_rect(i * src_w, 864, src_w, src_h) self.sprite.srcs.push(src) else: building_name_as_int = cast(building_name, "int") print("Building.set_to. Building name not handled. BulidingName:", building_name_as_int) exit(1)