Vampire clan battle gamemode (#1672)
* vampire returns + transformstions redo * carcat fangs fix + greetings music update * vampire skill trees * Blood essence gathering Introduces the vampire blood essence mechanic, including the CP14SpellVampireGatherEssence spell, new skill point consumable component, and related UI/localization updates. Adds clientside effects for spell casting, new vampire skill and action, and refines skill point gain/loss popups. Also restructures vampire components, updates spell logic for client/server prediction, and removes unused parallax files. * perma damage * Add skill point cost to magic system and vampire essence spell Introduced CP14MagicEffectSkillPointCostComponent to allow magic effects to consume skill points. Updated the shared magic system to handle skill point checks and consumption. Added a new vampire spell for creating blood essence, including new icons and localization. Adjusted vampire component to grant and remove skill points, and updated related skill tree and spell prototypes. Minor fixes and refactoring in spell logic and descriptions. * blood step + blood vision skills * vampire clans icons * 50 players limit + vampire objectives * fixes * devourers altar transmutation * Remove StealTarget component from animal, dino, and mole NPCs The StealTarget component and associated stealGroup were removed from boar, dinosaur, and mole NPC definitions. This likely disables these entities from being targeted for stealing, possibly to adjust gameplay balance or fix unintended behavior. * fix * essence creation improve * altars * voice masks * transmutation fix * teleportation glyph * crimson candles * candle crafting * fix pointer predictions * Add Vampire Clan Battle gamemode and update vampire roles Introduces the 'Vampire Clan Battle' gamemode with new localization in English and Russian, updated game preset definitions, and secret weights. Refactors vampire antagonist briefings and objectives for multiple clans, adjusts vampire role preferences and team settings, and reduces the damage of the Vampire Gather Essence spell. Also includes minor improvements to spell and game mode descriptions, and corrects file naming for game preset locales. * powerful kicks in * time gates + vampire tree * vampire proto faction * fix * fixes * tree progression * search enemy * Update CP14SharedVampireSystem.cs * blood essence gathering redo * essence gathering refactor 2 * blood healing * Update secret_weights.yml * tree planting * boodgrass * tree upgrade announcement * construction graph integration * delete transmutation system * workbench crafting returns * cloaks crafting + cloak invisibility * make vampire tree is generic red tree (sad) * clan heart sprite * Refactor vampire tree to clan heart system Replaces the CP14VampireTreeComponent with CP14VampireClanHeartComponent, updating all related logic, appearance, and localization. Adjusts skill requirements, examination, and level progression to use the new clan heart system. Updates entity prototypes, visuals, and adds new orb sprites for clan heart levels. Localization strings and logic are updated to reflect the new terminology and mechanics. * Update SpeciesBlacklist.cs * Refactor vampire clan heart and remove tree spell Refactored the vampire clan heart to support essence regeneration over time and adjusted level thresholds. Removed the vampire tree planting spell and related prototype fields, as well as unused tree system code. Updated localization, entity prototypes, and faction definitions to reflect these changes. * Add clan heart construction for vampire clans Introduces construction graphs, entities, and conditions for building unique clan hearts for each vampire clan (Unnameable, Devourers, NightChildrens). Adds new construction conditions (all clan vampires required, singleton enforcement), updates skill tree to unlock constructions, and removes the now-obsolete CP14MagicEffectAllVampireClanRequiredComponent. Also adds new frame sprites and updates localization and prototype files accordingly. * level up vfx * VFX + lobby track * orb resprite * sprites * Add vampire altar mechanics and improve clan heart behavior Introduces the CP14VampireAltarComponent and altar entity, which doubles blood essence extraction when victims are strapped to the altar. Adds a custom explosion behavior for vampire clan hearts upon destruction, updates construction graphs and recipes for altars, and improves localization. Also refines skill description handling and adjusts vampire bite action text. * essence get when heart destruction * Add clan heart damage and destruction announcements Introduces announcements for when a vampire clan heart is damaged or destroyed, with cooldown to prevent spam. Refactors examination logic and updates localization files for both English and Russian to support new messages and sender formatting. * glyph adaptation * resurrection * Add round end summary for Vampire Clan Battles Implemented detailed round end text for the Vampire Clan Battles game mode, displaying victory, defeat, or draw outcomes based on surviving factions and population percentage. Refactored alive player percentage logic into a shared method and updated localization files with new outcome messages in English and Russian. Also removed an unused field from the defence condition component. * Update vampire_cloak.yml * fix * fix * Update portal_glyph.yml
This commit is contained in:
@@ -30,6 +30,9 @@ public sealed partial class AdminVerbSystem
|
||||
private static readonly EntProtoId DefaultRevsRule = "Revolutionary";
|
||||
private static readonly EntProtoId DefaultThiefRule = "Thief";
|
||||
private static readonly ProtoId<StartingGearPrototype> PirateGearId = "PirateGear";
|
||||
//CP14
|
||||
private static readonly EntProtoId CP14VampireRule = "CP14GameRuleVampireClanBattle";
|
||||
//CP14 end
|
||||
|
||||
private static readonly EntProtoId ParadoxCloneRuleId = "ParadoxCloneSpawn";
|
||||
|
||||
@@ -49,6 +52,21 @@ public sealed partial class AdminVerbSystem
|
||||
|
||||
var targetPlayer = targetActor.PlayerSession;
|
||||
|
||||
Verb vampire = new()
|
||||
{
|
||||
Text = Loc.GetString("cp14-admin-verb-text-make-vampire"),
|
||||
Category = VerbCategory.Antag,
|
||||
Icon = new SpriteSpecifier.Rsi(new ResPath("/Textures/_CP14/Actions/Spells/vampire.rsi"),
|
||||
"bite"),
|
||||
Act = () =>
|
||||
{
|
||||
_antag.ForceMakeAntag<CP14VampireRuleComponent>(targetPlayer, CP14VampireRule);
|
||||
},
|
||||
Impact = LogImpact.High,
|
||||
Message = Loc.GetString("cp14-admin-verb-make-vampire"),
|
||||
};
|
||||
args.Verbs.Add(vampire);
|
||||
|
||||
/* CP14 disable default antags
|
||||
var traitorName = Loc.GetString("admin-verb-text-make-traitor");
|
||||
Verb traitor = new()
|
||||
|
||||
@@ -366,7 +366,7 @@ public sealed partial class ChatSystem : SharedChatSystem
|
||||
_chatManager.ChatMessageToManyFiltered(filter, ChatChannel.Radio, message, wrappedMessage, source ?? default, false, true, colorOverride);
|
||||
if (playSound)
|
||||
{
|
||||
_audio.PlayGlobal(announcementSound?.ToString() ?? DefaultAnnouncementSound, filter, true, AudioParams.Default.WithVolume(-2f));
|
||||
_audio.PlayGlobal(announcementSound == null ? DefaultAnnouncementSound : _audio.ResolveSound(announcementSound), filter, true, AudioParams.Default.WithVolume(-2f)); //CP14 bugfix with sound resolving
|
||||
}
|
||||
_adminLogger.Add(LogType.Chat, LogImpact.Low, $"Station Announcement from {sender}: {message}");
|
||||
}
|
||||
|
||||
@@ -375,6 +375,17 @@ namespace Content.Server.Construction
|
||||
return false;
|
||||
}
|
||||
|
||||
//CP14 requirements
|
||||
foreach (var req in constructionPrototype.CP14Restrictions)
|
||||
{
|
||||
if (!req.Check(EntityManager, user))
|
||||
{
|
||||
_popup.PopupEntity(req.GetDescription(EntityManager, PrototypeManager), user, user);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//CP14 end
|
||||
|
||||
var startNode = constructionGraph.Nodes[constructionPrototype.StartNode];
|
||||
var targetNode = constructionGraph.Nodes[constructionPrototype.TargetNode];
|
||||
var pathFind = constructionGraph.Path(startNode.Name, targetNode.Name);
|
||||
@@ -460,6 +471,17 @@ namespace Content.Server.Construction
|
||||
return;
|
||||
}
|
||||
|
||||
//CP14 requirements
|
||||
foreach (var req in constructionPrototype.CP14Restrictions)
|
||||
{
|
||||
if (!req.Check(EntityManager, user))
|
||||
{
|
||||
_popup.PopupEntity(req.GetDescription(EntityManager, PrototypeManager), user, user);
|
||||
return;
|
||||
}
|
||||
}
|
||||
//CP14 end
|
||||
|
||||
if (_container.IsEntityInContainer(user))
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("construction-system-inside-container"), user, user);
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
using Content.Shared._CP14.Vampire;
|
||||
using Content.Shared._CP14.Vampire.Components;
|
||||
using Content.Shared.Construction;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
using Content.Shared.SSDIndicator;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server._CP14.Construction.Condition;
|
||||
|
||||
[UsedImplicitly]
|
||||
[DataDefinition]
|
||||
public sealed partial class CP14AllVampireClanRequired : IGraphCondition
|
||||
{
|
||||
[DataField(required: true)]
|
||||
public ProtoId<CP14VampireFactionPrototype> Faction;
|
||||
|
||||
public bool Condition(EntityUid craft, IEntityManager entityManager)
|
||||
{
|
||||
if (!entityManager.TryGetComponent<TransformComponent>(craft, out var craftXform))
|
||||
return false;
|
||||
|
||||
var mobState = entityManager.System<MobStateSystem>();
|
||||
|
||||
var query = entityManager.EntityQueryEnumerator<CP14VampireComponent, TransformComponent>();
|
||||
while (query.MoveNext(out var uid, out var vampire, out var xform))
|
||||
{
|
||||
if (vampire.Faction != Faction)
|
||||
continue;
|
||||
|
||||
if (mobState.IsDead(uid))
|
||||
continue;
|
||||
|
||||
if (entityManager.TryGetComponent<SSDIndicatorComponent>(uid, out var ssd) && ssd.IsSSD)
|
||||
continue;
|
||||
|
||||
//Check distance to the vampire
|
||||
if (!xform.Coordinates.TryDistance(entityManager, craftXform.Coordinates, out var distance) || distance > 2)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool DoExamine(ExaminedEvent args)
|
||||
{
|
||||
if (Condition(args.Examined, IoCManager.Resolve<IEntityManager>()))
|
||||
return false;
|
||||
|
||||
args.PushMarkup(Loc.GetString("cp14-magic-spell-need-all-vampires"));
|
||||
return true;
|
||||
}
|
||||
|
||||
public IEnumerable<ConstructionGuideEntry> GenerateGuideEntry()
|
||||
{
|
||||
yield return new ConstructionGuideEntry()
|
||||
{
|
||||
Localization = "cp14-magic-spell-need-all-vampires",
|
||||
Icon = new SpriteSpecifier.Rsi(new ResPath("/Textures/_CP14/Actions/Spells/vampire.rsi"), "blood_moon"),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using Content.Shared._CP14.UniqueLoot;
|
||||
using Content.Shared.Construction;
|
||||
using Content.Shared.Examine;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Content.Server._CP14.Construction.Condition;
|
||||
|
||||
[UsedImplicitly]
|
||||
[DataDefinition]
|
||||
public sealed partial class CP14SingletonNotExist : IGraphCondition
|
||||
{
|
||||
[DataField(required: true)]
|
||||
public string Key = string.Empty;
|
||||
|
||||
public bool Condition(EntityUid craft, IEntityManager entityManager)
|
||||
{
|
||||
var query = entityManager.EntityQueryEnumerator<CP14SingletonComponent>();
|
||||
while (query.MoveNext(out var uid, out var singleton))
|
||||
{
|
||||
if (singleton.Key == Key)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool DoExamine(ExaminedEvent args)
|
||||
{
|
||||
if (Condition(args.Examined, IoCManager.Resolve<IEntityManager>()))
|
||||
return false;
|
||||
|
||||
args.PushMarkup(Loc.GetString("cp14-construction-condition-singleton"));
|
||||
return true;
|
||||
}
|
||||
|
||||
public IEnumerable<ConstructionGuideEntry> GenerateGuideEntry()
|
||||
{
|
||||
yield return new ConstructionGuideEntry()
|
||||
{
|
||||
Localization = "cp14-construction-condition-singleton",
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,96 +1,87 @@
|
||||
using System.Linq;
|
||||
using Content.Server._CP14.GameTicking.Rules.Components;
|
||||
using Content.Server._CP14.Vampire;
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Body.Components;
|
||||
using Content.Server.Body.Systems;
|
||||
using Content.Server._CP14.Objectives.Systems;
|
||||
using Content.Server.GameTicking;
|
||||
using Content.Server.GameTicking.Rules;
|
||||
using Content.Server.Temperature.Components;
|
||||
using Content.Server.Temperature.Systems;
|
||||
using Content.Shared._CP14.Vampire;
|
||||
using Content.Shared.Nutrition.Components;
|
||||
using Content.Shared.Nutrition.EntitySystems;
|
||||
using Content.Shared.Popups;
|
||||
using Robust.Shared.Timing;
|
||||
using Content.Shared._CP14.Vampire.Components;
|
||||
using Content.Shared.GameTicking.Components;
|
||||
using Content.Shared.Mobs;
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._CP14.GameTicking.Rules;
|
||||
|
||||
public sealed class CP14VampireRuleSystem : GameRuleSystem<CP14VampireRuleComponent>
|
||||
{
|
||||
[Dependency] private readonly BloodstreamSystem _bloodstream = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly TemperatureSystem _temperature = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
[Dependency] private readonly FlammableSystem _flammable = default!;
|
||||
[Dependency] private readonly BodySystem _body = default!;
|
||||
[Dependency] private readonly CP14VampireObjectiveConditionsSystem _condition = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
|
||||
public override void Initialize()
|
||||
protected override void AppendRoundEndText(EntityUid uid,
|
||||
CP14VampireRuleComponent component,
|
||||
GameRuleComponent gameRule,
|
||||
ref RoundEndTextAppendEvent args)
|
||||
{
|
||||
base.Initialize();
|
||||
base.AppendRoundEndText(uid, component, gameRule, ref args);
|
||||
|
||||
SubscribeLocalEvent<CP14VampireComponent, MapInitEvent>(OnVampireInit);
|
||||
SubscribeLocalEvent<CP14VampireComponent, CP14HungerChangedEvent>(OnVampireHungerChanged);
|
||||
}
|
||||
//Alive percentage
|
||||
var alivePercentage = _condition.CalculateAlivePlayersPercentage();
|
||||
|
||||
private void OnVampireHungerChanged(Entity<CP14VampireComponent> ent, ref CP14HungerChangedEvent args)
|
||||
{
|
||||
if (args.NewThreshold == HungerThreshold.Starving || args.NewThreshold == HungerThreshold.Dead)
|
||||
var aliveFactions = new HashSet<ProtoId<CP14VampireFactionPrototype>>();
|
||||
|
||||
var query = EntityQueryEnumerator<CP14VampireComponent, MobStateComponent>();
|
||||
while (query.MoveNext(out var vampireUid, out var vampire, out var mobState))
|
||||
{
|
||||
RevealVampire(ent);
|
||||
if (mobState.CurrentState != MobState.Alive)
|
||||
continue;
|
||||
|
||||
if (vampire.Faction is null)
|
||||
continue;
|
||||
|
||||
aliveFactions.Add(vampire.Faction.Value);
|
||||
}
|
||||
|
||||
args.AddLine($"[head=2][color=#ab1b3d]{Loc.GetString("cp14-vampire-clans-battle")}[/color][/head]");
|
||||
|
||||
if (alivePercentage > _condition.RequiredAlivePercentage)
|
||||
{
|
||||
if (aliveFactions.Count == 0)
|
||||
{
|
||||
//City win
|
||||
args.AddLine($"[head=3][color=#7d112b]{Loc.GetString("cp14-vampire-clans-battle-clan-city-win")}[/color][/head]");
|
||||
args.AddLine(Loc.GetString("cp14-vampire-clans-battle-clan-city-win-desc"));
|
||||
}
|
||||
|
||||
if (aliveFactions.Count == 1)
|
||||
{
|
||||
var faction = aliveFactions.First();
|
||||
|
||||
if (_proto.TryIndex(faction, out var indexedFaction))
|
||||
args.AddLine($"[head=3][color=#7d112b]{Loc.GetString("cp14-vampire-clans-battle-clan-win", ("name", Loc.GetString(indexedFaction.Name)))}[/color][/head]");
|
||||
args.AddLine(Loc.GetString("cp14-vampire-clans-battle-clan-win-desc"));
|
||||
}
|
||||
|
||||
if (aliveFactions.Count == 2)
|
||||
{
|
||||
var factions = aliveFactions.ToArray();
|
||||
|
||||
if (_proto.TryIndex(factions[0], out var indexedFaction1) && _proto.TryIndex(factions[1], out var indexedFaction2))
|
||||
args.AddLine($"[head=3][color=#7d112b]{Loc.GetString("cp14-vampire-clans-battle-clan-tie-2", ("name1", Loc.GetString(indexedFaction1.Name)), ("name2", Loc.GetString(indexedFaction2.Name)))}[/color][/head]");
|
||||
args.AddLine(Loc.GetString("cp14-vampire-clans-battle-clan-tie-2-desc"));
|
||||
}
|
||||
|
||||
if (aliveFactions.Count == 3)
|
||||
{
|
||||
args.AddLine($"[head=3][color=#7d112b]{Loc.GetString("cp14-vampire-clans-battle-clan-tie-3")}[/color][/head]");
|
||||
args.AddLine(Loc.GetString("cp14-vampire-clans-battle-clan-tie-3-desc"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
HideVampire(ent);
|
||||
args.AddLine($"[head=3][color=#7d112b]{Loc.GetString("cp14-vampire-clans-battle-clan-lose")}[/color][/head]");
|
||||
args.AddLine(Loc.GetString("cp14-vampire-clans-battle-clan-lose-desc"));
|
||||
}
|
||||
}
|
||||
|
||||
private void RevealVampire(Entity<CP14VampireComponent> ent)
|
||||
{
|
||||
EnsureComp<CP14VampireVisualsComponent>(ent);
|
||||
}
|
||||
|
||||
private void HideVampire(Entity<CP14VampireComponent> ent)
|
||||
{
|
||||
RemCompDeferred<CP14VampireVisualsComponent>(ent);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
var query = EntityQueryEnumerator<CP14VampireComponent, TemperatureComponent, FlammableComponent>();
|
||||
while (query.MoveNext(out var uid, out var vampire, out var temperature, out var flammable))
|
||||
{
|
||||
if (_timing.CurTime < vampire.NextHeatTime)
|
||||
continue;
|
||||
|
||||
vampire.NextHeatTime = _timing.CurTime + vampire.HeatFrequency;
|
||||
|
||||
return;
|
||||
//if (!_dayCycle.UnderSunlight(uid))
|
||||
// continue;
|
||||
|
||||
_temperature.ChangeHeat(uid, vampire.HeatUnderSunTemperature);
|
||||
_popup.PopupEntity(Loc.GetString("cp14-heat-under-sun"), uid, uid, PopupType.SmallCaution);
|
||||
|
||||
if (temperature.CurrentTemperature > vampire.IgniteThreshold && !flammable.OnFire)
|
||||
{
|
||||
_flammable.AdjustFireStacks(uid, 1, flammable);
|
||||
_flammable.Ignite(uid, uid, flammable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnVampireInit(Entity<CP14VampireComponent> ent, ref MapInitEvent args)
|
||||
{
|
||||
_bloodstream.ChangeBloodReagent(ent.Owner, ent.Comp.NewBloodReagent);
|
||||
|
||||
foreach (var (organUid, _) in _body.GetBodyOrgans(ent))
|
||||
{
|
||||
if (TryComp<MetabolizerComponent>(organUid, out var metabolizer) && metabolizer.MetabolizerTypes is not null)
|
||||
{
|
||||
metabolizer.MetabolizerTypes.Add(ent.Comp.MetabolizerType);
|
||||
}
|
||||
}
|
||||
args.AddLine(Loc.GetString("cp14-vampire-clans-battle-alive-people", ("percent", alivePercentage * 100)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,8 +45,6 @@ public sealed class CP14MagicSystem : CP14SharedMagicSystem
|
||||
SubscribeLocalEvent<CP14MagicEffectCastingVisualComponent, CP14StartCastMagicEffectEvent>(OnSpawnMagicVisualEffect);
|
||||
SubscribeLocalEvent<CP14MagicEffectCastingVisualComponent, CP14EndCastMagicEffectEvent>(OnDespawnMagicVisualEffect);
|
||||
|
||||
SubscribeLocalEvent<CP14MagicEffectManaCostComponent, CP14MagicEffectConsumeResourceEvent>(OnManaConsume);
|
||||
|
||||
SubscribeLocalEvent<CP14MagicEffectRequiredMusicToolComponent, CP14CastMagicEffectAttemptEvent>(OnMusicCheck);
|
||||
}
|
||||
|
||||
@@ -142,29 +140,6 @@ public sealed class CP14MagicSystem : CP14SharedMagicSystem
|
||||
ent.Comp.SpawnedEntity = null;
|
||||
}
|
||||
|
||||
private void OnManaConsume(Entity<CP14MagicEffectManaCostComponent> ent, ref CP14MagicEffectConsumeResourceEvent args)
|
||||
{
|
||||
if (!TryComp<CP14MagicEffectComponent>(ent, out var magicEffect))
|
||||
return;
|
||||
|
||||
var requiredMana = CalculateManacost(ent, args.Performer);
|
||||
|
||||
//First - used object
|
||||
if (magicEffect.SpellStorage is not null && TryComp<CP14MagicEnergyContainerComponent>(magicEffect.SpellStorage, out var magicStorage))
|
||||
{
|
||||
var spellEv = new CP14SpellFromSpellStorageUsedEvent(args.Performer, (ent, magicEffect), requiredMana);
|
||||
RaiseLocalEvent(magicEffect.SpellStorage.Value, ref spellEv);
|
||||
|
||||
_magicEnergy.ChangeEnergy((magicEffect.SpellStorage.Value, magicStorage), -requiredMana, out var changedEnergy, out var overloadedEnergy, safe: false);
|
||||
requiredMana -= FixedPoint2.Abs(changedEnergy + overloadedEnergy);
|
||||
}
|
||||
|
||||
//Second - action user
|
||||
if (requiredMana > 0 &&
|
||||
TryComp<CP14MagicEnergyContainerComponent>(args.Performer, out var playerMana))
|
||||
_magicEnergy.ChangeEnergy((args.Performer.Value, playerMana), -requiredMana, out _, out _, safe: false);
|
||||
}
|
||||
|
||||
private void OnMusicCheck(Entity<CP14MagicEffectRequiredMusicToolComponent> ent, ref CP14CastMagicEffectAttemptEvent args)
|
||||
{
|
||||
var passed = false;
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
using Content.Server._CP14.Objectives.Systems;
|
||||
using Content.Shared._CP14.Vampire;
|
||||
using Content.Shared.StatusIcon;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server._CP14.Objectives.Components;
|
||||
|
||||
[RegisterComponent, Access(typeof(CP14VampireObjectiveConditionsSystem))]
|
||||
public sealed partial class CP14VampireBloodPurityConditionComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public ProtoId<CP14VampireFactionPrototype>? Faction;
|
||||
|
||||
[DataField]
|
||||
public SpriteSpecifier Icon = new SpriteSpecifier.Rsi(new ResPath("/Textures/_CP14/Actions/Spells/vampire.rsi"), "blood_moon");
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using Content.Server._CP14.Objectives.Systems;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server._CP14.Objectives.Components;
|
||||
|
||||
[RegisterComponent, Access(typeof(CP14VampireObjectiveConditionsSystem))]
|
||||
public sealed partial class CP14VampireDefenceVillageConditionComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public SpriteSpecifier Icon = new SpriteSpecifier.Rsi(new ResPath("/Textures/_CP14/Actions/Spells/vampire.rsi"), "essence_create");
|
||||
}
|
||||
@@ -1,14 +1,9 @@
|
||||
using Content.Server._CP14.Objectives.Components;
|
||||
using Content.Server.Cargo.Systems;
|
||||
using Content.Server.Objectives.Components;
|
||||
using Content.Shared._CP14.Currency;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Mind;
|
||||
using Content.Shared.Mind.Components;
|
||||
using Content.Shared.Movement.Pulling.Components;
|
||||
using Content.Shared.Objectives.Components;
|
||||
using Content.Shared.Objectives.Systems;
|
||||
using Robust.Shared.Containers;
|
||||
|
||||
namespace Content.Server._CP14.Objectives.Systems;
|
||||
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
using Content.Server._CP14.Objectives.Components;
|
||||
using Content.Server.Station.Components;
|
||||
using Content.Shared._CP14.Vampire.Components;
|
||||
using Content.Shared.Mind;
|
||||
using Content.Shared.Mobs;
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
using Content.Shared.Objectives.Components;
|
||||
using Content.Shared.Objectives.Systems;
|
||||
using Content.Shared.Roles.Jobs;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._CP14.Objectives.Systems;
|
||||
|
||||
public sealed class CP14VampireObjectiveConditionsSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly MetaDataSystem _meta = default!;
|
||||
[Dependency] private readonly SharedObjectivesSystem _objectives = default!;
|
||||
[Dependency] private readonly SharedMindSystem _mind = default!;
|
||||
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||
[Dependency] private readonly SharedJobSystem _jobs = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
|
||||
public readonly float RequiredAlivePercentage = 0.5f;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<CP14VampireBloodPurityConditionComponent, ObjectiveAfterAssignEvent>(OnBloodPurityAfterAssign);
|
||||
SubscribeLocalEvent<CP14VampireBloodPurityConditionComponent, ObjectiveGetProgressEvent>(OnBloodPurityGetProgress);
|
||||
|
||||
SubscribeLocalEvent<CP14VampireDefenceVillageConditionComponent, ObjectiveAfterAssignEvent>(OnDefenceAfterAssign);
|
||||
SubscribeLocalEvent<CP14VampireDefenceVillageConditionComponent, ObjectiveGetProgressEvent>(OnDefenceGetProgress);
|
||||
}
|
||||
|
||||
private void OnDefenceAfterAssign(Entity<CP14VampireDefenceVillageConditionComponent> ent, ref ObjectiveAfterAssignEvent args)
|
||||
{
|
||||
_meta.SetEntityName(ent, Loc.GetString("cp14-objective-vampire-defence-settlement-title"));
|
||||
_meta.SetEntityDescription(ent, Loc.GetString("cp14-objective-vampire-defence-settlement-desc", ("count", RequiredAlivePercentage * 100)));
|
||||
_objectives.SetIcon(ent, ent.Comp.Icon);
|
||||
}
|
||||
|
||||
public float CalculateAlivePlayersPercentage()
|
||||
{
|
||||
var query = EntityQueryEnumerator<StationJobsComponent>();
|
||||
|
||||
var totalPlayers = 0f;
|
||||
var alivePlayers = 0f;
|
||||
while (query.MoveNext(out var uid, out var jobs))
|
||||
{
|
||||
totalPlayers += jobs.PlayerJobs.Count;
|
||||
|
||||
foreach (var (netUserId, jobsList) in jobs.PlayerJobs)
|
||||
{
|
||||
if (!_mind.TryGetMind(netUserId, out var mind))
|
||||
continue;
|
||||
|
||||
if (!_jobs.MindTryGetJob(mind, out var jobRole))
|
||||
continue;
|
||||
|
||||
var firstMindEntity = GetEntity(mind.Value.Comp.OriginalOwnedEntity);
|
||||
|
||||
if (firstMindEntity is null)
|
||||
continue;
|
||||
|
||||
if (!_mobState.IsDead(firstMindEntity.Value))
|
||||
alivePlayers++;
|
||||
}
|
||||
}
|
||||
|
||||
return totalPlayers > 0 ? (alivePlayers / totalPlayers) : 0f;
|
||||
}
|
||||
|
||||
private void OnDefenceGetProgress(Entity<CP14VampireDefenceVillageConditionComponent> ent, ref ObjectiveGetProgressEvent args)
|
||||
{
|
||||
args.Progress = CalculateAlivePlayersPercentage() > RequiredAlivePercentage ? 1 : 0;
|
||||
}
|
||||
|
||||
private void OnBloodPurityAfterAssign(Entity<CP14VampireBloodPurityConditionComponent> ent, ref ObjectiveAfterAssignEvent args)
|
||||
{
|
||||
if (!TryComp<CP14VampireComponent>(args.Mind?.OwnedEntity, out var vampireComp))
|
||||
return;
|
||||
|
||||
ent.Comp.Faction = vampireComp.Faction;
|
||||
|
||||
_meta.SetEntityName(ent, Loc.GetString("cp14-objective-vampire-pure-bood-title"));
|
||||
_meta.SetEntityDescription(ent, Loc.GetString("cp14-objective-vampire-pure-bood-desc"));
|
||||
_objectives.SetIcon(ent, ent.Comp.Icon);
|
||||
}
|
||||
|
||||
private void OnBloodPurityGetProgress(Entity<CP14VampireBloodPurityConditionComponent> ent, ref ObjectiveGetProgressEvent args)
|
||||
{
|
||||
var query = EntityQueryEnumerator<CP14VampireComponent, MobStateComponent>();
|
||||
|
||||
while (query.MoveNext(out var uid, out var vampire, out var mobState))
|
||||
{
|
||||
if (vampire.Faction != ent.Comp.Faction)
|
||||
{
|
||||
if (mobState.CurrentState == MobState.Dead)
|
||||
continue;
|
||||
|
||||
args.Progress = 0f;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
args.Progress = 1f;
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@ using System.Linq;
|
||||
using Content.Shared._CP14.UniqueLoot;
|
||||
using Content.Shared.GameTicking;
|
||||
using Content.Shared.Tag;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
@@ -23,10 +22,24 @@ public sealed partial class CP14UniqueLootSystem : EntitySystem
|
||||
SubscribeLocalEvent<RoundRestartCleanupEvent>(OnCleanup);
|
||||
|
||||
SubscribeLocalEvent<CP14UniqueLootSpawnerComponent, MapInitEvent>(OnMapInit);
|
||||
SubscribeLocalEvent<CP14SingletonComponent, MapInitEvent>(OnSingletonMapInit);
|
||||
|
||||
RefreshUniqueLoot();
|
||||
}
|
||||
|
||||
private void OnSingletonMapInit(Entity<CP14SingletonComponent> ent, ref MapInitEvent args)
|
||||
{
|
||||
var query = EntityQueryEnumerator<CP14SingletonComponent>();
|
||||
while (query.MoveNext(out var existingEnt, out var existingComp))
|
||||
{
|
||||
if (existingEnt == ent.Owner || existingComp.Key != ent.Comp.Key)
|
||||
continue;
|
||||
|
||||
// Remove the existing entity with the same key.
|
||||
QueueDel(existingEnt);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnMapInit(Entity<CP14UniqueLootSpawnerComponent> ent, ref MapInitEvent args)
|
||||
{
|
||||
var loot = GetNextUniqueLoot(ent.Comp.Tag);
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
using System.Numerics;
|
||||
using Content.Server.Destructible;
|
||||
using Content.Server.Destructible.Thresholds.Behaviors;
|
||||
using Content.Shared._CP14.Vampire.Components;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server._CP14.Vampire;
|
||||
|
||||
[Serializable]
|
||||
[DataDefinition]
|
||||
public sealed partial class CP14VampireAltarExplodeBehavior : IThresholdBehavior
|
||||
{
|
||||
[DataField]
|
||||
public EntProtoId Essence = "CP14BloodEssence";
|
||||
|
||||
[DataField]
|
||||
public float ExtractionPercentage = 0.5f;
|
||||
|
||||
public void Execute(EntityUid owner, DestructibleSystem system, EntityUid? cause = null)
|
||||
{
|
||||
if(!system.EntityManager.TryGetComponent<TransformComponent>(owner, out var transform))
|
||||
return;
|
||||
|
||||
if(!system.EntityManager.TryGetComponent<CP14VampireClanHeartComponent>(owner, out var clanHeart))
|
||||
return;
|
||||
|
||||
var random = IoCManager.Resolve<IRobustRandom>();
|
||||
|
||||
var collected = clanHeart.CollectedEssence;
|
||||
var spawnedEssence = MathF.Floor(collected.Float() * ExtractionPercentage);
|
||||
for (var i = 0; i < spawnedEssence; i++)
|
||||
{
|
||||
system.EntityManager.SpawnAtPosition(Essence, transform.Coordinates.Offset(new Vector2(random.NextFloat(-1f, 1f), random.NextFloat(-1f, 1f))));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
using Content.Server._CP14.GameTicking.Rules;
|
||||
using Content.Shared.Body.Prototypes;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._CP14.Vampire;
|
||||
|
||||
[RegisterComponent]
|
||||
[Access(typeof(CP14VampireRuleSystem))]
|
||||
public sealed partial class CP14VampireComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public ProtoId<ReagentPrototype> NewBloodReagent = "CP14BloodVampire";
|
||||
|
||||
[DataField]
|
||||
public ProtoId<MetabolizerTypePrototype> MetabolizerType = "CP14Vampire";
|
||||
|
||||
[DataField]
|
||||
public float HeatUnderSunTemperature = 12000f;
|
||||
|
||||
[DataField]
|
||||
public TimeSpan HeatFrequency = TimeSpan.FromSeconds(1);
|
||||
|
||||
[DataField]
|
||||
public TimeSpan NextHeatTime = TimeSpan.Zero;
|
||||
|
||||
[DataField]
|
||||
public float IgniteThreshold = 350f;
|
||||
}
|
||||
102
Content.Server/_CP14/Vampire/CP14VampireSystem.Announce.cs
Normal file
102
Content.Server/_CP14/Vampire/CP14VampireSystem.Announce.cs
Normal file
@@ -0,0 +1,102 @@
|
||||
using System.Text;
|
||||
using Content.Server.Chat.Systems;
|
||||
using Content.Shared._CP14.Vampire;
|
||||
using Content.Shared._CP14.Vampire.Components;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Destructible;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Ghost;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._CP14.Vampire;
|
||||
|
||||
public sealed partial class CP14VampireSystem
|
||||
{
|
||||
[Dependency] private readonly ChatSystem _chat = default!;
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||
|
||||
private void InitializeAnnounces()
|
||||
{
|
||||
SubscribeLocalEvent<CP14VampireClanHeartComponent, DamageChangedEvent>(OnHeartDamaged);
|
||||
SubscribeLocalEvent<CP14VampireClanHeartComponent, ComponentRemove>(OnHeartDestructed);
|
||||
}
|
||||
|
||||
|
||||
private void OnHeartDamaged(Entity<CP14VampireClanHeartComponent> ent, ref DamageChangedEvent args)
|
||||
{
|
||||
if (ent.Comp.Faction is null)
|
||||
return;
|
||||
|
||||
if (!args.DamageIncreased)
|
||||
return;
|
||||
|
||||
if (_timing.CurTime < ent.Comp.NextAnnounceTime)
|
||||
return;
|
||||
|
||||
ent.Comp.NextAnnounceTime = _timing.CurTime + ent.Comp.MaxAnnounceFreq;
|
||||
|
||||
AnnounceToFaction(ent.Comp.Faction.Value, Loc.GetString("cp14-vampire-tree-damaged"));
|
||||
}
|
||||
|
||||
private void OnHeartDestructed(Entity<CP14VampireClanHeartComponent> ent, ref ComponentRemove args)
|
||||
{
|
||||
if (ent.Comp.Faction is null)
|
||||
return;
|
||||
|
||||
if (!Proto.TryIndex(ent.Comp.Faction, out var indexedFaction))
|
||||
return;
|
||||
|
||||
AnnounceToFaction(ent.Comp.Faction.Value, Loc.GetString("cp14-vampire-tree-destroyed-self"));
|
||||
AnnounceToOpposingFactions(ent.Comp.Faction.Value, Loc.GetString("cp14-vampire-tree-destroyed", ("name", Loc.GetString(indexedFaction.Name))));
|
||||
}
|
||||
|
||||
public void AnnounceToFaction(ProtoId<CP14VampireFactionPrototype> faction, string message)
|
||||
{
|
||||
var filter = Filter.Empty();
|
||||
var query = EntityQueryEnumerator<CP14VampireComponent, ActorComponent>();
|
||||
|
||||
while (query.MoveNext(out var uid, out var vampire, out var actor))
|
||||
{
|
||||
if (vampire.Faction != faction)
|
||||
continue;
|
||||
|
||||
filter.AddPlayer(actor.PlayerSession);
|
||||
}
|
||||
|
||||
if (filter.Count == 0)
|
||||
return;
|
||||
|
||||
VampireAnnounce(filter, message);
|
||||
}
|
||||
|
||||
public void AnnounceToOpposingFactions(ProtoId<CP14VampireFactionPrototype> faction, string message)
|
||||
{
|
||||
var filter = Filter.Empty();
|
||||
var query = EntityQueryEnumerator<CP14VampireComponent, ActorComponent>();
|
||||
|
||||
while (query.MoveNext(out var uid, out var vampire, out var actor))
|
||||
{
|
||||
if (vampire.Faction == faction)
|
||||
continue;
|
||||
|
||||
filter.AddPlayer(actor.PlayerSession);
|
||||
}
|
||||
|
||||
if (filter.Count == 0)
|
||||
return;
|
||||
|
||||
VampireAnnounce(filter, message);
|
||||
}
|
||||
|
||||
private void VampireAnnounce(Filter players, string message)
|
||||
{
|
||||
_chat.DispatchFilteredAnnouncement(
|
||||
players,
|
||||
message,
|
||||
sender: Loc.GetString("cp14-vampire-sender"),
|
||||
announcementSound: new SoundPathSpecifier("/Audio/_CP14/Announce/vampire.ogg"),
|
||||
colorOverride: Color.FromHex("#820e22"));
|
||||
}
|
||||
}
|
||||
176
Content.Server/_CP14/Vampire/CP14VampireSystem.cs
Normal file
176
Content.Server/_CP14/Vampire/CP14VampireSystem.cs
Normal file
@@ -0,0 +1,176 @@
|
||||
using System.Text;
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Body.Components;
|
||||
using Content.Server.Body.Systems;
|
||||
using Content.Server.Temperature.Components;
|
||||
using Content.Server.Temperature.Systems;
|
||||
using Content.Shared._CP14.DayCycle;
|
||||
using Content.Shared._CP14.Vampire;
|
||||
using Content.Shared._CP14.Vampire.Components;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Ghost;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Stacks;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Physics.Events;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server._CP14.Vampire;
|
||||
|
||||
public sealed partial class CP14VampireSystem : CP14SharedVampireSystem
|
||||
{
|
||||
[Dependency] private readonly BodySystem _body = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly TemperatureSystem _temperature = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
[Dependency] private readonly FlammableSystem _flammable = default!;
|
||||
[Dependency] private readonly CP14DayCycleSystem _dayCycle = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
InitializeAnnounces();
|
||||
|
||||
SubscribeLocalEvent<CP14VampireClanHeartComponent, StartCollideEvent>(OnStartCollide);
|
||||
SubscribeLocalEvent<CP14VampireClanHeartComponent, ExaminedEvent>(OnExamined);
|
||||
}
|
||||
|
||||
private void OnStartCollide(Entity<CP14VampireClanHeartComponent> ent, ref StartCollideEvent args)
|
||||
{
|
||||
if (!TryComp<CP14VampireTreeCollectableComponent>(args.OtherEntity, out var collectable))
|
||||
return;
|
||||
|
||||
var collect = collectable.Essence;
|
||||
|
||||
if (TryComp<StackComponent>(args.OtherEntity, out var stack))
|
||||
collect *= stack.Count;
|
||||
|
||||
AddEssence(ent, collect);
|
||||
Del(args.OtherEntity);
|
||||
|
||||
_audio.PlayPvs(collectable.CollectSound, ent);
|
||||
}
|
||||
|
||||
private void OnExamined(Entity<CP14VampireClanHeartComponent> ent, ref ExaminedEvent args)
|
||||
{
|
||||
if (!HasComp<CP14VampireComponent>(args.Examiner) && !HasComp<GhostComponent>(args.Examiner))
|
||||
return;
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
||||
// Faction
|
||||
if (Proto.TryIndex(ent.Comp.Faction, out var indexedFaction))
|
||||
sb.Append(Loc.GetString("cp14-vampire-tree-examine-faction", ("faction", Loc.GetString(indexedFaction.Name))) + "\n");
|
||||
|
||||
// Are they friend or foe?
|
||||
if (TryComp<CP14VampireComponent>(args.Examiner, out var examinerVampire))
|
||||
{
|
||||
if (examinerVampire.Faction == ent.Comp.Faction)
|
||||
sb.Append(Loc.GetString("cp14-vampire-tree-examine-friend") + "\n");
|
||||
else
|
||||
sb.Append(Loc.GetString("cp14-vampire-tree-examine-enemy") + "\n");
|
||||
}
|
||||
|
||||
//Progress
|
||||
sb.Append(Loc.GetString("cp14-vampire-tree-examine-level",
|
||||
("level", ent.Comp.Level),
|
||||
("essence", ent.Comp.EssenceFromLevelStart),
|
||||
("left", ent.Comp.EssenceToNextLevel?.ToString() ?? "∞")) + "\n"+ "\n");
|
||||
|
||||
var query = EntityQueryEnumerator<CP14VampireClanHeartComponent>();
|
||||
|
||||
sb.Append(Loc.GetString("cp14-vampire-tree-other-title") + "\n");
|
||||
while (query.MoveNext(out var uid, out var heart))
|
||||
{
|
||||
if (uid == ent.Owner)
|
||||
continue;
|
||||
|
||||
if (!Proto.TryIndex(heart.Faction, out var indexedOtherFaction))
|
||||
continue;
|
||||
|
||||
sb.Append(Loc.GetString("cp14-vampire-tree-other-info",
|
||||
("name", Loc.GetString(indexedOtherFaction.Name)),
|
||||
("essence", heart.EssenceFromLevelStart),
|
||||
("left", heart.EssenceToNextLevel?.ToString() ?? "∞"),
|
||||
("lvl", heart.Level)) + "\n");
|
||||
}
|
||||
|
||||
args.PushMarkup(sb.ToString());
|
||||
}
|
||||
|
||||
private void AddEssence(Entity<CP14VampireClanHeartComponent> ent, FixedPoint2 amount)
|
||||
{
|
||||
if (!Proto.TryIndex(ent.Comp.Faction, out var indexedFaction) || ent.Comp.Faction == null)
|
||||
return;
|
||||
|
||||
var level = ent.Comp.Level;
|
||||
|
||||
ent.Comp.CollectedEssence += amount;
|
||||
Dirty(ent);
|
||||
|
||||
if (level < ent.Comp.Level) //Level up!
|
||||
{
|
||||
_appearance.SetData(ent, VampireClanLevelVisuals.Level, ent.Comp.Level);
|
||||
AnnounceToOpposingFactions(ent.Comp.Faction.Value, Loc.GetString("cp14-vampire-tree-growing", ("name", Loc.GetString(indexedFaction.Name)), ("level", ent.Comp.Level)));
|
||||
AnnounceToFaction(ent.Comp.Faction.Value, Loc.GetString("cp14-vampire-tree-growing-self", ("level", ent.Comp.Level)));
|
||||
|
||||
SpawnAtPosition(ent.Comp.LevelUpVfx, Transform(ent).Coordinates);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnVampireInit(Entity<CP14VampireComponent> ent, ref MapInitEvent args)
|
||||
{
|
||||
base.OnVampireInit(ent, ref args);
|
||||
|
||||
//Metabolism
|
||||
foreach (var (organUid, _) in _body.GetBodyOrgans(ent))
|
||||
{
|
||||
if (TryComp<MetabolizerComponent>(organUid, out var metabolizer) && metabolizer.MetabolizerTypes is not null)
|
||||
{
|
||||
metabolizer.MetabolizerTypes.Add(ent.Comp.MetabolizerType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
//Vampire under sun heating
|
||||
var query = EntityQueryEnumerator<CP14VampireComponent, CP14VampireVisualsComponent, TemperatureComponent, FlammableComponent>();
|
||||
while (query.MoveNext(out var uid, out var vampire, out var visuals, out var temperature, out var flammable))
|
||||
{
|
||||
if (_timing.CurTime < vampire.NextHeatTime)
|
||||
continue;
|
||||
|
||||
vampire.NextHeatTime = _timing.CurTime + vampire.HeatFrequency;
|
||||
|
||||
if (!_dayCycle.UnderSunlight(uid))
|
||||
continue;
|
||||
|
||||
_temperature.ChangeHeat(uid, vampire.HeatUnderSunTemperature);
|
||||
_popup.PopupEntity(Loc.GetString("cp14-heat-under-sun"), uid, uid, PopupType.SmallCaution);
|
||||
|
||||
if (temperature.CurrentTemperature > vampire.IgniteThreshold && !flammable.OnFire)
|
||||
{
|
||||
_flammable.AdjustFireStacks(uid, 1, flammable);
|
||||
_flammable.Ignite(uid, uid, flammable);
|
||||
}
|
||||
}
|
||||
|
||||
var heartQuery = EntityQueryEnumerator<CP14VampireClanHeartComponent>();
|
||||
//regen essence over time
|
||||
while (heartQuery.MoveNext(out var uid, out var heart))
|
||||
{
|
||||
if (_timing.CurTime < heart.NextRegenTime)
|
||||
continue;
|
||||
|
||||
heart.NextRegenTime = _timing.CurTime + heart.RegenFrequency;
|
||||
|
||||
AddEssence((uid, heart), heart.EssenceRegenPerLevel * heart.Level);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
using Content.Shared._CP14.Vampire;
|
||||
|
||||
namespace Content.Server._CP14.Vampire;
|
||||
|
||||
public sealed class CP14VampireVisualsSystem : CP14SharedVampireVisualsSystem
|
||||
{
|
||||
}
|
||||
Reference in New Issue
Block a user