Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Undo Accidental Revert Of Rampant Brand Intelligence #947

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 135 additions & 7 deletions Content.Server/Antag/MobReplacementRuleSystem.cs
Original file line number Diff line number Diff line change
@@ -1,38 +1,166 @@
using System.Numerics;
using Content.Server.Antag.Mimic;
using Content.Server.GameTicking.Components;
using Content.Server.Chat.Systems;
using Content.Server.GameTicking.Rules;
using Content.Server.GameTicking.Rules.Components;
using Content.Server.GameTicking.Components;
using Content.Server.NPC.Systems;
using Content.Server.Station.Systems;
using Content.Server.GameTicking;
using Content.Shared.VendingMachines;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Server.GameObjects;
using Robust.Shared.Physics.Systems;
using System.Linq;
using Robust.Shared.Physics;
using Content.Shared.Movement.Components;
using Content.Shared.Damage;
using Content.Server.NPC.HTN;
using Content.Server.NPC;
using Content.Shared.Weapons.Melee;
using Content.Server.Advertise.EntitySystems;
using Content.Server.Advertise.Components;
using Content.Server.Power.Components;
using Content.Shared.CombatMode;

namespace Content.Server.Antag;

public sealed class MobReplacementRuleSystem : GameRuleSystem<MobReplacementRuleComponent>
{
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly StationSystem _station = default!;
[Dependency] private readonly GameTicker _gameTicker = default!;
[Dependency] private readonly ChatSystem _chat = default!;
[Dependency] private readonly IPrototypeManager _prototype = default!;
[Dependency] private readonly IComponentFactory _componentFactory = default!;
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
[Dependency] private readonly NpcFactionSystem _npcFaction = default!;
[Dependency] private readonly NPCSystem _npc = default!;
[Dependency] private readonly TransformSystem _transform = default!;
[Dependency] private readonly AdvertiseSystem _advertise = default!;


protected override void Started(EntityUid uid, MobReplacementRuleComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args)
{
base.Started(uid, component, gameRule, args);

var query = AllEntityQuery<VendingMachineComponent, TransformComponent>();
var spawns = new List<(EntityUid Entity, EntityCoordinates Coordinates)>();
var stations = _gameTicker.GetSpawnableStations();

while (query.MoveNext(out var vendingUid, out _, out var xform))
{
if (!_random.Prob(component.Chance))
var ownerStation = _station.GetOwningStation(vendingUid);

if (ownerStation == null
|| ownerStation != stations[0])
continue;

// Make sure that we aren't running this on something that is already a mimic
if (HasComp<CombatModeComponent>(vendingUid))
continue;

spawns.Add((vendingUid, xform.Coordinates));
}

foreach (var entity in spawns)
if (spawns == null)
//WTF: THE STATION DOESN'T EXIST! WE MUST BE IN A TEST! QUICK, PUT A MIMIC AT 0,0!!!
Spawn(component.Proto, new EntityCoordinates(uid, new Vector2(0, 0)));
else
{
var coordinates = entity.Coordinates;
Del(entity.Entity);
// This is intentionally not clamped. If a server host wants to replace every vending machine in the entire station with a mimic, who am I to stop them?
var k = MathF.MaxMagnitude(component.NumberToReplace, 1);
while (k > 0 && spawns != null && spawns.Count > 0)
VMSolidus marked this conversation as resolved.
Show resolved Hide resolved
{
if (k > 1)
{
var spawnLocation = _random.PickAndTake(spawns);
BuildAMimicWorkshop(spawnLocation.Entity, component);
}
else
{
BuildAMimicWorkshop(spawns[0].Entity, component);
}
VMSolidus marked this conversation as resolved.
Show resolved Hide resolved

Spawn(component.Proto, coordinates);
if (k == MathF.MaxMagnitude(component.NumberToReplace, 1)
&& component.DoAnnouncement)
_chat.DispatchStationAnnouncement(stations[0], Loc.GetString("station-event-rampant-intelligence-announcement"), playDefaultSound: true,
colorOverride: Color.Red, sender: "Central Command");
VMSolidus marked this conversation as resolved.
Show resolved Hide resolved

k--;
}
}
}

/// It's like Build a Bear, but MURDER
public void BuildAMimicWorkshop(EntityUid uid, MobReplacementRuleComponent component)
{
var metaData = MetaData(uid);
var vendorPrototype = metaData.EntityPrototype;
var mimicProto = _prototype.Index(component.Proto);

var vendorComponents = vendorPrototype?.Components.Keys
.Where(n => n != "Transform" && n != "MetaData")
.Select(name => (name, _componentFactory.GetRegistration(name).Type))
.ToList() ?? new List<(string name, Type type)>();

var mimicComponents = mimicProto?.Components.Keys
.Where(n => n != "Transform" && n != "MetaData")
.Select(name => (name, _componentFactory.GetRegistration(name).Type))
.ToList() ?? new List<(string name, Type type)>();

foreach (var name in mimicComponents.Except(vendorComponents))
{
var newComponent = _componentFactory.GetComponent(name.name);
EntityManager.AddComponent(uid, newComponent);
}

var xform = Transform(uid);
if (xform.Anchored)
_transform.Unanchor(uid, xform);

SetupMimicNPC(uid, component);

if (TryComp<AdvertiseComponent>(uid, out var vendor)
&& component.VendorModify)
SetupMimicVendor(uid, component, vendor);
}

/// This handles getting the entity ready to be a hostile NPC
private void SetupMimicNPC(EntityUid uid, MobReplacementRuleComponent component)
{
_physics.SetBodyType(uid, BodyType.KinematicController);
_npcFaction.AddFaction(uid, "SimpleHostile");

var melee = EnsureComp<MeleeWeaponComponent>(uid);
melee.Angle = 0;
DamageSpecifier dspec = new()
{
DamageDict = new()
{
{ "Blunt", component.MimicMeleeDamage }
VMSolidus marked this conversation as resolved.
Show resolved Hide resolved
}
};
melee.Damage = dspec;

var movementSpeed = EnsureComp<MovementSpeedModifierComponent>(uid);
(movementSpeed.BaseSprintSpeed, movementSpeed.BaseWalkSpeed) = (component.MimicMoveSpeed, component.MimicMoveSpeed);
VMSolidus marked this conversation as resolved.
Show resolved Hide resolved

var htn = EnsureComp<HTNComponent>(uid);
htn.RootTask = new HTNCompoundTask() { Task = component.MimicAIType };
htn.Blackboard.SetValue(NPCBlackboard.NavSmash, component.MimicSmashGlass);
_npc.WakeNPC(uid, htn);
}

/// Handling specific interactions with vending machines
private void SetupMimicVendor(EntityUid uid, MobReplacementRuleComponent mimicComponent, AdvertiseComponent vendorComponent)
{
vendorComponent.MinimumWait = 5;
vendorComponent.MaximumWait = 15;
_advertise.SayAdvertisement(uid, vendorComponent);

if (TryComp<ApcPowerReceiverComponent>(uid, out var aPC))
aPC.NeedsPower = false;
VMSolidus marked this conversation as resolved.
Show resolved Hide resolved
}
}
2 changes: 1 addition & 1 deletion Resources/Prototypes/Entities/Mobs/NPCs/mimic.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# TODO: Pending a rewrite of Mob Replacement System, this entire list should just be moved into a ComponentRegistry on the event.
- type: entity
name: Mimic
id: MobMimic
Expand Down Expand Up @@ -43,4 +44,3 @@
damage:
types:
Blunt: 20
- type: PsionicInsulation
Loading