def update(self, game: Game) -> TweenCompletion: tween_completion = TweenCompletion() tween_completion.initial_has_started = False tween_completion.completed = False current_time = game.engine.current_time # set value to start value outside of update, as the update call order # is not guaranteed and a later tween that has not started can reset # the value to the start value after a previous tween has updated it. # i.e can't do self.val = self.start_val here. if current_time < self.spawn_time + self.delay: return tween_completion if not (self.has_started): self.has_started = True tween_completion.initial_has_started = True if self.is_constant_speed: delta_x = self.target_val_ptr.x - self.double_point.x delta_y = self.target_val_ptr.y - self.double_point.y delta_dist = sqrt(delta_x * delta_x + delta_y * delta_y) frac = self.speed / delta_dist x = frac * delta_x y = frac * delta_y self.double_point.x += x self.double_point.y += y self.val.x = cast(self.double_point.x, "int") self.val.y = cast(self.double_point.y, "int") # some min dist to check for if delta_dist < 4.0: tween_completion.completed = True return tween_completion else: duration_as_double = cast(self.duration, "double") total_delay = self.spawn_time + self.delay elapsed = current_time - total_delay frac = elapsed / duration_as_double if frac > 1.0: frac = 1.0 diff_x = self.target_val.x - self.start_val.x diff_y = self.target_val.y - self.start_val.y x = diff_x * frac y = diff_y * frac x_as_int = cast(x, "int") y_as_int = cast(y, "int") self.val.x = self.start_val.x + x_as_int self.val.y = self.start_val.y + y_as_int if current_time >= self.spawn_time + self.delay + self.duration: tween_completion.completed = True return tween_completion return tween_completion
def set_to(self, game: Game, ability_name: AbilityName): if ability_name == AbilityName.NA: print("SharedAbility.set_to. Cannot set to AbilityName.NA.") exit(1) ability_name_as_int = cast(ability_name, "int") self.ability = game.ability_db.abilities.at(ability_name_as_int) self.render_dst.is_camera_rendered = True self.current_frame_idx = 0 self.spawn_time = game.engine.current_time
def audio_set_bgm_volume(self, volume_pct: float): # volume_pct ranges from 0.0 - 1.0 # 128 is the max volume volume_val = volume_pct * 128 volume = cast(volume_val, "int") # volume is already this volume, return if self.bgm_audio_volume == volume: return self.bgm_audio_volume = volume Mix_VolumeMusic(volume)
def play_animation(self, game: Game, anim_state: UnitAnimState): # one shot anims will go back to idle automatically, so you don't need to set them again. self.anim_state = anim_state if self.anim_state == UnitAnimState.NA: print("UnitSprite.play_animation. Animation is NA.") exit(1) elif self.anim_state == UnitAnimState.Cast: self.playing_one_shot_anim = True anim_duration = cast(self.cast_down.size * self.cast_anim_speed, "Uint32") self.anim_finish_time = game.engine.current_time + anim_duration
def set_to(self, game: Game, item_name: ItemName): # clear previous data self.sprite.srcs.clear() # set new data self.item_name = item_name self.sprite.spawn_time = game.engine.current_time self.sprite.render_dst.is_camera_rendered = True self.item_type = ItemType.Misc if item_name == ItemName.NA: print("Item.set_to - attempted to call with ItemName.NA.") exit(1) elif item_name == ItemName.Jelly: self.sprite.image = game.engine.get_image(ImageName.Items) self.sprite.anim_speed = 100 src0 = create_rect(20, 0, 20, 20) self.sprite.srcs.push(src0) self.cost = 17 elif item_name == ItemName.FurPelt: self.sprite.image = game.engine.get_image(ImageName.Items) self.sprite.anim_speed = 100 src0 = create_rect(40, 0, 20, 20) self.sprite.srcs.push(src0) self.cost = 32 elif item_name == ItemName.Branch: self.sprite.image = game.engine.get_image(ImageName.Items) self.sprite.anim_speed = 100 src0 = create_rect(60, 0, 20, 20) self.sprite.srcs.push(src0) self.cost = 44 elif item_name == ItemName.Mushroom: self.sprite.image = game.engine.get_image(ImageName.Items) self.sprite.anim_speed = 100 src0 = create_rect(80, 0, 20, 20) self.sprite.srcs.push(src0) self.cost = 38 elif item_name == ItemName.BatWing: self.sprite.image = game.engine.get_image(ImageName.Items) self.sprite.anim_speed = 100 src0 = create_rect(100, 0, 20, 20) self.sprite.srcs.push(src0) self.cost = 27 elif item_name == ItemName.Apple: self.item_type = ItemType.Useable self.sprite.image = game.engine.get_image(ImageName.Items) self.sprite.anim_speed = 100 src0 = create_rect(120, 0, 20, 20) self.sprite.srcs.push(src0) self.cost = 50 else: item_name_as_int = cast(item_name, "int") print("Item.set_to. Item name not handled. ItemName:", item_name_as_int) exit(1)
def set(self, game: Game, start_val: SDL_Rect, val: SDL_Rect, target_val: SDL_Rect, is_constant_speed: bool, speed: float, duration: Uint32, delay: Uint32, callback: TweenCallback): self.start_val = deref(start_val) self.val = val self.target_val = deref(target_val) # for constant speed tweens where it needs to go to the target point even if it changes # after this call. self.target_val_ptr = target_val self.speed = speed self.is_constant_speed = is_constant_speed self.duration = duration self.delay = delay self.spawn_time = game.engine.current_time x_as_double = cast(start_val.x, "double") y_as_double = cast(start_val.y, "double") self.double_point.init(x_as_double, y_as_double) self.callback = deref(callback) self.remove_in_update = False self.has_started = False
def audio_set_se_volume(self, volume_pct: float): # volume_pct ranges from 0.0 - 1.0 # 128 is the max volume volume_val = volume_pct * 128 volume = cast(volume_val, "int") # volume is already this volume, return if self.se_audio_volume == volume: return self.se_audio_volume = volume # modify all sound effect volume for se_audio in self.se_audio: Mix_VolumeChunk(se_audio.audio, self.se_audio_volume)
def init(self, game: Game): self.items.size = array_capacity(self.items) last_enum_idx = last_enum_int(ItemName) if last_enum_idx > self.items.size - 1: print( "ItemDB.init - ItemName's last enum idx is > items capacity.") exit(1) # skip NA by starting at 1 for i in range(1, last_enum_idx): item_name = cast(i, "ItemName") game.temp_item.set_to(game, item_name) self.items[i] = game.temp_item
def init(self, game: Game): self.units.size = array_capacity(self.units) last_enum_idx = last_enum_int(UnitName) if last_enum_idx > self.units.size - 1: print("UnitDB.init - UnitName's last enum idx is > units capacity.") exit(1) # skip NA by starting at 1 for i in range(1, last_enum_idx): unit_name = cast(i, "UnitName") game.temp_unit.init(game, 0) game.temp_unit.set_to(game, unit_name, Faction.Ally) self.units[i] = game.temp_unit
def init(self, game: Game): self.abilities.size = array_capacity(self.abilities) last_enum_idx = last_enum_int(AbilityName) if last_enum_idx > self.abilities.size - 1: print( "AbilityDB.init - AbilityName's last enum idx is > abilities capacity." ) exit(1) # skip NA by starting at 1 for i in range(1, last_enum_idx): ability_name = cast(i, "AbilityName") game.temp_ability.set_to(game, ability_name) self.abilities[i] = game.temp_ability
def set_to(self, game: Game, ability_name: AbilityName): # clear previous ability data self.sprite.srcs.clear() self.portrait.srcs.clear() # set new data self.ability_name = ability_name self.sprite.spawn_time = game.engine.current_time self.sprite.render_dst.is_camera_rendered = True self.sprite.image = game.engine.get_image(ImageName.Abilities) self.portrait.image = game.engine.get_image(ImageName.Items) if ability_name == AbilityName.NA: print("Ability.set_to - attempted to call with AbilityName.NA.") exit(1) elif ability_name == AbilityName.MeleeAttack: self.sprite.anim_speed = 60 self.is_projectile = False self.stats.damage = 20 self.stats.range = 30 self.stats.max_skill_points = 10 portrait_src = create_rect(20, 20, 20, 20) self.portrait.srcs.push(portrait_src) x = 0 w = 30 for i in range(8): src = create_rect(x, 32, w, 30) self.sprite.srcs.push(src) x += w elif ability_name == AbilityName.Fire: self.sprite.anim_speed = 100 self.is_projectile = True self.projectile_speed = 2.0 self.start_offset = create_point(0, -30) self.delay = 500 self.stats.damage = 20 self.stats.range = 100 self.stats.max_skill_points = 10 portrait_src = create_rect(0, 20, 20, 20) self.portrait.srcs.push(portrait_src) src0 = create_rect(64, 0, 16, 21) src1 = create_rect(80, 0, 16, 21) src2 = create_rect(96, 0, 16, 21) self.sprite.srcs.push(src0) self.sprite.srcs.push(src1) self.sprite.srcs.push(src2) else: ability_name_as_int = cast(ability_name, "int") print("Ability.set_to. Ability name not handled. AbilityName:", ability_name_as_int) exit(1)
def set_to(self, game: Game, item_name: ItemName, quantity: int, drop_chance: int): if item_name == ItemName.NA: print("SharedItem.set_to. Cannot set to ItemName.NA.") exit(1) if drop_chance < 0 or drop_chance > 100: print( "SharedItem.set_to. Item drop chance must be >= 0 and <= 100, found drop chance:", drop_chance) exit(1) item_name_as_int = cast(item_name, "int") self.item = game.item_db.items.at(item_name_as_int) self.quantity = quantity self.drop_chance = drop_chance self.render_dst.is_camera_rendered = True self.current_frame_idx = 0 self.spawn_time = game.engine.current_time
def update(self, game: Game): mouse_tile_point = world_point_to_index_with_camera( game.engine.mouse_point_scaled, game.engine.camera.dst, game.tile_size) mouse_move_grid_tile_point = world_point_to_index_with_camera( game.engine.mouse_point_scaled, game.engine.camera.dst, game.move_grid_tile_size) w_int = cast(SDLK.w, "int") a_int = cast(SDLK.a, "int") s_int = cast(SDLK.s, "int") d_int = cast(SDLK.d, "int") q_int = cast(SDLK.q, "int") e_int = cast(SDLK.e, "int") z_int = cast(SDLK.z, "int") w_down = game.engine.keys_held_down[w_int] a_down = game.engine.keys_held_down[a_int] s_down = game.engine.keys_held_down[s_int] d_down = game.engine.keys_held_down[d_int] q_down = game.engine.keys_down[q_int] e_down = game.engine.keys_down[e_int] z_down = game.engine.keys_down[z_int] camera_move_dist = 4 if e_down: player_guild = self.guilds.at(0) unit_handle = player_guild.unit_handles[0] unit = self.units.at(unit_handle) if unit.unit_name == UnitName.Explorer: unit.stats.job_level = 10 elif unit.unit_name == UnitName.Mage: unit.stats.job_level = 40 if z_down: player_guild = self.guilds.at(0) unit_handle = player_guild.unit_handles[0] unit = self.units.at(unit_handle) stat_points = get_stat_points_for_level(unit.stats.level) stat_point_cost = get_stat_cost(unit.stats.strength.value) print(unit.stats.level, stat_points, "-", unit.stats.strength.value, stat_point_cost) unit.available_stat_points += get_stat_points_for_level( unit.stats.level) unit.stats.level += 1 uint64_1 = cast(1, "Uint64") unit.stats.strength.inc(uint64_1) if w_down: game.engine.camera.dst.y -= camera_move_dist if a_down: game.engine.camera.dst.x -= camera_move_dist if s_down: game.engine.camera.dst.y += camera_move_dist if d_down: game.engine.camera.dst.x += camera_move_dist if game.engine.is_mouse_down: self.mouse_down_tile_point = mouse_tile_point if game.engine.is_mouse_up: # is a click if the mouse is down and up on the same tile if points_are_equal(self.mouse_down_tile_point, mouse_tile_point): # find map the user clicked on in the overworld if self.visible_map_handle == 0: overworld = self.maps.at(0) for warp_point in overworld.warp_points: if points_are_equal(mouse_tile_point, warp_point.tile_point): self.visible_map_handle = warp_point.warp_to_map_handle break if game.engine.is_right_mouse_down: if self.visible_map_handle != 0: self.visible_map_handle = 0 # clear ui before everything is updated, which refills the ui rect buffer self.ui.clear() # update tweens self.update_tween_arr( game, self.tween_xys, self.tween_xys_last_in_use_handle, HandleType.TweenXY) # if the last handle is 0 then iterate to 1 for i in range(self.units_last_in_use_handle + 1): unit = self.units.at(i) if not(unit.in_use_in_pool): continue unit.update(game) for i in range(self.items_last_in_use_handle + 1): item = self.items.at(i) if not(item.in_use_in_pool): continue item.update(game) for i in range(self.abilities_last_in_use_handle + 1): ability = self.abilities.at(i) if not(ability.in_use_in_pool): continue ability.update(game) for i in range(self.damage_texts_last_in_use_handle + 1): damage_text = self.damage_texts.at(i) if not(damage_text.in_use_in_pool): continue damage_text.text_update(game) for map in self.maps: map.update(game) # call update_visible_map for the visible map visible_map = self.maps.at(self.visible_map_handle) visible_map.update_visible_map(game) # everything has been updated, so the ui buffer is populated # if any ui was meant to appear, update ui now. self.ui.update(game)
def set_to(self, game: Game, unit_name: UnitName): self.anim_state = UnitAnimState.Idle self.idle_down.clear() self.cast_down.clear() self.sit_down.clear() self.overworld_idle_down.clear() self.render_dst.is_camera_rendered = True # should this be set this here, should be fine I think. self.spawn_time = game.engine.current_time self.idle_anim_speed = 1 self.cast_anim_speed = 1 self.sit_anim_speed = 1 self.overworld_idle_anim_speed = 1 # hit_boxes need to be multiples of game.move_tile_grid_size if unit_name == UnitName.RandomTownsPerson0: self.image = game.engine.get_image(ImageName.Units) self.idle_anim_speed = 130 self.cast_anim_speed = 240 self.sit_anim_speed = 100 self.overworld_idle_anim_speed = 130 self.hit_box_size = create_point(20, 40) idle_down_src0 = create_rect(260, 0, 20, 40) self.idle_down.push(idle_down_src0) elif unit_name == UnitName.Merchant: self.image = game.engine.get_image(ImageName.Units) self.idle_anim_speed = 130 self.cast_anim_speed = 240 self.sit_anim_speed = 100 self.overworld_idle_anim_speed = 130 self.hit_box_size = create_point(20, 40) idle_down_src0 = create_rect(220, 0, 20, 40) self.idle_down.push(idle_down_src0) cast_down_src0 = create_rect(80, 0, 20, 40) self.cast_down.push(cast_down_src0) sit_down_src0 = create_rect(240, 0, 20, 40) self.sit_down.push(sit_down_src0) overworld_idle_down_src0 = create_rect(20, 40, 20, 20) overworld_idle_down_src1 = create_rect(40, 40, 20, 20) overworld_idle_down_src2 = create_rect(60, 40, 20, 20) self.overworld_idle_down.push(overworld_idle_down_src0) self.overworld_idle_down.push(overworld_idle_down_src1) self.overworld_idle_down.push(overworld_idle_down_src0) self.overworld_idle_down.push(overworld_idle_down_src2) elif unit_name == UnitName.Explorer: self.image = game.engine.get_image(ImageName.Units) self.idle_anim_speed = 130 self.cast_anim_speed = 240 self.sit_anim_speed = 100 self.overworld_idle_anim_speed = 130 self.hit_box_size = create_point(20, 40) idle_down_src0 = create_rect(0, 0, 20, 40) idle_down_src1 = create_rect(40, 0, 20, 40) idle_down_src2 = create_rect(0, 0, 20, 40) idle_down_src3 = create_rect(60, 0, 20, 40) self.idle_down.push(idle_down_src0) self.idle_down.push(idle_down_src1) self.idle_down.push(idle_down_src2) self.idle_down.push(idle_down_src3) cast_down_src0 = create_rect(80, 0, 20, 40) self.cast_down.push(cast_down_src0) sit_down_src0 = create_rect(200, 0, 20, 40) self.sit_down.push(sit_down_src0) overworld_idle_down_src0 = create_rect(20, 40, 20, 20) overworld_idle_down_src1 = create_rect(40, 40, 20, 20) overworld_idle_down_src2 = create_rect(60, 40, 20, 20) self.overworld_idle_down.push(overworld_idle_down_src0) self.overworld_idle_down.push(overworld_idle_down_src1) self.overworld_idle_down.push(overworld_idle_down_src0) self.overworld_idle_down.push(overworld_idle_down_src2) elif unit_name == UnitName.Mage: self.image = game.engine.get_image(ImageName.Units) self.idle_anim_speed = 100 self.cast_anim_speed = 240 self.sit_anim_speed = 100 self.overworld_idle_anim_speed = 130 self.hit_box_size = create_point(20, 40) idle_down_src0 = create_rect(20, 0, 20, 40) self.idle_down.push(idle_down_src0) cast_down_src0 = create_rect(100, 0, 20, 40) self.cast_down.push(cast_down_src0) sit_down_src0 = create_rect(200, 0, 20, 40) self.sit_down.push(sit_down_src0) overworld_idle_down_src0 = create_rect(80, 40, 20, 20) overworld_idle_down_src1 = create_rect(100, 40, 20, 20) overworld_idle_down_src2 = create_rect(120, 40, 20, 20) self.overworld_idle_down.push(overworld_idle_down_src0) self.overworld_idle_down.push(overworld_idle_down_src1) self.overworld_idle_down.push(overworld_idle_down_src0) self.overworld_idle_down.push(overworld_idle_down_src2) elif unit_name == UnitName.Wizard: self.image = game.engine.get_image(ImageName.Units) self.idle_anim_speed = 100 self.cast_anim_speed = 240 self.sit_anim_speed = 100 self.overworld_idle_anim_speed = 130 self.hit_box_size = create_point(20, 40) idle_down_src0 = create_rect(120, 0, 20, 40) self.idle_down.push(idle_down_src0) cast_down_src0 = create_rect(160, 0, 20, 40) self.cast_down.push(cast_down_src0) sit_down_src0 = create_rect(200, 0, 20, 40) self.sit_down.push(sit_down_src0) overworld_idle_down_src0 = create_rect(20, 40, 20, 20) overworld_idle_down_src1 = create_rect(40, 40, 20, 20) overworld_idle_down_src2 = create_rect(60, 40, 20, 20) self.overworld_idle_down.push(overworld_idle_down_src0) self.overworld_idle_down.push(overworld_idle_down_src1) self.overworld_idle_down.push(overworld_idle_down_src0) self.overworld_idle_down.push(overworld_idle_down_src2) elif unit_name == UnitName.Scholar: self.image = game.engine.get_image(ImageName.Units) self.idle_anim_speed = 100 self.cast_anim_speed = 240 self.sit_anim_speed = 100 self.overworld_idle_anim_speed = 130 self.hit_box_size = create_point(20, 40) idle_down_src0 = create_rect(140, 0, 20, 40) self.idle_down.push(idle_down_src0) cast_down_src0 = create_rect(180, 0, 20, 40) self.cast_down.push(cast_down_src0) sit_down_src0 = create_rect(200, 0, 20, 40) self.sit_down.push(sit_down_src0) overworld_idle_down_src0 = create_rect(20, 40, 20, 20) overworld_idle_down_src1 = create_rect(40, 40, 20, 20) overworld_idle_down_src2 = create_rect(60, 40, 20, 20) self.overworld_idle_down.push(overworld_idle_down_src0) self.overworld_idle_down.push(overworld_idle_down_src1) self.overworld_idle_down.push(overworld_idle_down_src0) self.overworld_idle_down.push(overworld_idle_down_src2) elif unit_name == UnitName.Slime: self.image = game.engine.get_image(ImageName.Units) self.idle_anim_speed = 100 self.cast_anim_speed = 300 self.sit_anim_speed = 100 self.hit_box_size = create_point(20, 18) idle_down_src0 = create_rect(0, 40, 20, 18) self.idle_down.push(idle_down_src0) self.cast_down.push(idle_down_src0) elif unit_name == UnitName.Bunny: self.image = game.engine.get_image(ImageName.Units) self.idle_anim_speed = 100 self.cast_anim_speed = 300 self.sit_anim_speed = 100 self.hit_box_size = create_point(20, 28) idle_down_src0 = create_rect(0, 64, 20, 28) self.idle_down.push(idle_down_src0) self.cast_down.push(idle_down_src0) elif unit_name == UnitName.Bat: self.image = game.engine.get_image(ImageName.Units) self.idle_anim_speed = 100 self.cast_anim_speed = 300 self.sit_anim_speed = 100 self.hit_box_size = create_point(20, 26) idle_down_src0 = create_rect(0, 96, 20, 26) self.idle_down.push(idle_down_src0) self.cast_down.push(idle_down_src0) elif unit_name == UnitName.Stump: self.image = game.engine.get_image(ImageName.Units) self.idle_anim_speed = 100 self.cast_anim_speed = 300 self.sit_anim_speed = 100 self.hit_box_size = create_point(28, 38) idle_down_src0 = create_rect(0, 128, 28, 37) self.idle_down.push(idle_down_src0) self.cast_down.push(idle_down_src0) elif unit_name == UnitName.Shroomed: self.image = game.engine.get_image(ImageName.Units) self.idle_anim_speed = 100 self.cast_anim_speed = 300 self.sit_anim_speed = 100 self.hit_box_size = create_point(26, 34) idle_down_src0 = create_rect(0, 165, 26, 33) self.idle_down.push(idle_down_src0) self.cast_down.push(idle_down_src0) else: unit_name_as_int = cast(unit_name, "int") print("UnitSprite.set_to. Unit name not handled. UnitName:", unit_name_as_int) exit(1)
def value_pct_of_max(self) -> float: value_as_double = cast(self.value, "double") max_as_double = cast(self.max, "double") return value_as_double / max_as_double
def get_stat_cost(stat_value: Uint64): stat_value -= 1 stat_div = stat_value / 10.0 value = floor(stat_div) + 2 value_as_int = cast(value, "int") return value_as_int
def handle_tween_on_complete(self, game: Game, tween_callback: TweenCallback): callback = TweenCallback() if tween_callback.tween_type == TweenType.NA: print("World - handle_tween_on_complete. tween_type is NA.") exit(1) elif tween_callback.tween_type == TweenType.UnitMoveToShop: if tween_callback.is_final_point_in_path: unit = self.units.at(tween_callback.handle) unit.inside_building = True # basically a set delay for in shop tween_handle = game.world.get_handle(HandleType.TweenXY) tween = game.world.tween_xys.at(tween_handle) callback.tween_type = TweenType.UnitInShop callback.handle = unit.handle duration = cast(2000, "Uint32") delay = cast(0, "Uint32") tween.set(game, unit.sprite.render_dst.dst, unit.sprite.render_dst.dst, unit.sprite.render_dst.dst, False, 0.0, duration, delay, callback) elif tween_callback.tween_type == TweenType.UnitInShop: unit = self.units.at(tween_callback.handle) # sell items unit.sell_items(game) unit.inside_building = False success = unit.try_find_and_move_to_merchant_shop(game) if not(success): unit.ai_state = UnitAIState.Battle unit.move_to_overworld_warp_point(game) elif tween_callback.tween_type == TweenType.UnitMoveToTeleporter: if tween_callback.is_final_point_in_path: unit = self.units.at(tween_callback.handle) battle_map = self.maps.at(unit.battle_map_handle) unit.join_map(game, battle_map) unit.set_random_spawn_point(game) elif tween_callback.tween_type == TweenType.UnitMoveToGuildBuilding: if tween_callback.is_final_point_in_path: unit = self.units.at(tween_callback.handle) unit.inside_building = True # basically a set delay for in guild building tween_handle = game.world.get_handle(HandleType.TweenXY) tween = game.world.tween_xys.at(tween_handle) callback.tween_type = TweenType.UnitInGuildBuilding callback.handle = unit.handle duration = cast(2000, "Uint32") delay = cast(0, "Uint32") tween.set(game, unit.sprite.render_dst.dst, unit.sprite.render_dst.dst, unit.sprite.render_dst.dst, False, 0.0, duration, delay, callback) elif tween_callback.tween_type == TweenType.UnitInGuildBuilding: unit = self.units.at(tween_callback.handle) unit.inside_building = False # give non-sellable items to the guild's inventory if unit.is_merchant(): unit.merchant_get_sellable_items_from_guild(game) unit.move_to_setup_merchant_shop(game) else: unit.give_items_to_guild(game) unit.move_to_shop(game) elif tween_callback.tween_type == TweenType.UnitMoveToSetupMerchantShop: if tween_callback.is_final_point_in_path: unit = self.units.at(tween_callback.handle) unit.ai_state = UnitAIState.MerchantSelling unit.sprite.play_animation(game, UnitAnimState.Sit) elif tween_callback.tween_type == TweenType.UnitRandomTownMove: if tween_callback.is_final_point_in_path: unit = self.units.at(tween_callback.handle) # start the random move point cycle again unit.move_to_random_town_point(game) elif tween_callback.tween_type == TweenType.UnitMoveToWarpPoint: if tween_callback.is_final_point_in_path: unit = self.units.at(tween_callback.handle) map = self.maps.at(unit.map_handle) warp_point_handle = tween_callback.warp_point_handle warp_point = map.warp_points.at(warp_point_handle) warping_to_map_handle = warp_point.warp_to_map_handle warping_to_map = self.maps.at(warping_to_map_handle) unit.join_map(game, warping_to_map) if warping_to_map.is_town_map or warping_to_map_handle == 0: # town maps or overworld can't get stuck as units dont check for # collissions when pathing. unit.set_spawn_point( game, warp_point.warp_to_tile_point_move_grid) else: # battle maps need a random spawn for now to avoid getting stuck # on each other on top of the warp point when they re-enter the battle # map. unit.set_random_spawn_point(game) if unit.ai_state == UnitAIState.Selling: if warping_to_map.handle == 0: unit.move_to_town_warp_point(game) elif warping_to_map.is_town_map: unit.move_to_guild_building(game) elif unit.ai_state == UnitAIState.Battle: if warping_to_map.handle == 0: unit.move_to_battle_warp_point(game) elif tween_callback.tween_type == TweenType.UnitMoveToBuyAtMerchantShop: if tween_callback.is_final_point_in_path: unit = self.units.at(tween_callback.handle) map = self.maps.at(unit.map_handle) # basically a set delay tween_handle = game.world.get_handle(HandleType.TweenXY) tween = game.world.tween_xys.at(tween_handle) callback.tween_type = TweenType.UnitBuyingAtMerchantShop callback.handle = unit.handle callback.merchant_unit_handle = tween_callback.merchant_unit_handle duration = cast(2000, "Uint32") delay = cast(0, "Uint32") tween.set(game, unit.sprite.render_dst.dst, unit.sprite.render_dst.dst, unit.sprite.render_dst.dst, False, 0.0, duration, delay, callback) elif tween_callback.tween_type == TweenType.UnitBuyingAtMerchantShop: unit = self.units.at(tween_callback.handle) merchant_unit = self.units.at(tween_callback.merchant_unit_handle) if not(merchant_unit.is_merchant()): print( "TweenType.UnitBuyingAtMerchantShop. Merchant handle unit is not a merchant.") exit(1) # let other units shop at the merchant merchant_unit.unit_handle_buying_from_merchant = -1 # have the merchant sell some items to the neutral unit merchant_unit.merchant_sell_to_unit(game) # unit can now go back to battle, Guild -> Shop -> Merchant Shop -> Battle unit.ai_state = UnitAIState.Battle unit.move_to_overworld_warp_point(game) elif tween_callback.tween_type == TweenType.PerformAbility: map = self.maps.at(tween_callback.map_handle) ability_handle = tween_callback.handle ability = self.abilities.at(ability_handle) acting_unit_handle = tween_callback.acting_unit_handle acting_unit = self.units.at(acting_unit_handle) receiving_unit = self.units.at( tween_callback.receiving_unit_handle) # remove the ability handle from the map and release the handle find_and_remove_handle(map.ability_handles, ability_handle) self.release_handle(HandleType.Ability, ability_handle) # set attacked by faction to prevent ksing receiving_unit.attacked_by_guild_handle = acting_unit.guild_handle # apply damage if unit is not already dead - prevents items from dropping to multiple # units, only the unit that killed gets the items if not(receiving_unit.stats.hp.value_is_at_min()): receiving_unit.stats.hp.dec(ability.ability.stats.damage) receiving_unit.on_hit(game, acting_unit_handle) if receiving_unit.stats.hp.value_is_at_min(): # normal exp exp = receiving_unit.stats.experience_drop * receiving_unit.stats.level exp_as_uint64 = cast(exp, "Uint64") acting_unit.stats.experience.inc(exp_as_uint64) if acting_unit.stats.experience.value_is_at_max(): # max level is 99, I am not wrapping exp to the next level, seems # to have a lot of problems and I don't think it matters. if acting_unit.stats.level < 99: acting_unit.available_stat_points += get_stat_points_for_level( acting_unit.stats.level) acting_unit.stats.level += 1 acting_unit.stats.experience.set_to_min() # double max exp to get to the next level acting_unit.stats.experience.max *= 2 # job exp job_exp = receiving_unit.stats.job_experience_drop * receiving_unit.stats.level job_exp_as_uint64 = cast(job_exp, "Uint64") acting_unit.stats.job_experience.inc(job_exp_as_uint64) if acting_unit.stats.job_experience.value_is_at_max(): if acting_unit.stats.job_level < 10: acting_unit.available_skill_points += 1 acting_unit.stats.job_level += 1 acting_unit.stats.job_experience.set_to_min() acting_unit.stats.job_experience.max *= 2 receiving_unit.on_dead(game, acting_unit_handle) # damage text damage_text_handle = self.get_handle(HandleType.DamageText) damage_text = self.damage_texts.at(damage_text_handle) sprintf(damage_text.str, "%lu", ability.ability.stats.damage) damage_text_dst = create_point( receiving_unit.sprite.render_dst.dst.x, receiving_unit.sprite.render_dst.dst.y) text_color = create_color(255, 255, 255, 255) text_outline_color = create_color(0, 0, 0, 255) damage_text.text_set_without_str(game, damage_text_dst, FontStyle.Bold, TextAlignment.Left, TextWordWrap.NoWrap, 500, 16, text_color, 1, text_outline_color, False) damage_text.render_dst.is_camera_rendered = True map.damage_text_handles.push_value(damage_text_handle) # damage text tween text_tween_handle = self.get_handle(HandleType.TweenXY) text_tween = self.tween_xys.at(text_tween_handle) start_rect = receiving_unit.sprite.render_dst.dst target_rect = start_rect target_rect.y -= 30 duration = cast(2000, "Uint32") delay = cast(0, "Uint32") callback.tween_type = TweenType.DamageText callback.handle = damage_text_handle callback.receiving_unit_handle = tween_callback.receiving_unit_handle callback.map_handle = tween_callback.map_handle text_tween.set(game, start_rect, damage_text.render_dst.dst, target_rect, False, 0.0, duration, delay, callback) elif tween_callback.tween_type == TweenType.ItemDrop: map = self.maps.at(tween_callback.map_handle) item_handle = tween_callback.handle item = self.items.at(item_handle) receiving_unit_handle = tween_callback.receiving_unit_handle receiving_unit = self.units.at(receiving_unit_handle) receiving_unit.inventory.add_item(game, item.item.item_name, item.quantity) find_and_remove_handle(map.item_handles, item_handle) self.release_handle(HandleType.Item, item_handle) if receiving_unit.ai_state != UnitAIState.Selling: receiving_unit.change_to_sell_item_ai_state(game) elif tween_callback.tween_type == TweenType.DamageText: # remove the damage text handle from the map and release the handle damage_text_handle = tween_callback.handle map = self.maps.at(tween_callback.map_handle) find_and_remove_handle( map.damage_text_handles, damage_text_handle) self.release_handle(HandleType.DamageText, damage_text_handle)
def get_unit(self, unit_name: UnitName) -> Unit: unit_name_as_int = cast(unit_name, "int") return self.units.at(unit_name_as_int)
def on_click(self, game: Game, ui_event: UIEvent): # only set on_click_fired_this frame for events, NA is fine becuase it won't set it # and other renderables still have a chance to have on click fire. Setting it to true # here and if no events trigger it will be set back to False, just so you don't forget # to set it in any of these conditionals. self.on_click_fired_this_frame = True if ui_event.event_name == UIEventName.BuyRecruitModal: # prevent click on modal triggering a backdrop click return elif ui_event.event_name == UIEventName.BuyRecruitBackdrop: # modal backdrop clicked, hide the recruit novice modal self.recruit_novice_modal.set_visible(False) elif ui_event.event_name == UIEventName.BuyRecruitClose: # modal backdrop clicked, hide the recruit novice modal self.recruit_novice_modal.set_visible(False) elif ui_event.event_name == UIEventName.BuyExplorer: player_guild = game.world.guilds.at(0) # if player_guild.current_money < 500: # return #player_guild.current_money -= 500 self.recruit_novice_modal.set_visible(False) # add unit unit_handle = game.world.get_handle(HandleType.Unit) unit = game.world.units.at(unit_handle) unit.set_to(game, UnitName.Explorer, Faction.Ally) map = game.world.maps.at(1) unit.join_guild(game, player_guild) unit.join_map(game, map) unit.set_random_spawn_point(game) elif ui_event.event_name == UIEventName.BuyMerchant: player_guild = game.world.guilds.at(0) # if player_guild.current_money < 500: # return #player_guild.current_money -= 500 self.recruit_novice_modal.set_visible(False) # add unit unit_handle = game.world.get_handle(HandleType.Unit) unit = game.world.units.at(unit_handle) unit.set_to(game, UnitName.Merchant, Faction.Ally) map = game.world.maps.at(2) unit.join_guild(game, player_guild) unit.join_map(game, map) unit.set_random_spawn_point(game) elif ui_event.event_name == UIEventName.UnitsWindowOpen: # toggle visibility opposite_visible_state = not (game.world.ui.units_window.visible) game.world.ui.units_window.set_visible(opposite_visible_state) elif ui_event.event_name == UIEventName.UnitsWindowClose: game.world.ui.units_window.set_visible(False) elif ui_event.event_name == UIEventName.UnitsWindowBackground: # prevent click on modal triggering a backdrop click return elif ui_event.event_name == UIEventName.UnitsWindowSlot: handle = ui_event.handle guild_handle = ui_event.guild_handle guild = game.world.guilds.at(guild_handle) if handle <= guild.unit_handles.size - 1: game.world.ui.units_window.active_slot_idx = handle elif ui_event.event_name == UIEventName.UnitsWindowStatusTab: game.world.ui.units_window.active_tab = UnitsWindowTabName.Status elif ui_event.event_name == UIEventName.UnitsWindowInventoryTab: game.world.ui.units_window.active_tab = UnitsWindowTabName.Inventory elif ui_event.event_name == UIEventName.UnitsWindowAbilityTab: game.world.ui.units_window.active_tab = UnitsWindowTabName.Ability elif ui_event.event_name == UIEventName.UnitsWindowJobChangeTab: game.world.ui.units_window.active_tab = UnitsWindowTabName.JobChange elif ui_event.event_name == UIEventName.UnitsWindowAITab: game.world.ui.units_window.active_tab = UnitsWindowTabName.AI elif ui_event.event_name == UIEventName.UnitsWindowJobChange: guild_unit_idx = game.world.ui.units_window.active_slot_idx player_guild = game.world.guilds.at(0) unit_handle = player_guild.unit_handles[guild_unit_idx] unit = game.world.units.at(unit_handle) unit_name = ui_event.unit_name unit.set_to(game, unit_name, unit.faction) elif ui_event.event_name == UIEventName.UnitsWindowLearnAbility: guild_unit_idx = game.world.ui.units_window.active_slot_idx player_guild = game.world.guilds.at(0) unit_handle = player_guild.unit_handles[guild_unit_idx] unit = game.world.units.at(unit_handle) job_ability = unit.job_abilities.at(ui_event.handle) ability = unit.get_ability(job_ability.ability.ability_name) if unit.available_skill_points == 0: return if ability.skill_points < job_ability.ability.stats.max_skill_points: unit.available_skill_points -= 1 ability.skill_points += 1 elif ui_event.event_name == UIEventName.UnitsWindowIncreaseStats: guild_unit_idx = game.world.ui.units_window.active_slot_idx player_guild = game.world.guilds.at(0) unit_handle = player_guild.unit_handles[guild_unit_idx] unit = game.world.units.at(unit_handle) stat_name = ui_event.stat_name inc_val = cast(1, "Uint64") stat_cost = 0 if stat_name == StatName.Strength: stat_cost = get_stat_cost(unit.stats.strength.value) if unit.available_stat_points >= stat_cost: unit.available_stat_points -= stat_cost unit.stats.strength.inc(inc_val) elif stat_name == StatName.Intelligence: stat_cost = get_stat_cost(unit.stats.intelligence.value) if unit.available_stat_points >= stat_cost: unit.available_stat_points -= stat_cost unit.stats.intelligence.inc(inc_val) elif stat_name == StatName.Dexterity: stat_cost = get_stat_cost(unit.stats.dexterity.value) if unit.available_stat_points >= stat_cost: unit.available_stat_points -= stat_cost unit.stats.dexterity.inc(inc_val) elif stat_name == StatName.Vitality: stat_cost = get_stat_cost(unit.stats.vitality.value) if unit.available_stat_points >= stat_cost: unit.available_stat_points -= stat_cost unit.stats.vitality.inc(inc_val) elif stat_name == StatName.Agility: stat_cost = get_stat_cost(unit.stats.agility.value) if unit.available_stat_points >= stat_cost: unit.available_stat_points -= stat_cost unit.stats.agility.inc(inc_val) elif stat_name == StatName.Luck: stat_cost = get_stat_cost(unit.stats.luck.value) if unit.available_stat_points >= stat_cost: unit.available_stat_points -= stat_cost unit.stats.luck.inc(inc_val) elif ui_event.event_name == UIEventName.UnitsWindowAISelect: if game.world.ui.units_window.ai_ability_dropdown_visible and game.world.ui.units_window.ai_ability_active_idx == ui_event.handle: game.world.ui.units_window.ai_ability_dropdown_visible = False else: game.world.ui.units_window.ai_ability_dropdown_visible = True game.world.ui.units_window.ai_ability_active_idx = ui_event.handle elif ui_event.event_name == UIEventName.UnitsWindowAISelectOption: guild_unit_idx = game.world.ui.units_window.active_slot_idx player_guild = game.world.guilds.at(0) unit_handle = player_guild.unit_handles[guild_unit_idx] unit = game.world.units.at(unit_handle) ability_handle = ui_event.handle # delete button, clear ai slot if ability_handle == game.world.ui.units_window.ai_ability_dropdown_options.size - 1: ai_ability_handle = game.world.ui.units_window.ai_ability_active_idx ai_ability = unit.ai_abilities.at(ai_ability_handle) ai_ability.clear() game.world.ui.units_window.ai_ability_dropdown_visible = False elif ability_handle <= unit.abilities.size - 1: ability = unit.abilities.at(ability_handle) ai_ability_handle = game.world.ui.units_window.ai_ability_active_idx ai_ability = unit.ai_abilities.at(ai_ability_handle) ai_ability.set(ability_handle, AIAbilityCondition.Always) game.world.ui.units_window.ai_ability_dropdown_visible = False elif ui_event.event_name == UIEventName.UnitsWindowAISelectBackground: return elif ui_event.event_name == UIEventName.MerchantsWindowOpen: # toggle visibility opposite_visible_state = not ( game.world.ui.merchants_window.visible) game.world.ui.merchants_window.set_visible(opposite_visible_state) elif ui_event.event_name == UIEventName.MerchantsWindowClose: game.world.ui.merchants_window.set_visible(False) elif ui_event.event_name == UIEventName.MerchantsWindowBackground: # prevent click on modal triggering a backdrop click return elif ui_event.event_name == UIEventName.MerchantsWindowSlot: handle = ui_event.handle guild_handle = ui_event.guild_handle guild = game.world.guilds.at(guild_handle) if handle <= guild.merchant_handles.size - 1: game.world.ui.merchants_window.active_slot_idx = handle elif ui_event.event_name == UIEventName.GuildWindowOpen: # toggle visibility opposite_visible_state = not (game.world.ui.guild_window.visible) game.world.ui.guild_window.set_visible(opposite_visible_state) elif ui_event.event_name == UIEventName.GuildWindowClose: game.world.ui.guild_window.set_visible(False) elif ui_event.event_name == UIEventName.GuildWindowBackground: # prevent click on modal triggering a backdrop click return else: self.on_click_fired_this_frame = False
def get_stat_points_for_level(level: int): level_div = level / 5.0 value = floor(level_div) + 3 value_as_int = cast(value, "int") return value_as_int
def create_initial(self, game: Game, rows: int, cols: int, is_town_map): if rows > game.max_map_size.x: print("Map.create_initial. rows is > game.max_map_size.x", "\nrows:", rows, "\nmax_map_size.x", game.max_map_size.x) exit(1) if cols > game.max_map_size.y: print("Map.create_initial. cols is > game.max_map_size.y", "\ncols:", cols, "\nmax_map_size.y", game.max_map_size.y) exit(1) self.is_town_map = is_town_map tile = Tile() warp_point = WarpPoint() self.rows = rows self.cols = cols self.move_grid_rows = rows * game.move_grid_ratio self.move_grid_cols = cols * game.move_grid_ratio for i in range(rows): for j in range(cols): tile_point = create_point(i, j) dst = tile_point_to_world_point(tile_point, game.tile_size) src = create_rect(0, 0, 20, 20) shared_srcs = game.sprite_db.find( game, ImageName.Tiles, src) tile.sprite.shared_srcs = shared_srcs tile.sprite.render_dst.dst.x = dst.x tile.sprite.render_dst.dst.y = dst.y tile.sprite.anim_speed = 100 tile.sprite.render_dst.is_camera_rendered = True self.tiles.push(tile) # create some warp points if self.handle == 1: tile_point = create_point(rows - 2, 15) warp_to_tile_point = create_point(10 + 1, 15) warp_point.set(game, WarpPointName.Standard, tile_point, warp_to_tile_point, 0) self.warp_points.push(warp_point) elif self.handle == 2: tile_point = create_point(0, 20) warp_to_tile_point = create_point(22 - 1, 8) warp_point.set(game, WarpPointName.Standard, tile_point, warp_to_tile_point, 0) self.warp_points.push(warp_point) elif self.handle == 3: tile_point = create_point(rows - 2, 15) warp_to_tile_point = create_point(32 - 1, 18) warp_point.set(game, WarpPointName.Standard, tile_point, warp_to_tile_point, 0) self.warp_points.push(warp_point) # create some initial units if not(self.is_town_map): num_enemies = game.engine.get_rand_int(20, 40) for i in range(num_enemies): unit_handle = game.world.get_handle(HandleType.Unit) unit = game.world.units.at(unit_handle) rand_unit_enum_int = game.engine.get_rand_int(7, 11) rand_unit_name = cast(rand_unit_enum_int, "UnitName") unit.set_to(game, rand_unit_name, Faction.Enemy) unit.join_map(game, self) unit.set_random_spawn_point(game)
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)