def read_vanilla(): nationalunits = {} _read_vanilla_unit_nation_map_file( "data/VanillaLeaderMaps/fort_leader_types_by_nation.csv", nationalunits) _read_vanilla_unit_nation_map_file( "data/VanillaLeaderMaps/coast_leader_types_by_nation.csv", nationalunits) _read_vanilla_unit_nation_map_file( "data/VanillaLeaderMaps/nonfort_leader_types_by_nation.csv", nationalunits) _read_vanilla_cap_only_site_recruits(nationalunits) # Get their info unitdata = {} with open("data/BaseU.csv", "r") as datacsv: reader = csv.DictReader(datacsv, delimiter="\t") for line in reader: unitdata[int(line["id"])] = copy.copy(line) for unitid in unitdata: dataline = unitdata[unitid] mage: NationalMage = NationalMage() for index, key in enumerate(["F", "A", "W", "E", "S", "D", "N", "B"]): if dataline[key] != "": mage.add_magic_path(2**index, int(dataline[key])) for n in range(1, 7): if dataline[f"mask{n}"] == "": break mask = int(dataline[f"mask{n}"]) >> 7 chance = int(dataline[f"rand{n}"]) instances = int(dataline[f"nbr{n}"]) link = int(dataline[f"link{n}"]) for i in range(instances): mage.add_magic_random( MagePathRandom(chance=chance, link=link, paths=mask)) mage.name = dataline[f"name"] if mage.is_mage(): vanillamages[unitid] = mage for nationid, units in nationalunits.items(): if nationid not in nations: nations[nationid] = Nation(nationid) for unitid in units: if unitid in vanillamages: mage = vanillamages[unitid] if mage.is_mage(): nations[nationid].add_mage(mage)
def _roll_path_for_national_spell(nation: Nation) -> int: pathweights = nation.get_pathweights() totalweights = 0 for i, weight in pathweights.items(): totalweights += weight if totalweights == 0: raise ValueError(f"Failed calculating national spell path weights.\n" f"Nation: {nation.to_text()}\n" f"Weights: {pprint.pformat(pathweights)}\n" f"Total Weight: {totalweights}") initialroll = roll = random.randrange(0, totalweights, 1) for path, weight in pathweights.items(): if roll < weight: DebugLogger.debuglog(f"Selected path {utils.pathstotext(path)} from weights {pathweights.items()}, " f"rolled {initialroll}", debugkeys.NATIONALSPELLGENERATION, debugkeys.NATIONALSPELLGENERATIONWEIGHTING) return path roll -= weight raise ValueError(f"Attempted and failed to roll for weighted path\n Rolled {initialroll}\n Total weight: " f"{totalweights}\n Weights: {pprint.pformat(pathweights)}\n")
def read_mods(modstring): global monsterids, weaponids, spellids, eventcodes, montagids, siteids, enchantids, vanillamages mods = modstring.strip().split(",") monsterids = [3499] weaponids = [799] siteids = [1499] spellids = [1299] eventcodes = [-299] montagids = [1000] enchantids = [500] for mod in mods: mod = mod.strip() if mod == "": continue with open(mod, "r", encoding="u8") as f: currentsite: Union[Site, None] = None sites: Dict[int, Site] = {} sitenames: Dict[str, int] = {} # TODO Sites that are defined after nations with them as startsite nationstartsites: Dict[Nation, List[Union[int, str]]] = {} sitecommanders: Dict[Site, List[Union[int, str]]] = {} currentnation: Union[Nation, None] = None currentunit: Union[NationalMage, None] = None units: Dict[int, NationalMage] = {} for line in f: if "--" in line: line = line[0:line.find("--")].strip() line = line.strip() if line == "": continue m = re.match("#newmonster (\\d+)", line) if m is None: m = re.match("#selectmonster (\\d+)", line) if m is not None: unitid = int(m.groups()[0]) print(f"Parsed newmonster {unitid}") if unitid not in units: units[unitid] = NationalMage() units[unitid].id = unitid monsterids.append(unitid) currentunit = units[unitid] elif line.startswith("#newmonster"): newid = max(monsterids) + 1 units[newid] = NationalMage() monsterids.append(newid) currentunit = units[newid] currentunit.id = newid m = re.match("#montag (\\d+)", line) if m is not None: newid = int(m.groups()[0]) montagids.append(newid) print(f"Parsed montag {newid}") m = re.match("#code (.+)", line) if m is None: m = re.match("#code2 (.+)", line) if m is None: m = re.match("#codedelay (.+)", line) if m is None: m = re.match("#codedelay2 (.+)", line) if m is not None: newid = int(m.groups()[0]) eventcodes.append(newid) print(f"Parsed event code {newid}") m = re.match("#newspell (\\d+)", line) if m is None: m = re.match("#selectspell (\\d+)", line) if m is not None: newid = int(m.groups()[0]) spellids.append(newid) print(f"Parsed spell {newid}") elif line.startswith("#newspell"): newid = max(spellids) + 1 print(f"Parsed spell with implied id {newid}") spellids.append(newid) m = re.match("#newweapon (\\d+)", line) if m is None: m = re.match("#selectweapon (\\d+)", line) if m is not None: newid = int(m.groups()[0]) weaponids.append(newid) elif line.startswith("#newweapon"): newid = max(weaponids) + 1 weaponids.append(newid) m = re.match("#newsite\\W+(\\d+)", line) if m is None: m = re.match("#selectsite\\W+(\\d+)", line) if m is not None: newid = int(m.groups()[0]) if newid not in sites: sites[newid] = Site(newid) sites[newid].id = newid siteids.append(newid) currentsite = sites[newid] elif line.startswith("#newsite"): newid = max(siteids) + 1 sites[newid] = Site(newid) sites[newid].id = newid siteids.append(newid) currentsite = sites[newid] m = re.match("#selectnation (\\d+)", line) if m is not None: nationid = int(m.groups()[0]) print(f"Parsed selectnation {nationid}") if nationid not in nations: nations[nationid] = Nation(nationid) currentnation = nations[nationid] m = re.match("#newnation", line) if m is not None: newid = -1 while newid in nations: newid -= 1 print(f"Parsed newnation, assigned id {newid}") if newid not in nations: nations[newid] = Nation(newid) currentnation = nations[newid] m = re.match("#name [\"](.+)[\"]", line) if m is not None: name = m.groups()[0] if currentsite is not None: print(f"Attach site name {name} to {currentsite}") currentsite.name = name sitenames[name] = currentsite.id elif currentnation is not None: print(f"Attach nation name {name} to {currentnation}") currentnation.name = name elif currentunit is not None: print(f"Attach unit name {name} to {currentunit}") currentunit.name = name m = re.match("#era\\W+(.+)", line) if m is not None: currentnation.era = int(m.groups()[0]) print( f"Set Era for nation {currentnation.id} to {currentnation.era}" ) m = re.match("#homecom (\\d+)", line) if m is not None: unitid = int(m.groups()[0]) if currentsite is None: raise ValueError( f"Attempt to assign home com {unitid} to nonexistent site" ) if currentsite not in sitecommanders: sitecommanders[currentsite] = [] sitecommanders[currentsite].append(unitid) print(f"Assign Commander {unitid} to site {currentsite}") m = re.match("#startsite [\"](.+)[\"]", line) if m is not None: name = m.groups()[0] if currentnation not in nationstartsites: nationstartsites[currentnation] = [] nationstartsites[currentnation].append(name) print( f"Assign startsite {name} as belonging to {currentnation}" ) m = re.match("#addreccom (\\d+)", line) if m is not None: unitid = int(m.groups()[0]) print( f"{unitid} is a recruitable commander of {currentnation}" ) if currentnation is None: print( f"Warning: {unitid} is set as a recruited commander, but no nation selected - ignored as" f" this is likely a poptype addition") else: if unitid in units: currentnation.add_mage(units[unitid]) else: if unitid in vanillamages: currentnation.add_mage(vanillamages[unitid]) else: print( f"{unitid} appears to be a non-mage non-modded unit, ignored" ) if line.strip() == "#disableoldnations": print(f"found disableoldnations") for x in range(0, 120): if x in nations: del nations[x] if line.strip() == "#end": print(f"Found #end") currentnation = None currentsite = None currentunit = None for enchCommand in [ "req_noench", "req_ench", "req_myench", "req_friendlyench", "req_hostileench", "req_enchdom" ]: m = re.match(f"#{enchCommand}\\W+(.*)", line) if m is not None: print( f"Found enchantment ID from event mod command: {line}" ) enchantids.append(int(m.groups()[0])) m = re.match("#copystats (\\d+)", line) if m is not None: uid = int(m.groups()[0]) print(f"Found #copystats {uid} for unit") if uid in vanillamages and vanillamages[uid] is not None: vanillamages[uid].copystats(currentunit) print(f"Successfully copied over paths: {currentunit}") m = re.match("#magicskill (\\d+) (\\d+)", line) if m is not None: # In normal dominions modding, path flags are 0-7, just for this I converted them into their # 2^n bitmask form path = 2**int(int(m.groups()[0])) level = int(m.groups()[1]) print( f"Give guaranteed path {path} of strength {level} to current commander" ) currentunit.add_magic_path(path, level) m = re.match("#custommagic (\\d+) (\\d+)", line) if m is not None: mask = int(m.groups()[0]) >> 7 chancemask = int(m.groups()[1]) if chancemask > 100: chance = 100 link = int(chancemask / 100) else: link = 1 chance = chancemask random = MagePathRandom(paths=mask, chance=chance, link=link) print(f"Give random path {mask} to current commander") currentunit.add_magic_random(random) for nation in nationstartsites: for siteid in nationstartsites[nation]: if siteid in sitenames: nation.sites.append(sites[sitenames[siteid]]) else: if siteid in sites: nation.sites.append(sites[siteid]) print( f"Added start site {site} to nation {nation}") else: print( f"Nation has start site with ID {siteid}, this site was not found, ignored" ) for site in sitecommanders: for unitid in sitecommanders[site]: if unitid in units: site.mages.append(units[unitid]) elif unitid in vanillamages: site.mages.append(vanillamages[unitid]) else: print( f"Site {site} had commander {unitid} added, but this seems to not be a mage: skipped" )
def _generate_spells_for_nation(nation: Nation, researchmod: int, spelleffects: Dict[str, SpellEffect], alreadygeneratedeffectsatlevels: Dict[int, List[str]], generatedspells: List[Spell], targetnumberofnationalspells: int, options: Dict[str, str]): DebugLogger.debuglog(f"Generating spells for nation: {nation.to_text()}", debugkeys.NATIONALSPELLGENERATION) if not nation.has_mages(): _writetoconsole(f"Skipping nation {nation.to_text()} because no national mages were found\n") return availableeffectpool = copy.copy(spelleffects) while len(nation.nationalspells) < targetnumberofnationalspells: primarypath: int = _roll_path_for_national_spell(nation) DebugLogger.debuglog(f"Attempting to generate for primary path {utils.pathstotext(primarypath)}\n", debugkeys.NATIONALSPELLGENERATION) # Select a commander to generate this spell for commander: NationalMage = nation.get_commander_with_path(primarypath) # calculate if blood shall be allowed as path in the spell allowblood = commander.can_have_blood() # Select effect for spell DebugLogger.debuglog(f"Selecting national spell effect\n", debugkeys.NATIONALSPELLGENERATION) researchlevel = _select_research_level(researchmod, alreadygeneratedeffectsatlevels) try: choseneffect = _choose_effect( effectpool=availableeffectpool, primarypath=primarypath, alreadygeneratedeffectsatlevels=alreadygeneratedeffectsatlevels, researchlevel=researchlevel ) # Only one attempt an effect per nation del availableeffectpool[choseneffect.name] except ValueError: raise ValueError( f"Couldn't make a national spell for nation {nation.name} (ID:{nation.id})\n" f"Primarypath={utils.pathstotext(primarypath)}\n" f"Researchlevel={researchlevel}\n " f"Available effects: {availableeffectpool}\n" f"No effect available\n") DebugLogger.debuglog( f"Try generating national spell for nation {nation.id} with effect {choseneffect.name}, " f"primarypath={utils.pathstotext(primarypath)}, secondaries={commander.get_total_possible_paths_mask()}, there are " f"{len(availableeffectpool)} effects available\n", debugkeys.NATIONALSPELLGENERATION) spell = _try_to_generate_a_national_spell( nation=nation, spelleffect=choseneffect, researchlevel=researchlevel, primarypath=primarypath, allowblood=allowblood, options=options, secondarypathoptions=commander.get_total_possible_paths_mask() ) if spell is None: DebugLogger.debuglog(f"Failed to generate spell for effect {choseneffect.name}\n", debugkeys.NATIONALSPELLGENERATION) else: generatedspells.append(spell) nation.register_national_spell(spell) NationalSpellGenerationInfoCollector.numberofgeneratedspells += 1 DebugLogger.debuglog("Spell successfully generated\n", debugkeys.NATIONALSPELLGENERATION)