Exemplo n.º 1
0
class Village:
    village_id = None
    builder = None
    units = None
    wrapper = None
    resources = {}
    game_data = {}
    logger = None
    force_troops = False
    area = None
    snobman = None
    attack = None
    resman = None
    def_man = None
    rep_man = None
    config = None
    village_set_name = None

    twp = TwPlus()

    def __init__(self, village_id=None, wrapper=None):
        self.village_id = village_id
        self.wrapper = wrapper

    def get_config(self, section, parameter, default=None):
        if section not in self.config:
            self.logger.warning("Configuration section %s does not exist!" %
                                section)
            return default
        if parameter not in self.config[section]:
            self.logger.warning(
                "Configuration parameter %s:%s does not exist!" %
                (section, parameter))
            return default
        return self.config[section][parameter]

    def get_village_config(self, village_id, parameter, default=None):
        if village_id not in self.config['villages']:
            return default
        vdata = self.config['villages'][village_id]
        if parameter not in vdata:
            self.logger.warning(
                "Village %s configuration parameter %s does not exist!" %
                (village_id, parameter))
            return default
        return vdata[parameter]

    def run(self, config=None, first_run=False):
        # setup and check if village still exists / is accessible
        self.config = config
        self.wrapper.delay = self.get_config(section="bot",
                                             parameter="delay_factor",
                                             default=1.0)
        if not self.village_id:
            data = self.wrapper.get_url("game.php?screen=overview&intro")
            if data:
                self.game_data = Extractor.game_state(data)
            if self.game_data:
                self.village_id = str(self.game_data['village']['id'])
                self.logger = logging.getLogger(
                    "Village %s" % self.game_data['village']['name'])
                self.logger.info("Read game state for village")
        else:
            data = self.wrapper.get_url("game.php?village=%s&screen=overview" %
                                        self.village_id)
            if data:
                self.game_data = Extractor.game_state(data)
                self.logger = logging.getLogger(
                    "Village %s" % self.game_data['village']['name'])
                self.logger.info("Read game state for village")
                self.wrapper.reporter.report(
                    self.village_id, "TWB_START",
                    "Starting run for village: %s" %
                    self.game_data['village']['name'])

        if not self.game_data:
            self.logger.error("Error reading game data for village %s" %
                              self.village_id)
            return None

        if self.village_set_name and self.game_data['village'][
                'name'] != self.village_set_name:
            self.logger.name = "Village %s" % self.village_set_name

        if not self.get_config(section="villages", parameter=self.village_id):
            return None
        if self.get_config(section="server",
                           parameter="server_on_twplus",
                           default=False):
            self.twp.run(
                world=self.get_config(section="server", parameter="world"))

        vdata = self.get_config(section="villages", parameter=self.village_id)
        if not self.get_village_config(
                self.village_id, parameter="managed", default=False):
            return False
        if not self.game_data:
            return False
        if not self.resman:
            self.resman = ResourceManager(wrapper=self.wrapper,
                                          village_id=self.village_id)

        self.resman.update(self.game_data)
        self.wrapper.reporter.report(self.village_id, "TWB_PRE_RESOURCE",
                                     str(self.resman.actual))

        if not self.rep_man:
            self.rep_man = ReportManager(wrapper=self.wrapper,
                                         village_id=self.village_id)
        self.rep_man.read(full_run=False)

        if not self.def_man:
            self.def_man = DefenceManager(wrapper=self.wrapper,
                                          village_id=self.village_id)
            self.def_man.map = self.area

        if not self.def_man.units:
            self.def_man.units = self.units

        last_attack = self.def_man.under_attack
        self.def_man.manage_flags_enabled = self.get_config(
            section="world", parameter="flags_enabled", default=False)
        self.def_man.support_factor = self.get_village_config(
            self.village_id, "support_others_factor", default=0.25)

        self.def_man.allow_support_send = self.get_village_config(
            self.village_id, parameter="support_others", default=False)
        self.def_man.allow_support_recv = self.get_village_config(
            self.village_id,
            parameter="request_support_on_attack",
            default=False)
        self.def_man.auto_evacuate = self.get_village_config(
            self.village_id,
            parameter="evacuate_fragile_units_on_attack",
            default=False)
        self.def_man.update(data.text,
                            with_defence=self.get_config(
                                section="units",
                                parameter="manage_defence",
                                default=False))

        disabled_units = []
        if not self.get_config(
                section="world", parameter="archers_enabled", default=True):
            disabled_units.extend(["archer", "marcher"])

        if not self.get_config(section="world",
                               parameter="building_destruction_enabled",
                               default=True):
            disabled_units.extend(["ram", "catapult"])

        if self.def_man.under_attack and not last_attack:
            self.logger.warning("Village under attack!")
            self.wrapper.reporter.report(
                self.village_id, "TWB_ATTACK",
                "Village: %s under attack" % self.game_data['village']['name'])

        # setup and check if village still exists / is accessible
        if self.get_config(section="world",
                           parameter="quests_enabled",
                           default=False):
            if self.get_quests():
                self.logger.info(
                    "There where completed quests, re-running function")
                self.wrapper.reporter.report(self.village_id, "TWB_QUEST",
                                             "Completed quest")
                return self.run(config=config)

        if not self.builder:
            self.builder = BuildingManager(wrapper=self.wrapper,
                                           village_id=self.village_id)
            self.builder.resman = self.resman
            # manage buildings (has to always run because recruit check depends on building levels)
        build_config = self.get_village_config(self.village_id,
                                               parameter="building",
                                               default=None)
        if not build_config:
            self.logger.warning(
                "Village %d does not have 'building' config override!" %
                self.village_id)
            build_config = self.get_config(section="building",
                                           parameter="default",
                                           default="purple_predator")
        new_queue = TemplateManager.get_template(category="builder",
                                                 template=build_config)
        if not self.builder.raw_template or self.builder.raw_template != new_queue:
            self.builder.queue = new_queue
            self.builder.raw_template = new_queue
            if not self.get_config(section="world",
                                   parameter="knight_enabled",
                                   default=False):
                self.builder.queue = [
                    x for x in self.builder.queue if "statue" not in x
                ]
        self.builder.max_lookahead = self.get_config(section="building",
                                                     parameter="max_lookahead",
                                                     default=2)
        self.builder.max_queue_len = self.get_config(
            section="building", parameter="max_queued_items", default=2)
        self.builder.start_update(build=self.get_config(
            section="building", parameter="manage_buildings", default=True),
                                  set_village_name=self.village_set_name)

        if not self.units:
            self.units = TroopManager(wrapper=self.wrapper,
                                      village_id=self.village_id)
            self.units.resman = self.resman
        self.units.max_batch_size = self.get_config(section="units",
                                                    parameter="batch_size",
                                                    default=25)

        # set village templates
        unit_config = self.get_village_config(self.village_id,
                                              parameter="units",
                                              default=None)
        if not unit_config:
            self.logger.warning(
                "Village %d does not have 'building' config override!" %
                self.village_id)
            unit_config = self.get_config(section="units",
                                          parameter="default",
                                          default="basic")
        self.units.template = TemplateManager.get_template(
            category="troops", template=unit_config, output_json=True)
        entry = self.units.get_template_action(self.builder.levels)

        if entry and self.units.wanted != entry["build"]:
            # update wanted units if template has changed
            self.logger.info("%s as wanted units for current village" %
                             (str(entry["build"])))
            self.units.wanted = entry["build"]

        if self.units.wanted_levels != {}:
            self.logger.info("%s as wanted upgrades for current village" %
                             (str(self.units.wanted_levels)))

        # get total amount of troops in village
        self.units.update_totals()
        if self.get_config(section="units", parameter="upgrade",
                           default=False) and self.units.wanted_levels != {}:
            self.units.attempt_upgrade()

        if self.get_village_config(
                self.village_id, parameter="snobs",
                default=None) and self.builder.levels['snob'] > 0:
            if not self.snobman:
                self.snobman = SnobManager(wrapper=self.wrapper,
                                           village_id=self.village_id)
                self.snobman.troop_manager = self.units
                self.snobman.resman = self.resman
            self.snobman.wanted = self.get_village_config(self.village_id,
                                                          parameter="snobs",
                                                          default=0)
            self.snobman.building_level = self.builder.get_level("snob")
            self.snobman.run()

        # recruitment management
        if self.get_config(section="units", parameter="recruit",
                           default=False):
            self.units.can_fix_queue = self.get_config(
                section="units",
                parameter="remove_manual_queued",
                default=False)
            self.units.randomize_unit_queue = self.get_config(
                section="units",
                parameter="randomize_unit_queue",
                default=True)
            # prioritize_building: will only recruit when builder has sufficient funds for queue items
            if self.get_village_config(
                    self.village_id,
                    parameter="prioritize_building",
                    default=False) and not self.resman.can_recruit():
                self.logger.info(
                    "Not recruiting because builder has insufficient funds")
            elif self.get_village_config(
                    self.village_id, parameter="prioritize_snob", default=False
            ) and self.snobman and self.snobman.can_snob and self.snobman.is_incomplete:
                self.logger.info(
                    "Not recruiting because snob has insufficient funds")
            else:
                # do a build run for every
                for building in self.units.wanted:
                    if not self.builder.get_level(building):
                        self.logger.debug(
                            "Recruit of %s will be ignored because building is not (yet) available"
                            % building)
                        continue
                    self.units.start_update(building)

        self.logger.debug("Current resources: %s" % str(self.resman.actual))
        self.logger.debug("Requested resources: %s" %
                          str(self.resman.requested))
        # attack management
        if self.units.can_attack:
            if not self.area:
                self.area = Map(wrapper=self.wrapper,
                                village_id=self.village_id)
            self.area.get_map()
            if self.area.villages:
                self.units.can_scout = self.get_config(
                    section="farms",
                    parameter="force_scout_if_available",
                    default=True)
                self.logger.info(
                    "%d villages from map cache, (your location: %s)" %
                    (len(self.area.villages), ':'.join(
                        [str(x) for x in self.area.my_location])))
                if not self.attack:
                    self.attack = AttackManager(wrapper=self.wrapper,
                                                village_id=self.village_id,
                                                troopmanager=self.units,
                                                map=self.area)
                    self.attack.repman = self.rep_man
                self.attack.target_high_points = self.get_config(
                    section="farms",
                    parameter="attack_higher_points",
                    default=False)
                self.attack.farm_minpoints = self.get_config(
                    section="farms", parameter="min_points", default=24)
                self.attack.farm_maxpoints = self.get_config(
                    section="farms", parameter="max_points", default=1080)

                self.attack.farm_default_wait = self.get_config(
                    section="farms",
                    parameter="default_away_time",
                    default=1200)
                self.attack.farm_high_prio_wait = self.get_config(
                    section="farms",
                    parameter="full_loot_away_time",
                    default=1800)
                self.attack.farm_low_prio_wait = self.get_config(
                    section="farms",
                    parameter="low_loot_away_time",
                    default=7200)
                if entry:
                    self.attack.template = entry['farm']
                if self.get_config(
                        section="farms", parameter="farm",
                        default=False) and not self.def_man.under_attack:
                    self.attack.extra_farm = self.get_village_config(
                        self.village_id,
                        parameter="additional_farms",
                        default=[])
                    self.attack.max_farms = self.get_config(
                        section="farms", parameter="max_farms", default=25)
                    self.attack.run()

        self.units.can_gather = self.get_village_config(
            self.village_id, parameter="gather_enabled", default=False)
        if not self.def_man or not self.def_man.under_attack:
            self.units.gather(selection=self.get_village_config(
                self.village_id, parameter="gather_selection", default=1),
                              disabled_units=disabled_units)
        # market management
        if self.get_config(section="market",
                           parameter="auto_trade",
                           default=False) and self.builder.get_level("market"):
            self.logger.info("Managing market")
            self.resman.trade_max_per_hour = self.get_config(
                section="market", parameter="trade_max_per_hour", default=1)
            self.resman.trade_max_duration = self.get_config(
                section="market", parameter="max_trade_duration", default=1)
            if self.get_config(section="market",
                               parameter="trade_multiplier",
                               default=False):
                self.resman.trade_bias = self.get_config(
                    section="market",
                    parameter="trade_multiplier_value",
                    default=1.0)
            self.resman.manage_market(drop_existing=self.get_config(
                section="market", parameter="auto_remove", default=True))

        res = self.wrapper.get_action(village_id=self.village_id,
                                      action="overview")
        self.game_data = Extractor.game_state(res)
        self.resman.update(self.game_data)
        if self.get_config(section="world",
                           parameter="trade_for_premium",
                           default=False) and self.get_village_config(
                               self.village_id,
                               parameter="trade_for_premium",
                               default=False):
            self.resman.do_premium_stuff()
        self.set_cache_vars()
        self.logger.info("Village cycle done, returning to overview")
        self.wrapper.reporter.report(self.village_id, "TWB_POST_RESOURCE",
                                     str(self.resman.actual))
        self.wrapper.reporter.add_data(self.village_id,
                                       data_type="village.resources",
                                       data=json.dumps(self.resman.actual))
        self.wrapper.reporter.add_data(self.village_id,
                                       data_type="village.buildings",
                                       data=json.dumps(self.builder.levels))
        self.wrapper.reporter.add_data(self.village_id,
                                       data_type="village.troops",
                                       data=json.dumps(
                                           self.units.total_troops))
        self.wrapper.reporter.add_data(self.village_id,
                                       data_type="village.config",
                                       data=json.dumps(vdata))

    def get_quests(self):
        result = Extractor.get_quests(self.wrapper.last_response)
        if result:
            qres = self.wrapper.get_api_action(action="quest_complete",
                                               village_id=self.village_id,
                                               params={
                                                   'quest': result,
                                                   'skip': 'false'
                                               })
            if qres:
                self.logger.info("Completed quest: %s" % str(result))
                return True
        self.logger.debug("There where no completed quests")
        return False

    def set_cache_vars(self):
        village_entry = {
            "name": self.game_data['village']['name'],
            "public":
            self.area.in_cache(self.village_id) if self.area else None,
            "resources": self.resman.actual,
            "required_resources": self.resman.requested,
            "available_troops": self.units.troops,
            "buidling_levels": self.builder.levels,
            "building_queue": self.builder.queue,
            "troops": self.units.total_troops,
            "under_attack": self.def_man.under_attack,
            "last_run": int(time.time())
        }
        self.set_cache(self.village_id, entry=village_entry)

    def set_cache(self, village_id, entry):
        t_path = os.path.join("cache", "managed", village_id + ".json")
        with open(t_path, 'w') as f:
            return json.dump(entry, f)
Exemplo n.º 2
0
class Village:
    village_id = None
    builder = None
    units = None
    wrapper = None
    resources = {

    }
    game_data = {

    }
    logger = None
    force_troops = False
    area = None
    snobman = None
    attack = None
    resman = None
    def_man = None
    rep_man = None
    config = None
    twp = TwPlus()

    def __init__(self, village_id=None, wrapper=None):
        self.village_id = village_id
        self.wrapper = wrapper

    def run(self, config=None):
        # setup and check if village still exists / is accessible
        self.config = config
        if not self.village_id:
            data = self.wrapper.get_url("game.php?screen=overview&intro")
            if data:
                self.game_data = Extractor.game_state(data)
            if self.game_data:
                self.village_id = str(self.game_data['village']['id'])
                self.logger = logging.getLogger("Village %s" % self.game_data['village']['name'])
                self.logger.info("Read game state for village")
        else:
            data = self.wrapper.get_url("game.php?village=%s&screen=overview" % self.village_id)
            if data:
                self.game_data = Extractor.game_state(data)
                self.logger = logging.getLogger("Village %s" % self.game_data['village']['name'])
                self.logger.info("Read game state for village")

        if str(self.village_id) not in self.config['villages']:
            return False

        self.twp.run(world=self.config['server']['world'])

        vdata = self.config['villages'][str(self.village_id)]
        if not vdata['managed']:
            return False
        if not self.game_data:
            return False

        # setup modules
        if not self.resman:
            self.resman = ResourceManager(wrapper=self.wrapper, village_id=self.village_id)

        self.resman.update(self.game_data)

        if not self.rep_man:
            self.rep_man = ReportManager(wrapper=self.wrapper, village_id=self.village_id)
        self.rep_man.read(full_run=False)

        if not self.def_man:
            self.def_man = DefenceManager(wrapper=self.wrapper, village_id=self.village_id)

        self.def_man.update(data.text)
        if self.def_man.under_attack:
            self.logger.warning("Village under attack!")

        # setup and check if village still exists / is accessible
        if self.config['world']['quests_enabled']:
            if self.get_quests():
                self.logger.info("There where completed quests, re-running function")
                return self.run()

        if not self.builder:
            self.builder = BuildingManager(wrapper=self.wrapper, village_id=self.village_id)
            self.builder.resman = self.resman
            # manage buildings (has to always run because recruit check depends on building levels)
            build_config = vdata['building'] if vdata['building'] else self.config['building']['default']

            self.builder.queue = TemplateManager.get_template(category="builder", template=build_config)
        self.builder.max_lookahead = self.config['building']['max_lookahead']
        self.builder.max_queue_len = self.config['building']['max_queued_items']
        self.builder.start_update(build=self.config['building']['manage_buildings'])

        if not self.units:
            self.units = TroopManager(wrapper=self.wrapper, village_id=self.village_id)
            self.units.max_batch_size = self.config['units']['batch_size']
            self.units.resman = self.resman

        # set village templates
        unit_config = vdata['units'] if vdata['units'] else self.config['units']['default']
        self.units.template = TemplateManager.get_template(category="troops", template=unit_config, output_json=True)
        entry = self.units.get_template_action(self.builder.levels)

        if entry and self.units.wanted != entry["build"]:
            # update wanted units if template has changed
            self.logger.info("%s as wanted units for current village" % (str(entry["build"])))
            self.units.wanted = entry["build"]

        if entry and 'upgrades' in entry and self.units.wanted_levels != entry['upgrades']:
            self.logger.info("%s as wanted upgrades for current village" % (str(entry["upgrades"])))
            self.units.wanted_levels = entry['upgrades']

        # get total amount of troops in village
        self.units.update_totals()
        if self.config['units']['upgrade'] and self.units.wanted_levels != {}:
            self.units.attempt_upgrade(self.units.wanted_levels)

        if 'snobs' in vdata and self.builder.levels['snob'] > 0:
            if not self.snobman:
                self.snobman = SnobManager(wrapper=self.wrapper, village_id=self.village_id)
                self.snobman.troop_manager = self.units
                self.snobman.resman = self.resman
            self.snobman.wanted = vdata['snobs']
            self.snobman.building_level = self.builder.levels['snob']
            self.snobman.run()

        if self.config['units']['recruit']:
            # prioritize_building: will only recruit when builder has sufficient funds for queue items
            if vdata['prioritize_building'] and not self.resman.can_recruit():
                self.logger.info("Not recruiting because builder has insufficient funds")
            elif vdata['prioritize_snob'] and self.snobman and self.snobman.can_snob and self.snobman.is_incomplete:
                self.logger.info("Not recruiting because snob has insufficient funds")
            else:
                # do a build run for every
                for building in self.units.wanted:
                    if building not in self.builder.levels or self.builder.levels[building] == 0:
                        self.logger.debug("Recruit of %s will be ignored because building is not available" % building)
                        continue
                    self.units.start_update(building)

        self.logger.debug("Current resources: %s" % str(self.resman.actual))
        self.logger.debug("Requested resources: %s" % str(self.resman.requested))

        if self.units.can_attack:
            if not self.area:
                self.area = Map(wrapper=self.wrapper, village_id=self.village_id)
                self.area.get_map()
            if self.area.villages:
                self.logger.info("%d villages from map cache, (your location: %s)" % (
                len(self.area.villages), ':'.join([str(x) for x in self.area.my_location])))
                if not self.attack:
                    self.attack = AttackManager(wrapper=self.wrapper, village_id=self.village_id,
                                                troopmanager=self.units, map=self.area)
                    self.attack.repman = self.rep_man
                if entry:
                    self.attack.template = entry['farm']
                if self.config['farms']['farm']:
                    self.attack.extra_farm = vdata['additional_farms']
                    self.attack.max_farms = self.config['farms']['max_farms']
                    self.attack.run()
        if not self.def_man.under_attack:
            self.units.gather()
        if self.config['market']['auto_trade'] and "market" in self.builder.levels and self.builder.levels["market"] > 0:
            self.logger.info("Managing market")
            self.resman.trade_max_per_hour = self.config['market']['trade_max_per_hour']
            self.resman.trade_max_duration = self.config['market']['max_trade_duration']
            if self.config['market']['trade_multiplier']:
                self.resman.trade_bias = self.config['market']['trade_multiplier_value']
            self.resman.manage_market(drop_existing=self.config['market']['auto_remove'])
        self.logger.info("Village cycle done, returning to overview")
        res = self.wrapper.get_action(village_id=self.village_id, action="overview")
        self.game_data = Extractor.game_state(res)
        self.resman.update(self.game_data)

    def get_quests(self):
        result = Extractor.get_quests(self.wrapper.last_response)
        if result:
            qres = self.wrapper.get_api_action(action="quest_complete", village_id=self.village_id, params={'quest': result, 'skip': 'false'})
            if qres:
                self.logger.info("Completed quest: %s" % str(result))
                return True
        self.logger.debug("There where no completed quests")
        return False