Skip to content

Instantly share code, notes, and snippets.

@penev92
Last active November 15, 2015 21:11
Show Gist options
  • Save penev92/57d177825a6640f687e0 to your computer and use it in GitHub Desktop.
Save penev92/57d177825a6640f687e0 to your computer and use it in GitHub Desktop.
#region Copyright & License Information
/*
* Copyright 2007-2015 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 COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using OpenRA.Activities;
using OpenRA.Mods.Common.Activities;
using OpenRA.Mods.Common.Orders;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits
{
enum DeployState { Undeployed, Deploying, Deployed }
public class DeployToUpgradeInfo : ITraitInfo, Requires<UpgradeManagerInfo>
{
[UpgradeGrantedReference]
[Desc("An upgrade that is granted while the actor is not deployed" +
" or in the process of deploying/undeploying.")]
public readonly string[] UndeployedUpgrades = { };
[UpgradeGrantedReference, FieldLoader.Require]
[Desc("The upgrades to grant after deploying and revoke before undeploying.")]
public readonly string[] DeployedUpgrades = { };
[Desc("The terrain types that this actor can deploy on to receive these upgrades. " +
"Leave empty to allow any.")]
public readonly HashSet<string> AllowedTerrainTypes = new HashSet<string>();
[Desc("Can this actor deploy on slopes?")]
public readonly bool CanDeployOnRamps = false;
[Desc("Cursor to display when able to (un)deploy the actor.")]
public readonly string DeployCursor = "deploy";
[Desc("Cursor to display when unable to (un)deploy the actor.")]
public readonly string DeployBlockedCursor = "deploy-blocked";
[SequenceReference, Desc("Animation to play for deploying/undeploying.")]
public readonly string DeployAnimation = null;
[Desc("Facing that the actor must face before deploying. Set to -1 to deploy regardless of facing.")]
public readonly int Facing = -1;
[Desc("Sound to play when deploying.")]
public readonly string DeploySound = null;
[Desc("Sound to play when undeploying.")]
public readonly string UndeploySound = null;
public object Create(ActorInitializer init) { return new DeployToUpgrade(init.Self, this); }
}
public class DeployToUpgrade : IResolveOrder, IIssueOrder, INotifyCreated
{
readonly Actor self;
readonly DeployToUpgradeInfo info;
readonly UpgradeManager manager;
readonly bool checkTerrainType;
readonly bool canTurn;
readonly Lazy<ISpriteBody> body;
DeployState deployState;
public DeployToUpgrade(Actor self, DeployToUpgradeInfo info)
{
this.self = self;
this.info = info;
manager = self.Trait<UpgradeManager>();
checkTerrainType = info.AllowedTerrainTypes.Count > 0;
canTurn = self.Info.HasTraitInfo<IFacingInfo>();
body = Exts.Lazy(self.TraitOrDefault<ISpriteBody>);
}
public void Created(Actor self)
{
GrantUndeployedUpgrades();
}
public IEnumerable<IOrderTargeter> Orders
{
get { yield return new DeployOrderTargeter("DeployToUpgrade", 5,
() => IsOnValidTerrain() ? info.DeployCursor : info.DeployBlockedCursor); }
}
public Order IssueOrder(Actor self, IOrderTargeter order, Target target, bool queued)
{
if (order.OrderID == "DeployToUpgrade")
return new Order(order.OrderID, self, queued);
return null;
}
public void ResolveOrder(Actor self, Order order)
{
if (order.OrderString != "DeployToUpgrade" || deployState == DeployState.Deploying)
return;
if (!IsOnValidTerrain())
return;
if (deployState == DeployState.Deployed)
{
self.CancelActivity();
self.QueueActivity(new CallFunc(Undeploy));
}
else if (deployState == DeployState.Undeployed)
{
// Turn to the required facing.
if (info.Facing != -1 && canTurn)
self.QueueActivity(new Turn(self, info.Facing));
self.QueueActivity(new CallFunc(Deploy));
}
}
bool IsOnValidTerrain()
{
return IsOnValidTerrainType() && IsOnValidRampType();
}
bool IsOnValidTerrainType()
{
if (!self.World.Map.Contains(self.Location))
return false;
if (!checkTerrainType)
return true;
var tileSet = self.World.TileSet;
var tiles = self.World.Map.MapTiles.Value;
var terrainType = tileSet[tileSet.GetTerrainIndex(tiles[self.Location])].Type;
return info.AllowedTerrainTypes.Contains(terrainType);
}
bool IsOnValidRampType()
{
if (info.CanDeployOnRamps)
return true;
var ramp = 0;
if (self.World.Map.Contains(self.Location))
{
var tile = self.World.Map.MapTiles.Value[self.Location];
var ti = self.World.TileSet.GetTileInfo(tile);
if (ti != null)
ramp = ti.RampType;
}
return ramp == 0;
}
/// <summary>Play deploy sound and animation.</summary>
void Deploy()
{
if (deployState != DeployState.Undeployed)
return;
if (!string.IsNullOrEmpty(info.DeploySound))
Game.Sound.Play(info.DeploySound, self.CenterPosition);
// Revoke upgrades that are used while undeployed.
RevokeUndeployedUpgrades();
// If there is no animation to play just grant the upgrades that are used while deployed.
if (string.IsNullOrEmpty(info.DeployAnimation) || body.Value == null)
GrantDeployedUpgrades();
else
{
// Play the deploy animation and then grant the upgrades.
body.Value.PlayCustomAnimation(self, info.DeployAnimation, GrantDeployedUpgrades);
}
}
/// <summary>Play undeploy sound and animation and after that revoke the upgrades.</summary>
void Undeploy()
{
// Something went wrong, most likely due to deploy order spam and the fact that this is a delayed action.
if (deployState != DeployState.Deployed)
return;
if (!string.IsNullOrEmpty(info.UndeploySound))
Game.Sound.Play(info.UndeploySound, self.CenterPosition);
RevokeDeployedUpgrades();
// If there is a deploy animation to be played, play it
// and grant the upgrades that are used while undeployed.
if (!string.IsNullOrEmpty(info.DeployAnimation))
body.Value.PlayCustomAnimationBackwards(self, info.DeployAnimation, GrantUndeployedUpgrades);
else
GrantUndeployedUpgrades();
}
void GrantDeployedUpgrades()
{
foreach (var up in info.DeployedUpgrades)
manager.GrantUpgrade(self, up, this);
deployState = DeployState.Deployed;
}
void RevokeDeployedUpgrades()
{
foreach (var up in info.DeployedUpgrades)
manager.RevokeUpgrade(self, up, this);
deployState = DeployState.Deploying;
}
void GrantUndeployedUpgrades()
{
if (info.UndeployedUpgrades.Length == 0)
return;
foreach (var up in info.UndeployedUpgrades)
manager.GrantUpgrade(self, up, this);
deployState = DeployState.Undeployed;
}
void RevokeUndeployedUpgrades()
{
if (info.UndeployedUpgrades.Length == 0)
return;
foreach (var up in info.UndeployedUpgrades)
manager.RevokeUpgrade(self, up, this);
deployState = DeployState.Deploying;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment