def getStates(hoi4path):
    stateMap = {}

    for filename in os.listdir(hoi4path + "history/states/"):
        stateData = open(hoi4path + "history/states/" + filename).read()

        stateData = stateData.replace("=\n{", "={")
        stateData = stateData.replace("=\n\t{", "={")
        stateData = stateData.replace("=\n\t\t{", "={")
        stateData = stateData.replace("=\n\t\t\t{", "={")
        stateData = stateData.replace("=\n\t\t\t\t{", "={")

        stateData = re.sub(r"#[^\n]*?\n", r"\n", stateData)

        state = naive_parser.ParseSaveData(stateData)

        stateId = int(naive_parser.drill(state, "state", "id"))
        provinces = naive_parser.drill(state, "state", "provinces",
                                       "").split(" ")

        provinceIds = []
        for province in provinces:
            if not province: continue
            provinceIds.append(int(province))

        for province in provinceIds:
            stateMap[province] = stateId

    return stateMap
    def getGovernment(self, empire):
        governmentSet = naive_parser.ParseSaveFile("files/governments.txt")

        empire.ideology = empire.ideology.replace("_neutral", "")
        government = Dotdict({})

        if naive_parser.drill(governmentSet, "governments", empire.ideology):
            government.authority = naive_parser.drill(governmentSet,
                                                      "governments",
                                                      empire.ideology,
                                                      "authority")
            government.ethics = naive_parser.splitstrings(
                naive_parser.drill(governmentSet, "governments",
                                   empire.ideology, "ethics", ""))
            government.civics = naive_parser.splitstrings(
                naive_parser.drill(governmentSet, "governments",
                                   empire.ideology, "civics", ""))

        else:
            print("WARNING: Did not recognise " + empire.longTag() + "'s \"" +
                  empire.ideology +
                  "\" ideology. Falling back to generic democracy.")

            government.authority = "auth_democratic"
            government.ethics = [
                "ethic_egalitarian", "ethic_pacifist", "ethic_xenophobe"
            ]
            government.civics = [
                "civic_parliamentary_system", "civic_environmentalist"
            ]

        return government
Example #3
0
def stringlist_drill(*args):
    output = []
    theStrings = naive_parser.drill(*args)
    if theStrings:
        for line in theStrings['']:
            output += ClunkyStringSplit(line)
    return output
    def Load(self):
        parser = naive_parser.Parser(self.savefile)
        self.topNations = parser.getTopNations()
        self.smallNations = parser.getSmallNations()
        self.gini = parser.getGiniCoeff()
        self.totalScore = parser.getTotalScore()

        self.seed = int(naive_parser.drill(self.savefile, "game_unique_seed"))
        currentDate = naive_parser.drill(self.savefile, "date")
        currentDate = currentDate.replace('"', '')
        self.currentDate = [int(n) for n in currentDate.split(".")]

        self.defcon = Config().defconResults
        if self.defcon:
            self.CreateEventsFromDefcon()
        else:
            self.CreateEvents()
def getStates():
    stateMap = {}

    statepath = config.Config().getModdedHoi4File("history/states/")
    for filename in os.listdir(statepath):
        stateData = open(statepath + filename).read()

        stateData = stateData.replace("=\n{", "={")
        stateData = stateData.replace("=\n\t{", "={")
        stateData = stateData.replace("=\n\t\t{", "={")
        stateData = stateData.replace("=\n\t\t\t{", "={")
        stateData = stateData.replace("=\n\t\t\t\t{", "={")

        stateData = re.sub(r"#[^\n]*?\n", r"\n", stateData)

        if not stateData:
            continue

        state = naive_parser.ParseSaveData(stateData)

        if 0 == len(state.keys()):
            print("WARNING: \"" + statepath + filename +
                  "\" could not be parsed. Skipping.")
            continue
        stateId = int(naive_parser.drill(state, "state", "id"))
        provinces = naive_parser.drill(state, "state", "provinces",
                                       "").split(" ")

        provinceIds = []
        for province in provinces:
            if not province:
                continue
            provinceIds.append(int(province))

        for province in provinceIds:
            stateMap[province] = stateId

    return stateMap
    def __init__(self):
        BorgSingleton.__init__(self)
        if hasattr(self, 'loaded'): return
        self.loaded = True

        self.configfile = naive_parser.ParseSaveFile("configuration.txt")
        config = naive_parser.drill(self.configfile, "configuration")

        if getattr(sys, 'frozen', False):
            # running in a bundle
            self.converterDir = self.makeSanePath(
                os.path.dirname(sys.executable))
        else:
            # running live
            self.converterDir = self.makeSanePath(
                os.path.dirname(os.path.realpath(__file__)))

        print("Running from: " + self.converterDir)

        self.savefileName = naive_parser.unquote(
            naive_parser.drill(config, "savefile"))
        self.hoi4Path = naive_parser.unquote(
            naive_parser.drill(config, "HoI4directory"))
        self.hoi4ModPath = naive_parser.unquote(
            naive_parser.drill(config, "HoI4ModDirectory"))
        self.stellarisModPath = naive_parser.unquote(
            naive_parser.drill(config, "StellarisModdirectory"))

        self.useDefconResults = naive_parser.unquote(
            naive_parser.drill(config, "useDefconResults"))
        if self.useDefconResults == "y" or self.useDefconResults == "yes":
            self.defconResults = naive_parser.unquote(
                naive_parser.drill(config, "defconResults"))
        else:
            self.defconResults = False

        self.modName = "outputMod"

        self.baseModPath = self.converterDir + self.modName + "_base/"
        self.outputPath = self.converterDir + self.modName + "/"
        self.outputModFile = self.converterDir + self.modName + ".mod"
        if self.stellarisModPath:
            self.stellarisModPath = self.makeSanePath(self.stellarisModPath)
            self.finalPath = self.stellarisModPath + self.modName + "/"
            self.finalModFile = self.stellarisModPath + self.modName + ".mod"
        else:
            self.finalPath = ""
            self.finalModFile = ""

        if not self.isSane():
            sys.exit(0)
Example #7
0
    def __init__(self):
        print("Parsing configuration")
        self.configfile = naive_parser.ParseSaveFile("configuration.txt")

        self.savefile = naive_parser.drill(self.configfile, "configuration",
                                           "savefile")
        self.hoi4path = naive_parser.drill(self.configfile, "configuration",
                                           "HoI4directory")
        self.targetdir = naive_parser.drill(self.configfile, "configuration",
                                            "StellarisModdirectory")

        print("Save file: " + self.savefile)
        print("HoI4 location: " + self.hoi4path)
        print("Stellaris mod path: " + self.targetdir)

        self.savefile = reformatPath(self.savefile, False)
        self.hoi4path = reformatPath(self.hoi4path, True)
        self.targetdir = reformatPath(self.targetdir, True)

        if not self.savefile:
            print("Error: Could not parse save file.")
            sys.exit(1)

        if not self.hoi4path:
            print("Error: Could not parse HoI4 path.")
            sys.exit(1)

        if not self.targetdir:
            print(
                "Warning: Could not parse Stellaris mod path. Mod will only be created in the converter directory."
            )

        for path in [self.savefile, self.hoi4path, self.targetdir]:
            if not os.path.exists(path):
                print("Error: Could not find " + path)
                sys.exit(1)
    def Load(self):
        parser = naive_parser.Parser(self.savefile, self.hoi4path)
        self.topNations = parser.getTopNations()
        self.smallNations = parser.getSmallNations()
        self.gini = parser.getGiniCoeff()
        self.totalScore = parser.getTotalScore()

        self.seed = int(naive_parser.drill(self.savefile, "game_unique_seed"))
        currentDate = naive_parser.drill(self.savefile, "date")
        currentDate = currentDate.replace('"', '')
        self.currentDate = [int(n) for n in currentDate.split(".")]

        self.events = []
        climateChange = 0
        self.nuclearWar = 0
        self.earthOwnedBy = ""
        climateAuthority = ""
        self.earthType = "pc_continental"

        self.empires = []
        for nation in self.topNations:
            self.empires.append(Empire(nation))

        if len(self.empires) == 1:
            self.events.append(Event("Hegemon", self.empires[0].tag))
            self.earthOwnedBy = self.empires[0].tag
            climateAuthority = self.empires[0].tag

        elif self.empires[
                0].score / self.totalScore > 0.5:  # largest nation has 50%

            if self.empires[1].score / self.empires[
                    0].score > 0.5:  # next largest is pretty big
                self.events.append(
                    Event("ColdWar", self.empires[0].tag, self.empires[1].tag))
                self.events.append(
                    Event("MinorNuclearWar", self.empires[0].tag,
                          self.empires[1].tag))
                self.events.append(
                    Event("MinorNuclearWarLose", self.empires[1].tag))
                self.events.append(
                    Event("MinorNuclearWarWin", self.empires[0].tag))

                self.nuclearWar = 1
                self.earthOwnedBy = self.empires[0].tag
                self.empires[0].nuclear = True
                self.empires[1].nuclear = True
                self.empires[1].population *= 0.25

            else:  # next largest is pretty small
                self.events.append(
                    Event("EconomicCollapse", self.empires[1].tag))
                self.empires[1].industry *= 0.75
                self.events.append(Event("Hegemon", self.empires[0].tag))
                self.earthOwnedBy = self.empires[0].tag

        else:  # largest nation does not have 50%

            if self.empires[
                    0].score / self.totalScore > 0.3:  # someone's large-ish
                if self.empires[1].score / self.empires[
                        0].score > 0.5:  # next largest is pretty big
                    if len(self.empires) == 2:  # only two nations
                        self.events.append(
                            Event("ColdWar", self.empires[0].tag,
                                  self.empires[1].tag))
                    elif (self.empires[2].score / self.empires[1].score >
                          0.5):  # and next after that is pretty big too
                        self.events.append(
                            Event("EconomicProblems", self.empires[2].tag))
                        self.empires[2].industry *= 0.9
                        self.events.append(
                            Event("ColdWar", self.empires[0].tag,
                                  self.empires[1].tag))
                        self.events.append(
                            Event("ColdWarStaysCold", self.empires[0].tag,
                                  self.empires[1].tag))
                        self.events.append(Event("Squabbling"))
                    else:  # and next after that is pretty small
                        self.events.append(
                            Event("EconomicCollapse", self.empires[2].tag))
                        self.empires[2].industry *= 0.75
                        self.events.append(
                            Event("ColdWar", self.empires[0].tag,
                                  self.empires[1].tag))
                        if self.empires[0].government == self.empires[
                                1].government and self.empires[
                                    0].government != "fascist":
                            self.events.append(
                                Event("ColdWarStaysCold", self.empires[0].tag,
                                      self.empires[1].tag))
                            self.events.append(Event("Squabbling"))
                        else:
                            self.events.append(
                                Event("NuclearWar", self.empires[0].tag,
                                      self.empires[1].tag))
                            self.nuclearWar = 2
                            self.events.append(
                                Event("NuclearWarLose", self.empires[0].tag,
                                      self.empires[1].tag))
                            self.empires[0].nuclear = True
                            self.empires[1].nuclear = True
                            self.empires[0].population *= 0.25
                            self.empires[1].population *= 0.25

                else:  # next largest is pretty small
                    self.events.append(
                        Event("EconomicCollapse", self.empires[1].tag))
                    self.empires[1].industry *= 0.75
                    self.events.append(Event("Hegemon", self.empires[0].tag))
                    self.earthOwnedBy = self.empires[0].longTag()

            else:  # everyone's tiny
                self.events.append(Event("Squabbling"))

        if self.gini > 0.4:
            if climateAuthority:
                self.events.append(
                    Event("GovernmentClimateControl", climateAuthority))
            elif self.gini > 0.6:
                climateChange = 2
            else:
                climateChange = 1
        else:
            self.events.append(Event("CleanIndustrialization"))

        self.events.append(Event("Migrations"))

        if self.nuclearWar == 2:
            self.events.append(Event("TombWorld"))
            self.events.append(Event("EscapeLaunches"))
            self.earthType = "pc_nuked"
        elif self.nuclearWar == 1:
            if climateChange == 0:
                self.events.append(Event("NuclearWinter"))
                self.events.append(Event("EscapeLaunches"))
                self.earthType = "pc_arctic"
            elif climateChange == 1:
                self.events.append(Event("SeaLevelsRise"))
                self.events.append(Event("Launches"))
                self.earthType = "pc_ocean"
            elif climateChange == 2:
                self.events.append(Event("NuclearIndustrialDesert"))
                self.events.append(Event("EscapeLaunches"))
                self.earthType = "pc_desert"
        else:
            if climateChange == 0:
                self.earthType = "pc_continental"
                self.events.append(Event("Launches"))
                pass
            elif climateChange == 1:
                self.events.append(Event("SeaLevelsRise"))
                self.events.append(Event("Launches"))
                self.earthType = "pc_ocean"
            elif climateChange == 2:
                self.events.append(Event("GlobalWarming"))
                self.events.append(Event("EscapeLaunches"))
                self.earthType = "pc_arid"

        #for event in self.events:
        #    print(event)

        colourMap = properties.getColours(self.hoi4path)

        for empire in self.empires:

            if empire.tag in colourMap:
                empire.colour = colourMap[empire.tag]

            empire.GoIntoSpace()
    def GetHistory(self):

        tagToName = {}
        tagToAdj = {}
        cityNames = getCountryNames.getCityNames()
        countryNames = getCountryNames.getCountryNames()
        for empire in self.topNations + self.smallNations:
            tagBlank = empire.longTag()
            tagDef = empire.longTag() + "_DEF"
            tagAdj = empire.longTag() + "_ADJ"

            if tagDef in countryNames:
                name = countryNames[tagDef]
            else:
                name = countryNames[tagBlank]
            name = name.replace("The", "the")
            tagToName[empire.tag] = name

            if tagAdj in countryNames:
                adj = countryNames[tagAdj]
            else:
                adj = countryNames[tagBlank]
            tagToAdj[empire.tag] = adj

        numpy.random.seed(self.seed)

        startYear = self.currentDate[0] + 5
        endYear = 2200

        yearRange = endYear - startYear
        eventCount = numpy.random.randint(8, 12)

        nationCount = len(self.topNations) + len(self.smallNations)
        if nationCount == 1:  # only one nation - so events about "nations" won't make much sense
            deleteKeys = []
            for key in self.eventStrings:
                if "nation" in self.eventStrings[key].lower():
                    deleteKeys.append(key)
            for key in deleteKeys:
                del self.eventStrings[key]

        realEvents = []
        for event in self.events:
            if event.eventType in self.eventStrings:
                realEvents.append(Event(event.eventType, *event.tags))

            if event.eventType + "0" in self.eventStrings:
                realEvents.append(Event(event.eventType + "0", *event.tags))

            for i in range(1, 10):
                if event.eventType + str(i) in self.eventStrings and (numpy.random.random() < 0.7):
                    realEvents.append(Event(event.eventType + str(i), *event.tags))

        randomEventCount = eventCount - len(realEvents)

        randomEventKeys = []
        for eventKey in sorted(self.eventStrings):
            if "Random" in eventKey:
                randomEventKeys.append(eventKey)

        randomEvents = []
        skips = 0
        while len(randomEvents) < randomEventCount:
            skips += 1
            if skips > 100:
                break
            chosenEvent = Event(numpy.random.choice(randomEventKeys))
            if chosenEvent not in randomEvents:
                randomEvents.append(chosenEvent)
        randomEvents.sort()

        if randomEventCount > 0:
            jump = eventCount // randomEventCount
            insertPoint = 2 - jump
            if jump == 1:
                insertPoint = 0
            for randomEvent in randomEvents:
                insertPoint += jump
                realEvents.insert(insertPoint, randomEvent)

        # Tried just having linear gaps between years; it doesn't feel right. We
        # need a pretty dense cold-war 20th century and a pretty sparse 22nd
        # century. Log scales to the rescue!
        logNudge = 80
        yearLogScale = numpy.logspace(
            numpy.log10(logNudge), numpy.log10(
                yearRange + logNudge), num=len(realEvents) + 1)

        yearLogScale = [x - logNudge for x in yearLogScale]

        defconResultsText = ""
        if self.defcon:
            def scoreSort(tag):
                try:
                    return self.defcon[tag].score
                except AttributeError:
                    return 0
                    
            survivorTags = []
            okTags = []
            oblitTags = []
            for tag in sorted(self.defcon, key=scoreSort):
                if not type(tag) is str: continue
                survivors = float(naive_parser.drill(self.defcon, tag, "survivors"))
                if survivors > 80:
                    survivorTags.append(tag)
                elif survivors > 40:
                    okTags.append(tag)
                else:
                    oblitTags.append(tag)

            # We've only got 3 "survived" messages and 2 "is basically ok" messages.
            while len(survivorTags) > 3:
                okTags.append(survivorTags.pop())
            while len(okTags) > 2:
                okTags.pop()

            def nameOfTagOrFaction(name):
                if name in tagToName:
                    return tagToName[name]
                return "the "+name.title()
                
            for n in range(len(survivorTags)):
                nationName = "the "+survivorTags[n]
                if survivorTags[n] in tagToName:
                    nationName = tagToName[survivorTags[n]]

                defconResultsText += self.eventStrings["DefconSurvive"+str(n+1)] + " "
                defconResultsText = defconResultsText.replace("&NATION_1&", nameOfTagOrFaction(survivorTags[n]))

            for n in range(len(okTags)):
                defconResultsText += self.eventStrings["DefconOk"+str(n+1)] + " "
                defconResultsText = defconResultsText.replace("&NATION_1&", nameOfTagOrFaction(okTags[n]))

            if len(oblitTags) == 1:
                defconResultsText += self.eventStrings["DefconObliterated1"] + " "
                defconResultsText = defconResultsText.replace("&NATION_1&", nameOfTagOrFaction(oblitTags[0]))
            elif len(oblitTags) > 1:
                for n in range(len(oblitTags)-1):
                    defconResultsText += nameOfTagOrFaction(oblitTags[n]) + ", "
                defconResultsText += "and " + self.eventStrings["DefconObliteratedPl1"]
                defconResultsText = defconResultsText.replace("&NATION_1&", nameOfTagOrFaction(oblitTags[-1]))

        historyString = ""

        for e in range(len(realEvents)):
            year = int(numpy.floor(startYear + yearLogScale[e]))
            yearJump = (yearLogScale[e + 1] - yearLogScale[e]) // 2
            if yearJump > 1:
                year += numpy.random.randint(-yearJump // 2, yearJump // 2)
            if year < startYear:
                year = startYear + 1
            if year > endYear:
                year = endYear - 1
            event = realEvents[e]
            print(event)

            replaces = {}
            replaces["&YEAR&"] = str(year)
            replaces["&DECADE&"] = str(year // 10) + "0s"
            replaces["&NATION_1&"] = tagToName[event.tags[0]] if len(event.tags) > 0 else ""
            replaces["&NATION_2&"] = tagToName[event.tags[1]] if len(event.tags) > 1 else ""
            replaces["&NATION_3&"] = tagToName[event.tags[2]] if len(event.tags) > 2 else ""
            replaces["&NATION_4&"] = tagToName[event.tags[3]] if len(event.tags) > 3 else ""
            replaces["&NATION_5&"] = tagToName[event.tags[4]] if len(event.tags) > 4 else ""
            replaces["&NATION_6&"] = tagToName[event.tags[5]] if len(event.tags) > 5 else ""
            replaces["&NATION_1_ADJ&"] = tagToAdj[event.tags[0]] if len(event.tags) > 0 else ""
            replaces["&NATION_2_ADJ&"] = tagToAdj[event.tags[1]] if len(event.tags) > 1 else ""
            replaces["&NATION_3_ADJ&"] = tagToAdj[event.tags[2]] if len(event.tags) > 2 else ""
            replaces["&NATION_4_ADJ&"] = tagToAdj[event.tags[3]] if len(event.tags) > 3 else ""
            replaces["&NATION_5_ADJ&"] = tagToAdj[event.tags[4]] if len(event.tags) > 4 else ""
            replaces["&NATION_6_ADJ&"] = tagToAdj[event.tags[5]] if len(event.tags) > 5 else ""
            replaces["&DEFCONRESULTS&"] = defconResultsText
            if len(cityNames) > 0:
                replaces["&RANDOM_SMALL_CITY&"] = numpy.random.choice(cityNames)
            else:
                replaces["&RANDOM_SMALL_CITY&"] = "Vienna"

            if len(self.smallNations) > 0:
                replaces["&RANDOM_SMALL_NATION&"] = tagToName[numpy.random.choice(self.smallNations).tag]
            else:
                replaces["&RANDOM_SMALL_NATION&"] = "Secret Denmark"

            eventline = self.eventStrings[event.eventType]
            for replaceString in replaces:
                eventline = eventline.replace(replaceString, replaces[replaceString])
            historyString += eventline + "\n"

        historyString = historyString.replace(". the", ". The")
        historyString = historyString.replace(": the", ": The")

        print(historyString)
        return historyString
def getColours():
    hoi4ColourData = naive_parser.ParseSaveFile(
        config.Config().getModdedHoi4File("common/countries/colors.txt"))
    stellarisGreyData = {
        "grey": [0.65, 0.05, 0.35],
        "dark_grey": [0.65, 0.05, 0.22],
        "black": [0.5, 0.3, 0.05]
    }
    stellarisColourData = {
        "grey": [0.65, 0.05, 0.35],
        "dark_grey": [0.65, 0.05, 0.22],
        "black": [0.5, 0.3, 0.05],
        "dark_brown": [0.07, 0.6, 0.23],
        "brown": [0.07, 0.6, 0.4],
        "beige": [0.1, 0.4, 0.6],
        "yellow": [0.11, 0.8, 0.8],
        "light_orange": [0.09, 1.0, 0.8],
        "orange": [0.06, 0.9, 0.7],
        "red_orange": [0.01, 0.75, 0.7],
        "red": [0.0, 0.95, 0.5],
        "burgundy": [0.95, 0.8, 0.35],
        "pink": [0.88, 0.61, 0.5],
        "purple": [0.74, 0.65, 0.61],
        "dark_purple": [0.74, 0.71, 0.37],
        "indigo": [0.71, 0.85, 0.5],
        "dark_blue": [0.64, 0.85, 0.45],
        "blue": [0.64, 0.7, 0.6],
        "light_blue": [0.6, 0.6, 0.7],
        "turquoise": [0.49, 0.6, 0.6],
        "dark_teal": [0.5, 0.6, 0.3],
        "teal": [0.42, 0.6, 0.5],
        "light_green": [0.35, 0.5, 0.60],
        "green": [0.32, 0.6, 0.40],
        "dark_green": [0.33, 0.6, 0.27],
    }

    hsvSet = {}
    nameSet = {}
    for tag in hoi4ColourData:
        colour = naive_parser.drill(hoi4ColourData, tag, "color", "")
        rgb = ("." not in colour)
        colour = [float(x) for x in colour.replace("  ", " ").split(" ")]

        if rgb:
            colour = list(colorsys.rgb_to_hsv(*colour))
            colour[2] = colour[2] / 255

        hsvSet[tag] = colour

        minDist = 9999
        bestColour = "red"

        if colour[1] < 0.2:
            colourData = stellarisGreyData
        else:
            colourData = stellarisColourData

        for stellarisColour in colourData:
            stellarisHsv = colourData[stellarisColour]
            newDist = colourDistance(colour, stellarisHsv)
            if newDist < minDist:
                minDist = newDist
                bestColour = stellarisColour

        nameSet[tag] = bestColour

    return nameSet
def getClimates():

    climateMap = {}
    stateMap = getStates()

    strategicRegionsPath = config.Config().getModdedHoi4File(
        "map/strategicregions/")
    for filename in os.listdir(strategicRegionsPath):
        climateData = naive_parser.ParseSaveFile(strategicRegionsPath +
                                                 filename)
        provinces = naive_parser.drill(climateData, "strategic_region",
                                       "provinces", "").split(" ")
        periodses = naive_parser.drill(climateData, "strategic_region",
                                       "weather")
        if "period" not in periodses:
            continue
        periods = periodses["period"]
        yearTemperatures = []
        yearRain = []
        yearSnow = []
        yearSand = []

        if len(periods) == 0:
            continue

        for period in periods:
            temperatureRange = naive_parser.drill(period, "temperature",
                                                  "").split(" ")
            maxTemp = temperatureRange[1].replace("\"", "")
            minTemp = temperatureRange[0].replace("\"", "")
            temperature = float(maxTemp) - float(minTemp)
            yearTemperatures.append(temperature)

            lightRain = naive_parser.unquote(
                naive_parser.drill(period, "rain_light"))
            heavyRain = naive_parser.unquote(
                naive_parser.drill(period, "rain_heavy"))
            snow = naive_parser.unquote(naive_parser.drill(period, "snow"))
            blizzard = naive_parser.unquote(
                naive_parser.drill(period, "blizzard"))
            sandstorm = naive_parser.unquote(
                naive_parser.drill(period, "sandstorm"))

            yearRain.append(float(lightRain) + float(heavyRain) * 2)
            yearSnow.append(float(snow) + float(blizzard) * 3)
            yearSand.append(float(sandstorm))

        averageTemperature = sum(yearTemperatures) / len(yearTemperatures)
        averageRain = sum(yearRain) / len(yearRain)
        averageSnow = sum(yearSnow) / len(yearSnow)
        averageSand = sum(yearSand) / len(yearSand)

        climate = "pc_arid"
        if averageSand > 0.05:
            climate = "pc_desert"
        elif averageSnow > 0.3:
            climate = "pc_arctic"
        elif averageSnow > 0.1:
            climate = "pc_tundra"
        elif averageTemperature > 10.0:
            climate = "pc_arid"
        elif averageTemperature < 4.7:
            climate = "pc_savannah"
        else:
            climate = "pc_alpine"

        for province in provinces:
            if not province:
                continue
            provinceId = int(province)
            if provinceId in stateMap:
                stateId = stateMap[provinceId]
                climateMap[stateId] = climate

    return climateMap