Ejemplo n.º 1
0
    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
Ejemplo n.º 2
0
    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
Ejemplo n.º 3
0
    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
Ejemplo n.º 4
0
    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)
Ejemplo n.º 5
0
    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)
Ejemplo n.º 6
0
    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
Ejemplo n.º 7
0
 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))
Ejemplo n.º 8
0
    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
Ejemplo n.º 9
0
    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
Ejemplo n.º 10
0
    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)
Ejemplo n.º 11
0
 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
Ejemplo n.º 12
0
    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
Ejemplo n.º 13
0
 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))
Ejemplo n.º 14
0
    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
Ejemplo n.º 15
0
    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
Ejemplo n.º 16
0
    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)
Ejemplo n.º 17
0
    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)
Ejemplo n.º 18
0
    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
Ejemplo n.º 19
0
    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)
Ejemplo n.º 20
0
    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
Ejemplo n.º 21
0
    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
Ejemplo n.º 22
0
    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)
Ejemplo n.º 23
0
    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