* Data-driven NPC behaviors * Nuked AiLogicProcessor * BehaviorSets are now all stored in yaml (might try making actions also yaml someday) * Added a test to validate all BehaviorSets * Might also try pooling actions in the future to reduce allocs but that'll be way down the line (cough physics). * Forgot to re-add sorting nothing suss * Remove last references * Proper vector2i serialization for tile atmos (#3266) * update map files * update submodule Co-authored-by: cyclowns <cyclowns@protonmail.ch> * Remove weird "S" jumpsuit from existence (#3267) * Change character names to use datasets prototypes (#3259) * Remove old name lists in .txts * Fix tests * LATEST MASTER TECHNOLOGY * Converts AdminMenu to partially use XAML (#3231) * Cleans up Hydroponics content. (#3025) * Adds to IgnoredComponents.cs * Jackboots * Half Done * Moved to diff PR * Everything functional * Fixed Sprays * Nice * Fixed * Update submodule * Fix tests Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com> * Stacked sprite visualizer (#3096) * Add Stack Visualizer * Add cigarette pack resources Adds transparent layers for visualizing cigarettes * Add Bag Open/Close Visualizer So storage opened in inventory can have different icons when opened or closed. * Create a component that only enumerates single item Used for creating stuff like matchbox, or cigarettes. As a bonus. It will only update stack visualizer for that particullar item. * Refactoring stuff * Fix other usage of stack in Resources * Add docs * Apply suggestions from code review Apply metalgearsloth suggestions Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> * Applied suggestions from metalgearsloth * Changed SingleItemStorageComponent to StorageCounterComponent Difference. New component doesn't spawn items, merely counts them. * Refactored StackVisualizer * Fix breakage with master * Update Resources/Prototypes/Entities/Objects/Consumable/fancy.yml Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> * Update with MGS suggestions Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> * ApcNet updating fix (#3078) * GridPowerComponent * ApcNet Powered update bugfix * PowerTest fix * Add GridPower to Saltern * test fix * Update canceling cleanup * code cleanup * nullable & code cleanup for test * undo power test nullable * Replaces GridPowerSystem with ApcNetSystem * build fix * Update Content.Server/GameObjects/EntitySystems/ApcNetSystem.cs Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> * Change all XAML to use spacestation14.io namespace (#3277) * fix pizzaboxes (#3291) Co-authored-by: cyclowns <cyclowns@protonmail.ch> * Spikes fix reopened (#3203) * DoAfter, dead and stun check, DragDropOn * Not ignored anymore * Copied comment deleted * Herbert's an ass * Woops Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com> * Make component states dependant on the player getting them (#3280) * Make component states dependant on the player getting them Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com> * Updated submodule to v0.3.7. Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com> Co-authored-by: Acruid <shatter66@gmail.com> * Hoe fix (#3296) * Initial (#3297) * Sort reagent dispenser entries (#3272) * Sort reagent dispenser entries Saves manually doing it. * zumzum's suggestion Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com> * Made firelocks damageable & destructible (#3303) * Move job priority enum parity test ot unit tests (#3300) * Spill hand contents when dropping them in a fall (#3304) * Spill hand contents when dropping them due to falling down * Better approach * cleanup * grammar * stupid * PauseManager moved to Shared (#3288) * Namespace changes for moving IPauseManager to shared. * Namespace changes for moving ITimerManager from Timers to Timing. * Rebase Fixes. * Update engine submodule to v0.3.8 * Improves kick, teleport and ban menus (#3312) * Fix the admin panel not showing the account name (#3322) * Fix name serialization for secret stashes (#3301) * Fix name serialization for secret stashes * Fix old usages of secret part name * Separate ghost warp message into two (#3310) * Separate ghost warp message into two * Remove redundant arguments * Address reviews * Move properties up * Add health overlay and a command to toggle it (#3278) * Add health overlay bar and a command to toggle it * Remove empty line * Content PR for YAML hot reloading (#3319) * Content PR for YAML hot reloading * Add CanAdminReloadPrototypes (host permission) * IndexedPrototype fixes * Update RobustToolbox * Update RobustToolbox * Add an unconspicuous, meaningless and in no way motivated by any external force XML doc to buckle component * Update RobustToolbox * Update submodule to v0.3.12. * Removed unused using statements that prevented compiling. Removed references to IIndexedPrototype that does not exist anymore in the engine. Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com> Co-authored-by: mirrorcult <notzombiedude@gmail.com> Co-authored-by: cyclowns <cyclowns@protonmail.ch> Co-authored-by: Visne <39844191+Visne@users.noreply.github.com> Co-authored-by: DrSmugleaf <DrSmugleaf@users.noreply.github.com> Co-authored-by: Leo <lzimann@users.noreply.github.com> Co-authored-by: Swept <sweptwastaken@protonmail.com> Co-authored-by: Ygg01 <y.laughing.man.y@gmail.com> Co-authored-by: collinlunn <60152240+collinlunn@users.noreply.github.com> Co-authored-by: komunre <49118681+komunre@users.noreply.github.com> Co-authored-by: Acruid <shatter66@gmail.com> Co-authored-by: Peptide90 <78795277+Peptide90@users.noreply.github.com> Co-authored-by: Clyybber <darkmine956@gmail.com>
140 lines
5.6 KiB
C#
140 lines
5.6 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using Content.Server.AI.Operators;
|
|
using Content.Server.AI.WorldState;
|
|
using Content.Server.AI.WorldState.States.Utility;
|
|
using Robust.Shared.GameObjects;
|
|
using Robust.Shared.Utility;
|
|
|
|
namespace Content.Server.AI.Utility.Actions
|
|
{
|
|
/// <summary>
|
|
/// The same DSE can be used across multiple actions.
|
|
/// </summary>
|
|
public abstract class UtilityAction : IAiUtility
|
|
{
|
|
/// <summary>
|
|
/// If we're trying to find a new action can we replace a currently running one with one of the same type.
|
|
/// e.g. If you're already wandering you don't want to replace it with a different wander.
|
|
/// </summary>
|
|
public virtual bool CanOverride => false;
|
|
|
|
/// <summary>
|
|
/// This is used to sort actions; if there's a top-tier action available we won't bother checking the lower tiers.
|
|
/// Threshold doesn't necessarily mean we'll do an action at a higher threshold;
|
|
/// if it's really un-optimal (i.e. low score) then we'll also check lower tiers
|
|
/// </summary>
|
|
public virtual float Bonus { get; set; } = IdleBonus;
|
|
// For GW2 they had the bonuses close together but IMO it feels better when they're more like discrete tiers.
|
|
|
|
// These are just baselines to make mass-updates easier; actions can do whatever
|
|
// e.g. if you want shooting a gun to be considered before picking up a gun you could + 1.0f it or w/e
|
|
public const float IdleBonus = 1.0f;
|
|
public const float NormalBonus = 5.0f;
|
|
public const float NeedsBonus = 10.0f;
|
|
public const float CombatPrepBonus = 20.0f;
|
|
public const float CombatBonus = 30.0f;
|
|
public const float DangerBonus = 50.0f;
|
|
|
|
public IEntity Owner { get; set; }
|
|
|
|
/// <summary>
|
|
/// All the considerations are multiplied together to get the final score; a consideration of 0.0 means the action is not possible.
|
|
/// Ideally you put anything that's easy to assess and can cause an early-out first just so the rest aren't evaluated.
|
|
/// </summary>
|
|
/// Uses Func<float> as you don't want to eval the later considerations unless necessary, but we also need the total count
|
|
/// so can't use IEnumerable
|
|
protected abstract IReadOnlyCollection<Func<float>> GetConsiderations(Blackboard context);
|
|
|
|
/// <summary>
|
|
/// To keep the operators simple we can chain them together here, e.g. move to can be chained with other operators.
|
|
/// </summary>
|
|
public Queue<AiOperator> ActionOperators { get; protected set; }
|
|
|
|
/// <summary>
|
|
/// Sometimes we may need to set the target for an action or the likes.
|
|
/// This is mainly useful for expandable states so each one can have a separate target.
|
|
/// </summary>
|
|
/// <param name="context"></param>
|
|
protected virtual void UpdateBlackboard(Blackboard context) {}
|
|
|
|
// Needs to be able to be instantiated without args via typefactory.
|
|
public UtilityAction() {}
|
|
|
|
public virtual void Shutdown() {}
|
|
|
|
/// <summary>
|
|
/// If this action is chosen then setup the operators to run. This also allows for operators to be reset.
|
|
/// </summary>
|
|
public abstract void SetupOperators(Blackboard context);
|
|
|
|
// Call the task's operator with Execute and get the outcome
|
|
public Outcome Execute(float frameTime)
|
|
{
|
|
if (!ActionOperators.TryPeek(out var op))
|
|
{
|
|
return Outcome.Success;
|
|
}
|
|
|
|
op.Startup();
|
|
var outcome = op.Execute(frameTime);
|
|
|
|
switch (outcome)
|
|
{
|
|
case Outcome.Success:
|
|
op.Shutdown(outcome);
|
|
ActionOperators.Dequeue();
|
|
break;
|
|
case Outcome.Continuing:
|
|
break;
|
|
case Outcome.Failed:
|
|
op.Shutdown(outcome);
|
|
ActionOperators.Clear();
|
|
break;
|
|
default:
|
|
throw new ArgumentOutOfRangeException();
|
|
}
|
|
|
|
return outcome;
|
|
}
|
|
|
|
/// <summary>
|
|
/// AKA the Decision Score Evaluator (DSE)
|
|
/// This is where the magic happens
|
|
/// </summary>
|
|
/// <param name="context"></param>
|
|
/// <param name="min"></param>
|
|
/// <returns></returns>
|
|
public float GetScore(Blackboard context, float min)
|
|
{
|
|
UpdateBlackboard(context);
|
|
var considerations = GetConsiderations(context);
|
|
DebugTools.Assert(considerations.Count > 0);
|
|
|
|
// Overall structure is based on Building a better centaur
|
|
// Ideally we should early-out each action as cheaply as possible if it's not valid, thus
|
|
// the finalScore can only go down over time.
|
|
|
|
var finalScore = 1.0f;
|
|
var minThreshold = min / Bonus;
|
|
context.GetState<ConsiderationState>().SetValue(considerations.Count);
|
|
|
|
foreach (var consideration in considerations)
|
|
{
|
|
var score = consideration.Invoke();
|
|
finalScore *= score;
|
|
DebugTools.Assert(!float.IsNaN(score));
|
|
|
|
// The score can only ever go down from each consideration so if we're below minimum no point continuing.
|
|
if (0.0f >= finalScore || finalScore < minThreshold) {
|
|
return 0.0f;
|
|
}
|
|
}
|
|
|
|
DebugTools.Assert(finalScore <= 1.0f);
|
|
|
|
return finalScore * Bonus;
|
|
}
|
|
}
|
|
}
|