Skip to content

Commit

Permalink
Blob gamemode, Vampirs mid round
Browse files Browse the repository at this point in the history
  • Loading branch information
Rxup committed Feb 22, 2024
1 parent 32a4489 commit aa2c871
Show file tree
Hide file tree
Showing 20 changed files with 755 additions and 303 deletions.
2 changes: 2 additions & 0 deletions Content.Server/Backmen/Blob/BlobCarrierSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ private void OnStartup(EntityUid uid, BlobCarrierComponent component, ComponentS
ghostRole.RoleName = Loc.GetString("blob-carrier-role-name");
ghostRole.RoleDescription = Loc.GetString("blob-carrier-role-desc");
ghostRole.RoleRules = Loc.GetString("blob-carrier-role-rules");

EnsureComp<BlobSpeakComponent>(uid);
}

private void OnShutdown(EntityUid uid, BlobCarrierComponent component, ComponentShutdown args)
Expand Down
67 changes: 67 additions & 0 deletions Content.Server/Backmen/Blob/BlobMobSystem.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
using Content.Server.Chat.Systems;
using Content.Server.Explosion.EntitySystems;
using Content.Server.Fluids.EntitySystems;
using Content.Server.Popups;
using Content.Server.Radio.Components;
using Content.Server.Radio.EntitySystems;
using Content.Shared.Backmen.Blob;
using Content.Shared.Backmen.Blob.Chemistry;
using Content.Shared.Chemistry.Components;
using Content.Shared.Damage;
using Content.Shared.Interaction.Events;
using Content.Shared.Popups;
using Content.Shared.Speech;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Prototypes;

namespace Content.Server.Backmen.Blob;

Expand All @@ -18,15 +24,76 @@ public sealed class BlobMobSystem : EntitySystem
//[Dependency] private readonly SmokeSystem _smokeSystem = default!;
//[Dependency] private readonly SharedAudioSystem _audioSystem = default!;

[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly RadioSystem _radioSystem = default!;

public override void Initialize()
{
base.Initialize();

SubscribeLocalEvent<BlobMobComponent, BlobMobGetPulseEvent>(OnPulsed);
SubscribeLocalEvent<BlobMobComponent, AttackAttemptEvent>(OnBlobAttackAttempt);
SubscribeLocalEvent<BlobSpeakComponent, EntitySpokeEvent>(OnSpoke, before: new []{ typeof(RadioSystem) });
SubscribeLocalEvent<BlobSpeakComponent, ComponentStartup>(OnSpokeAdd);
SubscribeLocalEvent<BlobSpeakComponent, ComponentShutdown>(OnSpokeRemove);
SubscribeLocalEvent<BlobSpeakComponent, TransformSpeakerNameEvent>(OnSpokeName);
SubscribeLocalEvent<BlobSpeakComponent, SpeakAttemptEvent>(OnSpokeCan, after: new []{ typeof(SpeechSystem) });
//SubscribeLocalEvent<SmokeOnTriggerComponent, TriggerEvent>(HandleSmokeTrigger);
}

private void OnSpokeName(Entity<BlobSpeakComponent> ent, ref TransformSpeakerNameEvent args)
{
args.Name = "Блоб";

}

private void OnSpokeCan(Entity<BlobSpeakComponent> ent, ref SpeakAttemptEvent args)
{
args.Uncancel();
}

private void OnSpokeRemove(Entity<BlobSpeakComponent> ent, ref ComponentShutdown args)
{
var radio = EnsureComp<ActiveRadioComponent>(ent);
radio.Channels.Remove(ent.Comp.Channel);
var snd = EnsureComp<IntrinsicRadioTransmitterComponent>(ent);
snd.Channels.Remove(ent.Comp.Channel);
}

private void OnSpokeAdd(Entity<BlobSpeakComponent> ent, ref ComponentStartup args)
{
EnsureComp<IntrinsicRadioReceiverComponent>(ent);
var radio = EnsureComp<ActiveRadioComponent>(ent);
radio.Channels.Add(ent.Comp.Channel);
var snd = EnsureComp<IntrinsicRadioTransmitterComponent>(ent);
snd.Channels.Add(ent.Comp.Channel);
}


private void OnSpoke(Entity<BlobSpeakComponent> ent, ref EntitySpokeEvent args)
{
if (args.Channel == null)
args.Channel = _prototypeManager.Index(ent.Comp.Channel);

if (!TryComp<IntrinsicRadioTransmitterComponent>(ent, out var component) ||
!component.Channels.Contains(args.Channel.ID) ||
args.Channel.ID != ent.Comp.Channel)
{
return;
}

if (TryComp<BlobObserverComponent>(ent, out var blobObserverComponent) && blobObserverComponent.Core.HasValue)
{
_radioSystem.SendRadioMessage(blobObserverComponent.Core.Value, args.OriginalMessage, args.Channel, blobObserverComponent.Core.Value);
}
else
{
_radioSystem.SendRadioMessage(ent, args.OriginalMessage, args.Channel, ent);
}

args.Channel = null; // prevent duplicate messages from other listeners.
}

private void OnPulsed(EntityUid uid, BlobMobComponent component, BlobMobGetPulseEvent args)
{
_damageableSystem.TryChangeDamage(uid, component.HealthOfPulse);
Expand Down
10 changes: 10 additions & 0 deletions Content.Server/Backmen/Blob/BlobSpeakComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using Content.Shared.Radio;
using Robust.Shared.Prototypes;

namespace Content.Server.Backmen.Blob;

[RegisterComponent]
public sealed partial class BlobSpeakComponent : Component
{
public ProtoId<RadioChannelPrototype> Channel = "Hivemind";
}
7 changes: 7 additions & 0 deletions Content.Server/Backmen/Blob/Rule/BlobGameRuleComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Content.Server.Backmen.Blob.Rule;

[RegisterComponent]
public sealed partial class BlobGameRuleComponent : Component
{
public int TotalBlobs = 0;
}
162 changes: 162 additions & 0 deletions Content.Server/Backmen/Blob/Rule/BlobRuleSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
using System.Linq;
using Content.Server.Antag;
using Content.Server.Backmen.Vampiric;
using Content.Server.Bible.Components;
using Content.Server.Chat.Managers;
using Content.Server.GameTicking;
using Content.Server.GameTicking.Rules;
using Content.Server.GameTicking.Rules.Components;
using Content.Server.Mind;
using Content.Shared.Backmen.Blob;
using Content.Shared.Backmen.CCVar;
using Content.Shared.Preferences;
using Content.Shared.Roles;
using Robust.Shared.Configuration;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;

namespace Content.Server.Backmen.Blob.Rule;

public sealed class BlobGameRuleSystem : GameRuleSystem<BlobGameRuleComponent>
{
private ISawmill _sawmill = default!;


private int PlayersPerBlob => _cfg.GetCVar(CCVars.BlobPlayersPer);
private int MaxBlob => _cfg.GetCVar(CCVars.BlobMax);

[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IChatManager _chatManager = default!;
[Dependency] private readonly AntagSelectionSystem _antagSelection = default!;
[Dependency] private readonly IRobustRandom _random = default!;


public override void Initialize()
{
base.Initialize();

_sawmill = Logger.GetSawmill("preset");

SubscribeLocalEvent<RoundStartAttemptEvent>(OnStartAttempt);
SubscribeLocalEvent<RulePlayerJobsAssignedEvent>(OnPlayersSpawned);
SubscribeLocalEvent<PlayerSpawnCompleteEvent>(HandleLatejoin);
}

private void HandleLatejoin(PlayerSpawnCompleteEvent ev)
{
var query = EntityQueryEnumerator<BlobGameRuleComponent, GameRuleComponent>();
while (query.MoveNext(out var uid, out var blob, out var gameRule))
{
if (!GameTicker.IsGameRuleAdded(uid, gameRule))
continue;

if (blob.TotalBlobs >= MaxBlob)
continue;

if (!ev.LateJoin)
continue;

if (!ev.Profile.AntagPreferences.Contains(Blob))
continue;

if (ev.JobId == null || !_prototypeManager.TryIndex<JobPrototype>(ev.JobId, out var job))
continue;

if (!job.CanBeAntag)
continue;

// the nth player we adjust our probabilities around
var target = PlayersPerBlob * blob.TotalBlobs + 1;

var chance = 1f / PlayersPerBlob;

// If we have too many traitors, divide by how many players below target for next traitor we are.
if (ev.JoinOrder < target)
{
chance /= (target - ev.JoinOrder);
}
else // Tick up towards 100% chance.
{
chance *= ((ev.JoinOrder + 1) - target);
}

if (chance > 1)
chance = 1;

// Now that we've calculated our chance, roll and make them a traitor if we roll under.
// You get one shot.
if (_random.Prob(chance) && ev.Player.AttachedEntity.HasValue)
{
MakeBlob(blob, ev.Player);
}
}
}

private void MakeBlob(BlobGameRuleComponent blob, ICommonSession player)
{
if (!player.AttachedEntity.HasValue)
return;

blob.TotalBlobs++;
EnsureComp<BlobCarrierComponent>(player.AttachedEntity.Value).HasMind = true;
}

private void OnPlayersSpawned(RulePlayerJobsAssignedEvent ev)
{
var query = EntityQueryEnumerator<BlobGameRuleComponent, GameRuleComponent>();
while (query.MoveNext(out var uid, out var blob, out var gameRule))
{
var plr = new Dictionary<ICommonSession, HumanoidCharacterProfile>();

if (!GameTicker.IsGameRuleAdded(uid, gameRule))
continue;

foreach (var player in ev.Players)
{
if (!ev.Profiles.ContainsKey(player.UserId))
continue;

plr.Add(player, ev.Profiles[player.UserId]);
}

DoBlobStart(blob, plr);
}
}

private void DoBlobStart(BlobGameRuleComponent blob,
Dictionary<ICommonSession, HumanoidCharacterProfile> startCandidates)
{
var numTraitors = MathHelper.Clamp(startCandidates.Count / PlayersPerBlob, 1, MaxBlob);
var traitorPool = _antagSelection.FindPotentialAntags(startCandidates, Blob);
var selectedTraitors = _antagSelection.PickAntag(numTraitors, traitorPool);

foreach (var traitor in selectedTraitors)
{
if (!traitor.AttachedEntity.HasValue)
continue;

MakeBlob(blob, traitor);
}
}

private void OnStartAttempt(RoundStartAttemptEvent ev)
{
var query = EntityQueryEnumerator<BlobGameRuleComponent, GameRuleComponent>();
while (query.MoveNext(out var uid, out _, out var gameRule))
{
if (!GameTicker.IsGameRuleAdded(uid, gameRule))
continue;

if (ev.Players.Length == 0)
{
_chatManager.DispatchServerAnnouncement(Loc.GetString("blob-no-one-ready"));
ev.Cancel();
}
}
}

[ValidatePrototypeId<AntagPrototype>]
private const string Blob = "Blob";
}
6 changes: 6 additions & 0 deletions Content.Server/Backmen/Blob/ZombieBlobSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ private void ReplaceFixtures(EntityUid uid, ZombieBlobComponent climbingComp, Fi
private void OnStartup(EntityUid uid, ZombieBlobComponent component, ComponentStartup args)
{
EnsureComp<BlobMobComponent>(uid);
EnsureComp<BlobSpeakComponent>(uid);

var oldFactions = new List<string>();
var factionComp = EnsureComp<NpcFactionMemberComponent>(uid);
Expand Down Expand Up @@ -114,6 +115,11 @@ private void OnShutdown(EntityUid uid, ZombieBlobComponent component, ComponentS
return;
}

if (HasComp<BlobSpeakComponent>(uid))
{
RemComp<BlobSpeakComponent>(uid);
}

if (HasComp<BlobMobComponent>(uid))
{
RemComp<BlobMobComponent>(uid);
Expand Down
Loading

0 comments on commit aa2c871

Please sign in to comment.