public static void AiCommandPhase(Faction ourFac, List <Commander> commandableCmders, CommandPhaseMan phaseScript) { Zone zoneCmderIsIn, moveDestZone, scoreCheckZone, fallbackMoveDestZone = null; List <Commander> ourCmders = ourFac.OwnedCommanders; List <Zone> emptyNewCmderZones = GameController.GetZonesForNewCmdersOfFaction(ourFac); bool curZoneIsContested; //how close to our max cmders? float factionCmderAmountRatio = ourCmders.Count / (float)ourFac.MaxCmders; float recruitChance, topMoveScore, scoreCheckScore, trainChance; bool isInDangerousZone = false; bool factionHasEnemy = ourFac.GetDiplomaticEnemies().Count > 0; //use the same random values for all cmders for more cohesion float friendlyTooDangerousThreshold = GetRandomFriendlyTooDangerousThreshold(), moveScoreThreshold = GetRandomMoveScoreThreshold(), allyNearbyInfluenceFactor = GetRandomNearbyTroopInfluenceFactor(), enemyNearbyInfluenceFactor = GetRandomNearbyTroopInfluenceFactor(), atkNeutralDiscouragement = GetRandomAtkOnNeutralFactionDiscouragement(); for (int i = commandableCmders.Count - 1; i >= 0; i--) { zoneCmderIsIn = GameController.GetZoneByID(commandableCmders[i].zoneIAmIn); curZoneIsContested = zoneCmderIsIn.IsContested(); //recruit chance might be more than 100%, //but it's ok as it will do something else if it can't recruit recruitChance = curZoneIsContested ? 0.0f : commandableCmders[i].GetPercentOfNewTroopsIfRecruitedComparedToCurrent() * RECRUIT_CHANCE_ENCOURAGEMENT; trainChance = curZoneIsContested ? 0.0f : commandableCmders[i].GetPercentOfTroopsUpgradedIfTrained(); moveDestZone = zoneCmderIsIn; //if no zone beats this score, we stay topMoveScore = GetZoneDangerScore(zoneCmderIsIn, ourFac, false, allyNearbyInfluenceFactor, enemyNearbyInfluenceFactor); //but too much danger is bad and should reduce our chances of staying! //(reduce all scores so that the cmder may flee to safety) if (topMoveScore >= friendlyTooDangerousThreshold) { recruitChance /= topMoveScore; trainChance /= topMoveScore; topMoveScore = moveScoreThreshold; isInDangerousZone = true; } //if our territories are full of cmders, also make it more likely to move around if (factionCmderAmountRatio < SHOULD_GET_MORE_CMDERS_THRESHOLD && emptyNewCmderZones.Count == 0) { topMoveScore *= factionCmderAmountRatio; recruitChance *= factionCmderAmountRatio; trainChance *= factionCmderAmountRatio; } foreach (int nearbyZoneID in zoneCmderIsIn.linkedZones) { scoreCheckZone = GameController.GetZoneByID(nearbyZoneID); scoreCheckScore = GetZoneMoveScore(scoreCheckZone, ourFac, isInDangerousZone, factionHasEnemy, allyNearbyInfluenceFactor, enemyNearbyInfluenceFactor, atkNeutralDiscouragement, friendlyTooDangerousThreshold, moveScoreThreshold); //if we're low on commanders, //we should try to be more selective in our attacks... //make room for new cmders by stacking existing cmders in a friendly zone and stuff if (factionCmderAmountRatio < SHOULD_GET_MORE_CMDERS_THRESHOLD) { if (scoreCheckZone.ownerFaction != ourFac.ID && ourFac.GetStandingWith(scoreCheckZone.ownerFaction) != GameFactionRelations.FactionStanding.ally) { scoreCheckScore *= factionCmderAmountRatio * factionCmderAmountRatio; } else { if (emptyNewCmderZones.Count == 1 && emptyNewCmderZones[0] == scoreCheckZone) { //better not move to this spot, it's the only place for a new cmder scoreCheckScore *= factionCmderAmountRatio * factionCmderAmountRatio; } else if (emptyNewCmderZones.Count == 0) { //make it more likely to move to this spot then scoreCheckScore += Mathf.Lerp(0.0f, MAX_MAKE_ROOM_SCORE_BONUS, (1 - factionCmderAmountRatio)); } } } if (scoreCheckScore > topMoveScore) { topMoveScore = scoreCheckScore; moveDestZone = scoreCheckZone; } } if (topMoveScore <= SHOULD_GO_DEFENSIVE_THRESHOLD) { //Debug.Log("safe-landlocked! move score is " + topMoveScore); //we're "safe-landlocked"! none of the zones around are too interesting. //we should find a path to danger then if (fallbackMoveDestZone == null) { //get a good destination zone for the faction fallbackMoveDestZone = FindInterestingZone(ourFac); //Debug.Log("Faction " + ourFac.name + " got " + fallbackMoveDestZone.name + // " as fallback moveDest zone"); } moveDestZone = GetNextZoneInPathToZone(fallbackMoveDestZone, zoneCmderIsIn); topMoveScore = MAX_MOVE_SCORE_THRESHOLD; //Debug.Log("when trying to go from " + zoneCmderIsIn.name + " to " + // fallbackMoveDestZone.name + ", cmder got " + moveDestZone.name + " as path"); } //action time! bool hasActed = false; bool plansOnStayingInCurZone = moveDestZone.ID == zoneCmderIsIn.ID; if (trainChance > recruitChance && (plansOnStayingInCurZone || trainChance > topMoveScore)) { hasActed = commandableCmders[i].OrderTrainTroops(); } if (!hasActed && (plansOnStayingInCurZone || recruitChance > topMoveScore)) { hasActed = commandableCmders[i].OrderRecruitTroops(); } if (!hasActed && topMoveScore > moveScoreThreshold) { if (!plansOnStayingInCurZone) { phaseScript.MoveCommander(commandableCmders[i], moveDestZone.MyZoneSpot, false); //refresh the empty zone list if we moved; //that way, our other cmders may not "feel" the same need to move as this one did emptyNewCmderZones = GameController.GetZonesForNewCmdersOfFaction(ourFac); hasActed = true; } } if (!hasActed && !curZoneIsContested) { //if we decided to do nothing else, train troops hasActed = commandableCmders[i].OrderTrainTroops(); //try recruiting again if we can't train! if (!hasActed) { commandableCmders[i].OrderRecruitTroops(); } //do nothing then //Debug.Log("commander from " + ourFac.name + " at " + zoneCmderIsIn.name + // " decided to do nothing. Move score: " + topMoveScore + ", rec score: " + recruitChance + // ", train score: " + trainChance); } commandableCmders.RemoveAt(i); } }