def generateHistory(fineMap, racialMap, civilLocMap, generalLocMap, historyLen, eventCellSize, maxCellEvents): unprocessedEvents = [] historyMap = HistoryMap(fineMap.getMapSize()) context = HistoricMapContext(fineMap, racialMap, civilLocMap, generalLocMap, historyMap) locCount = {} for civilLoc in civilLocMap.getNodes() + generalLocMap.getNodes(): name = civilLoc.getObject().getName() + str( locCount.setdefault(civilLoc.getObject().getName(), 0)) histLoc = HistoryLocation(civilLoc, context, r.random() < 0.3, name) historyMap.addLocation(histLoc) locCount[civilLoc.getObject().getName()] += 1 for year in range(historyLen): cCount = 0 for c in historyMap.getCharacters(): if c.getCurrentState().alive: cCount += 1 for x in range(round((fineMap.getMapSize() / eventCellSize).a)): for y in range(round((fineMap.getMapSize() / eventCellSize).b)): pos = Vector2.random(eventCellSize) + Vector2( x, y) * eventCellSize eventCount = r.randint( 0, min(maxCellEvents, math.ceil(maxCellEvents * (cCount / 200) + 0.01))) i = 0 while i < eventCount: eventIndex = r.random() * sum( HISTORIC_EVENT_CHANCES.values()) Event = None for ev in HISTORIC_EVENTS: eventIndex -= HISTORIC_EVENT_CHANCES[ev] if eventIndex <= 0: Event = ev break event = Event(pos, year, context) while event.getAlternateEvent(): event = event.getAlternateEvent() if not event.getSuccessful(): continue historyMap.addEvent(event) i += 1 for loc in historyMap.getLocations(): if not loc.getCurrentState().existing: loc.destroy(context) return historyMap
def __init__(self, pos, time, context): characters = context.getHistoryMap().getCharacters() r.shuffle(characters) for char in characters: if not (char.getAge(time) >= char.getCurrentState().getRace().adultAge and char.getCurrentState().alive and len(char.getCurrentState().items) < r.randint(1, 3) and not (not char.getCurrentState().occupation.warrior and r.random() < 0.5)): continue boughtItem = None seller = None for c in char.getCurrentState().livingPlace.getCurrentCharacters( time): if (c.getCurrentState().itemsOnSale and c != char and c.getCurrentState().alive): boughtItem = None for item in c.getCurrentState().itemsOnSale: if item.quality > char.getCurrentState( ).occupationLevel + r.randint(-1, 1): continue if item.art and char.getCurrentState( ).occupation.warrior: continue boughtItem = item break if boughtItem: seller = c break if not seller: continue self.seller = seller self.buyer = char self.item = boughtItem self.importantItem = r.random() < 0.5 super().__init__( self.seller.getCurrentState().livingPlace.getPos(), time, [self.seller, self.buyer], context) self.updateCharacters() return self.setSuccessful(False) return
def __init__(self, pos, time, context): newCharacter = HistoricCharacter(self) self.attributes = CharacterAttributes.generateRandom(r.randint(17, 20)) if r.random() >= 0.1: self.race = context.getRacialMap().getClosest( pos).getObject().getName() else: self.race = r.choice( context.getRacialMap().getNodes()).getObject().getName() self.livingPlace = context.getClosestLocation( pos, sort=lambda n: n.getAttachedContext(HistoryLocation). getLocationType().livable).getAttachedContext(HistoryLocation) super().__init__(self.livingPlace.getPos(), time, [newCharacter], context, [self.livingPlace]) context.getHistoryMap().addCharacter(newCharacter) self.name = "Person" + str( context.getHistoryMap().getCharacters().index(newCharacter)) self.personality = CharacterState.generatePersonality() self.updateCharacters() self.updateLocations()
def getRandomObjects(self, number, failChance=0.5): ret = [] for i in range(number): if r.random() < failChance: continue else: ret.append(self.getRandomObject()) return ret
def getRandomObject(self): index = r.random() * sum(self.weights.values()) for t in self.items: index -= self.weights[t] if index <= 0: if t.__class__ == LootTable: return t.getRandomObject() return t
def generateRandom(proficiency=20): values = [0, 0, 0] for i in range(proficiency): n = r.randint(0, 2) while values[n] >= 8 and not r.random() < 0.1: n = r.randint(0, 2) values[n] += 1 return CharacterAttributes(*values)
def __init__(self, pos, time, context): characters = context.getHistoryMap().getCharacters() r.shuffle(characters) char = None for c in characters: if (c.getAge(time) >= c.getCurrentState().getRace().adultAge and c.getCurrentState().alive and c.getCurrentState().traveling >= r.randint(1, 21) and c.getCurrentState().getPersonality().determination >= r.randint(1, 15) and (not c.getCurrentState().leadershipPos)): char = c break if not char: self.setSuccessful(False) return possible = None if c.getCurrentState().traveling >= r.randint(1, 31): possible = context.getCloseLocations( pos, 5, sort=lambda n: n.getAttachedContext( HistoryLocation).getLocationType().livable) else: possible = context.getCloseLocations( pos, 5, sort=lambda n: n.getAttachedContext( HistoryLocation).getLocationType().independant) possibleLocs = [] for p in possible: possibleLocs.append(p.getAttachedContext(HistoryLocation)) if r.random() < 0.3: self.target = r.choice(possibleLocs) else: popCount = [] self.target = max(possibleLocs, key=lambda p: len(p.getCurrentCharacters(time))) self.prevLoc = char.getCurrentState().livingPlace super().__init__(self.target.getPos(), time, [char], context, [self.target, self.prevLoc]) self.updateCharacters() self.updateLocations()
def __init__(self,node,context,existing = False,name=""): self.node = node self.context = context node.attachContext(self) self.events = [] self.state = LocationState(existing,name) self.ancient = existing self.locationType = HISTORIC_LOCATION_TYPE[node.getObject().getName()] if not self.locationType.foundable: self.state.existing = True self.ancient = True self.localRace = context.getRacialMap().getClosest(self.node.getPos()) self.state.race = self.localRace.getObject().getName() self.localRace = CHARACTER_RACES[self.localRace.getObject().getName()] if self.localRace.imperial and self.state.existing and self.locationType.independant: for locNode in (context.getCivilLocMap().getMultipleClosest(self.node.getPos(),5) +context.getGeneralLocMap().getMultipleClosest(self.node.getPos(),5)): if locNode == self.node: continue loc = None try: loc = locNode.getAttachedContext(HistoryLocation) except: continue if (loc.getLocationType().foundable and (loc.getLocalRace().imperial or (not loc.getLocationType().independant)) and loc.getLocalRace()==self.localRace and (not loc.getCurrentState().adminLocation) and loc.getCurrentState().existing): if loc.getLocationType().size < self.getLocationType().size: loc.setAdminLocation(self) elif loc.getLocationType().size > self.getLocationType().size: self.setAdminLocation(loc) break else: if r.random()<0.5: loc.setAdminLocation(self) else: self.setAdminLocation(loc) break
def generateHydraulicMap(mapSize, fineBiomes, sourceCellSize, sourceChance, iterationCount, smallStepLength, largeStepLength, mergeDistance): fineBiomeNodes = fineBiomes.getNodes() hydroGraph = MapGraph(0,mapSize) streamsInProcess = [] #generate stream sources usedFineBiomes = [] for x in range(sourceCellSize.a//2, mapSize.a, sourceCellSize.a): for y in range(sourceCellSize.b//2, mapSize.b, sourceCellSize.b): if r.random()<sourceChance: source = fineBiomes.getClosest(Vector2(x,y)) if source in usedFineBiomes: continue tags = source.getCollectiveTags() acceptable = False for tag in tags: if tag.getName()=="mountainous" and tag.getWeight()>=1: acceptable = True break if tag.getName()=="hilly" and tag.getWeight()>=0.5: acceptable = True break if tag.getName()=="forested" and tag.getWeight()>=1: acceptable = True break if not acceptable: continue usedFineBiomes.append(source) streamsInProcess.append(HydraulicNode(source.getPos(),1, evaluateRiverTarget(source), isSource=True)) #iterate stream extension for i in range(iterationCount): newStreams = [] for stream in streamsInProcess: #try twice, once with large step, once with small step stepLength = smallStepLength for j in range(2): #ignore streams outside map posDiff = mapSize - stream.getPos() if posDiff.a<0 or posDiff.b<0 or posDiff.a>mapSize.a or posDiff.b>mapSize.b: break #assign direction if not present if not stream.getDirection(): angles = [] angle = 0 while angle<1: angles.append(angle) angle+=0.1 r.shuffle(angles) minScore = 1000 for angle in angles: direction = Vector2.UNIT.rotate(angle).floatMultiply(stepLength) pos = direction + stream.pos score = evaluateRiverTarget(fineBiomes.getClosest(pos)) if score<stream.score and score<minScore : stream.setDirection(direction) minScore = score #generate possible next positions possiblePos = [] angleStep = 0.02 angleRange = 0.2 angle = -angleRange while angle <=angleRange: possAngle = angle + r.random()*angleStep possPos = Vector2.UNIT.rotate(possAngle).floatMultiply(stepLength) + stream.getPos() possiblePos.append(possPos) angle += angleStep streamParents = stream.getParents() riverScore = {} for pos in possiblePos: closest = fineBiomes.getClosest(pos) riverScore[pos] = evaluateRiverTarget(closest)*(0.8+r.random()*0.4) if closest in usedFineBiomes: riverScore[pos] = 100 #get highest scoring positions targetPos = max( possiblePos,key= lambda pos: stream.score-riverScore[pos] ) #merge streams if close enough closestStream = hydroGraph.getClosest(targetPos) if closestStream: closestDist = abs(closestStream.getPos() - targetPos) for nstream in newStreams: if abs(nstream.getPos() - targetPos) < closestDist: closestStream = nstream closestDist = abs(nstream.getPos() - targetPos) if (not closestStream in streamParents) and closestStream and ( abs(closestStream.getPos() - targetPos) < mergeDistance if not closestStream.stagnant else mergeDistance * max(1,min(1.7,1.7*closestStream.getPower()/5))): closestStream.addStreamInput(stream) break #maybe set stream as stagnant if difference isn't large enough ## if (stream.score-riverScore[pos])<r.random()*0.2-0.3 and (stream.length-2)%5==0 and r.random()<0.7: ## stream.stagnant = True if (stream.score-riverScore[pos])<r.random()*0.2-0.4 and stream.length>r.randint(3,8): if j==0: stepLength = largeStepLength continue else: stream.stagnant = True break #create next node newStream = HydraulicNode(targetPos, 0.05, riverScore[pos], targetPos-stream.getPos() ) stream.addStreamOutput(newStream) newStreams.append(newStream) usedFineBiomes.append(fineBiomes.getClosest(targetPos)) break for stream in streamsInProcess: hydroGraph.addNode(stream) streamsInProcess = newStreams #generate map graph data hydraulicObjects = {} for hydroObj in GetLoadedObjectClass("hydraulics"): hydraulicObjects[hydroObj.getName()] = hydroObj for node in hydroGraph.getNodes(): node.generateMapGraphData(hydraulicObjects) return hydroGraph
def fillMap(mapGraph, objectClass, superInfluence=1, nothingThreshold=0): templates = GetLoadedObjectClass(objectClass) objectSuggestions = [] for template in templates+templates: objectSuggestions.append(template.instantiate()) nodesToRemove = [] for node in mapGraph.getNodes(): r.shuffle(objectSuggestions) scoredSuggs = {} for obj in objectSuggestions: score = 0 connCount = 0 for conn in node.getConnections(): if conn.getObject(): score += obj.compare(conn.getObject()) / abs(node.getPos()-conn.getPos()) connCount+=1 superScore = 0 for superConn in node.getSuperConnections(): superScore += obj.compare(superConn.getObject()) finalScore = 0 if connCount>0: finalScore += score/connCount if node.getSuperConnections(): finalScore += superScore/len(node.getSuperConnections())*superInfluence scoredSuggs[obj] = finalScore obj.score = finalScore order = objectSuggestions[:] order.sort(key = lambda obj: scoredSuggs[obj]) order = order[2*len(order)//3:] for obj in objectSuggestions: if not obj in order: scoredSuggs.pop(obj) targetVal = r.random()*sum(scoredSuggs.values()) usedObject = r.choice(order) for obj in order: targetVal -= scoredSuggs[obj] if targetVal <= 0: usedObject = obj break objectSuggestions = [] for template in templates+templates: objectSuggestions.append(template.instantiate()) if scoredSuggs[obj] < nothingThreshold: nodesToRemove.append(node) else: node.setObject(usedObject) for node in nodesToRemove: mapGraph.removeNode(node)
def random(bounds): return Vector2(r.random() * bounds.a, r.random() * bounds.b)