class CategoryTracker(Tracker[CategoryTrackerConfig, WindowData]): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.proc = None self.time_total = None self.run_state = None def initialize(self): self.time_total = 0 self.run_state = RunState() def poll(self, proc: Spel2Process, config: CategoryTrackerConfig) -> WindowData: game_state = proc.get_state() if game_state is None: return None # Check if we've reset, if so, reinitialize new_time_total = game_state.time_total if new_time_total < self.time_total: self.initialize() self.time_total = new_time_total self.run_state.update(game_state) label = self.run_state.get_display(game_state.screen, config) return WindowData(label)
class CategoryWatcherThread(WatcherThread): def __init__(self, *args, always_show_modifiers=False, **kwargs): super().__init__(*args, **kwargs) self.time_total = None self.run_state = None self.always_show_modifiers = always_show_modifiers def initialize(self): self.time_total = 0 self.run_state = RunState( always_show_modifiers=self.always_show_modifiers, ) def poll(self): game_state = self.proc.get_state() if game_state is None: self.shutdown() return # Check if we've reset, if so, reinitialize new_time_total = game_state.time_total if new_time_total < self.time_total: self.initialize() self.time_total = new_time_total self.run_state.update(game_state) label = self.run_state.get_display(game_state.screen) self.send(Command.LABEL, label)
def test_could_tp_mount(mount_type, expected_could_tp): mount = Mount(type=EntityDBEntry(id=mount_type)) poly_mount = PolyPointer(101, mount, MemContext()) player = Player(overlay=poly_mount) run_state = RunState() assert run_state.could_tp(player, set(), set()) == expected_could_tp
def test_compute_player_motion_mount_and_active_floor(): elevator = Movable( type=EntityDBEntry(id=EntityType.ACTIVEFLOOR_ELEVATOR), position_x=0.5, position_y=0.7, velocity_x=-0.1, velocity_y=-0.3, ) poly_elevator = PolyPointer(101, elevator, MemContext()) # Turkey on an elevator mount = Mount( type=EntityDBEntry(id=EntityType.MOUNT_TURKEY), position_x=18, position_y=13, velocity_x=-2, velocity_y=-7, overlay=poly_elevator, ) poly_mount = PolyPointer(102, mount, MemContext()) player = Player(position_x=5, position_y=7, velocity_x=-1, velocity_y=-3, overlay=poly_mount) expected_motion = PlayerMotion(position_x=18.5, position_y=13.7, velocity_x=-2.1, velocity_y=-7.3) run_state = RunState() assert run_state.compute_player_motion(player) == expected_motion
def test_attacked_with_excalibur( layer, theme, presence_flags, chain_status, expected_failed_low_if_not_chain, expected_low, ): prev_state = CharState.PUSHING cur_state = CharState.ATTACKING item_set = {EntityType.ITEM_EXCALIBUR} # These should vary with theme, but there's already a lot of params world = 4 level = 2 run_state = RunState() run_state.sunken_chain_status = chain_status run_state.update_attacked_with( prev_state, cur_state, layer, world, level, theme, presence_flags, item_set, item_set, ) # We only expect these to be set together assert run_state.failed_low_if_not_chain == expected_failed_low_if_not_chain is_low = Label.LOW in run_state.run_label._set assert is_low == expected_low
def test_attacked_with_mattock(layer, theme, presence_flags, expected_low): prev_state = CharState.PUSHING cur_state = CharState.ATTACKING item_set = {EntityType.ITEM_MATTOCK} # These should vary with theme, but there's already a lot of params world = 2 level = 2 run_state = RunState() run_state.update_attacked_with( prev_state, cur_state, layer, world, level, theme, presence_flags, item_set, item_set, ) # We only expect this to be set when we're still low% assert run_state.mc_has_swung_mattock == expected_low is_low = Label.LOW in run_state.run_label._set assert is_low == expected_low
def test_run_recap(label, recap_flag, method): run_state = RunState() method(run_state, recap_flag) assert label in run_state.run_label._set run_state = RunState() method(run_state, RunRecapFlags(0)) assert label not in run_state.run_label._set
def test_compute_player_motion_wo_overlay(): player = Player(position_x=5, position_y=7, velocity_x=-1, velocity_y=-3) expected_motion = PlayerMotion(position_x=5, position_y=7, velocity_x=-1, velocity_y=-3) run_state = RunState() assert run_state.compute_player_motion(player) == expected_motion
def test_attacked_with_throwables(prev_state, cur_state, prev_item_set, cur_item_set, expected_low): run_state = RunState() run_state.update_attacked_with_throwables(prev_state, cur_state, prev_item_set, cur_item_set) is_low = Label.LOW in run_state.run_label._set assert is_low == expected_low
def test_wore_backpack(item_set, expected_no_jp, expected_low): run_state = RunState() run_state.update_wore_backpack(item_set) is_no_jp = Label.NO_JETPACK in run_state.run_label._set assert is_no_jp == expected_no_jp is_low = Label.LOW in run_state.run_label._set assert is_low == expected_low
def test_has_chain_powerup(chain_status, item_set, expected_had_ankh, expected_low): run_state = RunState() run_state.sunken_chain_status = chain_status run_state.update_has_chain_powerup(item_set) assert run_state.had_ankh == expected_had_ankh is_low = Label.LOW in run_state.run_label._set assert is_low == expected_low
def test_status_effects_cursed(player_state, prev_cursed, item_set, expected_cursed, expected_low): run_state = RunState() run_state.cursed = prev_cursed run_state.update_status_effects(player_state, item_set) assert run_state.cursed == expected_cursed is_low = Label.LOW in run_state.run_label._set assert is_low == expected_low
def test_has_mounted_tame(chain_status, theme, mount_type, mount_tamed, expected_low): mount = Mount(type=EntityDBEntry(id=mount_type), is_tamed=mount_tamed) poly_mount = PolyPointer(101, mount, MemContext()) run_state = RunState() run_state.sunken_chain_status = chain_status run_state.update_has_mounted_tame(theme, poly_mount) is_low = Label.LOW in run_state.run_label._set assert is_low == expected_low
def test_rope_deployed(new_entity_types, theme, expected_no): run_state = RunState() run_state.new_entities = [ poly_pointer_no_mem(Entity(type=EntityDBEntry(id=t))) for t in new_entity_types ] run_state.update_rope_deployed(theme) is_no = Label.NO in run_state.run_label._set assert is_no == expected_no
def test_millionaire_clone_gun_wo_bow(item_set, cosmic_status, expected_clone_gun_wo_cosmic, expected_millionaire): run_state = RunState() run_state.cosmic_stepper = FakeStepper(cosmic_status) run_state.update_millionaire(State(), Inventory(), item_set) assert run_state.clone_gun_wo_cosmic == expected_clone_gun_wo_cosmic is_millionaire = Label.MILLIONAIRE in run_state.run_label._set assert is_millionaire == expected_millionaire
def test_ice_caves(level_started, theme, world_start, level_start, expected_ice_caves): game_state = State(theme=theme, world_start=world_start, level_start=level_start) run_state = RunState() run_state.level_started = level_started run_state.update_ice_caves(game_state) is_ice_caves = Label.ICE_CAVES_SHORTCUT in run_state.run_label._set assert is_ice_caves == expected_ice_caves
def test_starting_resources_health(char_state, prev_health, cur_health, expected_low, expected_no): run_state = RunState() run_state.health = prev_health player = Player(state=char_state, health=cur_health) run_state.update_starting_resources(player, WinState.NO_WIN) assert run_state.health == cur_health is_low = Label.LOW in run_state.run_label._set assert is_low == expected_low is_no = Label.NO in run_state.run_label._set assert is_no == expected_no
def test_starting_resources_bombs(prev_bombs, cur_bombs, expected_low, expected_no): run_state = RunState() run_state.bombs = prev_bombs inventory = Inventory(bombs=cur_bombs) player = Player(inventory=inventory) run_state.update_starting_resources(player, WinState.NO_WIN) assert run_state.bombs == cur_bombs is_low = Label.LOW in run_state.run_label._set assert is_low == expected_low is_no = Label.NO in run_state.run_label._set assert is_no == expected_no
def test_compute_player_motion_active_floor(): elevator = Movable( type=EntityDBEntry(id=EntityType.ACTIVEFLOOR_ELEVATOR), position_x=0.5, position_y=0.7, velocity_x=-0.1, velocity_y=-0.3, ) poly_elevator = PolyPointer(101, elevator, MemContext()) player = Player(position_x=5, position_y=7, velocity_x=-1, velocity_y=-3, overlay=poly_elevator) expected_motion = PlayerMotion(position_x=5.5, position_y=7.7, velocity_x=-1.1, velocity_y=-3.3) run_state = RunState() assert run_state.compute_player_motion(player) == expected_motion
def test_compute_player_motion_mount(): mount = Mount( type=EntityDBEntry(id=EntityType.MOUNT_TURKEY), position_x=18, position_y=13, velocity_x=-2, velocity_y=-7, ) poly_mount = PolyPointer(101, mount, MemContext()) player = Player(position_x=5, position_y=7, velocity_x=-1, velocity_y=-3, overlay=poly_mount) expected_motion = PlayerMotion(position_x=18, position_y=13, velocity_x=-2, velocity_y=-7) run_state = RunState() assert run_state.compute_player_motion(player) == expected_motion
def test_attacked_with_hou_yi(layer, world, level, presence_flags, expected_low): prev_state = CharState.JUMPING cur_state = CharState.ATTACKING item_set = {EntityType.ITEM_HOUYIBOW} # This should vary with world+level, but there's already a lot of params theme = Theme.DWELLING run_state = RunState() run_state.update_attacked_with( prev_state, cur_state, layer, world, level, theme, presence_flags, item_set, item_set, ) is_low = Label.LOW in run_state.run_label._set assert is_low == expected_low
def test_no_tp( player_x, player_y, player_vx, player_vy, idle_counter, shadow_x, shadow_y, expected_no_tp, ): fx_shadow_type = EntityDBEntry(id=EntityType.FX_TELEPORTSHADOW) new_entities = [] src_shadow = LightEmitter(type=fx_shadow_type, idle_counter=idle_counter, emitted_light=Illumination()) new_entities.append(poly_pointer_no_mem(src_shadow)) dest_illumination = Illumination(light_pos_x=shadow_x, light_pos_y=shadow_y) dest_shadow = LightEmitter(type=fx_shadow_type, idle_counter=idle_counter, emitted_light=dest_illumination) new_entities.append(poly_pointer_no_mem(dest_shadow)) player = Player( position_x=player_x, position_y=player_y, velocity_x=player_vx, velocity_y=player_vy, ) item_set = {EntityType.ITEM_TELEPORTER_BACKPACK} prev_item_set = set() run_state = RunState() run_state.new_entities = new_entities run_state.update_no_tp(player, item_set, prev_item_set) is_no_tp = Label.NO_TELEPORTER in run_state.run_label._set assert is_no_tp == expected_no_tp
def test_millionaire_( money_shop_total, win_state, money, collected_money_total, clone_gun_wo_bow, expected_millionaire, ): run_state = RunState() run_state.clone_gun_wo_cosmic = clone_gun_wo_bow if clone_gun_wo_bow: # This would have been added on a previous update run_state.run_label.add(Label.MILLIONAIRE) game_state = State(money_shop_total=money_shop_total, win_state=win_state) inventory = Inventory(money=money, collected_money_total=collected_money_total) item_set = set() run_state.update_millionaire(game_state, inventory, item_set) is_millionaire = Label.MILLIONAIRE in run_state.run_label._set assert is_millionaire == expected_millionaire
def test_attacked_with_simple(prev_state, cur_state, item_set, prev_item_set, expected_low): # These shouldn't be location sensitive layer = Layer.FRONT world = 2 level = 2 theme = Theme.JUNGLE presence_flags = 0 run_state = RunState() run_state.sunken_chain_status = ChainStatus.IN_PROGRESS run_state.update_attacked_with( prev_state, cur_state, layer, world, level, theme, presence_flags, item_set, prev_item_set, ) is_low = Label.LOW in run_state.run_label._set assert is_low == expected_low
def test_update_terminus( world, win_state, final_death, had_ankh, sunken_status, eggplant_status, cosmic_status, expected_terminus, ): run_state = RunState() run_state.final_death = final_death run_state.had_ankh = had_ankh run_state.sunken_chain_status = sunken_status run_state.eggplant_stepper = FakeStepper(eggplant_status) run_state.cosmic_stepper = FakeStepper(cosmic_status) game_state = State(world=world, win_state=win_state) run_state.update_terminus(game_state) assert run_state.run_label._terminus == expected_terminus
def test_world_themes_label( world, theme, world2_theme, starting_labels, expected_jt, ): run_state = RunState() run_state.run_label = RunLabel(starting=starting_labels) run_state.world2_theme = world2_theme run_state.update_world_themes(world, theme) is_jt = Label.JUNGLE_TEMPLE in run_state.run_label._set assert is_jt == expected_jt
def test_starting_resources_ropes(level_start_ropes, prev_ropes, cur_ropes, win_state, expected_low, expected_no): run_state = RunState() run_state.level_start_ropes = level_start_ropes run_state.ropes = prev_ropes inventory = Inventory(ropes=cur_ropes) player = Player(inventory=inventory) run_state.update_starting_resources(player, win_state) assert run_state.ropes == cur_ropes is_low = Label.LOW in run_state.run_label._set assert is_low == expected_low is_no = Label.NO in run_state.run_label._set assert is_no == expected_no
def test_on_level_start_state( world, theme, ropes, prev_health, expected_level_start_ropes, expected_health, expected_no, ): run_state = RunState() run_state.level_started = True run_state.health = prev_health run_state.update_on_level_start(world, theme, ropes) assert run_state.level_start_ropes == expected_level_start_ropes assert run_state.health == expected_health is_no = Label.NO in run_state.run_label._set assert is_no == expected_no
def test_is_chain( abzu_chain_status, duat_chain_status, expected_abzu, expected_duat, expected_sunken_chain_status, ): run_state = RunState() run_state.abzu_stepper = FakeStepper(abzu_chain_status) run_state.duat_stepper = FakeStepper(duat_chain_status) run_state.update_is_chain() is_abzu = Label.ABZU in run_state.run_label._set assert is_abzu == expected_abzu is_duat = Label.DUAT in run_state.run_label._set assert is_duat == expected_duat assert run_state.sunken_chain_status == expected_sunken_chain_status is_chain = Label.CHAIN in run_state.run_label._set assert is_chain == expected_sunken_chain_status.in_progress
def test_new_entities(screen, level_started, entity_types, expected_entity_types): run_state = RunState() run_state.level_started = level_started fake_entity_db = {} for entity_type in entity_types: if entity_type not in fake_entity_db: fake_entity_db[entity_type] = EntityDBEntry(id=entity_type) entity_map = EntityMapBuilder() run_state.prev_next_uid = entity_map.next_uid entity_map.add_trivial_entities(entity_types) game_state = State( screen=screen, next_entity_uid=entity_map.next_uid, instance_id_to_pointer=entity_map.build(), ) run_state.update_new_entities(game_state) got_types = [e.value.type.id for e in run_state.new_entities] assert got_types == expected_entity_types