From 585cba8af80f526d211308db4d95a3462d7cf6b9 Mon Sep 17 00:00:00 2001 From: geckosoft Date: Mon, 15 Nov 2010 09:12:42 +0100 Subject: [PATCH] Added: StrategicVictoryConditions & StrategicPoint => allows 'koth' gameplay if used --- OpenRA.Mods.RA/OpenRA.Mods.RA.csproj | 2 + OpenRA.Mods.RA/Strategic/StrategicPoint.cs | 46 ++++ .../Strategic/StrategicVictoryConditions.cs | 211 ++++++++++++++++++ 3 files changed, 259 insertions(+) create mode 100644 OpenRA.Mods.RA/Strategic/StrategicPoint.cs create mode 100644 OpenRA.Mods.RA/Strategic/StrategicVictoryConditions.cs diff --git a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj index 6e48aa3145..73311e8565 100644 --- a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj +++ b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj @@ -60,6 +60,8 @@ + + diff --git a/OpenRA.Mods.RA/Strategic/StrategicPoint.cs b/OpenRA.Mods.RA/Strategic/StrategicPoint.cs new file mode 100644 index 0000000000..d798664b66 --- /dev/null +++ b/OpenRA.Mods.RA/Strategic/StrategicPoint.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + public class StrategicPointInfo : ITraitInfo + { + public readonly bool Critical = false; + + public object Create(ActorInitializer init) { return new StrategicPoint(init.self, this); } + } + + public class StrategicPoint : INotifyCapture, ITick + { + [Sync] public Actor Self; + [Sync] public bool Critical; + [Sync] public Player OriginalOwner; + [Sync] public int TicksOwned = 0; + + public StrategicPointInfo Info; + + public StrategicPoint(Actor self, StrategicPointInfo info) + { + Self = self; + Info = info; + OriginalOwner = self.Owner; + + Critical = info.Critical; + } + + public void OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner) + { + TicksOwned = 0; + } + + public void Tick(Actor self) + { + if (OriginalOwner == self.Owner || self.Owner.WinState != WinState.Undefined) return; + + TicksOwned++; + } + } +} diff --git a/OpenRA.Mods.RA/Strategic/StrategicVictoryConditions.cs b/OpenRA.Mods.RA/Strategic/StrategicVictoryConditions.cs new file mode 100644 index 0000000000..111b70b9fb --- /dev/null +++ b/OpenRA.Mods.RA/Strategic/StrategicVictoryConditions.cs @@ -0,0 +1,211 @@ +#region Copyright & License Information +/* + * Copyright 2007-2010 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see LICENSE. + */ +#endregion + +using System; +using System.Linq; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + /// + /// Attach to players only kthx :) + /// + public class StrategicVictoryConditionsInfo : ITraitInfo + { + public readonly int TicksToHold = 25 * 60 * 5; // ~5 minutes + public readonly bool ResetOnHoldLost = true; + public readonly float RatioRequired = 0.5f; // 50% required of all koth locations + public readonly float CriticalRatioRequired = 1f; // if someone owns 100% of all critical locations + public readonly bool SplitHolds = true; // disallow or allow the 'holdsrequired' to include critical locations + + public object Create(ActorInitializer init) { return new StrategicVictoryConditions(init.self, this); } + } + + public class StrategicVictoryConditions : ITick + { + [Sync] public Actor Self; + [Sync] public StrategicVictoryConditionsInfo Info; + + [Sync] public int TicksToHold; + [Sync] public bool ResetOnHoldLost; + [Sync] public float RatioRequired; + [Sync] public float CriticalRatioRequired; + [Sync] public bool SplitHolds; + [Sync] public int TicksLeft = 0; + [Sync] public int CriticalTicksLeft = 0; + + public StrategicVictoryConditions(Actor self, StrategicVictoryConditionsInfo info) + { + Self = self; + Info = info; + + TicksToHold = info.TicksToHold; + ResetOnHoldLost = info.ResetOnHoldLost; + RatioRequired = info.RatioRequired; + CriticalRatioRequired = info.CriticalRatioRequired; + SplitHolds = info.SplitHolds; + } + + /// + /// Includes your allies as well + /// + public int Owned + { + get { return (SplitHolds) ? CountOwnedPoints(false) : CountOwnedPoints(false) + OwnedCritical; } + } + + /// + /// Includes your allies as well + /// + public int OwnedCritical + { + get { return CountOwnedPoints(true); } + } + + public int Total + { + get + { + return (SplitHolds) ? Self.World.Actors.Where(a => !a.Destroyed && a.HasTrait() && a.TraitOrDefault().Critical == false).Count() : Self.World.Actors.Where(a => a.HasTrait()).Count(); + } + } + + public int TotalCritical + { + get + { + return Self.World.Actors.Where(a => !a.Destroyed && a.HasTrait() && a.TraitOrDefault().Critical).Count(); + } + } + + public int CountOwnedPoints(bool critical) + { + int total = 0; + + foreach (var p in Self.World.players.Select(k => k.Value)) + { + if (p == Self.Owner || (p.Stances[Self.Owner] == Stance.Ally && Self.Owner.Stances[p] == Stance.Ally)) + { + total += Self.World.Queries.OwnedBy[p].Where(a => a.HasTrait() && a.TraitOrDefault().Critical == critical).Count(); + } + } + return total; + } + + public bool HoldingCritical + { + get + { + var criticalOwned = 1f / TotalCritical * OwnedCritical; + + return (criticalOwned >= CriticalRatioRequired); + } + } + + public bool Holding + { + get + { + var owned = 1f / Total * Owned; + + return (owned >= RatioRequired); + } + } + + public void Tick(Actor self) + { + if (self.Owner.WinState != WinState.Undefined || self.Owner.NonCombatant) return; + + var cvc = self.TraitOrDefault(); + if (cvc == null) + return; // Cannot work without ConquestVictoryConditions + + // See if any of the conditions are met to increase the count + if (TotalCritical > 0) + { + if (HoldingCritical) + { + // Hah! We met ths critical owned condition + if (CriticalTicksLeft == 0) + { + // First time + CriticalTicksLeft = TicksToHold; + } + else + { + // nth time + if (--CriticalTicksLeft == 0) + { + // Player & allies have won! + Won(); + } + } + } + else if (CriticalTicksLeft != 0) + { + // we lost the hold :/ + if (ResetOnHoldLost) + { + CriticalTicksLeft = TicksToHold; // Reset the time hold + } + } + } + + // See if any of the conditions are met to increase the count + if (Total > 0) + { + if (Holding) + { + // Hah! We met ths critical owned condition + if (TicksLeft == 0) + { + // First time + TicksLeft = TicksToHold; + } + else + { + // nth time + if (--TicksLeft == 0) + { + // Player & allies have won! + Won(); + } + } + } + else if (TicksLeft != 0) + { + // we lost the hold :/ + if (ResetOnHoldLost) + { + TicksLeft = TicksToHold; // Reset the time hold + } + } + } + } + + public void Won() + { + // Player has won + foreach (var p in Self.World.players.Select(k => k.Value)) + { + var cvc = p.PlayerActor.TraitOrDefault(); + + if ((p.WinState == WinState.Undefined) && (p == Self.Owner || (p.Stances[Self.Owner] == Stance.Ally && Self.Owner.Stances[p] == Stance.Ally))) + { + cvc.Win(p.PlayerActor); + } + else if (p.WinState == WinState.Undefined) + { + cvc.Surrender(p.PlayerActor); + } + } + } + } +}