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

[Port] Heretics #1048

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
8 changes: 8 additions & 0 deletions Content.Client/ADT/Heretic/GhoulSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using Content.Shared.Heretic;

namespace Content.Client.Heretic;

public sealed class GhoulSystem : SharedGhoulSystem
{

}
8 changes: 8 additions & 0 deletions Content.Client/ADT/Heretic/HereticAbilitySystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using Content.Shared.Heretic;

namespace Content.Client.Heretic;

public sealed class HereticAbilitySystem : SharedHereticAbilitySystem
{

}
44 changes: 44 additions & 0 deletions Content.Client/ADT/Heretic/HereticCombatMarkSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using Content.Shared.Heretic;
using Robust.Client.GameObjects;
using Robust.Shared.Utility;

namespace Content.Client.Heretic;

public sealed partial class HereticCombatMarkSystem : EntitySystem
{
public override void Initialize()
{
base.Initialize();

SubscribeLocalEvent<HereticCombatMarkComponent, ComponentStartup>(OnStartup);
SubscribeLocalEvent<HereticCombatMarkComponent, ComponentShutdown>(OnShutdown);
}

private void OnStartup(Entity<HereticCombatMarkComponent> ent, ref ComponentStartup args)
{
if (!TryComp<SpriteComponent>(ent, out var sprite))
return;

if (sprite.LayerMapTryGet(0, out var l))
{
sprite.LayerSetState(l, ent.Comp.Path.ToString().ToLower());
return;
}

var rsi = new SpriteSpecifier.Rsi(new ResPath("ADT/Heretic/combat_marks.rsi"), ent.Comp.Path.ToString().ToLower());
var layer = sprite.AddLayer(rsi);

sprite.LayerMapSet(0, layer);
sprite.LayerSetShader(layer, "unshaded");
}
private void OnShutdown(Entity<HereticCombatMarkComponent> ent, ref ComponentShutdown args)
{
if (!TryComp<SpriteComponent>(ent, out var sprite))
return;

if (!sprite.LayerMapTryGet(0, out var layer))
return;

sprite.RemoveLayer(layer);
}
}
67 changes: 67 additions & 0 deletions Content.Client/ADT/Heretic/Ritual.CustomBehaviors.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using Content.Shared.Heretic.Prototypes;

namespace Content.Client.Heretic;

// these do nothing and are there just for yaml limter to shut the fuck up.
// make sure they stay up in sync with the server counterpart.
// regards.
// - john

public sealed partial class RitualAshAscendBehavior : RitualSacrificeBehavior { }
public sealed partial class RitualMuteGhoulifyBehavior : RitualSacrificeBehavior { }

[Virtual] public partial class RitualSacrificeBehavior : RitualCustomBehavior
{
public override bool Execute(RitualData args, out string? outstr)
{
outstr = null;
return true;
}

public override void Finalize(RitualData args)
{
// do nothing
}
}

public sealed partial class RitualTemperatureBehavior : RitualCustomBehavior
{
public override bool Execute(RitualData args, out string? outstr)
{
outstr = null;
return true;
}

public override void Finalize(RitualData args)
{
// do nothing
}
}

public sealed partial class RitualReagentPuddleBehavior : RitualCustomBehavior
{
public override bool Execute(RitualData args, out string? outstr)
{
outstr = null;
return true;
}

public override void Finalize(RitualData args)
{
// do nothing
}
}

public sealed partial class RitualKnowledgeBehavior : RitualCustomBehavior
{
public override bool Execute(RitualData args, out string? outstr)
{
outstr = null;
return true;
}

public override void Finalize(RitualData args)
{
// do nothing
}
}
69 changes: 69 additions & 0 deletions Content.Server/ADT/Clothing/MadnessMaskSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using Content.Server.EntityEffects.Effects;
using Content.Shared.Clothing.Components;
using Content.Shared.Damage.Components;
using Content.Shared.Damage.Systems;
using Content.Shared.Drugs;
using Content.Shared.Drunk;
using Content.Shared.Heretic;
using Content.Shared.Jittering;
using Content.Shared.StatusEffect;
using Content.Shared.Stunnable;
using Robust.Shared.Random;

namespace Content.Server.Goobstation.Clothing;

public sealed partial class MadnessMaskSystem : EntitySystem
{
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly StaminaSystem _stamina = default!;
[Dependency] private readonly SharedJitteringSystem _jitter = default!;
[Dependency] private readonly StatusEffectsSystem _statusEffect = default!;
[Dependency] private readonly IRobustRandom _random = default!;

private EntityQuery<HereticComponent> _hereticQuery;
private EntityQuery<GhoulComponent> _ghoulQuery;
private EntityQuery<StaminaComponent> _staminaQuery;
private HashSet<EntityUid> _maskEffectEntities = new();

public override void Initialize()
{
base.Initialize();
_hereticQuery = GetEntityQuery<HereticComponent>();
_ghoulQuery = GetEntityQuery<GhoulComponent>();
_staminaQuery = GetEntityQuery<StaminaComponent>();
}

public override void Update(float frameTime)
{
base.Update(frameTime);

var query = EntityQueryEnumerator<MadnessMaskComponent>();

while (query.MoveNext(out var owner, out var mask))
{
mask.UpdateAccumulator += frameTime;
if (mask.UpdateAccumulator < mask.UpdateTimer)
continue;

mask.UpdateAccumulator = 0;

_maskEffectEntities.Clear();
_lookup.GetEntitiesInRange(owner, 5f, _maskEffectEntities);
foreach (var look in _maskEffectEntities)
{
// heathens exclusive
if (_hereticQuery.HasComp(look) || _ghoulQuery.HasComp(look))
continue;

if (_random.Prob(.4f) && _staminaQuery.TryComp(look, out var staminaComp))
_stamina.TakeStaminaDamage(look, 5f, staminaComp, visual: false);

if (_random.Prob(.4f))
_jitter.DoJitter(look, TimeSpan.FromSeconds(.5f), true, amplitude: 5, frequency: 10);

if (_random.Prob(.25f))
_statusEffect.TryAddStatusEffect<SeeingRainbowsComponent>(look, "SeeingRainbows", TimeSpan.FromSeconds(10f), false);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using Content.Shared.Store;
using Robust.Shared.Prototypes;

namespace Content.Server.GameTicking.Rules.Components;

[RegisterComponent, Access(typeof(HereticRuleSystem))]
public sealed partial class HereticRuleComponent : Component
{
public readonly List<EntityUid> Minds = new();

public readonly List<ProtoId<StoreCategoryPrototype>> StoreCategories = new()
{
"HereticPathAsh",
//"HereticPathLock", //TODO
"HereticPathFlesh",
//"HereticPathBlade", //TODO
"HereticPathVoid",
//"HereticPathRust", //TODO
"HereticPathSide"
};
}
127 changes: 127 additions & 0 deletions Content.Server/ADT/GameTicking/Rules/HereticRuleSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
using Content.Server.Antag;
using Content.Server.GameTicking.Rules.Components;
using Content.Server.Mind;
using Content.Server.Objectives;
using Content.Server.Objectives.Components;
using Content.Server.Roles;
using Content.Shared.Heretic;
using Content.Shared.NPC.Prototypes;
using Content.Shared.NPC.Systems;
using Content.Shared.Roles;
using Content.Shared.Store;
using Content.Shared.Store.Components;
using Robust.Shared.Audio;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.GameObjects;
using System.Text;

namespace Content.Server.GameTicking.Rules;

public sealed partial class HereticRuleSystem : GameRuleSystem<HereticRuleComponent>
{
[Dependency] private readonly MindSystem _mind = default!;
[Dependency] private readonly SharedRoleSystem _role = default!;
[Dependency] private readonly NpcFactionSystem _npcFaction = default!;
[Dependency] private readonly ObjectivesSystem _objective = default!;
[Dependency] private readonly IRobustRandom _rand = default!;

public readonly SoundSpecifier BriefingSound =
new SoundPathSpecifier("/Audio/ADT/Heretic/Ambience/Antag/Heretic/heretic_gain.ogg");

public readonly ProtoId<NpcFactionPrototype> HereticFactionId = "Heretic";

public readonly ProtoId<NpcFactionPrototype> NanotrasenFactionId = "NanoTrasen";

public readonly ProtoId<CurrencyPrototype> Currency = "KnowledgePoint";

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

SubscribeLocalEvent<HereticRuleComponent, AfterAntagEntitySelectedEvent>(OnAntagSelect);
SubscribeLocalEvent<HereticRuleComponent, ObjectivesTextPrependEvent>(OnTextPrepend);
}

[ValidatePrototypeId<EntityPrototype>] private const string EldritchInfluence = "EldritchInfluence";

private void OnAntagSelect(Entity<HereticRuleComponent> ent, ref AfterAntagEntitySelectedEvent args)
{
TryMakeHeretic(args.EntityUid, ent.Comp);

var antagCount = _rand.Next(6, 12);
for (var i = 0; i < antagCount; i++)
{
if (TryFindRandomTile(out var _, out var _, out var _, out var coords))
Spawn(EldritchInfluence, coords);
}
}

[ValidatePrototypeId<EntityPrototype>]
private const string HereticMindRolePrototype = "Heretic";

public bool TryMakeHeretic(EntityUid target, HereticRuleComponent rule)
{
if (!_mind.TryGetMind(target, out var mindId, out var mind))
return false;

// briefing
if (HasComp<MetaDataComponent>(target))
{
_role.MindAddRole(mindId, HereticMindRolePrototype, mind);
}

_npcFaction.RemoveFaction(target, NanotrasenFactionId, false);
_npcFaction.AddFaction(target, HereticFactionId);

EnsureComp<HereticComponent>(target);

// add store
var store = EnsureComp<StoreComponent>(target);
foreach (var category in rule.StoreCategories)
{
store.Categories.Add(category);
}

store.CurrencyWhitelist.Add(Currency);
store.Balance.Add(Currency, 2);

rule.Minds.Add(mindId);
return true;
}

public void OnTextPrepend(Entity<HereticRuleComponent> ent, ref ObjectivesTextPrependEvent args)
{
var sb = new StringBuilder();

var mostKnowledge = 0f;
var mostKnowledgeName = string.Empty;

var query = EntityQueryEnumerator<HereticComponent>();

while (query.MoveNext(out var owner, out var heretic))
{
if (!_mind.TryGetMind(owner, out var mindId, out var mind))
continue;

var name = _objective.GetTitle((mindId, mind), Name(owner));
if (_mind.TryGetObjectiveComp<HereticKnowledgeConditionComponent>(mindId, out var objective, mind))
{
if (objective.Researched > mostKnowledge)
mostKnowledge = objective.Researched;
mostKnowledgeName = name;
}

var str = Loc.GetString($"roundend-prepend-heretic-ascension-{(heretic.Ascended ? "success" : "fail")}",
("name", name));
sb.AppendLine(str);
}

sb.AppendLine("\n" + Loc.GetString("roundend-prepend-heretic-knowledge-named",
("name", mostKnowledgeName),
("number", mostKnowledge)));

args.Text = sb.ToString();
}
}
Loading
Loading