diff --git a/Content.Client/NPC/Systems/NpcFactionSpriteStateSetterSystem.cs b/Content.Client/NPC/Systems/NpcFactionSpriteStateSetterSystem.cs new file mode 100644 index 00000000000..9767c87bf0d --- /dev/null +++ b/Content.Client/NPC/Systems/NpcFactionSpriteStateSetterSystem.cs @@ -0,0 +1,25 @@ + +using Content.Shared.NPC.Components; +using Content.Shared.NPC.Events; +using Robust.Client.GameObjects; + +namespace Content.Client.NPC.Systems; +public sealed partial class NpcFactionSpriteStateSetterSystem : EntitySystem +{ + + public override void Initialize() + { + base.Initialize(); + + SubscribeNetworkEvent(OnFactionAdded); + } + + private void OnFactionAdded(NpcFactionAddedEvent ev) + { + if (!TryGetEntity(ev.EntityUid, out var entity) || !TryComp(entity.Value, out var sprite) || !TryComp(entity.Value, out var _)|| !TryComp(entity.Value, out var factionSelector)) + return; + + if(factionSelector.SelectableFactions.Contains(ev.FactionID)) + sprite.LayerSetState(0, new (ev.FactionID)); + } +} diff --git a/Content.Server/NPC/Systems/NpcFactionSelectorSystem.cs b/Content.Server/NPC/Systems/NpcFactionSelectorSystem.cs new file mode 100644 index 00000000000..c17207028a0 --- /dev/null +++ b/Content.Server/NPC/Systems/NpcFactionSelectorSystem.cs @@ -0,0 +1,59 @@ +using Content.Server.NPC.Components; +using Content.Shared.Database; +using Content.Shared.Popups; +using Content.Shared.Verbs; +using Robust.Shared.Prototypes; +using System.Linq; +using Content.Shared.NPC.Components; + + +namespace Content.Server.NPC.Systems; +public sealed partial class NpcFactionSelectorSystem : EntitySystem +{ + + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly IPrototypeManager _prototype = default!; + [Dependency] private readonly NpcFactionSystem _factionSystem = default!; + [Dependency] private readonly EntityManager _entityManager = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent>(OnGetVerb); + } + + private void OnGetVerb(Entity entity, ref GetVerbsEvent args) + { + if (!args.CanAccess || !args.CanInteract || args.Hands == null) + return; + + if (!TryComp(entity, out var factionSelectorComponent) || factionSelectorComponent.SelectableFactions.Count < 2) + return; + + foreach (var type in factionSelectorComponent.SelectableFactions) + { + var proto = _prototype.Index(type); + + var v = new Verb + { + Priority = 1, + Category = VerbCategory.SelectFaction, + Text = proto.ID, + Impact = LogImpact.Medium, + DoContactInteraction = true, + Act = () => + { + _popup.PopupPredicted(Loc.GetString("npcfaction-component-faction-set", ("faction", proto.ID)), entity.Owner, null); + foreach (var type in factionSelectorComponent.SelectableFactions) + { + _factionSystem.RemoveFaction(entity.Owner, type); + } + + _factionSystem.AddFaction(entity.Owner, proto.ID); + } + }; + args.Verbs.Add(v); + } + } +} diff --git a/Content.Server/NPC/Systems/NpcFactionSystem.cs b/Content.Server/NPC/Systems/NpcFactionSystem.cs index 663dbac9c77..5af25647155 100644 --- a/Content.Server/NPC/Systems/NpcFactionSystem.cs +++ b/Content.Server/NPC/Systems/NpcFactionSystem.cs @@ -1,3 +1,4 @@ +using Content.Shared.NPC.Events; using System.Collections.Frozen; using System.Linq; using Content.Server.NPC.Components; @@ -8,7 +9,7 @@ namespace Content.Server.NPC.Systems; /// /// Outlines faction relationships with each other. -/// part of psionics rework was making this a partial class. Should've already been handled upstream, based on the linter. +/// part of psionics rework was making this a partial class. Should've already been handled upstream, based on the linter. /// public sealed partial class NpcFactionSystem : EntitySystem { @@ -76,6 +77,9 @@ public void AddFaction(EntityUid uid, string faction, bool dirty = true) if (!comp.Factions.Add(faction)) return; + if(TryGetNetEntity(uid, out var netEntity)) // Floofstation + RaiseNetworkEvent(new NpcFactionAddedEvent(netEntity.Value, faction)); + if (dirty) { RefreshFactions(comp); @@ -99,6 +103,9 @@ public void RemoveFaction(EntityUid uid, string faction, bool dirty = true) if (!component.Factions.Remove(faction)) return; + if(_lookup.TryGetNetEntity(uid, out var netEntity)) + RaiseNetworkEvent(new NpcFactionRemovedEvent(netEntity.Value, faction)); + if (dirty) { RefreshFactions(component); diff --git a/Content.Shared/NPC/Events/NpcFactionChangedEvent.cs b/Content.Shared/NPC/Events/NpcFactionChangedEvent.cs new file mode 100644 index 00000000000..4b85345f326 --- /dev/null +++ b/Content.Shared/NPC/Events/NpcFactionChangedEvent.cs @@ -0,0 +1,35 @@ +using Robust.Shared.Serialization; + +namespace Content.Shared.NPC.Events; + +/// +/// Raised from client to server to notify a faction was added to an NPC. +/// +[Serializable, NetSerializable] +public sealed class NpcFactionAddedEvent : EntityEventArgs +{ + public readonly string FactionID; + public readonly NetEntity EntityUid; + + public NpcFactionAddedEvent(NetEntity entity, string factionId) + { + FactionID = factionId; + EntityUid = entity; + } +} + +/// +/// Raised from client to server to notify a faction was removed from an NPC. +/// +[Serializable, NetSerializable] +public sealed class NpcFactionRemovedEvent : EntityEventArgs +{ + public readonly string FactionID; + public readonly NetEntity EntityUid; + + public NpcFactionRemovedEvent(NetEntity entity, string factionId) + { + FactionID = factionId; + EntityUid = entity; + } +} diff --git a/Content.Shared/NPC/NpcFactionSelectorComponent.cs b/Content.Shared/NPC/NpcFactionSelectorComponent.cs new file mode 100644 index 00000000000..4e59d2a26fc --- /dev/null +++ b/Content.Shared/NPC/NpcFactionSelectorComponent.cs @@ -0,0 +1,9 @@ +namespace Content.Shared.NPC.Components; + +[RegisterComponent] +public sealed partial class NpcFactionSelectorComponent : Component +{ + [DataField] + public List SelectableFactions = new(); +} + diff --git a/Content.Shared/NPC/NpcFactionSpriteStateSetterComponent.cs b/Content.Shared/NPC/NpcFactionSpriteStateSetterComponent.cs new file mode 100644 index 00000000000..4c90340fb84 --- /dev/null +++ b/Content.Shared/NPC/NpcFactionSpriteStateSetterComponent.cs @@ -0,0 +1,7 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.NPC.Components; + +[RegisterComponent] +public sealed partial class NpcFactionSpriteStateSetterComponent : Component {} + diff --git a/Content.Shared/Verbs/VerbCategory.cs b/Content.Shared/Verbs/VerbCategory.cs index 2d2a6044dfc..72580d7a086 100644 --- a/Content.Shared/Verbs/VerbCategory.cs +++ b/Content.Shared/Verbs/VerbCategory.cs @@ -89,5 +89,7 @@ public VerbCategory(string text, string? icon, bool iconsOnly = false) public static readonly VerbCategory Interaction = new("verb-categories-interaction", null); public static readonly VerbCategory Vore = new("verb-categories-vore", null); // Floofstation + + public static readonly VerbCategory SelectFaction = new("verb-categories-select-faction", null); // Floofstation } } diff --git a/Resources/Locale/en-US/npc/factions.ftl b/Resources/Locale/en-US/npc/factions.ftl new file mode 100644 index 00000000000..8aaa2b6e8f3 --- /dev/null +++ b/Resources/Locale/en-US/npc/factions.ftl @@ -0,0 +1 @@ +npcfaction-component-faction-set = Faction set to: {$faction} diff --git a/Resources/Locale/en-US/verbs/verb-system.ftl b/Resources/Locale/en-US/verbs/verb-system.ftl index dfb4e621dca..d579f045c5f 100644 --- a/Resources/Locale/en-US/verbs/verb-system.ftl +++ b/Resources/Locale/en-US/verbs/verb-system.ftl @@ -26,9 +26,11 @@ verb-categories-set-sensor = Sensor verb-categories-timer = Set Delay verb-categories-lever = Lever verb-categories-select-type = Select Type +verb-categories-select-faction = Select Faction verb-categories-fax = Set Destination verb-categories-power-level = Power Level verb-categories-interaction = Interact +verb-categories-blood-cult = Blood Cult verb-common-toggle-light = Toggle light verb-common-close = Close diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/gladiabot.yml b/Resources/Prototypes/Entities/Mobs/NPCs/gladiabot.yml index 2ad231acb6c..78faa6f6cb6 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/gladiabot.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/gladiabot.yml @@ -6,7 +6,7 @@ components: - type: Sprite sprite: Mobs/Silicon/Bots/gladiabot.rsi - state: gladiabot + state: GladiabotFFA - type: Inventory templateId: gladiabot - type: InventorySlots @@ -26,6 +26,14 @@ - type: NpcFactionMember factions: - GladiabotFFA + - type: NpcFactionSelector + selectableFactions: + - GladiabotFFA + - GladiabotRed + - GladiabotBlue + - GladiabotGreen + - GladiabotYellow + - type: NpcFactionSpriteStateSetter - type: CombatMode - type: MeleeWeapon altDisarm: false diff --git a/Resources/Prototypes/Recipes/Crafting/bots.yml b/Resources/Prototypes/Recipes/Crafting/bots.yml index 64106f663f1..8f67905b85b 100644 --- a/Resources/Prototypes/Recipes/Crafting/bots.yml +++ b/Resources/Prototypes/Recipes/Crafting/bots.yml @@ -87,4 +87,4 @@ description: This bot fights for honour and glory! icon: sprite: Mobs/Silicon/Bots/gladiabot.rsi - state: gladiabot + state: GladiabotFFA diff --git a/Resources/Prototypes/ai_factions.yml b/Resources/Prototypes/ai_factions.yml index 0e66069f15d..fef9c2bd7f8 100644 --- a/Resources/Prototypes/ai_factions.yml +++ b/Resources/Prototypes/ai_factions.yml @@ -131,3 +131,40 @@ id: GladiabotFFA hostile: - GladiabotFFA + - GladiabotRed + - GladiabotGreen + - GladiabotBlue + - GladiabotYellow + +- type: npcFaction + id: GladiabotRed + hostile: + - GladiabotFFA + - GladiabotGreen + - GladiabotBlue + - GladiabotYellow + +- type: npcFaction + id: GladiabotGreen + hostile: + - GladiabotFFA + - GladiabotRed + - GladiabotBlue + - GladiabotYellow + +- type: npcFaction + id: GladiabotBlue + hostile: + - GladiabotFFA + - GladiabotRed + - GladiabotGreen + - GladiabotYellow + +- type: npcFaction + id: GladiabotYellow + hostile: + - GladiabotFFA + - GladiabotRed + - GladiabotGreen + - GladiabotBlue + diff --git a/Resources/Textures/Mobs/Silicon/Bots/gladiabot.rsi/GladiabotBlue.png b/Resources/Textures/Mobs/Silicon/Bots/gladiabot.rsi/GladiabotBlue.png new file mode 100644 index 00000000000..800edcb8607 Binary files /dev/null and b/Resources/Textures/Mobs/Silicon/Bots/gladiabot.rsi/GladiabotBlue.png differ diff --git a/Resources/Textures/Mobs/Silicon/Bots/gladiabot.rsi/gladiabot.png b/Resources/Textures/Mobs/Silicon/Bots/gladiabot.rsi/GladiabotFFA.png similarity index 100% rename from Resources/Textures/Mobs/Silicon/Bots/gladiabot.rsi/gladiabot.png rename to Resources/Textures/Mobs/Silicon/Bots/gladiabot.rsi/GladiabotFFA.png diff --git a/Resources/Textures/Mobs/Silicon/Bots/gladiabot.rsi/GladiabotGreen.png b/Resources/Textures/Mobs/Silicon/Bots/gladiabot.rsi/GladiabotGreen.png new file mode 100644 index 00000000000..3e82302e6cf Binary files /dev/null and b/Resources/Textures/Mobs/Silicon/Bots/gladiabot.rsi/GladiabotGreen.png differ diff --git a/Resources/Textures/Mobs/Silicon/Bots/gladiabot.rsi/GladiabotRed.png b/Resources/Textures/Mobs/Silicon/Bots/gladiabot.rsi/GladiabotRed.png new file mode 100644 index 00000000000..68d0e24929b Binary files /dev/null and b/Resources/Textures/Mobs/Silicon/Bots/gladiabot.rsi/GladiabotRed.png differ diff --git a/Resources/Textures/Mobs/Silicon/Bots/gladiabot.rsi/GladiabotYellow.png b/Resources/Textures/Mobs/Silicon/Bots/gladiabot.rsi/GladiabotYellow.png new file mode 100644 index 00000000000..abdef3b926f Binary files /dev/null and b/Resources/Textures/Mobs/Silicon/Bots/gladiabot.rsi/GladiabotYellow.png differ diff --git a/Resources/Textures/Mobs/Silicon/Bots/gladiabot.rsi/meta.json b/Resources/Textures/Mobs/Silicon/Bots/gladiabot.rsi/meta.json index cc898e53cd6..d3ac6b30cf6 100644 --- a/Resources/Textures/Mobs/Silicon/Bots/gladiabot.rsi/meta.json +++ b/Resources/Textures/Mobs/Silicon/Bots/gladiabot.rsi/meta.json @@ -8,7 +8,43 @@ "copyright": "Tim Falken", "states": [ { - "name": "gladiabot", + "name": "GladiabotFFA", + "delays": [ + [ + 0.5, + 0.2 + ] + ] + }, + { + "name": "GladiabotRed", + "delays": [ + [ + 0.5, + 0.2 + ] + ] + }, + { + "name": "GladiabotGreen", + "delays": [ + [ + 0.5, + 0.2 + ] + ] + }, + { + "name": "GladiabotBlue", + "delays": [ + [ + 0.5, + 0.2 + ] + ] + }, + { + "name": "GladiabotYellow", "delays": [ [ 0.5,