/// <summary> /// The refugees civ searches the current hex for a similar race, and /// joins them if they find it. /// </summary> /// <param name="refugees"></param> /// <param name="hex"></param> /// <param name="homeName"></param> /// <returns>Returns true if a sutible settlement was found, /// returns false if not.</returns> bool RefugeesSearchHex(Civilization refugees, HexData hex, string homeName) { foreach (var lair in hex.LairList) { // can't keep the base they just lost. if (lair.Name == homeName) { continue; } // note it is interesting that a refugee group will not take up // in a ruins... if (lair.IsRuins()) { continue; } // search for a matching race in the hex Civilization targetCiv = lair.HomeCiv; if (targetCiv.Patricians.BaseAncestry.Name != refugees.Patricians.BaseAncestry.Name) { continue; } // found a match targetCiv.JoinOurCivilization(refugees.GetFullName()); targetCiv.Patricians.Members += refugees.Patricians.Members; refugees.DissolvePopulation(); return(true); } return(false); }
/// <summary> /// Defenders gather any like allied forces they can muster in the hex /// </summary> /// <param name="defender"></param> /// <param name="defenderHome"></param> public void GatherDefenders(Civilization defender, HexData defenderHome, string attackerFullName) { DefenderList.Add(defender); foreach (var lair in defenderHome.LairList) { if (lair.IsRuins()) { continue; } if (lair.HomeCiv.GetFullName() == defender.GetFullName()) { continue; } if (lair.HomeCiv.GetFullName() == attackerFullName) { continue; } if (lair.HomeCiv.Patricians.BaseAncestry.Name != defender.Patricians.BaseAncestry.Name) { continue; } if (defender.LeaderCompetency <= _dice.Roll(1, 12)) { continue; } DefenderList.Add(lair.HomeCiv); string record = "The " + defender.GetPluralName() + " have convinced the " + lair.HomeCiv.GetPluralName() + " to come to their defense."; defender.History.addRecord(record); lair.HomeCiv.History.addRecord(record, isLogged: false); } }
public HexData CreateRandomHex(int x, int y) { HexData hex = new HexData(this); Tuple <int, int> origin = new Tuple <int, int>(TierOriginX, TierOriginY); hex.InitializeAsRandomHex(x, y, origin, TierWidth); return(hex); }
/// <summary> /// New monsters move in from the edge of the map. /// </summary> /// <param name="hex"></param> public void ResolveOutsideSingleHexMigration(HexData hex) { // only for edge chances int numEdges = _worldMap.NumberOutsideEdges(hex); if (numEdges <= 0) { return; } // "5% chance per edge" int chance = numEdges * 5; int roll = _dice.Roll(1, 100); if (roll > chance) { return; } // Are they invaders, or settlers? var invaders = new Civilization(); invaders.InitializeAsRandomCiv(hex.Tier); // Depends on where they land: int subHexLoc = _dice.Roll(1, HexData.SUB_HEXES); var results = ResolveInvasionConflicts(hex, invaders, subHexLoc); if (results is null) { // no battle. settle in unclaimed land. var lair = new Lair(); lair.InitializeAsSettlerLair(invaders, subHexLoc, hex); lair.Treasure = 1; hex.LairList.Add(lair); return; } if ( (results.AttackerState == Battle.CombatantState.COMBATANT_STATE_ELIMINATED) || (results.AttackerState == Battle.CombatantState.COMBATANT_STATE_ROUTED) ) { // invaders have been dealt with. return; } // else the invaders win, and have been moved into their new lair. }
/// <summary> /// If there's a lair already in the area, they will fight for it. /// Otherwise, there's no battle to return. /// </summary> /// <param name="hex"></param> /// <param name="invaders"></param> /// <param name="subHexIndex"></param> /// <returns></returns> private Battle ResolveInvasionConflicts(HexData hex, Civilization invaders, int subHexIndex) { foreach (var lair in hex.LairList) { if (subHexIndex != lair.SubhexIndex) { continue; } var battle = new Battle(_worldMap); battle.ResolveBattle(invaders, hex, lair); return(battle); } return(null); }
private void _doMigration(Lair lair, HexData hex) { if (lair.IsRuins()) { return; } string record = "The " + lair.HomeCiv.GetPluralName() + " are migrating to a new home."; lair.HomeCiv.History.addRecord(record); HexData targetHex; do { int migrationDirection = _dice.Roll(1, 6); var neighborLocation = hex.FindNeighborByIndex(migrationDirection); targetHex = _worldMap.GetHexByCoordinates(neighborLocation); } while (targetHex is null); int subHexIndex = _dice.Roll(1, HexData.SUB_HEXES); var existingLair = targetHex.GetLairAtLocation(subHexIndex); if (existingLair is null) { // Free real estate! var newLair = new Lair(); newLair.InitializeAsSettlerLair(lair.HomeCiv, subHexIndex, targetHex); targetHex.LairList.Add(newLair); lair.ForceAbandon(); // move the treasure newLair.Treasure = lair.Treasure; lair.Treasure = 0; return; } // Going to have to fight for the space. var battle = new Battle(_worldMap); battle.ResolveBattle(hex, targetHex, lair, existingLair); }
/// <summary> /// Determines the number of edges of the hex that fall outside the /// existing map. /// </summary> /// <param name="hex"></param> /// <returns></returns> public int NumberOutsideEdges(HexData hex) { int numOuterEdges = 0; for (int i = 0; i < 6; ++i) { int index = i + 1; var neighborCoords = hex.FindNeighborByIndex(index); var neighbor = GetHexByCoordinates(neighborCoords.Item1, neighborCoords.Item2); if (neighbor == null) { ++numOuterEdges; } } return(numOuterEdges); }
/// <summary> /// Losers of a battle will try to search their home hex for a like /// race to join, or and adjacent hex if that fails. /// If that fails, they are eliminated. /// </summary> /// <param name="losers"></param> /// <param name="loserHome"></param> /// <param name="baseName">The name of the home base that the refugees /// just left. They can't go back here.</param> void MoveLosers(Civilization losers, HexData loserHome, string baseName) { bool isFoundHex = RefugeesSearchHex(losers, loserHome, baseName); if (isFoundHex) { return; } int nextIndex = _dice.Roll(1, 6); bool isFound = false; for (int i = 0; i < 6; ++i) { ++nextIndex; if (nextIndex > 6) { nextIndex = 1; } var nextCoords = loserHome.FindNeighborByIndex(nextIndex); var nextHex = _worldMap.GetHexByCoordinates(nextCoords.Item1, nextCoords.Item2); if (nextHex is null) { continue; } isFound = RefugeesSearchHex(losers, nextHex, baseName); if (isFound) { break; } } if (isFound) { return; } // no available place to go! string report = "The " + losers.GetPluralName() + " could not find refuge."; losers.History.addRecord(report); losers.DissolvePopulation(); }
public void QueueMigrations(HexData hex) { // isolated hexes can't migrate // (prevents infinite loop when searching) int outerEdges = _worldMap.NumberOutsideEdges(hex); if (outerEdges >= 6) { return; } // arrange migration schedule foreach (var lair in hex.LairList) { // 15% chance for internal civs to migrate int roll = _dice.Roll(1, 100); if (roll > 15) { continue; } int monthRoll = _dice.Roll(1, 6); int dayRoll = _dice.Roll(1, 30) - 1; if (monthRoll <= 3) { _mayMigrations[dayRoll] = lair; } else if (monthRoll <= 5) { _aprilMigrations[dayRoll] = lair; } else { _marchMigrations[dayRoll] = lair; } } }
/// <summary> /// The main battle resolution /// Combatants must come from a lair in a hex. /// </summary> /// <param name="attackerLands"></param> /// <param name="defenderLands"></param> /// <param name="attackerBase"></param> /// <param name="defenderBase"></param> public void ResolveBattle(HexData attackerLands, HexData defenderLands, Lair attackerBase, Lair defenderBase) { if (attackerBase.IsRuins()) { // no attackers! do not pass! AttackerState = CombatantState.COMBATANT_STATE_ELIMINATED; return; } Civilization attacker = attackerBase.HomeCiv; string record; if (defenderBase.IsRuins()) { record = (defenderBase.GetFullName() + " is found abandoned by the " + attacker.GetPluralName()); defenderBase.History.addRecord(record); attacker.History.addRecord(record, isLogged: false); defenderBase.MoveCivIn(attacker); attackerBase.ForceAbandon(); defenderBase.Treasure += attackerBase.Treasure; attackerBase.Treasure = 0; DefenderState = CombatantState.COMBATANT_STATE_ELIMINATED; return; } Civilization defender = defenderBase.HomeCiv; // since this method is only called on initial spawn, then the // rule is to merge if two of the same race spawn in the same // hex area. if (attacker.Patricians.BaseAncestry.Name == defender.Patricians.BaseAncestry.Name) { defender.JoinOurCivilization(attacker.GetFullName()); defender.Patricians.Members += attacker.Patricians.Members; attacker.DissolvePopulation(); return; } record = "The " + attacker.GetPluralName() + " are attacking the " + defender.GetPluralName() + " at " + defenderBase.GetFullName() + "!"; attacker.History.addRecord(record); defender.History.addRecord(record, isLogged: false); defenderBase.History.addRecord(record, isLogged: false); GatherAttackers(attacker, attackerLands, defender.GetFullName()); GatherDefenders(defender, defenderLands, attacker.GetFullName()); _attackerStartingForces = GetTotalCombatants(AttackerList); _defenderStartingForces = GetTotalCombatants(DefenderList); _executeMainBattleLoop(); // recover from battle ResolveSurvivors(_attackerStartingForces, AttackerList); ResolveSurvivors(_defenderStartingForces, DefenderList); // determine outcome of battle. bool isAttackerLost = (AttackerState == CombatantState.COMBATANT_STATE_ELIMINATED) || (AttackerState == CombatantState.COMBATANT_STATE_ROUTED); bool isDefenderLost = (DefenderState == CombatantState.COMBATANT_STATE_ELIMINATED) || (DefenderState == CombatantState.COMBATANT_STATE_ROUTED); bool isBothLost = isAttackerLost && isDefenderLost; bool isMutualDestruction = (DefenderState == CombatantState.COMBATANT_STATE_ELIMINATED && AttackerState == CombatantState.COMBATANT_STATE_ELIMINATED); if (isMutualDestruction) { // mutual destruction is highly unlikely, but not impossible. record = "The " + attacker.GetPluralName() + " and the " + defender.GetPluralName() + " have achieved mutual destruction at " + defenderBase.GetFullName() + "!"; attacker.DissolvePopulation(); defender.DissolvePopulation(); } else if (isBothLost) { if (DefenderState == CombatantState.COMBATANT_STATE_ELIMINATED) { // defenders lose record = "The " + defender.GetPluralName() + " have been defeated by the " + attacker.GetPluralName() + " at " + defenderBase.GetFullName() + "!"; string defenderBaseName = defenderBase.Name; MoveLosers(defender, defenderLands, defenderBaseName); defenderBase.MoveCivIn(attacker); attackerBase.ForceAbandon(); defenderBase.Treasure += attackerBase.Treasure; attackerBase.Treasure = 0; } else { record = "The " + attacker.GetPluralName() + " have been repelled by the " + defender.GetPluralName() + " at " + defenderBase.GetFullName() + "!"; string attackerBaseName = attackerBase.Name; // It's interesting that attackers don't go back home. MoveLosers(attacker, attackerLands, attackerBaseName); attackerBase.ForceAbandon(); } } else if (isDefenderLost) { // defender loses! record = "The " + defender.GetPluralName() + " have been defeated by the " + attacker.GetPluralName() + " at " + defenderBase.GetFullName() + "!"; string defenderBaseName = defenderBase.Name; MoveLosers(defender, defenderLands, defenderBaseName); defenderBase.MoveCivIn(attacker); attackerBase.ForceAbandon(); defenderBase.Treasure += attackerBase.Treasure; attackerBase.Treasure = 0; } else // attacker lost { // attacker loses! record = "The " + attacker.GetPluralName() + " have been repelled by the " + defender.GetPluralName() + " at " + defenderBase.GetFullName() + "!"; string attackerBaseName = attackerBase.Name; // It's interesting that attackers don't go back home. MoveLosers(attacker, attackerLands, attackerBaseName); attackerBase.ForceAbandon(); } _recordBattleReport(record, attacker, defender, defenderBase); // any lingering civs with zero population are removed. _worldMap.CleanOutRuins(); }
/// <summary> /// Overloaded function for determining battles started by outside /// or homeless invaders. /// </summary> /// <param name="attacker"></param> /// <param name="defenderLands"></param> /// <param name="defenderBase"></param> public void ResolveBattle(Civilization attacker, HexData defenderLands, Lair defenderBase) { string record; if (defenderBase.IsRuins()) { record = (defenderBase.GetFullName() + " is found abandoned by the " + attacker.GetPluralName()); defenderBase.History.addRecord(record); attacker.History.addRecord(record, isLogged: false); defenderBase.MoveCivIn(attacker); defenderBase.Treasure += 1; DefenderState = CombatantState.COMBATANT_STATE_ELIMINATED; return; } Civilization defender = defenderBase.HomeCiv; record = "The " + attacker.GetPluralName() + " are attacking the " + defender.GetPluralName() + " at " + defenderBase.GetFullName() + "!"; attacker.History.addRecord(record); defender.History.addRecord(record, isLogged: false); defenderBase.History.addRecord(record, isLogged: false); AttackerList.Add(attacker); GatherDefenders(defender, defenderLands, attacker.GetFullName()); _attackerStartingForces = GetTotalCombatants(AttackerList); _defenderStartingForces = GetTotalCombatants(DefenderList); _executeMainBattleLoop(); // recover from battle ResolveSurvivors(_attackerStartingForces, AttackerList); ResolveSurvivors(_defenderStartingForces, DefenderList); // determine outcome of battle. bool isAttackerLost = (AttackerState == CombatantState.COMBATANT_STATE_ELIMINATED) || (AttackerState == CombatantState.COMBATANT_STATE_ROUTED); bool isDefenderLost = (DefenderState == CombatantState.COMBATANT_STATE_ELIMINATED) || (DefenderState == CombatantState.COMBATANT_STATE_ROUTED); bool isBothLost = isAttackerLost && isDefenderLost; bool isMutualDestruction = (DefenderState == CombatantState.COMBATANT_STATE_ELIMINATED && AttackerState == CombatantState.COMBATANT_STATE_ELIMINATED); if (isMutualDestruction) { // mutual destruction is highly unlikely, but not impossible. record = "The " + attacker.GetPluralName() + " and the " + defender.GetPluralName() + " have achieved mutual destruction at " + defenderBase.GetFullName() + "!"; attacker.DissolvePopulation(); defender.DissolvePopulation(); } else if (isBothLost) { if (DefenderState == CombatantState.COMBATANT_STATE_ELIMINATED) { // defender loses! record = "The " + defender.GetPluralName() + " have been defeated by the " + attacker.GetPluralName() + " at " + defenderBase.GetFullName() + "!"; string defenderBaseName = defenderBase.Name; MoveLosers(defender, defenderLands, defenderBaseName); defenderBase.MoveCivIn(attacker); defenderBase.Treasure += 1; } else { // attacker loses! record = "The " + attacker.GetPluralName() + " have been repelled by the " + defender.GetPluralName() + " at " + defenderBase.GetFullName() + "!"; // In this case, the attackers seek to allign themselves // possibly where they landed. MoveLosers(attacker, defenderLands, baseName: ""); } } else if (isDefenderLost) { // defender loses! record = "The " + defender.GetPluralName() + " have been defeated by the " + attacker.GetPluralName() + " at " + defenderBase.GetFullName() + "!"; string defenderBaseName = defenderBase.Name; MoveLosers(defender, defenderLands, defenderBaseName); defenderBase.MoveCivIn(attacker); defenderBase.Treasure += 1; } else // attacker lost { // attacker loses! record = "The " + attacker.GetPluralName() + " have been repelled by the " + defender.GetPluralName() + " at " + defenderBase.GetFullName() + "!"; // In this case, the attackers seek to allign themselves // possibly where they landed. MoveLosers(attacker, defenderLands, baseName: ""); } _recordBattleReport(record, attacker, defender, defenderBase); // any lingering civs with zero population are removed. _worldMap.CleanOutRuins(); }