using System; using Goap.Agent.Core; using Goap.Agent.Runtime; using Goap.Core; namespace Goap.Runtime { // Backwards compatability for v2 actions public abstract class GoapActionBase : GoapActionBase where TActionData : IActionData, new() { } public abstract class GoapActionBase : AgentActionBase, IGoapAction where TActionData : IActionData, new() where TActionProperties : class, IActionProperties, new() { public IActionConfig Config { get; private set; } public Guid Guid { get; } = Guid.NewGuid(); public IEffect[] Effects => this.Config.Effects; public ICondition[] Conditions => this.Config.Conditions; public override TActionProperties Properties => this.Config.Properties as TActionProperties; /// /// Sets the configuration for the action. /// /// The action configuration. public void SetConfig(IActionConfig config) { this.Config = config; } [Obsolete("Use GetCost(IActionReceiver agent, IComponentReference references, ITarget target) instead")] public virtual float GetCost(IActionReceiver agent, IComponentReference references) { return this.Config.BaseCost; } /// /// Returns the cost of the action. /// /// The action receiver. /// The component references. /// The target of the action. /// The cost of the action. public virtual float GetCost(IActionReceiver agent, IComponentReference references, ITarget target) { return this.Config.BaseCost; } /// /// Gets the move mode for the action. /// /// The agent. /// The move mode for the action. public ActionMoveMode GetMoveMode(IMonoAgent agent) { return this.Config.MoveMode; } /// /// Gets the stopping distance for the action. /// /// The stopping distance for the action. public virtual float GetStoppingDistance() { return this.Config.StoppingDistance; } /// /// Determines whether the agent is in range for the action. /// /// The agent. /// The distance to the target. /// The action data. /// The component references. /// True if the agent is in range, otherwise false. public virtual bool IsInRange(IMonoAgent agent, float distance, IActionData data, IComponentReference references) { return distance <= this.GetStoppingDistance(); } /// /// Determines whether the action is valid. Don't override this method, use IsValid(IActionReceiver agent, TActionData /// data) instead. /// /// The action receiver. /// The action data. /// True if the action is valid, otherwise false. public bool IsValid(IActionReceiver agent, IActionData data) { if (agent.ActionProvider is not GoapActionProvider goapAgent) return false; if (this.Config.ValidateConditions && !goapAgent.AgentType.AllConditionsMet(goapAgent, this)) { agent.Logger.Warning($"Conditions not met: {this.Config.Name}"); return false; } if (this.Config.ValidateTarget && this.Config.RequiresTarget) { if (data.Target == null) { agent.Logger.Warning($"No target found for: {this.Config.Name}"); return false; } if (!data.Target.IsValid()) { agent.Logger.Warning($"Target became invalid: {this.Config.Name}"); return false; } } return this.IsValid(agent, (TActionData) data); } /// /// Determines whether the action is valid with the specified action data. This is the method you should overwrite (in /// most instances). /// /// The action receiver. /// The action data. /// True if the action is valid, otherwise false. public virtual bool IsValid(IActionReceiver agent, TActionData data) { return true; } /// /// Determines whether the action is executable. /// /// The action receiver. /// Whether the conditions are met. /// True if the action is executable, otherwise false. public bool IsExecutable(IActionReceiver agent, bool conditionsMet) { var goapAgent = agent.Injector.GetCachedComponent(); if (goapAgent == null) return false; if (!conditionsMet) return false; if (this.Config.RequiresTarget && goapAgent.WorldData.GetTarget(this) == null) return false; return true; } /// /// Determines whether the action is enabled. This is used by the planner. /// /// The action receiver. /// True if the action is enabled, otherwise false. public bool IsEnabled(IActionReceiver agent) { return this.IsEnabled(agent, agent.Injector); } /// /// Determines whether the action is enabled. This is used by the planner. /// /// The action receiver. /// The component references. /// True if the action is enabled, otherwise false. public virtual bool IsEnabled(IActionReceiver receiver, IComponentReference references) { return !receiver.ActionProvider.IsDisabled(this); } [Obsolete("Use Enable(IActionReceiver receiver) instead")] public void Enable() { throw new Exception("Use Enable(IActionReceiver receiver) instead"); } /// /// Enables the action. /// public void Enable(IActionReceiver receiver) { receiver.ActionProvider.Enable(this); } [Obsolete("Use Disable(IActionReceiver receiver, IActionDisabler disabler) instead")] public void Disable(IActionDisabler disabler) { throw new Exception("Use Disable(IActionReceiver receiver, IActionDisabler disabler) instead"); } /// /// Disables the action. /// /// The action receiver /// The action disabler. public void Disable(IActionReceiver receiver, IActionDisabler disabler) { receiver.ActionProvider.Disable(this, disabler); } } }