public void TestChangingCallbackAddLocks() { var obj = new DummyLockable(1); var obj2 = new DummyLockable(2); var obj3 = new DummyLockable(3); int callCount = 0; CallbackLock.CallbackLockHandler lockFunc = delegate { if (callCount == 0) { callCount++; return(new ILockable[] { obj2 }); } callCount++; return(new ILockable[] { obj3, obj2 }); }; var lck = new CallbackLock(multiObjectLockFactory).Lock(lockFunc, null, obj); DefaultMultiObjectLock.IsLocked(obj).Should().BeTrue(); DefaultMultiObjectLock.IsLocked(obj2).Should().BeTrue(); DefaultMultiObjectLock.IsLocked(obj3).Should().BeTrue(); lck.UnlockAll(); DefaultMultiObjectLock.IsLocked(obj).Should().BeFalse(); DefaultMultiObjectLock.IsLocked(obj2).Should().BeFalse(); DefaultMultiObjectLock.IsLocked(obj3).Should().BeFalse(); }
private void Delete(Session session, Packet packet) { if (!session.Player.IsInTribe) { ReplyError(session, packet, Error.TribeIsNull); return; } ITribe tribe = session.Player.Tribesman.Tribe; CallbackLock.CallbackLockHandler lockHandler = delegate { var locks = strongholdManager.StrongholdsForTribe(tribe) .SelectMany(stronghold => stronghold.LockList()) .ToList(); locks.AddRange(tribe.Tribesmen); return(locks.ToArray()); }; locker.Lock(lockHandler, new object[] {}, tribe).Do(() => { if (!session.Player.Tribesman.Tribe.IsOwner(session.Player)) { ReplyError(session, packet, Error.TribesmanNotAuthorized); return; } var result = tribeManager.Remove(tribe); ReplyWithResult(session, packet, result); }); }
public void Leave(Session session, Packet packet) { var tribe = session.Player.Tribesman == null ? null : session.Player.Tribesman.Tribe; if (tribe == null) { ReplyError(session, packet, Error.TribeIsNull); return; } CallbackLock.CallbackLockHandler lockHandler = delegate { var locks = strongholdManager.StrongholdsForTribe(tribe) .SelectMany(stronghold => stronghold.LockList()) .ToList(); return(locks.ToArray()); }; locker.Lock(lockHandler, new object[] {}, tribe, session.Player).Do(() => { if (session.Player.Tribesman == null || session.Player.Tribesman.Tribe != tribe) { ReplyError(session, packet, Error.Unexpected); return; } var result = tribe.LeaveTribesman(session.Player); ReplyWithResult(session, packet, result); }); }
private void AfterGateBattle(ActionState state) { if (state != ActionState.Completed) { return; } ICity city; IStronghold targetStronghold; if (!gameObjectLocator.TryGetObjects(cityId, out city)) { throw new Exception("City not found"); } if (!gameObjectLocator.TryGetObjects(targetStrongholdId, out targetStronghold)) { throw new Exception("Stronghold not found"); } CallbackLock.CallbackLockHandler lockAll = delegate { return(targetStronghold.LockList().ToArray()); }; locker.Lock(lockAll, null, city, targetStronghold).Do(() => { ITroopObject troopObject; if (!city.TryGetTroop(troopObjectId, out troopObject)) { throw new Exception("Troop object should still exist"); } // Remove troop if he's dead if (TroopIsDead(troopObject, city)) { StateChange(ActionState.Completed); return; } if (city.Owner.IsInTribe && targetStronghold.GateOpenTo == city.Owner.Tribesman.Tribe) { // If our city is the one that now has access to the stronghold then join the real battle JoinOrCreateStrongholdMainBattle(city); } else if (city.Owner.IsInTribe && targetStronghold.Tribe == city.Owner.Tribesman.Tribe) { StationTroopInStronghold(troopObject, targetStronghold); } else { //Remove notification to target once battle is over city.Notifications.Remove(this); city.Notifications.Add(troopObject, this); // Send troop back home var tma = actionFactory.CreateTroopMovePassiveAction(city.Id, troopObject.ObjectId, city.PrimaryPosition.X, city.PrimaryPosition.Y, true, true); ExecuteChainAndWait(tma, AfterTroopMovedHome); } }); }
private string Delete(Session session, string[] parms) { bool help = false; string tribeName = string.Empty; try { var p = new OptionSet { { "?|help|h", v => help = true }, { "tribe=", v => tribeName = v.TrimMatchingQuotes() }, }; p.Parse(parms); } catch (Exception) { help = true; } if (help || string.IsNullOrEmpty(tribeName)) { return("TribeDelete --name=tribe_name"); } uint tribeId; if (!tribeManager.FindTribeId(tribeName, out tribeId)) { return("Tribe not found"); } ITribe tribe; if (!world.TryGetObjects(tribeId, out tribe)) { return("Tribe not found"); } CallbackLock.CallbackLockHandler lockHandler = delegate { var locks = strongholdManager.StrongholdsForTribe(tribe) .SelectMany(stronghold => stronghold.LockList()) .ToList(); locks.AddRange(tribe.Tribesmen); return(locks.ToArray()); }; locker.Lock(lockHandler, new object[] {}, tribe).Do(() => { tribeManager.Remove(tribe); }); return("OK!"); }
public void TestEmptyListFromCallback() { var obj = new DummyLockable(1); CallbackLock.CallbackLockHandler lockFunc = custom => new ILockable[] {}; var lck = new CallbackLock(multiObjectLockFactory).Lock(lockFunc, null, obj); DefaultMultiObjectLock.IsLocked(obj).Should().BeTrue(); lck.UnlockAll(); DefaultMultiObjectLock.IsLocked(obj).Should().BeFalse(); }
public override void Callback(object custom) { IBarbarianTribe barbarianTribe; if (!gameObjectLocator.TryGetObjects(barbarianTribeId, out barbarianTribe)) { throw new Exception("Barb tribe is missing"); } CallbackLock.CallbackLockHandler lockHandler = delegate { var toBeLocked = new List <ILockable>(); toBeLocked.AddRange(barbarianTribe.Battle.LockList); toBeLocked.Add(barbarianTribe); return(toBeLocked.ToArray()); }; locker.Lock(lockHandler, null, barbarianTribe).Do(() => { if (barbarianTribe.Battle.ExecuteTurn()) { // Battle continues, just save it and reschedule dbManager.Save(barbarianTribe.Battle); endTime = SystemClock.Now.AddSeconds(formula.GetBattleInterval(barbarianTribe.Battle.Defenders, barbarianTribe.Battle.Attackers)); StateChange(ActionState.Fired); return; } // Battle has ended // Delete the battle world.Remove(barbarianTribe.Battle); dbManager.Delete(barbarianTribe.Battle); barbarianTribe.BeginUpdate(); barbarianTribe.Battle = null; barbarianTribe.State = GameObjectStateFactory.NormalState(); var initialBarbResources = formula.BarbarianTribeResources(barbarianTribe); if (!initialBarbResources.Equals(barbarianTribe.Resource)) { // Lower camps remaining barbarianTribe.CampRemains--; // Reset resources barbarianTribe.Resource.Clear(); barbarianTribe.Resource.Add(formula.BarbarianTribeResources(barbarianTribe)); } barbarianTribe.EndUpdate(); StateChange(ActionState.Completed); }); }
private void AfterTroopMoved(ActionState state) { if (state == ActionState.Completed) { ICity city; ICity targetCity; ITroopObject troopObject; if (!gameObjectLocator.TryGetObjects(cityId, troopObjectId, out city, out troopObject)) { throw new Exception("City or troop object is missing"); } if (!gameObjectLocator.TryGetObjects(targetCityId, out targetCity)) { //If the target is missing, walk back locker.Lock(city).Do(() => { TroopMovePassiveAction tma = actionFactory.CreateTroopMovePassiveAction(city.Id, troopObject.ObjectId, city.PrimaryPosition.X, city.PrimaryPosition.Y, true, true); ExecuteChainAndWait(tma, AfterTroopMovedHome); }); return; } // Get all of the stationed city id's from the target city since they will be used by the engage attack action CallbackLock.CallbackLockHandler lockAllStationed = delegate { return(targetCity.Troops.StationedHere() .Select(stationedStub => stationedStub.City) .Cast <ILockable>() .ToArray()); }; locker.Lock(lockAllStationed, null, city, targetCity).Do(() => { var bea = actionFactory.CreateCityEngageAttackPassiveAction(cityId, troopObject.ObjectId, targetCityId); ExecuteChainAndWait(bea, AfterBattle); }); } }
public override void Callback(object custom) { IStronghold stronghold; if (!gameObjectLocator.TryGetObjects(strongholdId, out stronghold)) { throw new Exception("Stronghold is missing"); } CallbackLock.CallbackLockHandler lockHandler = delegate { return(stronghold.LockList().ToArray()); }; locker.Lock(lockHandler, null, stronghold).Do(() => { if (stronghold.GateBattle.ExecuteTurn()) { // Battle continues, just save it and reschedule dbManager.Save(stronghold.GateBattle); endTime = SystemClock.Now.AddSeconds(formula.GetGateBattleInterval(stronghold)); StateChange(ActionState.Fired); return; } // Battle has ended // Delete the battle stronghold.GateBattle.GroupKilled -= BattleOnGroupKilled; stronghold.GateBattle.ActionAttacked -= BattleOnActionAttacked; world.Remove(stronghold.GateBattle); dbManager.Delete(stronghold.GateBattle); stronghold.BeginUpdate(); stronghold.GateBattle = null; stronghold.State = GameObjectStateFactory.NormalState(); // Heal the gate if no one made through otherwise we let it be healed after the main battle if (stronghold.GateOpenTo == null) { stronghold.GateMax = (int)formula.StrongholdGateLimit(stronghold.Lvl); stronghold.Gate = Math.Max(Math.Min(stronghold.GateMax, stronghold.Gate), formula.StrongholdGateHealHp(stronghold.StrongholdState, stronghold.Lvl)); } stronghold.EndUpdate(); StateChange(ActionState.Completed); }); }
public override void Callback(object custom) { ICity city; if (!gameObjectLocator.TryGetObjects(cityId, out city)) { throw new Exception("City is missing"); } CallbackLock.CallbackLockHandler lockHandler = delegate { var toBeLocked = new List <ILockable>(); toBeLocked.AddRange(city.Battle.LockList); toBeLocked.Add(city); toBeLocked.AddRange(city.Troops.StationedHere().Select(stub => stub.City).Distinct()); return(toBeLocked.ToArray()); }; locker.Lock(lockHandler, null, city).Do(() => { if (city.Battle.ExecuteTurn()) { // Battle continues, just save it and reschedule dbManager.Save(city.Battle); endTime = SystemClock.Now.AddSeconds(formula.GetBattleInterval(city.Battle.Defenders, city.Battle.Attackers)); StateChange(ActionState.Fired); return; } // Battle has ended // Delete the battle city.Battle.ActionAttacked -= BattleActionAttacked; city.Battle.UnitKilled -= BattleUnitKilled; city.Battle.EnterRound -= BattleEnterRound; world.Remove(city.Battle); dbManager.Delete(city.Battle); city.Battle = null; // Move the default troop back into normal and clear its temporary battle stats city.DefaultTroop.BeginUpdate(); city.DefaultTroop.Template.ClearStats(); city.DefaultTroop.State = TroopState.Idle; cityBattleProcedure.MoveUnitFormation(city.DefaultTroop, FormationType.InBattle, FormationType.Normal); city.DefaultTroop.EndUpdate(); // Get a COPY of the stubs that are stationed in the town since the loop below will modify city.Troops var stationedTroops = city.Troops.StationedHere().Where(stub => stub.State == TroopState.BattleStationed).ToList(); // Go through each stationed troop and either remove them from the city if they died // or set their states back to normal foreach (var stub in stationedTroops) { // Check if stub has died, if so, remove it completely from both cities if (stub.TotalCount == 0) { city.Troops.RemoveStationed(stub.StationTroopId); stub.City.Troops.Remove(stub.TroopId); continue; } // Set the stationed stub back to just TroopState.Stationed stub.BeginUpdate(); stub.State = TroopState.Stationed; stub.EndUpdate(); } // Handle SenseOfUrgency technology if (destroyedHp > 0) { battleProcedure.SenseOfUrgency(city, destroyedHp); } StateChange(ActionState.Completed); }); }
public override void Callback(object custom) { IStronghold stronghold; if (!gameObjectLocator.TryGetObjects(strongholdId, out stronghold)) { throw new Exception("Stronghold is missing"); } CallbackLock.CallbackLockHandler lockHandler = delegate { return(stronghold.LockList().ToArray()); }; locker.Lock(lockHandler, null, stronghold).Do(() => { if (stronghold.MainBattle.ExecuteTurn()) { // Battle continues, just save it and reschedule dbManager.Save(stronghold.MainBattle); endTime = SystemClock.Now.AddSeconds(formula.GetBattleInterval(stronghold.MainBattle.Defenders, stronghold.MainBattle.Attackers)); StateChange(ActionState.Fired); return; } // Battle has ended // Delete the battle stronghold.MainBattle.UnitCountDecreased -= MainBattleOnUnitKilled; stronghold.MainBattle.GroupKilled -= MainBattleOnGroupKilled; stronghold.MainBattle.ActionAttacked -= MainBattleOnActionAttacked; stronghold.MainBattle.ExitTurn -= MainBattleOnExitTurn; stronghold.MainBattle.EnterBattle -= MainBattleOnEnterBattle; // Set troop states to stationed and // send back anyone stationed here that doesn't belong // Make copy because it may change var stationedHere = stronghold.Troops.StationedHere().ToList(); foreach (var stub in stationedHere) { stub.BeginUpdate(); stub.State = TroopState.Stationed; stub.EndUpdate(); if (stub.City.Owner.IsInTribe && stub.City.Owner.Tribesman.Tribe == stronghold.Tribe) { continue; } var troopInitializer = troopInitializerFactory.CreateStationedTroopObjectInitializer(stub); var retreatChainAction = actionFactory.CreateRetreatChainAction(stub.City.Id, troopInitializer); var result = stub.City.Worker.DoPassive(stub.City, retreatChainAction, true); if (result != Error.Ok) { throw new Exception("Unexpected failure when retreating a unit from stronghold"); } } world.Remove(stronghold.MainBattle); dbManager.Delete(stronghold.MainBattle); stronghold.BeginUpdate(); stronghold.GateOpenTo = null; stronghold.MainBattle = null; stronghold.GateMax = (int)formula.StrongholdGateLimit(stronghold.Lvl); stronghold.Gate = Math.Max(Math.Min(stronghold.GateMax, stronghold.Gate), formula.StrongholdGateHealHp(stronghold.StrongholdState, stronghold.Lvl)); stronghold.State = GameObjectStateFactory.NormalState(); stronghold.EndUpdate(); StateChange(ActionState.Completed); }); }
private void AfterMainBattle(ActionState state) { if (state != ActionState.Completed) { return; } ICity city; IStronghold targetStronghold; if (!gameObjectLocator.TryGetObjects(cityId, out city)) { throw new Exception("City not found"); } if (!gameObjectLocator.TryGetObjects(targetStrongholdId, out targetStronghold)) { throw new Exception("Stronghold not found"); } CallbackLock.CallbackLockHandler lockAll = delegate { var locks = targetStronghold.LockList().ToList(); if (city.Owner.IsInTribe) { locks.Add(city.Owner.Tribesman.Tribe); } return(locks.ToArray()); }; locker.Lock(lockAll, null, city, targetStronghold).Do(() => { ITroopObject troopObject; if (!city.TryGetTroop(troopObjectId, out troopObject)) { throw new Exception("Troop object should still exist"); } //Remove notification once battle is over city.Notifications.Remove(this); // Attack points from SH battles go to tribe if (city.Owner.IsInTribe) { city.Owner.Tribesman.Tribe.AttackPoint += troopObject.Stats.AttackPoint; } city.BeginUpdate(); city.AttackPoint += troopObject.Stats.AttackPoint; city.EndUpdate(); // Remove troop if he's dead if (TroopIsDead(troopObject, city)) { StateChange(ActionState.Completed); return; } if (city.Owner.IsInTribe && targetStronghold.Tribe == city.Owner.Tribesman.Tribe) { // If our city is the one that now owns the stronghold then station there and we're done StationTroopInStronghold(troopObject, targetStronghold); } else { city.Notifications.Add(troopObject, this); // Send troop back home var tma = actionFactory.CreateTroopMovePassiveAction(city.Id, troopObject.ObjectId, city.PrimaryPosition.X, city.PrimaryPosition.Y, true, true); ExecuteChainAndWait(tma, AfterTroopMovedHome); } }); }
private void AfterTroopMoved(ActionState state) { if (state == ActionState.Fired) { // Verify the target is still good, otherwise we walk back immediately ICity city; IStronghold targetStronghold; ITroopObject troopObject; if (!gameObjectLocator.TryGetObjects(cityId, troopObjectId, out city, out troopObject)) { throw new Exception("City or troop object is missing"); } if (!gameObjectLocator.TryGetObjects(targetStrongholdId, out targetStronghold)) { CancelCurrentChain(); return; } bool invalidTarget = false; locker.Lock(city, targetStronghold).Do(() => { invalidTarget = strongholdBattleProcedure.CanStrongholdBeDefended(city, targetStronghold) != Error.Ok; }); // If the stronghold is not there or we are unable to attack/defense it, then cancel the current TroopMoveAction if (invalidTarget) { CancelCurrentChain(); } } else if (state == ActionState.Failed) { // If TroopMove failed it's because we cancelled it and the target is invalid. Walk back home ICity city; ITroopObject troopObject; locker.Lock(cityId, troopObjectId, out city, out troopObject).Do(() => { TroopMovePassiveAction tma = actionFactory.CreateTroopMovePassiveAction(city.Id, troopObject.ObjectId, city.PrimaryPosition.X, city.PrimaryPosition.Y, true, false); ExecuteChainAndWait(tma, AfterTroopMovedHome); }); } else if (state == ActionState.Completed) { ICity city; IStronghold targetStronghold; ITroopObject troopObject; if (!gameObjectLocator.TryGetObjects(cityId, troopObjectId, out city, out troopObject)) { throw new Exception("City or troop object is missing"); } if (!gameObjectLocator.TryGetObjects(targetStrongholdId, out targetStronghold)) { throw new Exception("Stronghold is missing"); } CallbackLock.CallbackLockHandler lockAll = delegate { return(targetStronghold.LockList().ToArray()); }; locker.Lock(lockAll, null, city, targetStronghold).Do(() => { if (targetStronghold.Tribe == city.Owner.Tribesman.Tribe) { if (targetStronghold.MainBattle != null) { battleProcedure.AddReinforcementToBattle(targetStronghold.MainBattle, troopObject.Stub, FormationType.Defense); StationTroopInStronghold(troopObject, targetStronghold, TroopState.BattleStationed); } else { StationTroopInStronghold(troopObject, targetStronghold); } return; } // Walk back to city if we dont own it anymore TroopMovePassiveAction tma = actionFactory.CreateTroopMovePassiveAction(city.Id, troopObject.ObjectId, city.PrimaryPosition.X, city.PrimaryPosition.Y, true, false); ExecuteChainAndWait(tma, AfterTroopMovedHome); }); } }
public IMultiObjectLock Lock(CallbackLock.CallbackLockHandler lockHandler, object[] lockHandlerParams, params ILockable[] baseLocks) { return(callbackLockFactory().Lock(lockHandler, lockHandlerParams, baseLocks)); }
public void Remove(Session session, Packet packet) { uint playerId; try { playerId = packet.GetUInt32(); } catch (Exception) { ReplyError(session, packet, Error.Unexpected); return; } IPlayer playerToBeRemoved; if (!world.TryGetObjects(playerId, out playerToBeRemoved)) { ReplyError(session, packet, Error.PlayerNotFound); return; } CallbackLock.CallbackLockHandler lockHandler = delegate { var tribe = session.Player.IsInTribe ? session.Player.Tribesman.Tribe : null; if (tribe == null) { return(new ILockable[] {}); } var locks = strongholdManager.StrongholdsForTribe(tribe) .SelectMany(stronghold => stronghold.LockList()) .ToList(); locks.Add(tribe); return(locks.ToArray()); }; locker.Lock(lockHandler, new object[] {}, session.Player, playerToBeRemoved).Do(() => { if (!session.Player.IsInTribe || !playerToBeRemoved.IsInTribe || playerToBeRemoved.Tribesman.Tribe != session.Player.Tribesman.Tribe) { ReplyError(session, packet, Error.TribeIsNull); return; } ITribe tribe = session.Player.Tribesman.Tribe; if (!tribe.HasRight(session.Player.PlayerId, TribePermission.Kick)) { ReplyError(session, packet, Error.TribesmanNotAuthorized); return; } if (tribe.IsOwner(playerToBeRemoved)) { ReplyError(session, packet, Error.TribesmanIsOwner); return; } var result = session.Player.Tribesman.Tribe.KickTribesman(playerToBeRemoved, session.Player); ReplyWithResult(session, packet, result); }); }
private void Subscribe(Session session, Packet packet) { uint battleId; try { battleId = packet.GetUInt32(); } catch (Exception) { ReplyError(session, packet, Error.Unexpected); return; } IBattleManager battleManager; if (!world.TryGetObjects(battleId, out battleManager)) { ReplyError(session, packet, Error.BattleNotViewable); return; } CallbackLock.CallbackLockHandler lockHandler = delegate { var toBeLocked = new List <ILockable>(); toBeLocked.AddRange(battleManager.LockList); return(toBeLocked.ToArray()); }; locker.Lock(lockHandler, null, session.Player).Do(() => { IEnumerable <string> errorParams; var canWatchBattle = battleManager.CanWatchBattle(session.Player, out errorParams); if (!Config.battle_instant_watch && canWatchBattle != Error.Ok) { packet = ReplyError(session, packet, canWatchBattle, false); packet.AddByte((byte)errorParams.Count()); foreach (var errorParam in errorParams) { packet.AddString(errorParam); } session.Write(packet); return; } var reply = new Packet(packet); reply.AddByte((byte)battleManager.Location.Type); reply.AddUInt32(battleManager.Location.Id); reply.AddString(battleManager.Location.GetName()); reply.AddUInt32(battleManager.Round); // Battle properties PacketHelper.AddBattleProperties(battleManager.ListProperties(), reply); PacketHelper.AddToPacket(battleManager.Attackers, reply); PacketHelper.AddToPacket(battleManager.Defenders, reply); try { Global.Current.Channel.Subscribe(session, "/BATTLE/" + battleManager.BattleId); } catch (DuplicateSubscriptionException) { } session.Write(reply); }); }
private void AfterTroopMoved(ActionState state) { if (state == ActionState.Fired) { // Verify the target is still good, otherwise we walk back immediately ICity city; IStronghold targetStronghold; ITroopObject troopObject; if (!gameObjectLocator.TryGetObjects(cityId, troopObjectId, out city, out troopObject)) { throw new Exception("City or troop object is missing"); } if (!gameObjectLocator.TryGetObjects(targetStrongholdId, out targetStronghold)) { CancelCurrentChain(); return; } /* * Commenting out this logic to return if stronghold is not attackable/defendable until we are able to correctly cancel assignments. At the moment, * there are cases where when troops are in an assignment and a stronghold is taken over, * the ones that are on the walk will return and then the ones that are dispatched will be sent to the stronghold. * * bool invalidTarget; * using (locker.Lock(city, targetStronghold)) * { * invalidTarget = strongholdBattleProcedure.CanStrongholdBeAttacked(city, targetStronghold) != Error.Ok && * strongholdBattleProcedure.CanStrongholdBeDefended(city, targetStronghold) != Error.Ok; * } */ // If player is no longer in a tribe, return if (!city.Owner.IsInTribe) { CancelCurrentChain(); } return; } if (state == ActionState.Failed) { // If TroopMove failed it's because we cancelled it and the target is invalid. Walk back home ICity city; ITroopObject troopObject; locker.Lock(cityId, troopObjectId, out city, out troopObject).Do(() => { // Remove from remote stronghold and add only to this troop city.Notifications.Remove(this); city.Notifications.Add(troopObject, this); TroopMovePassiveAction tma = actionFactory.CreateTroopMovePassiveAction(city.Id, troopObject.ObjectId, city.PrimaryPosition.X, city.PrimaryPosition.Y, true, true); ExecuteChainAndWait(tma, AfterTroopMovedHome); }); return; } if (state == ActionState.Completed) { ICity city; IStronghold targetStronghold; ITroopObject troopObject; if (!gameObjectLocator.TryGetObjects(cityId, troopObjectId, out city, out troopObject)) { throw new Exception("City or troop object is missing"); } if (!gameObjectLocator.TryGetObjects(targetStrongholdId, out targetStronghold)) { throw new Exception("Stronghold is missing"); } CallbackLock.CallbackLockHandler lockAll = delegate { return(targetStronghold.LockList().ToArray()); }; locker.Lock(lockAll, null, city, targetStronghold).Do(() => { if (city.Owner.IsInTribe) { if (targetStronghold.Tribe == city.Owner.Tribesman.Tribe) { if (targetStronghold.MainBattle != null) { MoveFromAttackToDefenseFormation(troopObject); battleProcedure.AddReinforcementToBattle(targetStronghold.MainBattle, troopObject.Stub, FormationType.Defense); StationTroopInStronghold(troopObject, targetStronghold, TroopState.BattleStationed); } else { StationTroopInStronghold(troopObject, targetStronghold); } return; } if (targetStronghold.GateOpenTo == city.Owner.Tribesman.Tribe) { // If stronghold's gate is open to the tribe, then it should engage the stronghold JoinOrCreateStrongholdMainBattle(city); return; } if (targetStronghold.GateOpenTo == null) { // If gate isn't open to anyone then engage the gate var bea = actionFactory.CreateStrongholdEngageGateAttackPassiveAction(cityId, troopObject.ObjectId, targetStrongholdId); ExecuteChainAndWait(bea, AfterGateBattle); return; } } city.Notifications.Remove(this); city.Notifications.Add(troopObject, this); // Walk back to city if none of the above conditions apply TroopMovePassiveAction tma = actionFactory.CreateTroopMovePassiveAction(city.Id, troopObject.ObjectId, city.PrimaryPosition.X, city.PrimaryPosition.Y, true, true); ExecuteChainAndWait(tma, AfterTroopMovedHome); }); } }