Example #1
0
    def create_city(self, name=''):
        if name == '':
            name = self.language.make_name_word()

        x, y = self.get_average_city_position()
        candidates = self.get_city_candidate_cells()
        candidate = utility.weighted_random_choice(candidates, lambda _, cell: 1.0 / (
                utility.distance_squared((cell.x, cell.y), (x, y)) + 1.0))
        self.cities.append(city.City(self, name, candidate, self.parent))

        self.chance_add_new_name(self.cities[-1].name)

        self.parent.event_log.add_event('CityFounded', {'nation_a': self.id, 'city_a': self.cities[-1].name},
                                        self.parent.get_current_date())

        self.cities[-1].army = self.army_structure.copy().zero()

        self.money -= CITY_FOUND_COST

        self.mod_morale(city.MORALE_INCREMENT)

        if self.parent.cells[self.cities[-1].position[0]][self.cities[-1].position[1]].owner is None:
            self.parent.change_cell_ownership(self.cities[-1].position[0], self.cities[-1].position[1], self.cities[-1],
                                              new_type='city')

        religion_populations = self.get_nation_religion_populations()

        if len(religion_populations) > 0:
            religion, _ = utility.weighted_random_choice(religion_populations, lambda i, (_, adherents): adherents)
            religion.adherents[self.cities[-1].name] = self.cities[-1].population
Example #2
0
    def history_step(self):
        self.name.history_step(self)

        # we lost our capital somehow
        if not self.has_capital():
            # choose a new capital from our cities, weighted by population
            if len(self.cities) > 0:  # Just to be sure
                new_capital = utility.weighted_random_choice(self.cities, weight=lambda i, v: v.population)

                new_capital.make_capital()
        else:
            self.mod_morale(city.CAPITAL_CITY_MORALE_BONUS)

        self.handle_treaties()

        for curCity in self.cities:
            # It's more likely to found a new city when this city is near population capacity
            # Because as there's no more space, people want to go to a new city
            try:
                found_city_chance = max(1, int(
                    len(self.cities) ** 4 * math.math.log(curCity.population_capacity - curCity.population)))
            except:  # Log is negative
                found_city_chance = max(1, len(self.cities) ** 4)
            if random.randint(0, found_city_chance) == 0 and self.money > CITY_FOUND_COST:
                self.create_city()

            if self.current_research is None or self.current_research.is_unlocked():
                if self.current_research is not None and self.current_research.is_unlocked():
                    self.parent.event_log.add_event('TechResearch', {'nation_a': self.id,
                                                                     'tech_a': self.current_research.name},
                                                    self.parent.get_current_date())
                available = self.tech.get_available_research()

                if len(available) > 0:
                    self.current_research = random.choice(available)
                else:  # There's nothing left to research
                    self.current_research = None
            else:
                self.current_research.do_research(random.randint(1, int(math.log(curCity.population + 1) ** 2 + 1)))

                for cell in curCity.cells:
                    for building in cell.buildings:
                        research_rate = building.get_research_rate()

                        if research_rate > 0:
                            self.current_research.do_research(random.randint(1, research_rate))

        self.handle_rearming()
        self.handle_people()

        self.age += 1

        # More cities means less happiness
        self.mod_morale(-(len(self.cities) ** 2 + 1))
Example #3
0
    def build_buildings(self):
        improvement_chance = int((self.building_count() + 1) / (math.sqrt(self.owner.population) + 1))
        if random.randint(0, improvement_chance + 1) == 0:
            available_buildings = filter(lambda b: b.get_size() <= self.get_available_building_capacity(),
                                         self.buildings)

            if len(available_buildings) > 0:
                build_building = utility.weighted_random_choice(available_buildings,
                                                                weight=lambda _, b: 1.0 / b.get_cost())

                if self.owner.nation.money > build_building.get_cost():
                    self.owner.nation.money -= build_building.get_cost()
                    build_building.number += 1
Example #4
0
    def build_buildings(self):
        improvement_chance = int((self.building_count() + 1) /
                                 (math.sqrt(self.owner.population) + 1))
        if random.randint(0, improvement_chance + 1) == 0:
            available_buildings = filter(
                lambda b: b.get_size() <= self.get_available_building_capacity(
                ), self.buildings)

            if len(available_buildings) > 0:
                build_building = utility.weighted_random_choice(
                    available_buildings,
                    weight=lambda _, b: 1.0 / b.get_cost())

                if self.owner.nation.money > build_building.get_cost():
                    self.owner.nation.money -= build_building.get_cost()
                    build_building.number += 1
Example #5
0
    def handle_army_dispatch(self):
        # Determine if we want to launch an attack with this city's army
        for city in self.cities:
            if len(self.at_war) > 0 and city.army.size() > 0:
                enemy = random.choice(self.at_war)

                # Make sure our enemy actually still exists.
                if len(enemy.cities) > 0 and enemy in self.parent.nations:
                    attacking_city = utility.weighted_random_choice(enemy.cities,
                                                                    weight=lambda _, v: 1.0 / utility.distance(
                                                                        city.position, v.position))

                    if random.randint(0, max(20,
                                             city.army.size() + city.population // 8 - attacking_city.population // 3 - attacking_city.army.size())) > 20:
                        if random.randint(0, len(self.moving_armies) ** 3) == 0:
                            fx, fy = city.position

                            dx, dy = attacking_city.position

                            # Conscript some levies to join the army.
                            if city.population // 3 > 1:
                                conscript_max = max(city.population // 4, 3)
                                conscript_min = min(city.population // 8, 2)
                                conscripted = int(
                                    random.randint(conscript_min, conscript_max) * self.get_conscription_bonus())
                            else:
                                conscripted = 0

                            city.population -= conscripted
                            city.army.add_to(city.army.name, conscripted)

                            action = self.parent.do_attack(self, city, enemy, attacking_city)

                            self.moving_armies.append(
                                Group(self.parent, self.id, city.army, (fx, fy), (dx, dy), self.color, lambda s: False,
                                      action, is_army=True, has_boat=(city.resources['boats'] > 0)))

                            self.parent.event_log.add_event('ArmyDispatched', {'nation_a': self.id,
                                                                              'nation_b': enemy.id,
                                                                              'city_a': city.name,
                                                                              'city_b': attacking_city.name,
                                                                              'reason': 'attack',
                                                                              'army_size': city.army.size()},
                                                            self.parent.get_current_date())

                            city.army = city.army.zero()
Example #6
0
    def create_city(self, name=''):
        if name == '':
            name = self.language.make_name_word()

        x, y = self.get_average_city_position()
        candidates = self.get_city_candidate_cells()
        candidate = utility.weighted_random_choice(
            candidates, lambda _, cell: 1.0 / (utility.distance_squared(
                (cell.x, cell.y), (x, y)) + 1.0))
        self.cities.append(city.City(self, name, candidate, self.parent))

        self.chance_add_new_name(self.cities[-1].name)

        self.parent.event_log.add_event('CityFounded', {
            'nation_a': self.id,
            'city_a': self.cities[-1].name
        }, self.parent.get_current_date())

        self.cities[-1].army = self.army_structure.copy().zero()

        self.money -= CITY_FOUND_COST

        self.mod_morale(city.MORALE_INCREMENT)

        if self.parent.cells[self.cities[-1].position[0]][
                self.cities[-1].position[1]].owner is None:
            self.parent.change_cell_ownership(self.cities[-1].position[0],
                                              self.cities[-1].position[1],
                                              self.cities[-1],
                                              new_type='city')

        religion_populations = self.get_nation_religion_populations()

        if len(religion_populations) > 0:
            religion, _ = utility.weighted_random_choice(
                religion_populations, lambda i, (_, adherents): adherents)
            religion.adherents[
                self.cities[-1].name] = self.cities[-1].population
Example #7
0
    def choice(self, options, amount=1):
        def weight(_, v):
            if v in self.custom_weights:
                return self.custom_weights[v]
            else:
                return 1

        converted = {}
        for i in xrange(len(options)):
            if isinstance(options[i], list):
                converted[utility.tuplize(options[i])] = options[i]
                options[i] = utility.tuplize(options[i])

        chosen_item = utility.weighted_random_choice(options, weight=weight)

        if chosen_item in self.custom_weights:
            self.custom_weights[chosen_item] += amount
        else:
            self.custom_weights[chosen_item] = 1 + amount

        if chosen_item in converted:
            return converted[chosen_item]
        else:
            return chosen_item
Example #8
0
    def choice(self, options, amount=1):
        def weight(_, v):
            if v in self.custom_weights:
                return self.custom_weights[v]
            else:
                return 1

        converted = {}
        for i in xrange(len(options)):
            if isinstance(options[i], list):
                converted[utility.tuplize(options[i])] = options[i]
                options[i] = utility.tuplize(options[i])

        chosen_item = utility.weighted_random_choice(options, weight=weight)

        if chosen_item in self.custom_weights:
            self.custom_weights[chosen_item] += amount
        else:
            self.custom_weights[chosen_item] = 1 + amount

        if chosen_item in converted:
            return converted[chosen_item]
        else:
            return chosen_item
Example #9
0
    def __init__(self, person, role=None):
        self.person = person

        #  Measured in months
        self.length = 0

        self.custom_weights = {}
        self.art = []

        if role is not None:
            self.role = role
        else:
            # Could possibly change roles. This is less likely if the person has spent more time in a particular role, and if they have created more works.
            # If it's our first run, then our role is only determined by our religion, otherwise, religion plays a more minor role as the person becomes more cemented.
            role_weights = person.get_role_weights()
            self.role = utility.weighted_random_choice(PERSON_ROLES.keys(), lambda _, role: role_weights[role])

        base_create_chance = PERSON_ROLES[self.role]['art_create_chance']
        base_create_variance = PERSON_ROLES[self.role]['art_create_variance']
        self.art_create_chance = base_create_chance + random.randint(-base_create_variance, base_create_variance)

        custom_tags = {'role': [self.role]}

        if (self.art_create_chance - base_create_variance // 10) > base_create_chance:
            custom_tags['creation_rate'] = ['prolific', 'productive', 'creative']
        elif (self.art_create_chance + base_create_chance // 10) < base_create_chance:
            custom_tags['creation_rate'] = ['quiet', 'lazy', 'unproductive', 'barren']
        else:
            custom_tags['creation_rate'] = ['normal', 'average', 'standard']

        if self.role in ART_CATEGORIES.keys():
            gen = Form(PERIOD_FORMS, custom_tags=custom_tags)
        else:
            gen = Form(NORMAL_FORMS, custom_tags=custom_tags)

        self.name = gen.generate(nation=self.person.nation, creator=self.person)[0]
Example #10
0
    def __init__(self, person, role=None):
        self.person = person

        #  Measured in months
        self.length = 0

        self.custom_weights = {}
        self.art = []

        if role is not None:
            self.role = role
        else:
            # Could possibly change roles. This is less likely if the person has spent more time in a particular role, and if they have created more works.
            # If it's our first run, then our role is only determined by our religion, otherwise, religion plays a more minor role as the person becomes more cemented.
            role_weights = person.get_role_weights()
            self.role = utility.weighted_random_choice(PERSON_ROLES.keys(), lambda _, role: role_weights[role])

        base_create_chance = PERSON_ROLES[self.role]['art_create_chance']
        base_create_variance = PERSON_ROLES[self.role]['art_create_variance']
        self.art_create_chance = base_create_chance + random.randint(-base_create_variance, base_create_variance)

        custom_tags = {'role': [self.role]}

        if (self.art_create_chance - base_create_variance // 10) > base_create_chance:
            custom_tags['creation_rate'] = ['prolific', 'productive', 'creative']
        elif (self.art_create_chance + base_create_chance // 10) < base_create_chance:
            custom_tags['creation_rate'] = ['quiet', 'lazy', 'unproductive', 'barren']
        else:
            custom_tags['creation_rate'] = ['normal', 'average', 'standard']

        if self.role in ART_CATEGORIES.keys():
            gen = Form(PERIOD_FORMS, custom_tags=custom_tags)
        else:
            gen = Form(NORMAL_FORMS, custom_tags=custom_tags)

        self.name = gen.generate(nation=self.person.nation, creator=self.person)[0]
Example #11
0
 def get_random_religion(self):
     religion_populations = self.get_religion_populations()
     weight = lambda _, (religion, adherents): adherents
     religion, _ = utility.weighted_random_choice(religion_populations,
                                                  weight=weight)
     return religion
Example #12
0
    def generate_tags(self, actual_forms, nation=None, creator=None):
        # So that tags are generated in the correct order.
        tag_order = []
        for form in actual_forms:
            for part in form:
                if part.startswith('tag:'):
                    tag_order.append(part.split(':')[1])

        for tag in tag_order:
            base = self.tags[tag]

            # () allow you to group text without using any actual tag
            # For example, <test:(<animal>'s hair)> allows you to give the name 'test' to 'lion's hair'
            while '<(' in base:
                i = base.find('<(')

                # Get the full tag and remove the brackets
                group = utility.get_container(base, '<', '>', i)
                base = base.replace(group,
                                    group[2:-2])  # Remove the containing stuff

            # Checks if tags exist. Replaces the tag's text with the first tag that exists. Otherwise replaces it with nothing.
            while '<tagexists' in base:
                i = base.find('<tagexists')
                section = utility.get_container(base, '<', '>', i)
                check_tags = section[1:-1].split(';')[1:]
                replacement = ''

                for tag_name in check_tags:
                    if tag_name in self.chosen_tags:
                        replacement = self.chosen_tags[tag_name]

                base = base.replace(section, replacement)

            while '|' in base:
                start_pos, end_pos = utility.find_container_of(
                    base, '<', '>', '|')
                choice_section = base[start_pos + 1:end_pos]

                choice = utility.separate_container(choice_section, '<', '>',
                                                    '|')
                valid_choice = filter(is_valid(nation), choice)

                base = base.replace('<' + choice_section + '>',
                                    self.choice(valid_choice), 1)

            while ',' in base:
                start_pos, end_pos = utility.find_container_of(
                    base, '<', '>', ',')
                select_section = base[start_pos + 1:end_pos]

                select = utility.separate_container(select_section, '<', '>',
                                                    ',')
                valid_select = filter(is_valid(nation), select)
                search = '<' + select_section + '>'
                replacement = '<{}>'.format('> <'.join(
                    random.sample(valid_select,
                                  random.randint(1, len(valid_select)))))

                base = base.replace(search, replacement)

            base = base.replace('<> ', '')
            base = base.replace('<>', '')

            while '<paint>' in base:
                base = base.replace('<paint>', self.choice(PAINTS), 1)
            while '<medium>' in base:
                base = base.replace('<medium>', self.choice(MEDIUMS), 1)
            while '<sketch>' in base:
                base = base.replace('<sketch>', self.choice(SKETCHING), 1)
            while '<material>' in base:
                base = base.replace('<material>', self.choice(MATERIALS), 1)
            while '<animal>' in base:
                base = base.replace('<animal>', self.choice(ANIMALS), 1)
            while '<nature>' in base:
                base = base.replace('<nature>', self.choice(NATURE), 1)
            while '<philosophy>' in base:
                base = base.replace('<philosophy>', self.choice(PHILOSOPHIES),
                                    1)
            while '<nation>' in base:
                if nation is not None:
                    base = base.replace(
                        '<nation>',
                        str(self.choice(nation.parent.nations).name), 1)
                else:
                    base = base.replace('<nation>', '')
            while '<notable_person>' in base:
                if nation is not None:
                    base = base.replace(
                        '<notable_person>',
                        self.choice(nation.notable_people).name, 1)
                else:
                    base = base.replace('<notable_person>', '')
            while '<notable_person_role>' in base:
                if nation is not None:
                    person = self.choice(nation.notable_people)
                    base = base.replace(
                        '<notable_person_role>',
                        '{} the {}'.format(person.name,
                                           person.periods[-1].role), 1)
                else:
                    base = base.replace('<notable_person_role>', '')
            while '<god>' in base:
                if nation is not None:
                    religion_populations = nation.get_nation_religion_populations(
                    )
                    if len(religion_populations) > 0:
                        religion, _ = utility.weighted_random_choice(
                            religion_populations,
                            weight=lambda i, (_, adherents): adherents)
                        base = base.replace('<god>',
                                            self.choice(religion.gods).name, 1)
                    else:
                        base = base.replace('<god>', '')
                else:
                    base = base.replace('<god>', '')
            while '<name>' in base:
                if nation is not None:
                    base = base.replace('<name>',
                                        nation.language.generate_name(), 1)
                else:
                    base = base.replace('<name>', '')
            while '<art>' in base:
                if nation is not None and len(nation.culture.art) > 0:
                    base = base.replace(
                        '<art>', '\'{}\''.format(
                            self.choice(nation.culture.art).subject), 1)
                else:
                    base = base.replace('<art>', '')
            while '<art_creator>' in base:
                if nation is not None and len(nation.culture.art) > 0:
                    art = self.choice(nation.culture.art)
                    base = base.replace(
                        '<art_creator>',
                        '{}\'s \'{}\''.format(art.creator.name,
                                              art.subject), 1)
                else:
                    base = base.replace('<art_creator>', '')
            while '<place>' in base:
                if nation is not None and len(
                        nation.parent.get_all_cities()) > 0:
                    base = base.replace(
                        '<place>',
                        self.choice(nation.parent.get_all_cities()).name, 1)
                else:
                    base = base.replace('<place>', '')
            while '<nation_place>' in base:
                if nation is not None and len(nation.cities) > 0:
                    base = base.replace('<nation_place>',
                                        self.choice(nation.cities).name, 1)
                else:
                    base = base.replace('<nation_place>', '')
            while '<battle>' in base:
                if nation is not None and len(
                        nation.parent.battle_history) > 0:
                    battle = self.choice(nation.parent.battle_history)

                    battle_bases = [
                        '<The Battle of|The Battle for|>{}'.format(
                            battle.location.name)
                    ]
                    base = base.replace(
                        '<battle>', gen_simple_form(self.choice(battle_bases)),
                        1)
                else:
                    base = base.replace('<battle>', '')
            while '<treaty>' in base:
                if nation is not None and len(nation.parent.treaties) > 0:
                    treaty = self.choice(
                        nation.parent.treaties).get_treaty_name(
                            nation.parent.get_current_date(), nation)
                    base = base.replace('<treaty>', treaty)
                else:
                    base = base.replace('<treaty>', '')
            while '<nation_treaty>' in base:
                if nation is not None and len(nation.treaties) > 0:
                    treaty = self.choice(nation.treaties).get_treaty_name(
                        nation.parent.get_current_date(), nation)
                    base = base.replace('<nation_treaty>', treaty)
                else:
                    base = base.replace('<nation_treaty>', '')
            while '<weapon>' in base:
                base = base.replace(
                    '<weapon>',
                    self.choice(equipment_list.weapon_list).name, 1)
            while '<armor>' in base:
                base = base.replace(
                    '<armor>',
                    self.choice(equipment_list.armor_list).name, 1)
            while '<color>' in base:
                base = base.replace('<color>', self.choice(COLORS), 1)
            while '<flower>' in base:
                base = base.replace('<flower>', self.choice(FLOWERS), 1)
            while '<scientific_subject>' in base:
                base = base.replace('<scientific_subject>',
                                    self.choice(SCIENTIFIC_SUBJECTS), 1)
            while '<n>' in base:
                base = base.replace('<n>', self.choice(NOUNS), 1)
            while '<v>' in base:
                base = base.replace('<v>', self.choice(VERBS), 1)
            while '<prep>' in base:
                base = base.replace('<prep>', self.choice(PREPOSITIONS), 1)
            while '<adj>' in base:
                base = base.replace('<adj>', self.choice(ADJECTIVES), 1)

            if creator is not None:
                if '<self>' in base:
                    base = base.replace('<self>', creator.name)
                if '<self_role>' in base:
                    base = base.replace(
                        '<self_role>',
                        '{} the {}'.format(creator.name,
                                           creator.periods[-1].role))

            randoms = re.findall(r'<rand(.*?);(.*?);(.*?)>', base)

            for rand_type, minimum, maximum in randoms:
                if rand_type == 'int':
                    minimum, maximum = int(minimum), int(maximum)
                    res = random.randint(minimum, maximum)
                elif rand_type == 'om':  # Float
                    minimum, maximum = float(minimum), float(maximum)
                    res = random.random() * (maximum - minimum) + minimum

                base = base.replace(
                    '<rand{};{};{}>'.format(rand_type, minimum, maximum),
                    str(res))

            # So we can access the previously used tags
            remaining_tags = re.findall(r'<(.*?)>', base)

            for check_tag in remaining_tags:
                if check_tag in self.chosen_tags:
                    base = base.replace('<' + check_tag + '>',
                                        self.chosen_tags[check_tag])
                elif check_tag in self.custom_tags:
                    base = base.replace(
                        '<' + check_tag + '>',
                        self.choice(self.custom_tags[check_tag]))

            while True:
                try:
                    i = base.index('<article>')

                    base = base[:i] + base[i + len('<article>'):]

                    next_word = re.sub(r'<.*?>', '', base)

                    article = 'the '
                    for word in COUNTABLE_WORDS:
                        if next_word.startswith(word):
                            article = random.choice(['<indef>', 'the '])
                            break

                    base = base[:i] + article + base[i:]
                except:
                    break
            while True:
                try:
                    i = base.index('<indef>')

                    base = base[:i] + base[i + len('<indef>'):]

                    test = re.sub(r'<.*?>', '', str(base))
                    if test[i].lower() in 'aeiou':
                        article = 'an '
                    else:
                        article = 'a '

                    base = base[:i] + article + base[i:]
                except:
                    break
            while True:
                try:
                    i = base.index('<cap>')

                    base = base[:i] + base[i + len('<cap>'):]

                    test = re.sub(r'<.*?>', '', str(base))
                    base = base[:i] + test[i].upper() + base[i + 1:]
                except:
                    break
            while True:
                try:
                    i = base.index('<lower>')

                    base = base[:i] + base[i + len('<lower>'):]

                    test = re.sub(r'<.*?>', '', str(base))
                    base = base[:i] + test[i].lower() + base[i + 1:]
                except:
                    break
            while True:
                try:
                    i = base.index('<all_lower>')

                    base = base[:i] + base[i + len('<all_lower>'):]

                    test = re.sub(r'<.*?>', '', str(base))
                    base = base[:i] + test[i:].lower()
                except:
                    break
            while True:
                try:
                    i = base.index('<titlecase>')

                    base = base[:i] + base[i + len('<titlecase>'):]

                    test = re.sub(r'<.*?>', '', str(base))
                    base = base[:i] + utility.titlecase(test[i:])
                except:
                    break
            while True:
                try:
                    i = base.index('<pl>')

                    base = base[:i] + base[i + len('<pl>'):]

                    test = re.sub(r'<.*?>', '', str(base[i:]))
                    words = test.split()
                    if len(words) > 0:
                        next_word = words[0]
                        if next_word in COUNTABLE_WORDS:
                            if next_word in IRREGULAR_PLURALS:
                                pluralized = IRREGULAR_PLURALS[next_word]
                            else:
                                pluralized = str(next_word)
                                if next_word.endswith(
                                        's') or next_word.endswith(
                                            'x') or next_word.endswith(
                                                'ch') or next_word.endswith(
                                                    'sh'):
                                    pluralized += 'es'
                                elif next_word.endswith('y'):
                                    pluralized = pluralized[:-1] + 'ies'
                                else:
                                    pluralized += 's'

                            base = base.replace(next_word, pluralized)
                except:
                    break

            conjugate = re.findall(r'<conj;(.*?);(.*?);(.*?);(.*?)>', base)

            for person, tense, number, verb in conjugate:
                conjugated = self.do_conjugate(verb, person, tense, number)

                base = base.replace(
                    '<conj;{};{};{};{}>'.format(person, tense, number, verb),
                    conjugated)

            conjugate = re.findall(r'<conj;(.*?);(.*?)>', base)
            for conj_type, verb in conjugate:
                conjugated = self.do_conjugate_type(verb, conj_type)

                base = base.replace('<conj;{};{}>'.format(conj_type, verb),
                                    conjugated)

            base = base.replace('  ', ' ').strip()

            self.chosen_tags[tag] = base
Example #13
0
 def get_random_religion(self):
     religion_populations = self.get_religion_populations()
     weight = lambda _, (religion, adherents): adherents
     religion, _ = utility.weighted_random_choice(religion_populations, weight=weight)
     return religion
Example #14
0
    def history_step(self):
        self.name.history_step(self)

        # we lost our capital somehow
        if not self.has_capital():
            # choose a new capital from our cities, weighted by population
            if len(self.cities) > 0:  # Just to be sure
                new_capital = utility.weighted_random_choice(
                    self.cities, weight=lambda i, v: v.population)

                new_capital.make_capital()
        else:
            self.mod_morale(city.CAPITAL_CITY_MORALE_BONUS)

        self.handle_treaties()

        for curCity in self.cities:
            # It's more likely to found a new city when this city is near population capacity
            # Because as there's no more space, people want to go to a new city
            found_city_chance = max(
                1,
                int(
                    len(self.cities)**2 * float(curCity.population_capacity) /
                    curCity.population))
            if random.randint(
                    0,
                    found_city_chance) == 0 and self.money > CITY_FOUND_COST:
                self.create_city()

            if self.current_research is None or self.current_research.is_unlocked(
            ):
                if self.current_research is not None and self.current_research.is_unlocked(
                ):
                    self.parent.event_log.add_event(
                        'TechResearch', {
                            'nation_a': self.id,
                            'tech_a': self.current_research.name
                        }, self.parent.get_current_date())
                available = self.tech.get_available_research()

                if len(available) > 0:
                    self.current_research = random.choice(available)
                else:  # There's nothing left to research
                    self.current_research = None
            else:
                self.current_research.do_research(
                    random.randint(
                        1, int(math.log(curCity.population + 1)**2 + 1)))

                for cell in curCity.cells:
                    for building in cell.buildings:
                        research_rate = building.get_research_rate()

                        if research_rate > 0:
                            self.current_research.do_research(
                                random.randint(1, research_rate))

        self.handle_rearming()
        self.handle_people()

        self.age += 1

        # More cities means less happiness
        self.mod_morale(-(len(self.cities)**2 + 1))
Example #15
0
    def handle_army_dispatch(self):
        # Determine if we want to launch an attack with this city's army
        for city in self.cities:
            if len(self.at_war) > 0 and city.army.size() > 0:
                enemy = random.choice(self.at_war)

                # Make sure our enemy actually still exists.
                if len(enemy.cities) > 0 and enemy in self.parent.nations:
                    attacking_city = utility.weighted_random_choice(
                        enemy.cities,
                        weight=lambda _, v: 1.0 / utility.distance(
                            city.position, v.position))

                    if random.randint(
                            0,
                            max(
                                20,
                                city.army.size() + city.population // 8 -
                                attacking_city.population // 3 -
                                attacking_city.army.size())) > 20:
                        if random.randint(0, len(self.moving_armies)**3) == 0:
                            fx, fy = city.position

                            dx, dy = attacking_city.position

                            # Conscript some levies to join the army.
                            if city.population // 3 > 1:
                                conscript_max = max(city.population // 4, 3)
                                conscript_min = min(city.population // 8, 2)
                                conscripted = int(
                                    random.randint(conscript_min,
                                                   conscript_max) *
                                    self.get_conscription_bonus())
                            else:
                                conscripted = 0

                            city.population -= conscripted
                            city.army.add_to(city.army.name, conscripted)

                            action = self.parent.do_attack(
                                self, city, enemy, attacking_city)

                            self.moving_armies.append(
                                Group(self.parent,
                                      self.id,
                                      city.army, (fx, fy), (dx, dy),
                                      self.color,
                                      lambda s: False,
                                      action,
                                      is_army=True,
                                      has_boat=(city.resources['boats'] > 0)))

                            self.parent.event_log.add_event(
                                'ArmyDispatched', {
                                    'nation_a': self.id,
                                    'nation_b': enemy.id,
                                    'city_a': city.name,
                                    'city_b': attacking_city.name,
                                    'reason': 'attack',
                                    'army_size': city.army.size()
                                }, self.parent.get_current_date())

                            city.army = city.army.zero()
Example #16
0
    def generate_tags(self, actual_forms, nation=None, creator=None):
        # So that tags are generated in the correct order.
        tag_order = []
        for form in actual_forms:
            for part in form:
                if part.startswith('tag:'):
                    tag_order.append(part.split(':')[1])

        for tag in tag_order:
            base = self.tags[tag]

            # () allow you to group text without using any actual tag
            # For example, <test:(<animal>'s hair)> allows you to give the name 'test' to 'lion's hair'
            while '<(' in base:
                i = base.find('<(')

                # Get the full tag and remove the brackets
                group = utility.get_container(base, '<', '>', i)
                base = base.replace(group, group[2:-2])  # Remove the containing stuff

            # Checks if tags exist. Replaces the tag's text with the first tag that exists. Otherwise replaces it with nothing.
            while '<tagexists' in base:
                i = base.find('<tagexists')
                section = utility.get_container(base, '<', '>', i)
                check_tags = section[1:-1].split(';')[1:]
                replacement = ''

                for tag_name in check_tags:
                    if tag_name in self.chosen_tags:
                        replacement = self.chosen_tags[tag_name]

                base = base.replace(section, replacement)

            while '|' in base:
                start_pos, end_pos = utility.find_container_of(base, '<', '>', '|')
                choice_section = base[start_pos + 1:end_pos]

                choice = utility.separate_container(choice_section, '<', '>', '|')
                valid_choice = filter(is_valid(nation), choice)

                base = base.replace('<' + choice_section + '>', self.choice(valid_choice), 1)

            while ',' in base:
                start_pos, end_pos = utility.find_container_of(base, '<', '>', ',')
                select_section = base[start_pos + 1:end_pos]

                select = utility.separate_container(select_section, '<', '>', ',')
                valid_select = filter(is_valid(nation), select)
                search = '<' + select_section + '>'
                replacement = '<{}>'.format(
                    '> <'.join(random.sample(valid_select, random.randint(1, len(valid_select)))))

                base = base.replace(search, replacement)

            base = base.replace('<> ', '')
            base = base.replace('<>', '')

            while '<paint>' in base:
                base = base.replace('<paint>', self.choice(PAINTS), 1)
            while '<medium>' in base:
                base = base.replace('<medium>', self.choice(MEDIUMS), 1)
            while '<sketch>' in base:
                base = base.replace('<sketch>', self.choice(SKETCHING), 1)
            while '<material>' in base:
                base = base.replace('<material>', self.choice(MATERIALS), 1)
            while '<animal>' in base:
                base = base.replace('<animal>', self.choice(ANIMALS), 1)
            while '<nature>' in base:
                base = base.replace('<nature>', self.choice(NATURE), 1)
            while '<philosophy>' in base:
                base = base.replace('<philosophy>', self.choice(PHILOSOPHIES), 1)
            while '<nation>' in base:
                if nation is not None:
                    base = base.replace('<nation>', str(self.choice(nation.parent.nations).name), 1)
                else:
                    base = base.replace('<nation>', '')
            while '<notable_person>' in base:
                if nation is not None:
                    base = base.replace('<notable_person>', self.choice(nation.notable_people).name, 1)
                else:
                    base = base.replace('<notable_person>', '')
            while '<notable_person_role>' in base:
                if nation is not None:
                    person = self.choice(nation.notable_people)
                    base = base.replace('<notable_person_role>',
                                        '{} the {}'.format(person.name, person.periods[-1].role), 1)
                else:
                    base = base.replace('<notable_person_role>', '')
            while '<god>' in base:
                if nation is not None:
                    religion_populations = nation.get_nation_religion_populations()
                    if len(religion_populations) > 0:
                        religion, _ = utility.weighted_random_choice(religion_populations,
                                                                     weight=lambda i, (_, adherents): adherents)
                        base = base.replace('<god>', self.choice(religion.gods).name, 1)
                    else:
                        base = base.replace('<god>', '')
                else:
                    base = base.replace('<god>', '')
            while '<name>' in base:
                if nation is not None:
                    base = base.replace('<name>', nation.language.generate_name(), 1)
                else:
                    base = base.replace('<name>', '')
            while '<art>' in base:
                if nation is not None and len(nation.culture.art) > 0:
                    base = base.replace('<art>', '\'{}\''.format(self.choice(nation.culture.art).subject), 1)
                else:
                    base = base.replace('<art>', '')
            while '<art_creator>' in base:
                if nation is not None and len(nation.culture.art) > 0:
                    art = self.choice(nation.culture.art)
                    base = base.replace('<art_creator>', '{}\'s \'{}\''.format(art.creator.name, art.subject), 1)
                else:
                    base = base.replace('<art_creator>', '')
            while '<place>' in base:
                if nation is not None and len(nation.parent.get_all_cities()) > 0:
                    base = base.replace('<place>', self.choice(nation.parent.get_all_cities()).name, 1)
                else:
                    base = base.replace('<place>', '')
            while '<nation_place>' in base:
                if nation is not None and len(nation.cities) > 0:
                    base = base.replace('<nation_place>', self.choice(nation.cities).name, 1)
                else:
                    base = base.replace('<nation_place>', '')
            while '<battle>' in base:
                if nation is not None and len(nation.parent.battle_history) > 0:
                    battle = self.choice(nation.parent.battle_history)

                    battle_bases = ['<The Battle of|The Battle for|>{}'.format(battle.location.name)]
                    base = base.replace('<battle>', gen_simple_form(self.choice(battle_bases)), 1)
                else:
                    base = base.replace('<battle>', '')
            while '<treaty>' in base:
                if nation is not None and len(nation.parent.treaties) > 0:
                    treaty = self.choice(nation.parent.treaties).get_treaty_name(nation.parent.get_current_date(),
                                                                                 nation)
                    base = base.replace('<treaty>', treaty)
                else:
                    base = base.replace('<treaty>', '')
            while '<nation_treaty>' in base:
                if nation is not None and len(nation.treaties) > 0:
                    treaty = self.choice(nation.treaties).get_treaty_name(nation.parent.get_current_date(), nation)
                    base = base.replace('<nation_treaty>', treaty)
                else:
                    base = base.replace('<nation_treaty>', '')
            while '<weapon>' in base:
                base = base.replace('<weapon>', self.choice(equipment_list.weapon_list).name, 1)
            while '<armor>' in base:
                base = base.replace('<armor>', self.choice(equipment_list.armor_list).name, 1)
            while '<color>' in base:
                base = base.replace('<color>', self.choice(COLORS), 1)
            while '<flower>' in base:
                base = base.replace('<flower>', self.choice(FLOWERS), 1)
            while '<scientific_subject>' in base:
                base = base.replace('<scientific_subject>', self.choice(SCIENTIFIC_SUBJECTS), 1)
            while '<n>' in base:
                base = base.replace('<n>', self.choice(NOUNS), 1)
            while '<v>' in base:
                base = base.replace('<v>', self.choice(VERBS), 1)
            while '<prep>' in base:
                base = base.replace('<prep>', self.choice(PREPOSITIONS), 1)
            while '<adj>' in base:
                base = base.replace('<adj>', self.choice(ADJECTIVES), 1)

            if creator is not None:
                if '<self>' in base:
                    base = base.replace('<self>', creator.name)
                if '<self_role>' in base:
                    base = base.replace('<self_role>', '{} the {}'.format(creator.name, creator.periods[-1].role))

            randoms = re.findall(r'<rand(.*?);(.*?);(.*?)>', base)

            for rand_type, minimum, maximum in randoms:
                if rand_type == 'int':
                    minimum, maximum = int(minimum), int(maximum)
                    res = random.randint(minimum, maximum)
                elif rand_type == 'om':  # Float
                    minimum, maximum = float(minimum), float(maximum)
                    res = random.random() * (maximum - minimum) + minimum

                base = base.replace('<rand{};{};{}>'.format(rand_type, minimum, maximum), str(res))

            # So we can access the previously used tags
            remaining_tags = re.findall(r'<(.*?)>', base)

            for check_tag in remaining_tags:
                if check_tag in self.chosen_tags:
                    base = base.replace('<' + check_tag + '>', self.chosen_tags[check_tag])
                elif check_tag in self.custom_tags:
                    base = base.replace('<' + check_tag + '>', self.choice(self.custom_tags[check_tag]))

            while True:
                try:
                    i = base.index('<article>')

                    base = base[:i] + base[i + len('<article>'):]

                    next_word = re.sub(r'<.*?>', '', base)

                    article = 'the '
                    for word in COUNTABLE_WORDS:
                        if next_word.startswith(word):
                            article = random.choice(['<indef>', 'the '])
                            break

                    base = base[:i] + article + base[i:]
                except:
                    break
            while True:
                try:
                    i = base.index('<indef>')

                    base = base[:i] + base[i + len('<indef>'):]

                    test = re.sub(r'<.*?>', '', str(base))
                    if test[i].lower() in 'aeiou':
                        article = 'an '
                    else:
                        article = 'a '

                    base = base[:i] + article + base[i:]
                except:
                    break
            while True:
                try:
                    i = base.index('<cap>')

                    base = base[:i] + base[i + len('<cap>'):]

                    test = re.sub(r'<.*?>', '', str(base))
                    base = base[:i] + test[i].upper() + base[i + 1:]
                except:
                    break
            while True:
                try:
                    i = base.index('<lower>')

                    base = base[:i] + base[i + len('<lower>'):]

                    test = re.sub(r'<.*?>', '', str(base))
                    base = base[:i] + test[i].lower() + base[i + 1:]
                except:
                    break
            while True:
                try:
                    i = base.index('<all_lower>')

                    base = base[:i] + base[i + len('<all_lower>'):]

                    test = re.sub(r'<.*?>', '', str(base))
                    base = base[:i] + test[i:].lower()
                except:
                    break
            while True:
                try:
                    i = base.index('<titlecase>')

                    base = base[:i] + base[i + len('<titlecase>'):]

                    test = re.sub(r'<.*?>', '', str(base))
                    base = base[:i] + utility.titlecase(test[i:])
                except:
                    break
            while True:
                try:
                    i = base.index('<pl>')

                    base = base[:i] + base[i + len('<pl>'):]

                    test = re.sub(r'<.*?>', '', str(base[i:]))
                    words = test.split()
                    if len(words) > 0:
                        next_word = words[0]
                        if next_word in COUNTABLE_WORDS:
                            if next_word in IRREGULAR_PLURALS:
                                pluralized = IRREGULAR_PLURALS[next_word]
                            else:
                                pluralized = str(next_word)
                                if next_word.endswith('s') or next_word.endswith('x') or next_word.endswith(
                                        'ch') or next_word.endswith('sh'):
                                    pluralized += 'es'
                                elif next_word.endswith('y'):
                                    pluralized = pluralized[:-1] + 'ies'
                                else:
                                    pluralized += 's'

                            base = base.replace(next_word, pluralized)
                except:
                    break

            conjugate = re.findall(r'<conj;(.*?);(.*?);(.*?);(.*?)>', base)

            for person, tense, number, verb in conjugate:
                conjugated = self.do_conjugate(verb, person, tense, number)

                base = base.replace('<conj;{};{};{};{}>'.format(person, tense, number, verb), conjugated)

            conjugate = re.findall(r'<conj;(.*?);(.*?)>', base)
            for conj_type, verb in conjugate:
                conjugated = self.do_conjugate_type(verb, conj_type)

                base = base.replace('<conj;{};{}>'.format(conj_type, verb), conjugated)

            base = base.replace('  ', ' ').strip()

            self.chosen_tags[tag] = base