Add conditional spawning component (#1069)

* Add conditional spawning component

* Remove null checks

* Remove leftover return

* Properly spawn items when game rule gets added

* Fix duplicate uids in saltern

* GameRules returns IEnumerable using yield.
This commit is contained in:
Víctor Aguilera Puerto
2020-06-05 19:42:43 +02:00
committed by GitHub
parent 470f81fca1
commit e1df008bce
11 changed files with 429 additions and 1 deletions

View File

@@ -162,6 +162,9 @@ namespace Content.Client
"Tool", "Tool",
"TilePrying", "TilePrying",
"RandomToolColor", "RandomToolColor",
"ConditionalSpawner",
"PottedPlantHide",
"SecureEntityStorage",
}; };
foreach (var ignoreName in registerIgnore) foreach (var ignoreName in registerIgnore)

View File

@@ -19,6 +19,12 @@ namespace Content.IntegrationTests
remove { } remove { }
} }
public event Action<GameRuleAddedEventArgs> OnRuleAdded
{
add{ }
remove { }
}
public void Initialize() public void Initialize()
{ {
} }
@@ -64,6 +70,11 @@ namespace Content.IntegrationTests
return new T(); return new T();
} }
public bool HasGameRule(Type type)
{
return false;
}
public void RemoveGameRule(GameRule rule) public void RemoveGameRule(GameRule rule)
{ {
} }

View File

@@ -0,0 +1,104 @@
using System;
using System.Collections.Generic;
using Content.Server.GameTicking;
using Content.Server.Interfaces.GameTicking;
using NFluidsynth;
using Robust.Server.Interfaces.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Random;
using Robust.Shared.Interfaces.Reflection;
using Robust.Shared.IoC;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
using SQLitePCL;
using Logger = Robust.Shared.Log.Logger;
namespace Content.Server.GameObjects.Components.Markers
{
[RegisterComponent]
public class ConditionalSpawnerComponent : Component, IMapInit
{
public override string Name => "ConditionalSpawner";
#pragma warning disable 649
[Dependency] private IGameTicker _gameTicker;
[Dependency] private IReflectionManager _reflectionManager;
[Dependency] private IEntityManager _entityManager;
[Dependency] private IRobustRandom _robustRandom;
#pragma warning restore 649
[ViewVariables(VVAccess.ReadWrite)]
public List<string> Prototypes { get; set; } = new List<string>();
[ViewVariables(VVAccess.ReadWrite)]
private List<string> _gameRules = new List<string>();
[ViewVariables(VVAccess.ReadWrite)]
public float Chance { get; set; } = 1.0f;
public IEnumerable<Type> GameRules
{
get
{
foreach (var rule in _gameRules)
{
yield return _reflectionManager.GetType(rule);
}
}
}
public override void ExposeData(ObjectSerializer serializer)
{
base.ExposeData(serializer);
serializer.DataField(this, x => Prototypes, "prototypes", new List<string>());
serializer.DataField(this, x => Chance, "chance", 1.0f);
serializer.DataField(this, x => _gameRules, "gameRules", new List<string>());
}
private void RuleAdded(GameRuleAddedEventArgs obj)
{
if(_gameRules.Contains(obj.GameRule.GetType().Name))
Spawn();
}
private void TrySpawn()
{
if (_gameRules.Count == 0)
{
Spawn();
return;
}
foreach (var rule in GameRules)
{
if (!_gameTicker.HasGameRule(rule)) continue;
Spawn();
return;
}
}
private void Spawn()
{
if (Chance != 1.0f && !_robustRandom.Prob(Chance))
return;
if (Prototypes.Count == 0)
{
Logger.Warning($"Prototype list in ConditionalSpawnComponent is empty! Entity: {Owner}");
return;
}
_entityManager.SpawnEntity(_robustRandom.Pick(Prototypes), Owner.Transform.GridPosition);
}
public void MapInit()
{
_gameTicker.OnRuleAdded += RuleAdded;
TrySpawn();
}
}
}

View File

@@ -98,6 +98,7 @@ namespace Content.Server.GameTicking
} }
public event Action<GameRunLevelChangedEventArgs> OnRunLevelChanged; public event Action<GameRunLevelChangedEventArgs> OnRunLevelChanged;
public event Action<GameRuleAddedEventArgs> OnRuleAdded;
private TimeSpan LobbyDuration => private TimeSpan LobbyDuration =>
TimeSpan.FromSeconds(_configurationManager.GetCVar<int>("game.lobbyduration")); TimeSpan.FromSeconds(_configurationManager.GetCVar<int>("game.lobbyduration"));
@@ -327,9 +328,25 @@ namespace Content.Server.GameTicking
_gameRules.Add(instance); _gameRules.Add(instance);
instance.Added(); instance.Added();
OnRuleAdded?.Invoke(new GameRuleAddedEventArgs(instance));
return instance; return instance;
} }
public bool HasGameRule(Type t)
{
if (t == null || !t.IsAssignableFrom(typeof(GameRule)))
return false;
foreach (var rule in _gameRules)
{
if (rule.GetType().Equals(t))
return true;
}
return false;
}
public void RemoveGameRule(GameRule rule) public void RemoveGameRule(GameRule rule)
{ {
if (_gameRules.Contains(rule)) return; if (_gameRules.Contains(rule)) return;
@@ -786,4 +803,14 @@ The current game mode is: [color=white]{0}[/color].
public GameRunLevel OldRunLevel { get; } public GameRunLevel OldRunLevel { get; }
public GameRunLevel NewRunLevel { get; } public GameRunLevel NewRunLevel { get; }
} }
public class GameRuleAddedEventArgs : EventArgs
{
public GameRule GameRule { get; }
public GameRuleAddedEventArgs(GameRule rule)
{
GameRule = rule;
}
}
} }

View File

@@ -15,6 +15,7 @@ namespace Content.Server.Interfaces.GameTicking
GameRunLevel RunLevel { get; } GameRunLevel RunLevel { get; }
event Action<GameRunLevelChangedEventArgs> OnRunLevelChanged; event Action<GameRunLevelChangedEventArgs> OnRunLevelChanged;
event Action<GameRuleAddedEventArgs> OnRuleAdded;
void Initialize(); void Initialize();
void Update(FrameEventArgs frameEventArgs); void Update(FrameEventArgs frameEventArgs);
@@ -34,6 +35,7 @@ namespace Content.Server.Interfaces.GameTicking
// GameRule system. // GameRule system.
T AddGameRule<T>() where T : GameRule, new(); T AddGameRule<T>() where T : GameRule, new();
bool HasGameRule(Type type);
void RemoveGameRule(GameRule rule); void RemoveGameRule(GameRule rule);
IEnumerable<GameRule> ActiveGameRules { get; } IEnumerable<GameRule> ActiveGameRules { get; }

View File

@@ -23219,4 +23219,186 @@ entities:
pos: 0.5,9.5 pos: 0.5,9.5
rot: -1.5707963267948966 rad rot: -1.5707963267948966 rad
type: Transform type: Transform
- uid: 2987
type: SuspicionMeleeSpawner
components:
- parent: 0
pos: -20.5,1.5
rot: -1.5707963267948966 rad
type: Transform
- uid: 2988
type: SuspicionMeleeSpawner
components:
- parent: 0
pos: -28.5,13.5
rot: -1.5707963267948966 rad
type: Transform
- uid: 2989
type: SuspicionMeleeSpawner
components:
- parent: 0
pos: -29.5,10.5
rot: -1.5707963267948966 rad
type: Transform
- uid: 2990
type: SuspicionMeleeSpawner
components:
- parent: 0
pos: -0.5,0.5
rot: -1.5707963267948966 rad
type: Transform
- uid: 2991
type: SuspicionMeleeSpawner
components:
- parent: 0
pos: 6.5,8.5
rot: -1.5707963267948966 rad
type: Transform
- uid: 2992
type: SuspicionMeleeSpawner
components:
- parent: 0
pos: 10.5,8.5
rot: -1.5707963267948966 rad
type: Transform
- uid: 2993
type: SuspicionMeleeSpawner
components:
- parent: 0
pos: 15.5,8.5
rot: -1.5707963267948966 rad
type: Transform
- uid: 2994
type: SuspicionMeleeSpawner
components:
- parent: 0
pos: 10.5,-13.5
rot: -1.5707963267948966 rad
type: Transform
- uid: 2995
type: SuspicionMeleeSpawner
components:
- parent: 0
pos: 18.5,-24.5
rot: -1.5707963267948966 rad
type: Transform
- uid: 2996
type: SuspicionMeleeSpawner
components:
- parent: 0
pos: 17.5,-20.5
rot: -1.5707963267948966 rad
type: Transform
- uid: 2997
type: SuspicionMeleeSpawner
components:
- parent: 0
pos: 22.5,-4.5
rot: -1.5707963267948966 rad
type: Transform
- uid: 2998
type: SuspicionRifleSpawner
components:
- parent: 0
pos: 23.5,-0.5
rot: -1.5707963267948966 rad
type: Transform
- uid: 2999
type: SuspicionRifleSpawner
components:
- parent: 0
pos: -2.5,-4.5
rot: -1.5707963267948966 rad
type: Transform
- uid: 3000
type: SuspicionRifleSpawner
components:
- parent: 0
pos: -14.5,-0.5
rot: -1.5707963267948966 rad
type: Transform
- uid: 3001
type: SuspicionRifleSpawner
components:
- parent: 0
pos: -32.5,-8.5
rot: -1.5707963267948966 rad
type: Transform
- uid: 3002
type: SuspicionPistolSpawner
components:
- parent: 0
pos: -18.5,-11.5
rot: -1.5707963267948966 rad
type: Transform
- uid: 3003
type: SuspicionPistolSpawner
components:
- parent: 0
pos: -31.5,8.5
rot: -1.5707963267948966 rad
type: Transform
- uid: 3004
type: SuspicionPistolSpawner
components:
- parent: 0
pos: -20.5,14.5
rot: -1.5707963267948966 rad
type: Transform
- uid: 3005
type: SuspicionRifleSpawner
components:
- parent: 0
pos: -7.5,20.5
rot: -1.5707963267948966 rad
type: Transform
- uid: 3006
type: SuspicionRifleSpawner
components:
- parent: 0
pos: -7.5,21.5
rot: -1.5707963267948966 rad
type: Transform
- uid: 3007
type: SuspicionPistolSpawner
components:
- parent: 0
pos: 6.5,20.5
rot: -1.5707963267948966 rad
type: Transform
- uid: 3008
type: SuspicionRifleSpawner
components:
- parent: 0
pos: 0.5,28.5
rot: -1.5707963267948966 rad
type: Transform
- uid: 3009
type: SuspicionRifleSpawner
components:
- parent: 0
pos: 6.5,28.5
rot: -1.5707963267948966 rad
type: Transform
- uid: 3010
type: SuspicionPistolSpawner
components:
- parent: 0
pos: -13.5,24.5
rot: -1.5707963267948966 rad
type: Transform
- uid: 3011
type: SuspicionMeleeSpawner
components:
- parent: 0
pos: -4.5,20.5
rot: -1.5707963267948966 rad
type: Transform
- uid: 3012
type: SuspicionRifleSpawner
components:
- parent: 0
pos: 5.5,16.5
rot: -1.5707963267948966 rad
type: Transform
... ...

View File

@@ -0,0 +1,99 @@
- type: entity
name: base conditional spawner
id: BaseConditionalSpawner
abstract: true
components:
- type: Sprite
netsync: false
visible: false
sprite: Objects/markers.rsi
state: cross_blue
- type: Icon
sprite: Objects/markers.rsi
state: cross_blue
- type: Marker
- type: Clickable
- type: InteractionOutline
- type: Collidable
- type: ConditionalSpawner
placement:
mode: AlignTileAny
- type: entity
name: Suspicion Rifle Spawner
id: SuspicionRifleSpawner
parent: BaseConditionalSpawner
components:
- type: Sprite
netsync: false
visible: false
sprite: Objects/markers.rsi
state: spawner_rifle
- type: Icon
sprite: Objects/markers.rsi
state: spawner_rifle
- type: ConditionalSpawner
prototypes:
- RifleAk
- RifleBlackAk
- RifleCarbine
- RifleDallas
- RifleIhHeavy
- RifleSolEot
- RifleSolPara
- RifleSts
chance: 0.75
gameRules:
- RuleSuspicion
- type: entity
name: Suspicion Pistol Spawner
id: SuspicionPistolSpawner
parent: BaseConditionalSpawner
components:
- type: Sprite
netsync: false
visible: false
sprite: Objects/markers.rsi
state: spawner_pistol
- type: Icon
sprite: Objects/markers.rsi
state: spawner_pistol
- type: ConditionalSpawner
prototypes:
- PistolClarissa
- PistolDeagle
- PistolDeckard
- PistolGiskard
- PistolGyro
- PistolLamia
- PistolMakarov
- PistolMk58
- PistolOlivawCivil
chance: 0.75
gameRules:
- RuleSuspicion
- type: entity
name: Suspicion Melee Spawner
id: SuspicionMeleeSpawner
parent: BaseConditionalSpawner
components:
- type: Sprite
netsync: false
visible: false
sprite: Objects/markers.rsi
state: spawner_melee
- type: Icon
sprite: Objects/markers.rsi
state: spawner_melee
- type: ConditionalSpawner
prototypes:
- ButchCleaver
- Pickaxe
- Spear
- ToolboxEmergency
- CrowbarRed
chance: 0.75
gameRules:
- RuleSuspicion

View File

@@ -1 +1 @@
{"version": 1, "size": {"x": 32, "y": 32}, "license": "CC-BY-SA-3.0", "copyright": "Taken from https://github.com/vgstation-coders/vgstation13/blob/e71d6c4fba5a51f99b81c295dcaec4fc2f58fb19/icons/mob/screen1.dmi", "states": [{"name": "cross_blue", "directions": 1, "delays": [[1.0]]}, {"name": "cross_green", "directions": 1, "delays": [[1.0]]}, {"name": "cross_red", "directions": 1, "delays": [[1.0]]}, {"name": "AI", "directions": 1, "delays": [[1.0]]}, {"name": "Assistant", "directions": 1, "delays": [[1.0]]}, {"name": "Atmospheric Technician", "directions": 1, "delays": [[1.0]]}, {"name": "Bartender", "directions": 1, "delays": [[1.0]]}, {"name": "Botanist", "directions": 1, "delays": [[1.0]]}, {"name": "Captain", "directions": 1, "delays": [[1.0]]}, {"name": "Cargo Technician", "directions": 1, "delays": [[1.0]]}, {"name": "Chaplain", "directions": 1, "delays": [[1.0]]}, {"name": "Chemist", "directions": 1, "delays": [[1.0]]}, {"name": "Chief Engineer", "directions": 1, "delays": [[1.0]]}, {"name": "Chief Medical Officer", "directions": 1, "delays": [[1.0]]}, {"name": "Clown", "directions": 1, "delays": [[1.0]]}, {"name": "Cook", "directions": 1, "delays": [[1.0]]}, {"name": "Curator", "directions": 1, "delays": [[1.0]]}, {"name": "Cyborg", "directions": 1, "delays": [[1.0]]}, {"name": "Detective", "directions": 1, "delays": [[1.0]]}, {"name": "Geneticist", "directions": 1, "delays": [[1.0]]}, {"name": "Head of Personnel", "directions": 1, "delays": [[1.0]]}, {"name": "Head of Security", "directions": 1, "delays": [[1.0]]}, {"name": "Janitor", "directions": 1, "delays": [[1.0]]}, {"name": "Lawyer", "directions": 1, "delays": [[1.0]]}, {"name": "Medical Doctor", "directions": 1, "delays": [[1.0]]}, {"name": "Mime", "directions": 1, "delays": [[1.0]]}, {"name": "Paramedic", "directions": 1, "delays": [[1.0]]}, {"name": "Prisoner", "directions": 1, "delays": [[1.0]]}, {"name": "Psychologist", "directions": 1, "delays": [[1.0]]}, {"name": "Quartermaster", "directions": 1, "delays": [[1.0]]}, {"name": "Research Director", "directions": 1, "delays": [[1.0]]}, {"name": "Roboticist", "directions": 1, "delays": [[1.0]]}, {"name": "Scientist", "directions": 1, "delays": [[1.0]]}, {"name": "Security Officer", "directions": 1, "delays": [[1.0]]}, {"name": "Shaft Miner", "directions": 1, "delays": [[1.0]]}, {"name": "Station Engineer", "directions": 1, "delays": [[1.0]]}, {"name": "Virologist", "directions": 1, "delays": [[1.0]]}, {"name": "Warden", "directions": 1, "delays": [[1.0]]}, {"name": "cross_pink", "directions": 1, "delays": [[1.0]]}, {"name": "observer_start", "directions": 1, "delays": [[1.0]]}]} {"version": 1, "size": {"x": 32, "y": 32}, "license": "CC-BY-SA-3.0", "copyright": "Taken from https://github.com/vgstation-coders/vgstation13/blob/e71d6c4fba5a51f99b81c295dcaec4fc2f58fb19/icons/mob/screen1.dmi", "states": [{"name": "cross_blue", "directions": 1, "delays": [[1.0]]}, {"name": "cross_green", "directions": 1, "delays": [[1.0]]}, {"name": "cross_red", "directions": 1, "delays": [[1.0]]}, {"name": "AI", "directions": 1, "delays": [[1.0]]}, {"name": "Assistant", "directions": 1, "delays": [[1.0]]}, {"name": "Atmospheric Technician", "directions": 1, "delays": [[1.0]]}, {"name": "Bartender", "directions": 1, "delays": [[1.0]]}, {"name": "Botanist", "directions": 1, "delays": [[1.0]]}, {"name": "Captain", "directions": 1, "delays": [[1.0]]}, {"name": "Cargo Technician", "directions": 1, "delays": [[1.0]]}, {"name": "Chaplain", "directions": 1, "delays": [[1.0]]}, {"name": "Chemist", "directions": 1, "delays": [[1.0]]}, {"name": "Chief Engineer", "directions": 1, "delays": [[1.0]]}, {"name": "Chief Medical Officer", "directions": 1, "delays": [[1.0]]}, {"name": "Clown", "directions": 1, "delays": [[1.0]]}, {"name": "Cook", "directions": 1, "delays": [[1.0]]}, {"name": "Curator", "directions": 1, "delays": [[1.0]]}, {"name": "Cyborg", "directions": 1, "delays": [[1.0]]}, {"name": "Detective", "directions": 1, "delays": [[1.0]]}, {"name": "Geneticist", "directions": 1, "delays": [[1.0]]}, {"name": "Head of Personnel", "directions": 1, "delays": [[1.0]]}, {"name": "Head of Security", "directions": 1, "delays": [[1.0]]}, {"name": "Janitor", "directions": 1, "delays": [[1.0]]}, {"name": "Lawyer", "directions": 1, "delays": [[1.0]]}, {"name": "Medical Doctor", "directions": 1, "delays": [[1.0]]}, {"name": "Mime", "directions": 1, "delays": [[1.0]]}, {"name": "Paramedic", "directions": 1, "delays": [[1.0]]}, {"name": "Prisoner", "directions": 1, "delays": [[1.0]]}, {"name": "Psychologist", "directions": 1, "delays": [[1.0]]}, {"name": "Quartermaster", "directions": 1, "delays": [[1.0]]}, {"name": "Research Director", "directions": 1, "delays": [[1.0]]}, {"name": "Roboticist", "directions": 1, "delays": [[1.0]]}, {"name": "Scientist", "directions": 1, "delays": [[1.0]]}, {"name": "Security Officer", "directions": 1, "delays": [[1.0]]}, {"name": "Shaft Miner", "directions": 1, "delays": [[1.0]]}, {"name": "Station Engineer", "directions": 1, "delays": [[1.0]]}, {"name": "Virologist", "directions": 1, "delays": [[1.0]]}, {"name": "Warden", "directions": 1, "delays": [[1.0]]}, {"name": "cross_pink", "directions": 1, "delays": [[1.0]]}, {"name": "observer_start", "directions": 1, "delays": [[1.0]]}, {"name": "spawner_melee", "directions": 1, "delays": [[1.0]]}, {"name": "spawner_rifle", "directions": 1, "delays": [[1.0]]}, {"name": "spawner_pistol", "directions": 1, "delays": [[1.0]]}]}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB