def __parse_item_add(self, line_number, line): """ Parse an item and push it to the state """ if len(self.splitfile) > 1 and self.splitfile[line_number + self.seek - 1] == line: self.log.debug("Skipped duplicate item line from baby presence") return False space_split = line.split(" ") numeric_id = space_split[2] # When you pick up an item, this has the form: "Adding collectible 105 (The D6)" item_name = " ".join(space_split[3:])[1:-1] item_id = "" # Check if we recognize the numeric id if Item.contains_info(numeric_id): item_id = numeric_id else: # it might be a modded custom item. let's see if we recognize the name item_id = Item.modded_item_id_prefix + item_name if not Item.contains_info(item_id): item_id = "NEW" self.log.debug("Picked up item. id: %s, name: %s", item_id, item_name) if ((line_number + self.seek) - self.spawned_coop_baby) < (len(self.state.item_list) + 10) \ and self.state.contains_item(item_id): self.log.debug("Skipped duplicate item line from baby entry") return False # It's a blind pickup if we're on a blind floor and we don't have the Black Candle blind_pickup = self.state.last_floor.floor_has_curse(Curse.Blind) and not self.state.contains_item('260') added = self.state.add_item(Item(item_id, self.state.last_floor, self.getting_start_items, blind=blind_pickup)) if not added: self.log.debug("Skipped adding item %s to avoid space-bar duplicate", item_id) return True
def __parse_trinket_gulp(self, line): """ Parse a (modded) trinket gulp and push it to the state """ space_split = line.split(" ") # When using a mod like racing+ on AB+, a trinket gulp has the form: "Gulping trinket 10" # In Repentance, a gulped trinket has the form : "Adding smelted trinket 10" if self.opt.game_version == "Repentance" and int(space_split[3]) > 30000: numeric_id = str(int(space_split[3])) elif self.opt.game_version == "Repentance": numeric_id = str(int(space_split[3]) + 2000) # the tracker hackily maps trinkets to items 2000 and up. else: numeric_id = str(int(space_split[2]) + 2000) # the tracker hackily maps trinkets to items 2000 and up. is_Jacob_item = line.endswith("(Jacob)") and self.opt.game_version == "Repentance" and self.state.player != 37 and self.state.player != 39 is_Esau_item = line.endswith("(Esau)") and self.opt.game_version == "Repentance" # Check if we recognize the numeric id if Item.contains_info(numeric_id): item_id = numeric_id else: item_id = "NEW" self.log.debug("Gulped trinket: %s", item_id) added = self.state.add_item(Item(item_id, self.state.last_floor, self.getting_start_items, is_Jacob_item=is_Jacob_item, is_Esau_item=is_Esau_item)) if not added: self.log.debug("Skipped adding item %s to avoid space-bar duplicate", item_id) self.state.export_state() return True
def __init__(self): new_updater_dir = wdir_prefix + "update_scratchdir/updater-lib" if os.path.exists(new_updater_dir): # We found a new version of the updater, from when the updater presumably just ran old_updater_dir = wdir_prefix + "updater-lib" if os.path.exists(old_updater_dir): shutil.rmtree(old_updater_dir) shutil.copytree(new_updater_dir, old_updater_dir) shutil.rmtree(wdir_prefix + "update_scratchdir") # Load items/trinkets info with open(wdir_prefix + "items.json", "r") as items_file: Item.items_info = json.load(items_file) ItemInfo.check_item_keys(Item.items_info, "items.json") with open(wdir_prefix + "items_custom.json", "r") as custom_items_file: Item.custom_items_info = json.load(custom_items_file) Item.determine_custom_item_names() ItemInfo.check_item_keys(Item.custom_items_info, "items_custom.json") # Load version with open(wdir_prefix + 'version.txt', 'r') as f: self.tracker_version = f.read() # Load options Options().load_options(wdir_prefix + "options.json") defaults_path = "options_default.json" # If we're running in production, this file will be in our dir. # If we're running from source, it will be up a level if not os.path.exists(defaults_path): defaults_path = wdir_prefix + defaults_path Options().load_missing_defaults(defaults_path)
def __parse_item(self, line_number, line): """ Parse an Item and push it to the state """ if len(self.splitfile) > 1 and self.splitfile[line_number + self.seek - 1] == line: self.log.debug("Skipped duplicate item line from baby presence") return False space_split = line.split(" ") # Hacky string manipulation item_id = space_split[ 2] # A string has the form of "Adding collectible 105 (The D6)" # Check if the item ID exists if not Item.contains_info(item_id): item_id = "NEW" item_name = " ".join(space_split[3:])[1:-1] self.log.debug("Picked up item. id: %s, name: %s", item_id, item_name) if ((line_number + self.seek) - self.spawned_coop_baby) < (len(self.state.item_list) + 10) \ and self.state.contains_item(item_id): self.log.debug("Skipped duplicate item line from baby entry") return False #it's a blind pickup if we're on a blind floor and they don't have the black candle blind_pickup = self.state.last_floor.floor_has_curse( Curse.Blind) and not self.state.contains_item('260') added = self.state.add_item( Item(item_id, self.state.last_floor, self.getting_start_items, blind=blind_pickup)) if not added: self.log.debug( "Skipped adding item %s to avoid space-bar duplicate", item_id) return True
def __parse_add_multi_items(self): """Add custom sprites for multi-segmented items like Super Bum, key pieces or knife pieces""" if self.state.contains_item('238') and self.state.contains_item( '239') and not self.state.contains_item('3000'): for item in reversed(self.state.item_list): if item.item_id in ("238", "239"): item.info.shown = False self.state.add_item(Item("3000", self.state.last_floor)) elif self.state.contains_item('550') and self.state.contains_item( '552'): for item in reversed(self.state.item_list): if item.item_id == "550": item.info.shown = False elif self.state.contains_item('144') and self.state.contains_item( '278' ) and self.state.contains_item('388') and not self.state.contains_item( '3001' ) and self.opt.game_version != "Rebirth" and self.opt.game_version != "Antibirth": for item in reversed(self.state.item_list): if item.item_id in ("144", "278", "388"): item.info.shown = False self.state.add_item(Item("3001", self.state.last_floor)) elif self.state.contains_item('626') and self.state.contains_item( '627') and not self.state.contains_item('3002'): for item in reversed(self.state.item_list): if item.item_id in ("626", "627"): item.info.shown = False self.state.add_item(Item("3002", self.state.last_floor))
def __parse_item_add(self, line_number, line): """ Parse an item and push it to the state """ if len(self.splitfile) > 1 and self.splitfile[line_number + self.seek - 1] == line: self.log.debug("Skipped duplicate item line from baby presence") return False is_Jacob_item = line.endswith("(Jacob)") and self.opt.game_version == "Repentance" and self.state.player == 19 is_Esau_item = line.endswith("(Esau)") and self.opt.game_version == "Repentance" # The second part of the condition is to avoid showing Esau's Head if you play on a modded char in AB+ if self.state.player == 19 and not is_Esau_item and not is_Jacob_item: # This is when J&E transform into another character self.state.player = 8 # Put it on Lazarus by default just in case we got another Anemic elif self.state.player != 19 and is_Jacob_item: self.state.player = 19 end_name = -1 space_split = line.split(" ") numeric_id = space_split[2] # When you pick up an item, this has the form: "Adding collectible 105 (The D6)" or "Adding collectible 105 (The D6) to Player 0 (Isaac)" in Repentance if self.opt.game_version == "Repentance": item_name = " ".join(space_split[3:-4])[1:end_name] else: item_name = " ".join(space_split[3:])[1:end_name] item_id = "" if int(numeric_id) < 0: numeric_id = "-1" # Check if we recognize the numeric id if Item.contains_info(numeric_id): item_id = numeric_id else: # it might be a modded custom item. let's see if we recognize the name item_id = Item.modded_item_id_prefix + item_name if not Item.contains_info(item_id): item_id = "NEW" self.log.debug("Picked up item. id: %s, name: %s", item_id, item_name) if ((line_number + self.seek) - self.spawned_coop_baby) < (len(self.state.item_list) + 10) \ and self.state.contains_item(item_id): self.log.debug("Skipped duplicate item line from baby entry") return False # It's a blind pickup if we're on a blind floor and we don't have the Black Candle blind_pickup = self.state.last_floor.floor_has_curse(Curse.Blind) and not self.state.contains_item('260') if not (numeric_id == "214" and ((self.state.contains_item('214') and self.state.contains_item('332')) or (self.state.player == 8 and self.state.contains_item('214')))): added = self.state.add_item(Item(item_id, self.state.last_floor, self.getting_start_items, blind=blind_pickup, is_Jacob_item=is_Jacob_item, is_Esau_item=is_Esau_item)) if not added: self.log.debug("Skipped adding item %s to avoid space-bar duplicate", item_id) else: self.log.debug("Skipped adding Anemic from Lazarus Rags because we already have Anemic") if item_id in ("144", "238", "239", "278", "388", "550", "552", "626", "627"): self.__parse_add_multi_items() self.state.export_state() return True
def from_valid_json(json_dic, *args): """ Create a state from a type-checked dic """ state = TrackerState(json_dic['seed'], json_dic['tracker_version'], json_dic['game_version']) # The order is important, we want a list of legal floors the item can # be picked up on before parsing items for floor_dic in json_dic['floor_list']: floor = Floor.from_json(floor_dic) if not floor: return None state.add_floor(floor) for bossstr in json_dic['bosses']: # TODO create a serializable boss class that would create # a boss object with description from a bossid # In any case it's sufficient to (de)serialize only bossids if not isinstance(bossstr, basestring): return None state.add_boss(bossstr) for item_dic in json_dic['item_list']: item = Item.from_json(item_dic, state.floor_list) if not item: return None state.add_item(item) return state
def __parse_item_remove(self, line): """ Parse an item and remove it from the state """ space_split = line.split(" ") # Hacky string manipulation # When you lose an item, this has the form: "Removing collectible 105 (The D6)" or "Removing voided collectible 105 (The D6)" if self.opt.game_version == "Repentance": item_id = space_split[3] if space_split[2] == "trinket" and int(space_split[3]) > 30000: item_id = space_split[3] elif space_split[2] == "trinket": item_id = str(int(space_split[3]) + 2000) else: item_id = space_split[2] item_name = " ".join(space_split[3:])[1:-1] # Check if the item ID exists if Item.contains_info(item_id): removal_id = item_id else: # that means it's probably a custom item removal_id = Item.modded_item_id_prefix + item_name self.log.debug("Removed item. id: %s", removal_id) if item_id in ("144", "238", "239", "278", "388", "626", "627"): self.__parse_remove_multi_items(item_id=item_id) # A check will be made inside the remove_item function # to see if this item is actually in our inventory or not. return self.state.remove_item(removal_id)
def load_from_export_state(self): new_floor_list = [] new_item_list = [] data = self.get_export_state() try: if self.game_version == "Repentance" or self.game_version == "Afterbirth+": data = data[self.game_version][str(self.save)] else: data = data[self.game_version] self.seed = data['seed'] self.player = data['player'] self.greedmode = data['greedmode'] for floor in data['floor_list']: new_floor = Floor(floor["floor_id"], floor["curse"]) new_floor_list.append(new_floor) self.floor_list = new_floor_list for item in data['item_list']: new_item = Item(flagstr=item["flags"], item_id=item['item_id'], floor=Floor(floor_id=item['floor_id'])) new_item_list.append(new_item) self.item_list = new_item_list self.player_transforms = data['player_transforms'] if self.player == "19": self.player2_transforms = data['player2_transforms'] self.modified = True except: return True
def __parse_trinket_gulp(self, line): """ Parse a (modded) trinket gulp and push it to the state """ space_split = line.split(" ") # When using a mod like racing+, a trinket gulp has the form: "Gulping trinket 10" numeric_id = str(int(space_split[2]) + 2000) # the tracker hackily maps trinkets to items 2000 and up. # Check if we recognize the numeric id if Item.contains_info(numeric_id): item_id = numeric_id else: item_id = "NEW" self.log.debug("Gulped trinket: %s", item_id) added = self.state.add_item(Item(item_id, self.state.last_floor, self.getting_start_items)) if not added: self.log.debug("Skipped adding item %s to avoid space-bar duplicate", item_id) return True
def __parse_add_multi_items(self): """Add custom sprites for multi-segmented items like Super Bum, key pieces or knife pieces""" # item.info.shown = False is for not showing the item on the tracker # item.shown = False is for the export_state function to store the actual shown value instead of the initial value item.info.shown if self.state.contains_item('238') and self.state.contains_item( '239') and not self.state.contains_item('3000'): for item in reversed(self.state.item_list): if item.item_id in ("238", "239"): item.info.shown = False item.shown = False self.state.add_item( Item("3000", "3000", floor=self.state.last_floor)) elif self.state.contains_item('550') and self.state.contains_item( '552'): for item in reversed(self.state.item_list): if item.item_id == "550": item.info.shown = False item.shown = False elif self.state.contains_item('144') and self.state.contains_item( '278' ) and self.state.contains_item('388') and not self.state.contains_item( '3001' ) and self.opt.game_version != "Rebirth" and self.opt.game_version != "Antibirth": for item in reversed(self.state.item_list): if item.item_id in ("144", "278", "388"): item.info.shown = False item.shown = False self.state.add_item( Item("3001", "3001", floor=self.state.last_floor)) elif self.state.contains_item('626') and self.state.contains_item( '627') and not self.state.contains_item('3002'): for item in reversed(self.state.item_list): if item.item_id in ("626", "627"): item.info.shown = False item.shown = False self.state.add_item( Item("3002", "3002", floor=self.state.last_floor))
def from_valid_json(json_dic, *args): """ Create a state from a type-checked dic """ state = TrackerState(json_dic['seed'], json_dic['tracker_version'], json_dic['game_version']) # The order is important, we want a list of legal floors the item can # be picked up on before parsing items for floor_dic in json_dic['floor_list']: floor = Floor.from_json(floor_dic) if not floor: return None state.add_floor(floor) for item_dic in json_dic['item_list']: item = Item.from_json(item_dic, state.floor_list) if not item: return None state.add_item(item) return state
def __parse_item_remove(self, line): """ Parse an item and remove it from the state """ space_split = line.split(" ") # Hacky string manipulation item_id = space_split[2] # When you lose an item, this has the form: "Removing collectible 105 (The D6)" item_name = " ".join(space_split[3:])[1:-1] # Check if the item ID exists if Item.contains_info(item_id): removal_id = item_id else: # that means it's probably a custom item removal_id = Item.modded_item_id_prefix + item_name self.log.debug("Removed item. id: %s", removal_id) # A check will be made inside the remove_item function # to see if this item is actually in our inventory or not. return self.state.remove_item(removal_id)
def __parse_item_remove(self, line): """ Parse an item and remove it from the state """ space_split = line.split(" ") # Hacky string manipulation double_word_char = line.endswith("(The Lost)") or line.endswith( "(The Forgotten)") or line.endswith("(The Soul)") or line.endswith( "(Black Judas)") or line.endswith("(Random Baby)") # When you lose an item, this has the form: "Removing collectible 105 (The D6)" if self.opt.game_version == "Repentance" and space_split[ 2] == "trinket" and int(space_split[3]) < 30000: item_id = str(int(space_split[3]) + 2000) item_name = " ".join( space_split[3:-5])[3:-1] if double_word_char else " ".join( space_split[3:-4])[3:-1] else: item_id = space_split[2] item_name = " ".join( space_split[3:-5])[1:-1] if double_word_char else " ".join( space_split[3:-4])[1:-1] # Check if the item ID exists if Item.contains_info(item_id): removal_id = item_id else: # that means it's probably a custom item removal_id = Item.modded_item_id_prefix + item_name self.log.debug("Removed item. id: %s", removal_id) if item_id in ("144", "238", "239", "278", "388", "626", "627"): self.__parse_remove_multi_items(item_id=item_id) if item_id == "667": self.state.remove_additional_char_items(strawman=True) # A check will be made inside the remove_item function # to see if this item is actually in our inventory or not. return self.state.remove_item(removal_id)
def from_valid_json(json_dic, *args): """ Create a state from a type-checked dic """ state = TrackerState(json_dic['seed'], json_dic['tracker_version']) # The order is important, we want a list of legal floors the item can # be picked up on before parsing items for floor_dic in json_dic['floor_list']: floor = Floor.from_json(floor_dic) if not floor: return None state.add_floor(floor) for bossstr in json_dic['bosses']: # TODO create a serializable boss class that would create # a boss object with description from a bossid # In any case it's sufficient to (de)serialize only bossids if not isinstance(bossstr, basestring): return None state.add_boss(bossstr) for item_dic in json_dic['item_list']: item = Item.from_json(item_dic, state.floor_list) if not item: return None state.add_item(item) return state
def __parse_item(self, line_number, line): """ Parse an Item and push it to the state """ if len(self.splitfile) > 1 and self.splitfile[line_number + self.seek - 1] == line: self.log.debug("Skipped duplicate item line from baby presence") return False space_split = line.split(" ") # Hacky string manipulation item_id = space_split[2] # A string has the form of "Adding collectible 105 (The D6)" # Check if the item ID exists if not Item.contains_info(item_id): item_id = "NEW" item_name = " ".join(space_split[3:])[1:-1] self.log.debug("Picked up item. id: %s, name: %s", item_id, item_name) if ((line_number + self.seek) - self.spawned_coop_baby) < (len(self.state.item_list) + 10) \ and self.state.contains_item(item_id): self.log.debug("Skipped duplicate item line from baby entry") return False #it's a blind pickup if we're on a blind floor and they don't have the black candle blind_pickup = self.state.last_floor.floor_has_curse(Curse.Blind) and not self.state.contains_item('260') added = self.state.add_item(Item(item_id, self.state.last_floor, self.getting_start_items, blind=blind_pickup)) if not added: self.log.debug("Skipped adding item %s to avoid space-bar duplicate", item_id) return True
def run(self): self.current_floor = None # Initialize pygame system stuff pygame.init() update_notifier = self.check_for_update() pygame.display.set_caption("Rebirth Item Tracker" + update_notifier) # Create drawing tool to use to draw everything - it'll create its own screen self.drawing_tool = DrawingTool() os.environ['SDL_VIDEO_WINDOW_POS'] = "%d, %d" % ( self.drawing_tool.options[Option.X_POSITION], self.drawing_tool.options[Option.Y_POSITION]) self.drawing_tool.start_pygame() pygame.display.set_icon(self.drawing_tool.get_image("collectibles_333.png")) done = False clock = pygame.time.Clock() winInfo = None if platform.system() == "Windows": winInfo = pygameWindowInfo.PygameWindowInfo() del os.environ['SDL_VIDEO_WINDOW_POS'] while not done: # pygame logic for event in pygame.event.get(): if event.type == pygame.QUIT: if platform.system() == "Windows": winPos = winInfo.getScreenPosition() self.drawing_tool.options[Option.X_POSITION] = winPos["left"] self.drawing_tool.options[Option.Y_POSITION] = winPos["top"] self.drawing_tool.save_options() done = True elif event.type == VIDEORESIZE: screen = pygame.display.set_mode(event.dict['size'], RESIZABLE) self.drawing_tool.options[Option.WIDTH] = event.dict["w"] self.drawing_tool.options[Option.HEIGHT] = event.dict["h"] self.drawing_tool.save_options() self.drawing_tool.reflow(self.collected_items) pygame.display.flip() elif event.type == MOUSEMOTION: if pygame.mouse.get_focused(): pos = pygame.mouse.get_pos() self.drawing_tool.select_item_on_hover(*pos) elif event.type == KEYDOWN: if len(self.collected_items) > 0: if event.key == pygame.K_RIGHT: self.drawing_tool.adjust_select_item_on_keypress(1) elif event.key == pygame.K_LEFT: self.drawing_tool.adjust_select_item_on_keypress(-1) elif event.key == pygame.K_RETURN: self.drawing_tool.load_selected_detail_page() elif event.key == pygame.K_c and pygame.key.get_mods() & pygame.KMOD_CTRL: pass #self.generate_run_summary() # This is commented out because run summaries are broken with the new "state" model rewrite of the item tracker elif event.type == MOUSEBUTTONDOWN: if event.button == 1: self.drawing_tool.load_selected_detail_page() if event.button == 3: import option_picker pygame.event.set_blocked([QUIT, MOUSEBUTTONDOWN, KEYDOWN, MOUSEMOTION]) option_picker.options_menu(self.file_prefix + "options.json").run() pygame.event.set_allowed([QUIT, MOUSEBUTTONDOWN, KEYDOWN, MOUSEMOTION]) self.drawing_tool.reset() self.drawing_tool.load_options() self.drawing_tool.reflow(self.collected_items) # Drawing logic clock.tick(int(self.drawing_tool.options[Option.FRAMERATE_LIMIT])) if self.log_not_found: self.drawing_tool.write_message("log.txt not found. Put the RebirthItemTracker folder inside the isaac folder, next to log.txt") self.drawing_tool.draw_items(self) self.framecount += 1 # Now we re-process the log file to get anything that might have loaded; do it every read_delay seconds (making sure to truncate to an integer or else it might never mod to 0) if self.framecount % int(self.drawing_tool.options[Option.FRAMERATE_LIMIT] * self.read_delay) == 0: self.load_log_file() self.splitfile = self.content.splitlines() # Return to start if seek passes the end of the file (usually because the log file restarted) if self.seek > len(self.splitfile): self.log_msg("Current line number longer than lines in file, returning to start of file", "D") self.seek = 0 should_reflow = False getting_start_items = False # This will become true if we are getting starting items # Process log's new output for current_line_number, line in enumerate(self.splitfile[self.seek:]): self.log_msg(line, "V") # The end floor boss should be defeated now if line.startswith('Mom clear time:'): kill_time = int(line.split(" ")[-1]) # If you re-enter a room you get a "mom clear time" again, check for that (can you fight the same boss twice?) if self.current_room not in [x[0] for x in self.bosses]: self.bosses.append((self.current_room, kill_time)) self.log_msg( "Defeated %s%s boss %s at time %s" % (len(self.bosses), self.suffix(len(self.bosses)), self.current_room, kill_time), "D") # Check and handle the end of the run; the order is important - we want it after boss kill but before "RNG Start Seed" self.check_end_run(line, current_line_number + self.seek) if line.startswith('RNG Start Seed:'): # The start of a run self.seed = line[16:25] # This assumes a fixed width, but from what I see it seems safe if line.startswith('Room'): self.current_room = re.search('\((.*)\)', line).group(1) if 'Start Room' not in line: getting_start_items = False self.log_msg("Entered room: %s" % self.current_room,"D") if line.startswith('Level::Init'): if self.GAME_VERSION == "Afterbirth": floor_tuple = tuple([re.search("Level::Init m_Stage (\d+), m_StageType (\d+)",line).group(x) for x in [1, 2]]) else: floor_tuple = tuple([re.search("Level::Init m_Stage (\d+), m_AltStage (\d+)",line).group(x) for x in [1, 2]]) # Assume floors aren't cursed until we see they are self.blind_floor = False getting_start_items = True floor = int(floor_tuple[0]) alt = floor_tuple[1] # Special handling for cath and chest if alt == '1' and (floor == 9 or floor == 11): floor += 1 floor_id = 'f' + str(floor) # when we see a new floor 1, that means a new run has started if floor == 1: self.start_new_run(current_line_number) self.current_floor=Floor(floor_id,self,(alt=='1')) should_reflow = True if line.startswith("Curse of the Labyrinth!"): # It SHOULD always begin with f (that is, it's a floor) because this line only comes right after the floor line self.current_floor.add_curse(Curse.Labyrinth) if line.startswith("Curse of Blind"): self.current_floor.add_curse(Curse.Blind) if line.startswith("Curse of the Lost!"): self.current_floor.add_curse(Curse.Lost) if line.startswith("Spawn co-player!"): self.spawned_coop_baby = current_line_number + self.seek if re.search("Added \d+ Collectibles", line): self.log_msg("Reroll detected!", "D") map(lambda item: item.rerolled(),self.collected_items) if line.startswith('Adding collectible'): if len(self.splitfile) > 1 and self.splitfile[current_line_number + self.seek - 1] == line: self.log_msg("Skipped duplicate item line from baby presence", "D") continue space_split = line.split(" ") # Hacky string manipulation item_id = space_split[2] # A string has the form of "Adding collectible 105 (The D6)" # Check if the item ID exists if item_id.zfill(3) not in self.items_info: item_id = "NEW" item_info = self.get_item_info(item_id) # Default current floor to basement 1 if none if self.current_floor is None: self.current_floor = Floor("f1", self, False) # If the item IDs are equal, it should say this item already exists temp_item = Item(item_id,self.current_floor,item_info,getting_start_items) if ((current_line_number + self.seek) - self.spawned_coop_baby) < (len(self.collected_items) + 10) \ and temp_item in self.collected_items: self.log_msg("Skipped duplicate item line from baby entry","D") continue item_name = " ".join(space_split[3:])[1:-1] self.log_msg("Picked up item. id: %s, name: %s" % (item_id, item_name), "D") with open(self.file_prefix + "overlay text/itemInfo.txt", "w+") as f: desc = temp_item.generate_item_description() f.write(item_info[ItemProperty.NAME] + ":" + desc) # Ignore repeated pickups of space bar items if not (item_info.get(ItemProperty.SPACE,False) and temp_item in self.collected_items): self.collected_items.append(temp_item) self.item_message_start_time = self.framecount self.item_pickup_time = self.framecount self.drawing_tool.item_picked_up() else: self.log_msg("Skipped adding item %s to avoid space-bar duplicate" % item_id, "D") self.add_stats_for_item(temp_item, item_id) should_reflow = True self.seek = len(self.splitfile) if should_reflow: self.drawing_tool.reflow(self.collected_items)
def __parse_item_add(self, line_number, line): """ Parse an item and push it to the state """ if len(self.splitfile) > 1 and self.splitfile[line_number + self.seek - 1] == line: self.log.debug("Skipped duplicate item line from baby presence") return False is_Jacob_item = line.endswith( "(Jacob)" ) and self.opt.game_version == "Repentance" # The second part of the condition is to avoid showing Jacob's Head if you play on a modded char in AB+ is_Esau_item = line.endswith( "(Esau)" ) and self.opt.game_version == "Repentance" # The second part of the condition is to avoid showing Esau's Head if you play on a modded char in AB+ end_name = -15 if is_Jacob_item or is_Esau_item else -1 space_split = line.split(" ") numeric_id = space_split[ 2] # When you pick up an item, this has the form: "Adding collectible 105 (The D6)" item_name = " ".join(space_split[3:])[1:end_name] item_id = "" if int(numeric_id) < 0: numeric_id = "-1" if int( numeric_id ) == 577: # Damocles can't be rerolled by D4 so no need to show it twice numeric_id = "656" # Check if we recognize the numeric id if Item.contains_info(numeric_id): item_id = numeric_id else: # it might be a modded custom item. let's see if we recognize the name item_id = Item.modded_item_id_prefix + item_name if not Item.contains_info(item_id): item_id = "NEW" self.log.debug("Picked up item. id: %s, name: %s", item_id, item_name) if ((line_number + self.seek) - self.spawned_coop_baby) < (len(self.state.item_list) + 10) \ and self.state.contains_item(item_id): self.log.debug("Skipped duplicate item line from baby entry") return False # It's a blind pickup if we're on a blind floor and we don't have the Black Candle blind_pickup = self.state.last_floor.floor_has_curse( Curse.Blind) and not self.state.contains_item('260') if not (numeric_id == "214" and ((self.state.contains_item('214') and self.state.contains_item('332')) or (self.lazarus and self.state.contains_item('214')))): added = self.state.add_item( Item(item_id, self.state.last_floor, self.getting_start_items, blind=blind_pickup, is_Jacob_item=is_Jacob_item, is_Esau_item=is_Esau_item)) if not added: self.log.debug( "Skipped adding item %s to avoid space-bar duplicate", item_id) else: self.log.debug( "Skipped adding Anemic from Lazarus Rags because we already have Anemic" ) return True