moved traits from engine into mod
This commit is contained in:
@@ -1,41 +0,0 @@
|
||||
#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.Collections.Generic;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Effects
|
||||
{
|
||||
class RepairIndicator : IEffect
|
||||
{
|
||||
int framesLeft;
|
||||
Actor a;
|
||||
Animation anim = new Animation("select");
|
||||
|
||||
public RepairIndicator(Actor a)
|
||||
{
|
||||
this.a = a; anim.PlayRepeating("repair");
|
||||
framesLeft = (int)(a.Info.Traits.Get<RepairableBuildingInfo>().RepairRate * 25 * 60 / 2);
|
||||
}
|
||||
|
||||
public void Tick( World world )
|
||||
{
|
||||
if (--framesLeft == 0 || a.IsDead())
|
||||
world.AddFrameEndTask(w => w.Remove(this));
|
||||
}
|
||||
|
||||
public IEnumerable<Renderable> Render()
|
||||
{
|
||||
yield return new Renderable(anim.Image,
|
||||
a.CenterLocation - .5f * anim.Image.size, "chrome", (int)a.CenterLocation.Y);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,7 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
readonly World world;
|
||||
internal readonly TerrainRenderer terrainRenderer;
|
||||
internal readonly UiOverlay uiOverlay;
|
||||
public readonly UiOverlay uiOverlay;
|
||||
internal readonly HardwarePalette palette;
|
||||
|
||||
internal WorldRenderer(World world)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
@@ -75,7 +75,6 @@
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Effects\RepairIndicator.cs" />
|
||||
<Compile Include="GameRules\WeaponInfo.cs" />
|
||||
<Compile Include="Group.cs" />
|
||||
<Compile Include="Orders\GenericSelectTarget.cs" />
|
||||
@@ -135,7 +134,6 @@
|
||||
<Compile Include="Traits\Activities\RemoveSelf.cs" />
|
||||
<Compile Include="Traits\Activities\Sell.cs" />
|
||||
<Compile Include="Orders\IOrderGenerator.cs" />
|
||||
<Compile Include="Orders\PlaceBuildingOrderGenerator.cs" />
|
||||
<Compile Include="Player.cs" />
|
||||
<Compile Include="Graphics\Sheet.cs" />
|
||||
<Compile Include="PathFinder.cs" />
|
||||
@@ -158,17 +156,13 @@
|
||||
<Compile Include="Traits\Buildable.cs" />
|
||||
<Compile Include="Traits\Building.cs" />
|
||||
<Compile Include="Traits\World\BuildingInfluence.cs" />
|
||||
<Compile Include="Traits\Player\PlaceBuilding.cs" />
|
||||
<Compile Include="Traits\World\PlayerColorPalette.cs" />
|
||||
<Compile Include="Traits\World\ResourceLayer.cs" />
|
||||
<Compile Include="Traits\World\ResourceType.cs" />
|
||||
<Compile Include="Traits\SupportPower.cs" />
|
||||
<Compile Include="Traits\ProvidesRadar.cs" />
|
||||
<Compile Include="Traits\Selectable.cs" />
|
||||
<Compile Include="Traits\Player\ProductionQueue.cs" />
|
||||
<Compile Include="Traits\Mobile.cs" />
|
||||
<Compile Include="Traits\Production.cs" />
|
||||
<Compile Include="Traits\RallyPoint.cs" />
|
||||
<Compile Include="Traits\Render\RenderSimple.cs" />
|
||||
<Compile Include="Traits\TraitsInterfaces.cs" />
|
||||
<Compile Include="Traits\Turreted.cs" />
|
||||
@@ -215,7 +209,6 @@
|
||||
<Compile Include="Traits\RevealsShroud.cs" />
|
||||
<Compile Include="Traits\Targetable.cs" />
|
||||
<Compile Include="Traits\Health.cs" />
|
||||
<Compile Include="Traits\RepairableBuilding.cs" />
|
||||
<Compile Include="Traits\Activities\Drag.cs" />
|
||||
<Compile Include="Widgets\VqaPlayerWidget.cs" />
|
||||
<Compile Include="Widgets\Delegates\VideoPlayerDelegate.cs" />
|
||||
@@ -226,7 +219,6 @@
|
||||
<Compile Include="Traits\Armor.cs" />
|
||||
<Compile Include="Graphics\CursorProvider.cs" />
|
||||
<Compile Include="Traits\Player\TechTree.cs" />
|
||||
<Compile Include="Traits\Player\ClassicProductionQueue.cs" />
|
||||
<Compile Include="Traits\Player\PowerManager.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -242,7 +234,6 @@
|
||||
<Compile Include="ObjectCreator.cs" />
|
||||
<Compile Include="Network\SyncReport.cs" />
|
||||
<Compile Include="TraitDictionary.cs" />
|
||||
<Compile Include="Traits\PrimaryBuilding.cs" />
|
||||
<Compile Include="Widgets\Delegates\DeveloperModeDelegate.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
#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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.GameRules;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Orders
|
||||
{
|
||||
public class PlaceBuildingOrderGenerator : IOrderGenerator
|
||||
{
|
||||
readonly Actor Producer;
|
||||
readonly string Building;
|
||||
BuildingInfo BuildingInfo { get { return Rules.Info[ Building ].Traits.Get<BuildingInfo>(); } }
|
||||
|
||||
public PlaceBuildingOrderGenerator(Actor producer, string name)
|
||||
{
|
||||
Producer = producer;
|
||||
Building = name;
|
||||
}
|
||||
|
||||
public IEnumerable<Order> Order(World world, int2 xy, MouseInput mi)
|
||||
{
|
||||
if (mi.Button == MouseButton.Right)
|
||||
world.CancelInputMode();
|
||||
|
||||
return InnerOrder(world, xy, mi);
|
||||
}
|
||||
|
||||
IEnumerable<Order> InnerOrder(World world, int2 xy, MouseInput mi)
|
||||
{
|
||||
if (mi.Button == MouseButton.Left)
|
||||
{
|
||||
var topLeft = xy - Footprint.AdjustForBuildingSize( BuildingInfo );
|
||||
if (!world.CanPlaceBuilding( Building, BuildingInfo, topLeft, null)
|
||||
|| !world.IsCloseEnoughToBase(Producer.Owner, Building, BuildingInfo, topLeft))
|
||||
{
|
||||
var eva = world.WorldActor.Info.Traits.Get<EvaAlertsInfo>();
|
||||
Sound.Play(eva.BuildingCannotPlaceAudio);
|
||||
yield break;
|
||||
}
|
||||
|
||||
if (Rules.Info[ Building ].Traits.Contains<LineBuildInfo>())
|
||||
yield return new Order("LineBuild", Producer.Owner.PlayerActor, topLeft, Building);
|
||||
else
|
||||
yield return new Order("PlaceBuilding", Producer.Owner.PlayerActor, topLeft, Building);
|
||||
}
|
||||
}
|
||||
|
||||
public void Tick( World world )
|
||||
{
|
||||
// Find the queue with the target actor
|
||||
var queue = Producer.TraitsImplementing<ProductionQueue>()
|
||||
.Where(p => p.CurrentItem() != null &&
|
||||
p.CurrentItem().Item == Building &&
|
||||
p.CurrentItem().RemainingTime == 0)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (queue == null)
|
||||
world.CancelInputMode();
|
||||
}
|
||||
|
||||
public void RenderAfterWorld( World world ) {}
|
||||
|
||||
public void RenderBeforeWorld(World world)
|
||||
{
|
||||
world.WorldRenderer.uiOverlay.DrawBuildingGrid(world, Building, BuildingInfo);
|
||||
}
|
||||
|
||||
public string GetCursor(World world, int2 xy, MouseInput mi) { return "default"; }
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
#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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
public class ClassicProductionQueueInfo : ProductionQueueInfo, ITraitPrerequisite<TechTreeInfo>, ITraitPrerequisite<PowerManagerInfo>, ITraitPrerequisite<PlayerResourcesInfo>
|
||||
{
|
||||
public override object Create(ActorInitializer init) { return new ClassicProductionQueue(init.self, this); }
|
||||
}
|
||||
|
||||
public class ClassicProductionQueue : ProductionQueue
|
||||
{
|
||||
public ClassicProductionQueue( Actor self, ClassicProductionQueueInfo info )
|
||||
: base(self, self, info as ProductionQueueInfo) {}
|
||||
|
||||
[Sync] bool QueueActive = true;
|
||||
public override void Tick( Actor self )
|
||||
{
|
||||
QueueActive = self.World.Queries.OwnedBy[self.Owner].WithTrait<Production>()
|
||||
.Where(x => x.Trait.Info.Produces.Contains(Info.Type))
|
||||
.Any();
|
||||
|
||||
base.Tick(self);
|
||||
}
|
||||
|
||||
ActorInfo[] None = new ActorInfo[]{};
|
||||
public override IEnumerable<ActorInfo> AllItems()
|
||||
{
|
||||
return QueueActive ? base.AllItems() : None;
|
||||
}
|
||||
|
||||
public override IEnumerable<ActorInfo> BuildableItems()
|
||||
{
|
||||
return QueueActive ? base.BuildableItems() : None;
|
||||
}
|
||||
|
||||
protected override void BuildUnit( string name )
|
||||
{
|
||||
// Find a production structure to build this actor
|
||||
var producers = self.World.Queries.OwnedBy[self.Owner]
|
||||
.WithTrait<Production>()
|
||||
.Where(x => x.Trait.Info.Produces.Contains(Info.Type))
|
||||
.OrderByDescending(x => x.Actor.IsPrimaryBuilding() ? 1 : 0 ); // prioritize the primary.
|
||||
|
||||
if (producers.Count() == 0)
|
||||
{
|
||||
CancelProduction(name);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var p in producers)
|
||||
{
|
||||
if (IsDisabledBuilding(p.Actor)) continue;
|
||||
|
||||
if (p.Trait.Produce(p.Actor, Rules.Info[ name ]))
|
||||
{
|
||||
FinishProduction();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
#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.Linq;
|
||||
using OpenRA.Effects;
|
||||
using OpenRA.GameRules;
|
||||
using OpenRA.FileFormats;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
class PlaceBuildingInfo : TraitInfo<PlaceBuilding> {}
|
||||
|
||||
class PlaceBuilding : IResolveOrder
|
||||
{
|
||||
public void ResolveOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString == "PlaceBuilding" || order.OrderString == "LineBuild")
|
||||
{
|
||||
self.World.AddFrameEndTask(w =>
|
||||
{
|
||||
var prevItems = GetNumBuildables(self.Owner);
|
||||
|
||||
// Find the queue with the target actor
|
||||
var queue = w.Queries.WithTraitMultiple<ProductionQueue>()
|
||||
.Where(p => p.Actor.Owner == self.Owner &&
|
||||
p.Trait.CurrentItem() != null &&
|
||||
p.Trait.CurrentItem().Item == order.TargetString &&
|
||||
p.Trait.CurrentItem().RemainingTime == 0)
|
||||
.Select(p => p.Trait)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (queue == null)
|
||||
return;
|
||||
|
||||
var unit = Rules.Info[order.TargetString];
|
||||
var buildingInfo = unit.Traits.Get<BuildingInfo>();
|
||||
|
||||
if (order.OrderString == "LineBuild")
|
||||
{
|
||||
bool playSounds = true;
|
||||
foreach (var t in LineBuildUtils.GetLineBuildCells(w, order.TargetLocation, order.TargetString, buildingInfo))
|
||||
{
|
||||
var building = w.CreateActor(order.TargetString, new TypeDictionary
|
||||
{
|
||||
new LocationInit( t ),
|
||||
new OwnerInit( order.Player ),
|
||||
});
|
||||
|
||||
if (playSounds)
|
||||
foreach (var s in buildingInfo.BuildSounds)
|
||||
Sound.PlayToPlayer(order.Player, s, building.CenterLocation);
|
||||
playSounds = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var building = w.CreateActor(order.TargetString, new TypeDictionary
|
||||
{
|
||||
new LocationInit( order.TargetLocation ),
|
||||
new OwnerInit( order.Player ),
|
||||
});
|
||||
foreach (var s in buildingInfo.BuildSounds)
|
||||
Sound.PlayToPlayer(order.Player, s, building.CenterLocation);
|
||||
}
|
||||
|
||||
PlayBuildAnim( self, unit );
|
||||
|
||||
queue.FinishProduction();
|
||||
|
||||
if (GetNumBuildables(self.Owner) > prevItems)
|
||||
w.Add(new DelayedAction(10,
|
||||
() => Sound.PlayToPlayer(order.Player,
|
||||
w.WorldActor.Info.Traits.Get<EvaAlertsInfo>().NewOptions)));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// finds a construction yard (or equivalent) and runs its "build" animation.
|
||||
static void PlayBuildAnim( Actor self, ActorInfo unit )
|
||||
{
|
||||
var bi = unit.Traits.GetOrDefault<BuildableInfo>();
|
||||
if (bi == null)
|
||||
return;
|
||||
|
||||
var producers = self.World.Queries.OwnedBy[ self.Owner ].WithTrait<Production>()
|
||||
.Where( x => x.Actor.Info.Traits.Get<ProductionInfo>().Produces.Contains( bi.Queue ) )
|
||||
.ToList();
|
||||
var producer = producers.Where( x => x.Actor.IsPrimaryBuilding() ).Concat( producers )
|
||||
.FirstOrDefault();
|
||||
|
||||
if( producer.Actor != null )
|
||||
producer.Actor.TraitsImplementing<RenderSimple>().First().PlayCustomAnim( producer.Actor, "build" );
|
||||
}
|
||||
|
||||
static int GetNumBuildables(Player p)
|
||||
{
|
||||
if (p != p.World.LocalPlayer) return 0; // this only matters for local players.
|
||||
|
||||
return p.World.Queries.WithTraitMultiple<ProductionQueue>()
|
||||
.Where(a => a.Actor.Owner == p)
|
||||
.SelectMany(a => a.Trait.BuildableItems()).Distinct().Count();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ using System.Linq;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
class PlayerResourcesInfo : ITraitInfo
|
||||
public class PlayerResourcesInfo : ITraitInfo
|
||||
{
|
||||
public readonly int InitialCash = 10000;
|
||||
public readonly int InitialOre = 0;
|
||||
|
||||
@@ -1,296 +0,0 @@
|
||||
#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.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
public class ProductionQueueInfo : ITraitInfo
|
||||
{
|
||||
public readonly string Type = null;
|
||||
public float BuildSpeed = 0.4f;
|
||||
public readonly int LowPowerSlowdown = 3;
|
||||
public virtual object Create(ActorInitializer init) { return new ProductionQueue(init.self, init.self.Owner.PlayerActor, this); }
|
||||
}
|
||||
|
||||
public class ProductionQueue : IResolveOrder, ITick, ITechTreeElement
|
||||
{
|
||||
public readonly Actor self;
|
||||
public ProductionQueueInfo Info;
|
||||
readonly PowerManager PlayerPower;
|
||||
readonly PlayerResources PlayerResources;
|
||||
|
||||
// TODO: sync these
|
||||
// A list of things we are currently building
|
||||
List<ProductionItem> Queue = new List<ProductionItem>();
|
||||
|
||||
// A list of things we could possibly build, even if our race doesn't normally get it
|
||||
Dictionary<ActorInfo, ProductionState> Produceable = new Dictionary<ActorInfo, ProductionState>();
|
||||
|
||||
public ProductionQueue( Actor self, Actor playerActor, ProductionQueueInfo info )
|
||||
{
|
||||
this.self = self;
|
||||
this.Info = info;
|
||||
PlayerResources = playerActor.Trait<PlayerResources>();
|
||||
PlayerPower = playerActor.Trait<PowerManager>();
|
||||
|
||||
var ttc = playerActor.Trait<TechTree>();
|
||||
|
||||
foreach (var a in AllBuildables(Info.Type))
|
||||
{
|
||||
var bi = a.Traits.Get<BuildableInfo>();
|
||||
// Can our race build this by satisfying normal prereqs?
|
||||
var buildable = bi.Owner.Contains(self.Owner.Country.Race);
|
||||
Produceable.Add( a, new ProductionState(){ Visible = buildable && !bi.Hidden } );
|
||||
if (buildable)
|
||||
ttc.Add( a.Name, a.Traits.Get<BuildableInfo>().Prerequisites.ToList(), this );
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerable<ActorInfo> AllBuildables(string category)
|
||||
{
|
||||
return Rules.Info.Values
|
||||
.Where( x => x.Name[ 0 ] != '^' )
|
||||
.Where( x => x.Traits.Contains<BuildableInfo>() )
|
||||
.Where( x => x.Traits.Get<BuildableInfo>().Queue == category );
|
||||
}
|
||||
|
||||
public void OverrideProduction(ActorInfo type, bool buildable)
|
||||
{
|
||||
Produceable[type].Buildable = buildable;
|
||||
Produceable[type].Sticky = true;
|
||||
}
|
||||
|
||||
public void PrerequisitesAvailable(string key)
|
||||
{
|
||||
var ps = Produceable[ Rules.Info[key] ];
|
||||
if (!ps.Sticky)
|
||||
ps.Buildable = true;
|
||||
}
|
||||
|
||||
public void PrerequisitesUnavailable(string key)
|
||||
{
|
||||
var ps = Produceable[ Rules.Info[key] ];
|
||||
if (!ps.Sticky)
|
||||
ps.Buildable = false;
|
||||
}
|
||||
|
||||
public ProductionItem CurrentItem()
|
||||
{
|
||||
return Queue.ElementAtOrDefault(0);
|
||||
}
|
||||
|
||||
public IEnumerable<ProductionItem> AllQueued()
|
||||
{
|
||||
return Queue;
|
||||
}
|
||||
|
||||
public virtual IEnumerable<ActorInfo> AllItems()
|
||||
{
|
||||
if (Game.LobbyInfo.GlobalSettings.AllowCheats && self.Owner.PlayerActor.Trait<DeveloperMode>().AllTech)
|
||||
return Produceable.Select(a => a.Key);
|
||||
|
||||
return Produceable.Where(a => a.Value.Buildable || a.Value.Visible).Select(a => a.Key);
|
||||
}
|
||||
|
||||
public virtual IEnumerable<ActorInfo> BuildableItems()
|
||||
{
|
||||
if (Game.LobbyInfo.GlobalSettings.AllowCheats && self.Owner.PlayerActor.Trait<DeveloperMode>().AllTech)
|
||||
return Produceable.Select(a => a.Key);
|
||||
|
||||
return Produceable.Where(a => a.Value.Buildable).Select(a => a.Key);
|
||||
}
|
||||
|
||||
public bool CanBuild(ActorInfo actor)
|
||||
{
|
||||
return Produceable.ContainsKey(actor) && Produceable[actor].Buildable;
|
||||
}
|
||||
|
||||
public virtual void Tick( Actor self )
|
||||
{
|
||||
while( Queue.Count > 0 && !BuildableItems().Any(b => b.Name == Queue[ 0 ].Item) )
|
||||
{
|
||||
self.Owner.PlayerActor.Trait<PlayerResources>().GiveCash(Queue[0].TotalCost - Queue[0].RemainingCost); // refund what's been paid so far.
|
||||
FinishProduction();
|
||||
}
|
||||
if( Queue.Count > 0 )
|
||||
Queue[ 0 ].Tick( PlayerResources, PlayerPower );
|
||||
}
|
||||
|
||||
public void ResolveOrder( Actor self, Order order )
|
||||
{
|
||||
switch( order.OrderString )
|
||||
{
|
||||
case "StartProduction":
|
||||
{
|
||||
var unit = Rules.Info[order.TargetString];
|
||||
var bi = unit.Traits.Get<BuildableInfo>();
|
||||
if (bi.Queue != Info.Type)
|
||||
return; /* Not built by this queue */
|
||||
|
||||
var cost = unit.Traits.Contains<ValuedInfo>() ? unit.Traits.Get<ValuedInfo>().Cost : 0;
|
||||
var time = GetBuildTime(order.TargetString);
|
||||
|
||||
if (!BuildableItems().Any(b => b.Name == order.TargetString))
|
||||
return; /* you can't build that!! */
|
||||
|
||||
bool hasPlayedSound = false;
|
||||
|
||||
for (var n = 0; n < order.TargetLocation.X; n++) // repeat count
|
||||
{
|
||||
BeginProduction(new ProductionItem(this, order.TargetString, (int)time, cost,
|
||||
() => self.World.AddFrameEndTask(
|
||||
_ =>
|
||||
{
|
||||
var isBuilding = unit.Traits.Contains<BuildingInfo>();
|
||||
if (!hasPlayedSound)
|
||||
{
|
||||
var eva = self.World.WorldActor.Info.Traits.Get<EvaAlertsInfo>();
|
||||
Sound.PlayToPlayer(order.Player, isBuilding ? eva.BuildingReadyAudio : eva.UnitReadyAudio);
|
||||
hasPlayedSound = true;
|
||||
}
|
||||
if (!isBuilding)
|
||||
BuildUnit(order.TargetString);
|
||||
})));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "PauseProduction":
|
||||
{
|
||||
if( Queue.Count > 0 && Queue[0].Item == order.TargetString )
|
||||
Queue[0].Paused = ( order.TargetLocation.X != 0 );
|
||||
break;
|
||||
}
|
||||
case "CancelProduction":
|
||||
{
|
||||
CancelProduction(order.TargetString);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int GetBuildTime(String unitString)
|
||||
{
|
||||
var unit = Rules.Info[unitString];
|
||||
if (unit == null || ! unit.Traits.Contains<BuildableInfo>())
|
||||
return 0;
|
||||
|
||||
if (Game.LobbyInfo.GlobalSettings.AllowCheats && self.Owner.PlayerActor.Trait<DeveloperMode>().FastBuild) return 0;
|
||||
var cost = unit.Traits.Contains<ValuedInfo>() ? unit.Traits.Get<ValuedInfo>().Cost : 0;
|
||||
var time = cost
|
||||
* Info.BuildSpeed
|
||||
* (25 * 60) /* frames per min */ /* todo: build acceleration, if we do that */
|
||||
/ 1000;
|
||||
return (int) time;
|
||||
}
|
||||
|
||||
protected void CancelProduction( string itemName )
|
||||
{
|
||||
if (Queue.Count == 0)
|
||||
return; // Nothing to do here
|
||||
|
||||
var lastIndex = Queue.FindLastIndex( a => a.Item == itemName );
|
||||
if (lastIndex > 0)
|
||||
Queue.RemoveAt(lastIndex);
|
||||
else if( lastIndex == 0 )
|
||||
{
|
||||
var item = Queue[0];
|
||||
self.Owner.PlayerActor.Trait<PlayerResources>().GiveCash(item.TotalCost - item.RemainingCost); // refund what's been paid so far.
|
||||
FinishProduction();
|
||||
}
|
||||
}
|
||||
|
||||
public void FinishProduction()
|
||||
{
|
||||
if (Queue.Count == 0) return;
|
||||
Queue.RemoveAt(0);
|
||||
}
|
||||
|
||||
protected void BeginProduction( ProductionItem item )
|
||||
{
|
||||
Queue.Add(item);
|
||||
}
|
||||
|
||||
protected static bool IsDisabledBuilding(Actor a)
|
||||
{
|
||||
return a.TraitsImplementing<IDisable>().Any(d => d.Disabled);
|
||||
}
|
||||
|
||||
protected virtual void BuildUnit( string name )
|
||||
{
|
||||
// queue lives on actor; is produced at same actor
|
||||
var sp = self.TraitsImplementing<Production>().Where(p => p.Info.Produces.Contains(Info.Type)).FirstOrDefault();
|
||||
if (sp != null && !IsDisabledBuilding(self) && sp.Produce(self, Rules.Info[ name ]))
|
||||
FinishProduction();
|
||||
}
|
||||
}
|
||||
|
||||
public class ProductionState
|
||||
{
|
||||
public bool Visible = false;
|
||||
public bool Buildable = false;
|
||||
public bool Sticky = false;
|
||||
}
|
||||
|
||||
public class ProductionItem
|
||||
{
|
||||
public readonly string Item;
|
||||
public readonly ProductionQueue Queue;
|
||||
public readonly int TotalTime;
|
||||
public readonly int TotalCost;
|
||||
public int RemainingTime { get; private set; }
|
||||
public int RemainingCost { get; private set; }
|
||||
|
||||
public bool Paused = false, Done = false;
|
||||
public Action OnComplete;
|
||||
int slowdown = 0;
|
||||
|
||||
public ProductionItem(ProductionQueue queue, string item, int time, int cost, Action onComplete)
|
||||
{
|
||||
if (time <= 0) time = 1;
|
||||
Item = item;
|
||||
RemainingTime = TotalTime = time;
|
||||
RemainingCost = TotalCost = cost;
|
||||
OnComplete = onComplete;
|
||||
Queue = queue;
|
||||
|
||||
Log.Write("debug", "new ProductionItem: {0} time={1} cost={2}", item, time, cost);
|
||||
}
|
||||
|
||||
public void Tick(PlayerResources pr, PowerManager pm)
|
||||
{
|
||||
if (Done)
|
||||
{
|
||||
if (OnComplete != null) OnComplete();
|
||||
return;
|
||||
}
|
||||
|
||||
if (Paused) return;
|
||||
|
||||
if (pm.PowerState != PowerState.Normal)
|
||||
{
|
||||
if (--slowdown <= 0)
|
||||
slowdown = Queue.Info.LowPowerSlowdown;
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
var costThisFrame = RemainingCost / RemainingTime;
|
||||
if (costThisFrame != 0 && !pr.TakeCash(costThisFrame)) return;
|
||||
RemainingCost -= costThisFrame;
|
||||
RemainingTime -= 1;
|
||||
if (RemainingTime > 0) return;
|
||||
|
||||
Done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
#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.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
class PrimaryBuildingInfo : TraitInfo<PrimaryBuilding> { }
|
||||
|
||||
class PrimaryBuilding : IIssueOrder, IResolveOrder, IOrderCursor, ITags
|
||||
{
|
||||
bool isPrimary = false;
|
||||
public bool IsPrimary { get { return isPrimary; } }
|
||||
|
||||
public IEnumerable<TagType> GetTags()
|
||||
{
|
||||
yield return (isPrimary) ? TagType.Primary : TagType.None;
|
||||
}
|
||||
|
||||
public int OrderPriority(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
{
|
||||
if (mi.Button == MouseButton.Right && underCursor == self)
|
||||
return new Order("PrimaryProducer", self);
|
||||
return null;
|
||||
}
|
||||
|
||||
public string CursorForOrder(Actor self, Order order)
|
||||
{
|
||||
return (order.OrderString == "PrimaryProducer") ? "deploy" : null;
|
||||
}
|
||||
|
||||
public void ResolveOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString == "PrimaryProducer")
|
||||
SetPrimaryProducer(self, !isPrimary);
|
||||
}
|
||||
|
||||
public void SetPrimaryProducer(Actor self, bool state)
|
||||
{
|
||||
if (state == false)
|
||||
{
|
||||
isPrimary = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Cancel existing primaries
|
||||
foreach (var p in self.Info.Traits.Get<ProductionInfo>().Produces)
|
||||
foreach (var b in self.World.Queries.OwnedBy[self.Owner]
|
||||
.WithTrait<PrimaryBuilding>()
|
||||
.Where(x => x.Trait.IsPrimary
|
||||
&& (x.Actor.Info.Traits.Get<ProductionInfo>().Produces.Contains(p))))
|
||||
b.Trait.SetPrimaryProducer(b.Actor, false);
|
||||
|
||||
isPrimary = true;
|
||||
|
||||
var eva = self.World.WorldActor.Info.Traits.Get<EvaAlertsInfo>();
|
||||
Sound.PlayToPlayer(self.Owner, eva.PrimaryBuildingSelected);
|
||||
}
|
||||
}
|
||||
|
||||
static class PrimaryExts
|
||||
{
|
||||
public static bool IsPrimaryBuilding(this Actor a)
|
||||
{
|
||||
var pb = a.TraitOrDefault<PrimaryBuilding>();
|
||||
return pb != null && pb.IsPrimary;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
#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.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using OpenRA.FileFormats;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
public class ProductionInfo : ITraitInfo
|
||||
{
|
||||
public readonly string[] Produces = { };
|
||||
|
||||
public virtual object Create(ActorInitializer init) { return new Production(this); }
|
||||
}
|
||||
|
||||
public class ExitInfo : TraitInfo<Exit>
|
||||
{
|
||||
public readonly float2 SpawnOffset = float2.Zero; // in px relative to CenterLocation
|
||||
public readonly int2 ExitCell = int2.Zero; // in cells relative to TopLeft
|
||||
public readonly int Facing = -1;
|
||||
}
|
||||
public class Exit {}
|
||||
|
||||
public class Production
|
||||
{
|
||||
public ProductionInfo Info;
|
||||
public Production(ProductionInfo info)
|
||||
{
|
||||
Info = info;
|
||||
}
|
||||
|
||||
public void DoProduction(Actor self, ActorInfo producee, ExitInfo exitinfo)
|
||||
{
|
||||
var newUnit = self.World.CreateActor(false, producee.Name, new TypeDictionary
|
||||
{
|
||||
new OwnerInit( self.Owner ),
|
||||
});
|
||||
|
||||
var exit = self.Location + exitinfo.ExitCell;
|
||||
var spawn = self.CenterLocation + exitinfo.SpawnOffset;
|
||||
|
||||
var move = newUnit.Trait<IMove>();
|
||||
var facing = newUnit.TraitOrDefault<IFacing>();
|
||||
|
||||
// Set the physical position of the unit as the exit cell
|
||||
move.SetPosition(newUnit,exit);
|
||||
var to = Util.CenterOfCell(exit);
|
||||
newUnit.CenterLocation = spawn;
|
||||
if (facing != null)
|
||||
facing.Facing = exitinfo.Facing < 0 ? Util.GetFacing(to - spawn, facing.Facing) : exitinfo.Facing;
|
||||
self.World.Add(newUnit);
|
||||
|
||||
// Animate the spawn -> exit transition
|
||||
var speed = move.MovementSpeedForCell(self, exit);
|
||||
var length = speed > 0 ? (int)( ( to - spawn ).Length*3 / speed ) : 0;
|
||||
newUnit.QueueActivity(new Activities.Drag(spawn, to, length));
|
||||
|
||||
// Log.Write("debug", "length={0} facing={1} exit={2} spawn={3}", length, facing.Facing, exit, spawn);
|
||||
|
||||
// For the target line
|
||||
var target = exit;
|
||||
var rp = self.TraitOrDefault<RallyPoint>();
|
||||
if (rp != null)
|
||||
{
|
||||
target = rp.rallyPoint;
|
||||
// Todo: Move implies unit has Mobile
|
||||
newUnit.QueueActivity(new Activities.Move(target, 1));
|
||||
}
|
||||
|
||||
if (newUnit.Owner == self.World.LocalPlayer)
|
||||
{
|
||||
self.World.AddFrameEndTask(w =>
|
||||
{
|
||||
var line = newUnit.TraitOrDefault<DrawLineToTarget>();
|
||||
if (line != null)
|
||||
line.SetTargetSilently(newUnit, Target.FromCell(target), Color.Green);
|
||||
});
|
||||
}
|
||||
|
||||
foreach (var t in self.TraitsImplementing<INotifyProduction>())
|
||||
t.UnitProduced(self, newUnit, exit);
|
||||
|
||||
Log.Write("debug", "{0} #{1} produced by {2} #{3}", newUnit.Info.Name, newUnit.ActorID, self.Info.Name, self.ActorID);
|
||||
}
|
||||
|
||||
public virtual bool Produce( Actor self, ActorInfo producee )
|
||||
{
|
||||
// Todo: remove assumption on Mobile;
|
||||
// required for 3-arg CanEnterCell
|
||||
//var mobile = newUnit.Trait<Mobile>();
|
||||
var mobileInfo = producee.Traits.Get<MobileInfo>();
|
||||
var bim = self.World.WorldActor.Trait<BuildingInfluence>();
|
||||
var uim = self.World.WorldActor.Trait<UnitInfluence>();
|
||||
|
||||
// Pick a spawn/exit point pair
|
||||
// Todo: Reorder in a synced random way
|
||||
foreach (var s in self.Info.Traits.WithInterface<ExitInfo>())
|
||||
if( Mobile.CanEnterCell( mobileInfo, self.World, uim, bim, self.Location + s.ExitCell,self,true ) )
|
||||
{
|
||||
DoProduction(self, producee, s);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
#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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Graphics;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
class RallyPointInfo : ITraitInfo, ITraitPrerequisite<RenderSimpleInfo>
|
||||
{
|
||||
public readonly int[] RallyPoint = { 1, 3 };
|
||||
|
||||
public object Create(ActorInitializer init) { return new RallyPoint(init.self); }
|
||||
}
|
||||
|
||||
public class RallyPoint : IRender, IIssueOrder, IResolveOrder, ITick
|
||||
{
|
||||
[Sync]
|
||||
public int2 rallyPoint;
|
||||
public Animation anim;
|
||||
|
||||
public RallyPoint(Actor self)
|
||||
{
|
||||
var info = self.Info.Traits.Get<RallyPointInfo>();
|
||||
rallyPoint = self.Location + new int2(info.RallyPoint[0], info.RallyPoint[1]);
|
||||
anim = new Animation("flagfly");
|
||||
anim.PlayRepeating("idle");
|
||||
}
|
||||
|
||||
public IEnumerable<Renderable> Render(Actor self)
|
||||
{
|
||||
if (self.Owner == self.World.LocalPlayer && self.World.Selection.Actors.Contains(self))
|
||||
yield return Util.Centered(self,
|
||||
anim.Image, Util.CenterOfCell(rallyPoint));
|
||||
}
|
||||
|
||||
public int OrderPriority(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor)
|
||||
{
|
||||
if (mi.Button == MouseButton.Left || underCursor != null) return null;
|
||||
return new Order("SetRallyPoint", self, xy);
|
||||
}
|
||||
|
||||
public void ResolveOrder( Actor self, Order order )
|
||||
{
|
||||
if( order.OrderString == "SetRallyPoint" )
|
||||
rallyPoint = order.TargetLocation;
|
||||
}
|
||||
|
||||
public void Tick(Actor self) { anim.Tick(); }
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
#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.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.Effects;
|
||||
using OpenRA.GameRules;
|
||||
using OpenRA.Traits.Activities;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
public class RepairableBuildingInfo : ITraitInfo, ITraitPrerequisite<HealthInfo>
|
||||
{
|
||||
public readonly float RepairPercent = 0.2f;
|
||||
public readonly float RepairRate = 0.016f;
|
||||
public readonly int RepairStep = 7;
|
||||
public object Create(ActorInitializer init) { return new RepairableBuilding(init.self, this); }
|
||||
}
|
||||
|
||||
public class RepairableBuilding : ITick, IResolveOrder
|
||||
{
|
||||
[Sync]
|
||||
bool isRepairing = false;
|
||||
|
||||
Health Health;
|
||||
RepairableBuildingInfo Info;
|
||||
public RepairableBuilding(Actor self, RepairableBuildingInfo info)
|
||||
{
|
||||
Health = self.Trait<Health>();
|
||||
Info = info;
|
||||
}
|
||||
|
||||
public void ResolveOrder(Actor self, Order order)
|
||||
{
|
||||
if (order.OrderString == "Repair")
|
||||
{
|
||||
isRepairing = !isRepairing;
|
||||
}
|
||||
}
|
||||
|
||||
int remainingTicks;
|
||||
public void Tick(Actor self)
|
||||
{
|
||||
if (!isRepairing) return;
|
||||
|
||||
if (remainingTicks == 0)
|
||||
{
|
||||
var csv = self.Info.Traits.GetOrDefault<CustomSellValueInfo>();
|
||||
var buildingValue = csv != null ? csv.Value : self.Info.Traits.Get<ValuedInfo>().Cost;
|
||||
|
||||
var costPerHp = (Info.RepairPercent * buildingValue) / Health.MaxHP;
|
||||
var hpToRepair = Math.Min(Info.RepairStep, Health.MaxHP - Health.HP);
|
||||
var cost = (int)Math.Ceiling(costPerHp * hpToRepair);
|
||||
if (!self.Owner.PlayerActor.Trait<PlayerResources>().TakeCash(cost))
|
||||
{
|
||||
remainingTicks = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
self.World.AddFrameEndTask(w => w.Add(new RepairIndicator(self)));
|
||||
self.InflictDamage(self, -hpToRepair, null);
|
||||
if (Health.DamageState == DamageState.Undamaged)
|
||||
{
|
||||
isRepairing = false;
|
||||
return;
|
||||
}
|
||||
remainingTicks = (int)(Info.RepairRate * 60 * 25);
|
||||
}
|
||||
else
|
||||
--remainingTicks;
|
||||
}
|
||||
}
|
||||
public class AllowsBuildingRepairInfo : TraitInfo<AllowsBuildingRepair> {}
|
||||
public class AllowsBuildingRepair {}
|
||||
|
||||
}
|
||||
@@ -18,7 +18,7 @@ using OpenRA.Widgets;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
class UiOverlay
|
||||
public class UiOverlay
|
||||
{
|
||||
Sprite buildOk, buildBlocked, unitDebug;
|
||||
|
||||
@@ -79,7 +79,7 @@ namespace OpenRA
|
||||
}
|
||||
}
|
||||
|
||||
static class LineBuildUtils
|
||||
public static class LineBuildUtils
|
||||
{
|
||||
public static IEnumerable<int2> GetLineBuildCells(World world, int2 location, string name, BuildingInfo bi)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user