def init_position(self): def equivalent_type(t): tn = getattr(t, "type_name", "") if rules.get(self.race, tn): return self.world.unit_class(rules.get(self.race, tn)[0]) return t self.resources = self.start[0][:] normalize_cost_or_resources(self.resources) self.gathered_resources = self.resources[:] for place, type_ in self.start[1]: type_ = equivalent_type(type_) if isinstance(type_, str) and type_[0:1] == "-": self.forbidden_techs.append(type_[1:]) elif isinstance(type_, Upgrade): self.upgrades.append(type_.type_name) # XXX type_.upgrade_player(self)? else: place = self.world.grid[place] x, y = place.find_and_remove_meadow(type_) x, y = place.find_free_space(type_.airground_type, x, y) if x is not None: type_(self, place, x, y) self.triggers = self.start[2] if rules.get(self.race, getattr(self, "AI_type", "")): self.set_ai(rules.get(self.race, self.AI_type)[0])
def init_position(self): def equivalent_type(t): tn = getattr(t, "type_name", "") if rules.get(self.faction, tn): return self.world.unit_class(rules.get(self.faction, tn)[0]) return t self.resources = self.start[0][:] normalize_cost_or_resources(self.resources) self.gathered_resources = self.resources[:] for place, type_ in self.start[1]: type_ = equivalent_type(type_) if isinstance(type_, str) and type_[0:1] == "-": self.forbidden_techs.append(type_[1:]) elif isinstance(type_, Upgrade): self.upgrades.append(type_.type_name) # XXX type_.upgrade_player(self)? else: place = self.world.grid[place] x, y, land = place.find_and_remove_meadow(type_) x, y = place.find_free_space(type_.airground_type, x, y) if x is not None: unit = type_(self, place, x, y) unit.building_land = land self.triggers = self.start[2] if rules.get(self.faction, getattr(self, "AI_type", "")): self.set_ai(rules.get(self.faction, self.AI_type)[0])
def init_position(self): def equivalent_type(t): tn = getattr(t, "type_name", "") if rules.get(self.faction, tn): return self.world.unit_class(rules.get(self.faction, tn)[0]) return t self.resources = self.start[0][:] normalize_cost_or_resources(self.resources) self.gathered_resources = self.resources[:] for place, type_ in self.start[1]: if self.world.must_apply_equivalent_type: type_ = equivalent_type(type_) if isinstance(type_, str) and type_[0:1] == "-": self.forbidden_techs.append(type_[1:]) elif isinstance(type_, Upgrade): self.upgrades.append(type_.type_name) # type_.upgrade_player(self) would require the units already there elif not type_: warning("couldn't create an initial unit") else: place = self.world.grid[place] x, y, land = place.find_and_remove_meadow(type_) x, y = place.find_free_space(type_.airground_type, x, y) if x is not None: unit = type_(self, place, x, y) unit.building_land = land self.triggers = self.start[2] if rules.get(self.faction, getattr(self, "AI_type", "")): self.set_ai(rules.get(self.faction, self.AI_type)[0])
def unit_class(self, s): """Get a class-like unit generator from its name. Example: unit_class("peasant") to get a peasant generator At the moment, unit_classes contains also: upgrades, abilities... """ if not self.unit_classes.has_key(s): try: base = self.unit_base_classes[rules.get(s, "class")[0]] except: if rules.get(s, "class") != ["faction"]: warning("no class defined for %s", s) self.unit_classes[s] = None return try: dct = rules.get_dict(s) t = Type(s, (base, ), dct) if base is Upgrade: t = base(s, dct) # factory-prototypes are only for units self.unit_classes[s] = t except: exception("problem with unit_class('%s')", s) self.unit_classes[s] = None return return self.unit_classes[s]
def unit_class(self, s): """Get a class-like unit generator from its name. Example: unit_class("peasant") to get a peasant generator At the moment, unit_classes contains also: upgrades, abilities... """ if not self.unit_classes.has_key(s): try: base = self.unit_base_classes[rules.get(s, "class")[0]] except: if rules.get(s, "class") != ["race"]: warning("no class defined for %s", s) self.unit_classes[s] = None return try: dct = rules.get_dict(s) t = Type(s, (base,), dct) if base is Upgrade: t = base(s, dct) # factory-prototypes are only for units self.unit_classes[s] = t except: exception("problem with unit_class('%s')", s) self.unit_classes[s] = None return return self.unit_classes[s]
def build_or_train_or_upgradeto_or_summon(self, t, nb=1): if t.__class__ == str: t = self.world.unit_class(t) type = t.__name__ makers = self.world.get_makers(type) if self._get(1, makers) and self._get_requirements(t): for maker in makers: # TODO: choose one without orders if possible if self.nb(maker): break if type in self.world.unit_class(maker).can_upgrade_to: if self.nb(maker) >= nb: if self.gather(t.cost, t.food_cost): self.order(nb, maker, ["upgrade_to", type]) else: self._get(nb, maker) elif type in self.world.unit_class(maker).can_build: if not self.gather(t.cost, t.food_cost): return if t.storable_resource_types: meadow = self.choose( Meadow, resource_type=t.storable_resource_types[0]) if meadow is None or meadow.place.shortest_path_distance_to( self._builders_place( )) > self.world.square_width * 3: if self.nb(t): return else: meadow = self.choose( Meadow, starting_place=self._builders_place()) else: meadow = self.choose(Meadow, starting_place=self._builders_place()) if meadow: self.order(4, maker, ["build", type, meadow.id], requisition=True, near=meadow) elif type in self.world.unit_class(maker).can_train: if (self.nb(Worker) and nb > self.nb(maker) * 3 and self.potential(t.cost) > self.nb(maker) * 100): # additional production sites self.build_or_train_or_upgradeto_or_summon(maker) if self.gather(t.cost, t.food_cost): self.order(nb, maker, ["train", type]) elif type in self.world.unit_class(maker).can_research: if self.gather(t.cost, t.food_cost): self.order(1, maker, ["research", type]) else: for ability in self.world.unit_class(maker).can_use: effect = rules.get(ability, "effect") if effect and "summon" in effect[:1] and type in effect: if rules.get(ability, "effect_target") == ["ask"]: self.order(1, maker, ["use", ability, self.units[0].id]) # TODO select best place else: self.order(1, maker, ["use", ability]) break
def _cataclysm_is_efficient(self, a, units): type_names = set(u.type_name for u in units) e = rules.get(a, "effect") if e[0] == "summon": for item in e[1:]: if rules.get(item, "harm_level"): for t in type_names: if self.world.can_harm(item, t): return True
def __init__(self, prototype, player, place, x, y, o=90): if prototype is not None: prototype.init_dict(self) self.orders = [] # transport data self.objects = [] self.world = place.world # XXXXXXXXXX required by transport # set a player self.set_player(player) # stats "with a max" self.hp = self.hp_max # Start with mana_start if self.mana_start > 0: self.mana = self.mana_start else: # start with mana_max self.mana = self.mana_max # stat defined for the whole game self.minimal_damage = rules.get("parameters", "minimal_damage") if self.minimal_damage is None: self.minimal_damage = DEFAULT_MINIMAL_DAMAGE # move to initial place Entity.__init__(self, place, x, y, o) if self.decay: self.time_limit = self.world.time + self.decay
def __init__(self, prototype, player, place, x, y, o=90): if prototype is not None: prototype.init_dict(self) self.orders = [] # attributes required by transports and shelters (inside) self.objects = [] self.world = place.world self.neighbors = [] self.title = [] self.set_player(player) # stats "with a max" self.hp = self.hp_max if self.mana_start > 0: self.mana = self.mana_start else: self.mana = self.mana_max # stat defined for the whole game self.minimal_damage = rules.get("parameters", "minimal_damage") if self.minimal_damage is None: self.minimal_damage = int(.17 * PRECISION) # move to initial place Entity.__init__(self, place, x, y, o) self.position_to_hold = place # defend the creation place if self.decay: self.time_limit = self.world.time + self.decay
def __init__(self, prototype, player, place, x, y, o=90): if prototype is not None: prototype.init_dict(self) self.orders = [] # transport data self.objects = [] self.world = place.world # XXXXXXXXXX required by transport # set a player self.set_player(player) # stats "with a max" self.hp = self.hp_max if self.mana_start > 0: self.mana = self.mana_start else: self.mana = self.mana_max # stat defined for the whole game self.minimal_damage = rules.get("parameters", "minimal_damage") if self.minimal_damage is None: self.minimal_damage = DEFAULT_MINIMAL_DAMAGE # move to initial place Entity.__init__(self, place, x, y, o) if self.decay: self.time_limit = self.world.time + self.decay
def can_make(uc, t): for a in ("can_build", "can_train", "can_upgrade_to", "can_research"): if t in getattr(uc, a, []): return True for ability in getattr(uc, "can_use", []): effect = rules.get(ability, "effect") if effect and "summon" in effect[:1] and t in effect: return True
def _update_effect_users_and_workers(self): self._workers = [] self._gathered_deposits = {} self._building_sites = [] self._raise_dead_users = [] self._teleportation_users = [] self._cataclysm_users = [] self._detector_users = [] self._summon_users = [] for u in self.units: if isinstance(u, Worker): self._workers.append(u) if u.orders and u.orders[0].keyword == "gather": try: self._gathered_deposits[u.orders[0].target] += 1 except: self._gathered_deposits[u.orders[0].target] = 1 elif isinstance(u, BuildingSite): self._building_sites.append(u) for a in u.can_use: if not UseOrder.is_allowed(u, a): continue e = rules.get(a, "effect") if not e: continue elif e[0] == "raise_dead": self._raise_dead_users.append((u, a)) elif e[0] == "teleportation": self._teleportation_users.append((u, a)) elif e[0] == "summon": for item in e[1:]: if rules.get(item, "harm_level"): self._cataclysm_users.append((u, a)) if rules.get(item, "is_a_detector"): self._detector_users.append((u, a)) if rules.get(item, "damage"): self._summon_users.append((u, a))
def __init__(self, name, bases, dct): self.__name__ = name self.type_name = name self.cls = bases[0] if "cost" not in dct and hasattr(self.cls, "cost"): dct["cost"] = [0] * rules.get("parameters", "nb_of_resource_types") if "sight_range" in dct and dct["sight_range"] == 1 * PRECISION: dct["sight_range"] = 12 * PRECISION dct["bonus_height"] = 1 info("in %s: replacing sight_range 1 with sight_range 12 and bonus_height 1", name) if "special_range" in dct: del dct["special_range"] dct["range"] = 12 * PRECISION dct["minimal_range"] = 4 * PRECISION dct["is_ballistic"] = 1 info("in %s: replacing special_range 1 with range 12, minimal_range 4 and is_ballistic 1", name) self.dct = dct self.init_dict(self)
def __init__(self, name, bases, dct): self.__name__ = name self.type_name = name self.cls = bases[0] if "cost" not in dct and hasattr(self.cls, "cost"): dct["cost"] = [0] * rules.get("parameters", "nb_of_resource_types") if "sight_range" in dct and dct["sight_range"] == 1 * PRECISION: dct["sight_range"] = 12 * PRECISION dct["bonus_height"] = 1 info( "in %s: replacing sight_range 1 with sight_range 12 and bonus_height 1", name) if "special_range" in dct: del dct["special_range"] dct["range"] = 12 * PRECISION dct["minimal_range"] = 4 * PRECISION dct["is_ballistic"] = 1 info( "in %s: replacing special_range 1 with range 12, minimal_range 4 and is_ballistic 1", name) self.dct = dct self.init_dict(self)
def normalize_cost_or_resources(lst): n = rules.get("parameters", "nb_of_resource_types") while len(lst) < n: lst += [0] while len(lst) > n: del lst[-1]
def equivalent_type(t): tn = getattr(t, "type_name", "") if rules.get(self.faction, tn): return self.world.unit_class(rules.get(self.faction, tn)[0]) return t
def equivalent(self, tn): if rules.get(self.race, tn): return rules.get(self.race, tn)[0] return tn
def equivalent(self, tn): if rules.get(self.faction, tn): return rules.get(self.faction, tn)[0] return tn
def normalize_cost_or_resources(lst): n = int(rules.get("parameters", "nb_of_resource_types")[0]) while len(lst) < n: lst += [0] while len(lst) > n: del lst[-1]
def additional_condition(cls, unused_unit, type_name): e = rules.get(type_name, "effect") return e and hasattr(cls, "execute_%s" % e[0])
def get_races(self): return [c for c in rules.classnames() if rules.get(c, "class") == ["race"]]
def _load_map(self, map): def random_choice_repl(matchobj): return worldrandom.choice( matchobj.group(1).split("\n#end_choice\n")) def check_squares(squares): for sq in squares: if re.match("^[a-z]+[0-9]+$", sq) is None: map_error(line, "%s is not a square" % sq) self.objective = [] self.intro = [] self.timer_coefficient = 1 triggers = [] self.map_objects = [] self.computers_starts = [] self.players_starts = [] self.starting_units = [] squares_words = [ "starting_squares", "additional_meadows", "remove_meadows", "high_grounds" ] self.square_width = 12 # default value self.nb_lines = 0 self.nb_columns = 0 self.nb_rows = 0 # deprecated (was incorrectly used for columns instead of lines) self.nb_meadows_by_square = 0 self.west_east = [] self.south_north = [] # "squares words" self.starting_squares = [] self.additional_meadows = [] self.remove_meadows = [] self.high_grounds = [] self.starting_resources = [0 for _ in range(self.nb_res)] self.nb_players_min = 1 self.nb_players_max = 1 s = map.read() # "universal newlines" s = re.sub("(?m);.*$", "", s) # remove comments s = re.sub("(?m)^[ \t]*$\n", "", s) # remove empty lines s = re.sub(r"(?m)\\[ \t]*$\n", " ", s) # join lines ending with "\" s = s.replace("(", " ( ") s = s.replace(")", " ) ") s = re.sub(r"\s*\n\s*", r"\n", s) # strip lines s = re.sub(r"(?ms)^#random_choice\n(.*?)\n#end_random_choice$", random_choice_repl, s) s = re.sub(r"(?m)^(goldmine|wood)s\s+([0-9]+)\s+(.*)$", r"\1 \2 \3", s) s = re.sub(r"(south_north|west_east)_paths", r"\1 path", s) s = re.sub(r"(south_north|west_east)_bridges", r"\1 bridge", s) for line in s.split("\n"): # TODO: error msg words = line.strip().split() if not words: continue # empty line w = words[0] if w[0:1] == ";": continue # comment for _w in words[1:]: if w in ["south_north", "west_east"]: continue # TODO: check that the exit type_name is defined in style for _w in _w.split(","): if _w and _w[0] == "-": _w = _w[1:] if re.match("^([a-z]+[0-9]+|[0-9]+(.[0-9]*)?|.[0-9]+)$", _w) is None and \ not hasattr(Player, "lang_" + _w) and \ _w not in rules.classnames() and \ _w not in get_ai_names() and \ _w not in ["(", ")", "all", "players", "computers"] and \ _w not in ORDERS_DICT: map_error(line, "unknown: %s" % _w) if w in ["title", "objective", "intro"]: setattr(self, w, [int(x) for x in words[1:]]) # TODO: error msg (sounds) elif w in [ "square_width", "nb_rows", "nb_columns", "nb_lines", "nb_players_min", "nb_players_max", "scenario", "nb_meadows_by_square", "global_food_limit", "timer_coefficient" ]: try: setattr(self, w, int(words[1])) if w == "nb_rows": self.nb_columns = self.nb_rows warning( "nb_rows is deprecated, use nb_columns instead") except: map_error(line, "%s must be an integer" % w) elif w in ["south_north", "west_east"]: squares = words[2:] check_squares(squares) getattr(self, w).append((words[1], squares)) elif w in squares_words: squares = words[1:] check_squares(squares) getattr(self, w).extend(squares) elif w in ["starting_resources"]: self.starting_resources = [] for c in words[1:]: try: self.starting_resources.append(to_int(c)) except: map_error(line, "expected an integer but found %s" % c) elif rules.get(w, "class") == ["deposit"]: for sq in words[2:]: # TODO: error msg (squares) self.map_objects.append([sq, w, words[1]]) elif w in ["starting_units"]: getattr(self, w).extend(words[1:]) # TODO: error msg (types) elif w in ["player", "computer_only", "computer"]: self._add_start(w, words, line) elif w == "trigger": triggers.append(words[1:]) else: map_error(line, "unknown command: %s" % w) # build self.players_starts for sq in self.starting_squares: self._add_start_to(self.players_starts, self.starting_resources, self.starting_units, sq) if self.nb_players_min > self.nb_players_max: map_error("", "nb_players_min > nb_players_max") if len(self.players_starts) < self.nb_players_max: map_error("", "not enough starting places for nb_players_max") # 2 multiplayer map types: with or without standard triggers # TODO: select in a menu: User Map Settings, melee, free for all, etc if not triggers and self.default_triggers: triggers = self.default_triggers for t in triggers: self._add_trigger(t)
def get_factions(self): return [c for c in rules.classnames() if rules.get(c, "class") == ["faction"]]
def nb_res(self): return int(rules.get("parameters", "nb_of_resource_types")[0])
def get_factions(self): return [ c for c in rules.classnames() if rules.get(c, "class") == ["faction"] ]
def _load_map(self, map): def random_choice_repl(matchobj): return worldrandom.choice(matchobj.group(1).split("\n#end_choice\n")) def check_squares(squares): for sq in squares: if re.match("^[a-z]+[0-9]+$", sq) is None: map_error(line, "%s is not a square" % sq) self.objective = [] self.intro = [] self.timer_coefficient = 1 triggers = [] self.map_objects = [] self.computers_starts = [] self.players_starts = [] self.starting_units = [] squares_words = ["starting_squares", "additional_meadows", "remove_meadows", "high_grounds"] self.square_width = 12 # default value self.nb_lines = 0 self.nb_columns = 0 self.nb_rows = 0 # deprecated (was incorrectly used for columns instead of lines) self.nb_meadows_by_square = 0 self.west_east = [] self.south_north = [] # "squares words" self.starting_squares = [] self.additional_meadows = [] self.remove_meadows = [] self.high_grounds = [] self.starting_resources = [0 for _ in range(self.nb_res)] self.nb_players_min = 1 self.nb_players_max = 1 s = map.read() # "universal newlines" s = re.sub("(?m);.*$", "", s) # remove comments s = re.sub("(?m)^[ \t]*$\n", "", s) # remove empty lines s = re.sub(r"(?m)\\[ \t]*$\n", " ", s) # join lines ending with "\" s = s.replace("(", " ( ") s = s.replace(")", " ) ") s = re.sub(r"\s*\n\s*", r"\n", s) # strip lines s = re.sub(r"(?ms)^#random_choice\n(.*?)\n#end_random_choice$", random_choice_repl, s) s = re.sub(r"(?m)^(goldmine|wood)s\s+([0-9]+)\s+(.*)$", r"\1 \2 \3", s) s = re.sub(r"(south_north|west_east)_paths", r"\1 path", s) s = re.sub(r"(south_north|west_east)_bridges", r"\1 bridge", s) for line in s.split("\n"): # TODO: error msg words = line.strip().split() if not words: continue # empty line w = words[0] if w[0:1] == ";": continue # comment for _w in words[1:]: if w in ["south_north", "west_east"]: continue # TODO: check that the exit type_name is defined in style for _w in _w.split(","): if _w and _w[0] == "-": _w = _w[1:] if re.match("^([a-z]+[0-9]+|[0-9]+(.[0-9]*)?|.[0-9]+)$", _w) is None and \ not hasattr(Player, "lang_" + _w) and \ _w not in rules.classnames() and \ _w not in get_ai_names() and \ _w not in ["(", ")", "all", "players", "computers"] and \ _w not in ORDERS_DICT: map_error(line, "unknown: %s" % _w) if w in ["title", "objective", "intro"]: setattr(self, w, [int(x) for x in words[1:]]) # TODO: error msg (sounds) elif w in ["square_width", "nb_rows", "nb_columns", "nb_lines", "nb_players_min", "nb_players_max", "scenario", "nb_meadows_by_square", "global_food_limit", "timer_coefficient"]: try: setattr(self, w, int(words[1])) if w == "nb_rows": self.nb_columns = self.nb_rows warning("nb_rows is deprecated, use nb_columns instead") except: map_error(line, "%s must be an integer" % w) elif w in ["south_north", "west_east"]: squares = words[2:] check_squares(squares) getattr(self, w).append((words[1], squares)) elif w in squares_words: squares = words[1:] check_squares(squares) getattr(self, w).extend(squares) elif w in ["starting_resources"]: self.starting_resources = [] for c in words[1:]: try: self.starting_resources.append(to_int(c)) except: map_error(line, "expected an integer but found %s" % c) elif rules.get(w, "class") == ["deposit"]: for sq in words[2:]: # TODO: error msg (squares) self.map_objects.append([sq, w, words[1]]) elif w in ["starting_units"]: getattr(self, w).extend(words[1:]) # TODO: error msg (types) elif w in ["player", "computer_only", "computer"]: self._add_start(w, words, line) elif w == "trigger": triggers.append(words[1:]) else: map_error(line, "unknown command: %s" % w) # build self.players_starts for sq in self.starting_squares: self._add_start_to(self.players_starts, self.starting_resources, self.starting_units, sq) if self.nb_players_min > self.nb_players_max: map_error("", "nb_players_min > nb_players_max") if len(self.players_starts) < self.nb_players_max: map_error("", "not enough starting places for nb_players_max") # 2 multiplayer map types: with or without standard triggers # TODO: select in a menu: User Map Settings, melee, free for all, etc if not triggers and self.default_triggers: triggers = self.default_triggers for t in triggers: self._add_trigger(t)