Magic vision nerf (#1697)

* Update ShowHealthBarsComponent.cs

* mana split now can destroy mana trace

* delete aura examine

* Add aura confusion status effect and concealment reagent

Introduces the Confused Aura status effect, which causes entities to leave randomized magical aura imprints. Adds the CP14HideMagicAuraStatusEffectComponent, new localization strings, alert, and reagent (Aura concealment solution) that applies the effect. Updates magic vision logic to support the new effect, and adds related icons and prototype definitions.

* vampire market

* easy vampire clothing craft

* obscure magic trace
This commit is contained in:
Red
2025-08-23 15:03:33 +03:00
committed by GitHub
parent 5699b4a7a0
commit 9bda0c85e2
30 changed files with 258 additions and 60 deletions

View File

@@ -1,6 +1,8 @@
using Content.Shared._CP14.AuraDNA;
using Content.Shared._CP14.MagicVision;
using Content.Shared._CP14.MagicVision.Components;
using Content.Shared.Mobs;
using Content.Shared.StatusEffectNew;
using Robust.Shared.Random;
using Robust.Shared.Utility;
@@ -18,17 +20,27 @@ public sealed partial class CP14AuraImprintSystem : CP14SharedAuraImprintSystem
base.Initialize();
SubscribeLocalEvent<CP14AuraImprintComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<CP14HideMagicAuraStatusEffectComponent, StatusEffectAppliedEvent>(OnShuffleStatusApplied);
SubscribeLocalEvent<CP14AuraImprintComponent, MobStateChangedEvent>(OnMobStateChanged);
}
private void OnShuffleStatusApplied(Entity<CP14HideMagicAuraStatusEffectComponent> ent, ref StatusEffectAppliedEvent args)
{
ent.Comp.Imprint = GenerateAuraImprint(args.Target);
Dirty(ent);
}
private void OnMapInit(Entity<CP14AuraImprintComponent> ent, ref MapInitEvent args)
{
ent.Comp.Imprint = GenerateAuraImprint(ent);
ent.Comp.Imprint = GenerateAuraImprint((ent.Owner, ent.Comp));
Dirty(ent);
}
public string GenerateAuraImprint(Entity<CP14AuraImprintComponent> ent)
public string GenerateAuraImprint(Entity<CP14AuraImprintComponent?> ent)
{
if (!Resolve(ent, ref ent.Comp))
return string.Empty;
var letters = new[] { "ä", "ã", "ç", "ø", "ђ", "œ", "Ї", "Ћ", "ў", "ž", "Ћ", "ö", "є", "þ"};
var imprint = string.Empty;
@@ -46,7 +58,7 @@ public sealed partial class CP14AuraImprintSystem : CP14SharedAuraImprintSystem
{
case MobState.Critical:
{
_vision.SpawnMagicVision(
_vision.SpawnMagicTrace(
Transform(ent).Coordinates,
new SpriteSpecifier.Rsi(new ResPath("_CP14/Actions/Spells/misc.rsi"), "skull"),
Loc.GetString("cp14-magic-vision-crit"),
@@ -56,7 +68,7 @@ public sealed partial class CP14AuraImprintSystem : CP14SharedAuraImprintSystem
}
case MobState.Dead:
{
_vision.SpawnMagicVision(
_vision.SpawnMagicTrace(
Transform(ent).Coordinates,
new SpriteSpecifier.Rsi(new ResPath("_CP14/Actions/Spells/misc.rsi"), "skull_red"),
Loc.GetString("cp14-magic-vision-dead"),

View File

@@ -19,7 +19,7 @@ public sealed partial class ShowHealthBarsComponent : Component
[AutoNetworkedField]
public List<ProtoId<DamageContainerPrototype>> DamageContainers = new()
{
"Biological"
"CP14Biological" //CP14 variant
};
[DataField]

View File

@@ -151,7 +151,7 @@ public abstract partial class CP14SharedMagicSystem : EntitySystem
&& TryComp<ActionComponent>(ent, out var actionComp)
&& TryComp<CP14MagicEffectManaCostComponent>(ent, out var manaCost))
{
_magicVision.SpawnMagicVision(
_magicVision.SpawnMagicTrace(
Transform(args.User.Value).Coordinates,
actionComp.Icon,
Loc.GetString("cp14-magic-vision-used-spell", ("name", MetaData(ent).EntityName)),

View File

@@ -1,7 +1,10 @@
using System.Linq;
using System.Text;
using Content.Shared._CP14.AuraDNA;
using Content.Shared._CP14.MagicVision.Components;
using Content.Shared.Actions;
using Content.Shared.Examine;
using Content.Shared.StatusEffectNew;
using Robust.Shared.Map;
using Robust.Shared.Network;
using Robust.Shared.Prototypes;
@@ -15,6 +18,7 @@ public abstract class CP14SharedMagicVisionSystem : EntitySystem
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly MetaDataSystem _meta = default!;
[Dependency] private readonly INetManager _net = default!;
[Dependency] private readonly StatusEffectsSystem _statusEffects = default!;
public readonly EntProtoId MagicTraceProto = "CP14MagicVisionMarker";
@@ -23,15 +27,6 @@ public abstract class CP14SharedMagicVisionSystem : EntitySystem
base.Initialize();
SubscribeLocalEvent<CP14MagicVisionMarkerComponent, ExaminedEvent>(OnExamined);
SubscribeLocalEvent<CP14AuraImprintComponent, ExaminedEvent>(OnAuraHolderExamine);
}
private void OnAuraHolderExamine(Entity<CP14AuraImprintComponent> ent, ref ExaminedEvent args)
{
if (!HasComp<CP14MagicVisionComponent>(args.Examiner))
return;
args.PushMarkup($"{Loc.GetString("cp14-magic-vision-aura")} {ent.Comp.Imprint}");
}
protected virtual void OnExamined(Entity<CP14MagicVisionMarkerComponent> ent, ref ExaminedEvent args)
@@ -39,16 +34,85 @@ public abstract class CP14SharedMagicVisionSystem : EntitySystem
var sb = new StringBuilder();
var timePassed = _timing.CurTime - ent.Comp.SpawnTime;
sb.Append($"{Loc.GetString("cp14-magic-vision-timed-past")} {timePassed.Minutes}:{(timePassed.Seconds < 10 ? "0" : "")}{timePassed.Seconds}\n");
var timeRemaining = ent.Comp.EndTime - _timing.CurTime;
var totalDuration = ent.Comp.EndTime - ent.Comp.SpawnTime;
if (ent.Comp.AuraImprint is not null)
sb.Append($"{Loc.GetString("cp14-magic-vision-timed-past")} {timePassed.Minutes}:{timePassed.Seconds:D2}\n");
if (string.IsNullOrEmpty(ent.Comp.AuraImprint))
{
sb.Append($"{Loc.GetString("cp14-magic-vision-aura")} {ent.Comp.AuraImprint}");
args.AddMarkup(sb.ToString());
return;
}
var imprint = ent.Comp.AuraImprint;
// Try to extract the content between [color=...] and [/color]
var startTag = imprint.IndexOf(']') + 1;
var endTag = imprint.LastIndexOf('[');
if (startTag <= 0 || endTag <= startTag)
{
sb.Append($"{Loc.GetString("cp14-magic-vision-aura")} {imprint}");
args.AddMarkup(sb.ToString());
return;
}
var content = imprint[startTag..endTag];
var obscuredContent = new StringBuilder(content.Length);
// Progress goes from 0 (fresh) to 1 (completely faded)
var progress = Math.Clamp(1.0 - (timeRemaining.TotalSeconds / totalDuration.TotalSeconds), 0.0, 1.0);
// Number of characters to obscure
var charsToObscure = (int)Math.Round(content.Length * progress);
// Deterministic pseudo-random based on content + entity id
var hash = (content + ent.Owner.Id).GetHashCode();
var obscuredCount = 0;
for (var i = 0; i < content.Length; i++)
{
// Pick bits from hash + index to ensure distribution
var mask = ((hash >> (i % 32)) ^ i) & 1;
var shouldObscure = obscuredCount < charsToObscure && mask == 1;
obscuredContent.Append(shouldObscure ? '~' : content[i]);
if (shouldObscure)
obscuredCount++;
}
// If we still didn't obscure enough (due to unlucky bit pattern), obscure remaining from the start
while (obscuredCount < charsToObscure && obscuredCount < obscuredContent.Length)
{
for (var i = 0; i < obscuredContent.Length && obscuredCount < charsToObscure; i++)
{
if (obscuredContent[i] != '~')
{
obscuredContent[i] = '~';
obscuredCount++;
}
}
}
var obscuredImprint = imprint.Substring(0, startTag) + obscuredContent + imprint.Substring(endTag);
sb.Append($"{Loc.GetString("cp14-magic-vision-aura")} {obscuredImprint}");
args.AddMarkup(sb.ToString());
}
public string? GetAuraImprint(Entity<CP14AuraImprintComponent?> ent)
{
if (!Resolve(ent, ref ent.Comp))
return null;
if (_statusEffects.TryEffectsWithComp<CP14HideMagicAuraStatusEffectComponent>(ent, out var hideComps))
{
return hideComps.First().Comp1.Imprint;
}
return ent.Comp.Imprint;
}
/// <summary>
/// Creates an invisible “magical trace” entity that can be seen with magical vision.
/// </summary>
@@ -58,7 +122,12 @@ public abstract class CP14SharedMagicVisionSystem : EntitySystem
/// <param name="duration">Duration of the magical trace</param>
/// <param name="target">Optional: The direction in which this trace “faces.” When studying the trace,
/// this direction can be seen in order to understand, for example, in which direction the spell was used.</param>
public void SpawnMagicVision(EntityCoordinates position, SpriteSpecifier? icon, string description, TimeSpan duration, EntityUid? aura = null, EntityCoordinates? target = null)
public void SpawnMagicTrace(EntityCoordinates position,
SpriteSpecifier? icon,
string description,
TimeSpan duration,
EntityUid? aura = null,
EntityCoordinates? target = null)
{
if (_net.IsClient)
return;
@@ -71,10 +140,8 @@ public abstract class CP14SharedMagicVisionSystem : EntitySystem
markerComp.TargetCoordinates = target;
markerComp.Icon = icon;
if (aura is not null && TryComp<CP14AuraImprintComponent>(aura, out var auraImprint))
{
markerComp.AuraImprint = auraImprint.Imprint;
}
if (aura is not null)
markerComp.AuraImprint = GetAuraImprint(aura.Value);
_meta.SetEntityDescription(ent, description);

View File

@@ -0,0 +1,16 @@
using Content.Shared._CP14.AuraDNA;
using Content.Shared.StatusEffectNew.Components;
using Robust.Shared.GameStates;
namespace Content.Shared._CP14.MagicVision.Components;
/// <summary>
/// Makes you leave random imprints of magical aura instead of the original
/// Use only in conjunction with <see cref="StatusEffectComponent"/>, on the status effect entity.
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(CP14SharedAuraImprintSystem))]
public sealed partial class CP14HideMagicAuraStatusEffectComponent : Component
{
[DataField, AutoNetworkedField]
public string Imprint = string.Empty;
}

View File

@@ -1,6 +1,8 @@
using Content.Shared._CP14.Skill;
using Content.Shared._CP14.Skill.Components;
using Content.Shared._CP14.Skill.Prototypes;
using Content.Shared._CP14.Trading.Prototypes;
using Content.Shared._CP14.Trading.Systems;
using Content.Shared._CP14.Vampire.Components;
using Content.Shared.Actions;
using Content.Shared.Body.Systems;
@@ -27,9 +29,11 @@ public abstract partial class CP14SharedVampireSystem : EntitySystem
[Dependency] private readonly CP14SharedSkillSystem _skill = default!;
[Dependency] protected readonly IPrototypeManager Proto = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly CP14SharedTradingPlatformSystem _trade = default!;
private readonly ProtoId<CP14SkillPointPrototype> _skillPointType = "Blood";
private readonly ProtoId<CP14SkillPointPrototype> _memorySkillPointType = "Memory";
private readonly ProtoId<CP14TradingFactionPrototype> _tradeFaction = "VampireMarket";
public override void Initialize()
{
@@ -85,6 +89,9 @@ public abstract partial class CP14SharedVampireSystem : EntitySystem
essenceHolder.Essence = 0;
Dirty(ent, essenceHolder);
}
//Additional trade faction
_trade.AddReputation(ent.Owner, _tradeFaction, 1);
}
private void OnVampireRemove(Entity<CP14VampireComponent> ent, ref ComponentRemove args)

View File

@@ -2,4 +2,7 @@ cp14-alerts-magic-energy-name = Magic energy
cp14-alerts-magic-energy-desc = A reserve of your internal magic power that allows you to use spells.
cp14-alerts-health-name = Health
cp14-alerts-health-desc = Vitality reserve. The less, the worse. Try to survive, please.
cp14-alerts-health-desc = Vitality reserve. The less, the worse. Try to survive, please.
cp14-alerts-confused-aura-name = Confused aura
cp14-alerts-confused-aura-desc = Your magical aura is altered, and you leave false traces when using magic spells.

View File

@@ -86,4 +86,7 @@ cp14-reagent-name-basic-sleep = Sleeping solution
cp14-reagent-desc-basic-sleep = Dangerous substance, even in small doses, that sends you to sleep.
cp14-reagent-name-basic-unsleep = Awakening solution
cp14-reagent-desc-basic-unsleep = A substance that stimulates the body and instantly brings it out of any sleep.
cp14-reagent-desc-basic-unsleep = A substance that stimulates the body and instantly brings it out of any sleep.
cp14-reagent-name-basic-confuse-aura = Aura concealment solution
cp14-reagent-desc-basic-confuse-aura = A substance that temporarily alters your magical aura.

View File

@@ -8,4 +8,5 @@ cp14-trade-faction-horticulture = Horticulture Consortium
cp14-trade-faction-butchers = Master Butchers Union
cp14-trade-faction-dairy = Golden Udder Dairy
cp14-trade-faction-tailors = Silk & Needle Tailors Guild
cp14-trade-faction-guard = Imperial Guard
cp14-trade-faction-guard = Imperial Guard
cp14-trade-faction-vampire-market = Vampire's lair

View File

@@ -2,4 +2,7 @@ cp14-alerts-magic-energy-name = Магическая энергия
cp14-alerts-magic-energy-desc = Запас вашей внутренней магической силы, позволяющий вам использовать заклинания.
cp14-alerts-health-name = Здоровье
cp14-alerts-health-desc = Запас жизненных сил. Чем меньше, тем хуже. Постарайтесь выжить, пожалуйста.
cp14-alerts-health-desc = Запас жизненных сил. Чем меньше, тем хуже. Постарайтесь выжить, пожалуйста.
cp14-alerts-confused-aura-name = Спутанная аура
cp14-alerts-confused-aura-desc = Ваша магическая аура изменена, и вы оставляете ненастоящие следы, используя магические заклинания.

View File

@@ -83,4 +83,7 @@ cp14-reagent-name-basic-sleep = Усыпляющий раствор
cp14-reagent-desc-basic-sleep = Опасное вещество, даже в малых дозах оправляющее в сон.
cp14-reagent-name-basic-unsleep = Пробуждающий раствор
cp14-reagent-desc-basic-unsleep = Вещество, стимулирующее организм, и моментально выводящее из любого сна.
cp14-reagent-desc-basic-unsleep = Вещество, стимулирующее организм, и моментально выводящее из любого сна.
cp14-reagent-name-basic-confuse-aura = Раствор сокрытия ауры
cp14-reagent-desc-basic-confuse-aura = Вещество, изменяющее вашу магическую ауру на некоторое время.

View File

@@ -8,4 +8,5 @@ cp14-trade-faction-horticulture = Консорциум садоводов
cp14-trade-faction-butchers = Союз мастеровых мясников
cp14-trade-faction-dairy = Молочная ферма 'Златовымя'
cp14-trade-faction-tailors = Гильдия портных 'Шелк и игла'
cp14-trade-faction-guard = Имперская стража
cp14-trade-faction-guard = Имперская стража
cp14-trade-faction-vampire-market = Вампирское логово

View File

@@ -14,4 +14,12 @@
id: CP14VampireSleeping
icons:
- sprite: _CP14/Actions/Spells/vampire.rsi
state: blood_moon
state: blood_moon
- type: alert
id: CP14ConfusedAura
name: cp14-alerts-confused-aura-name
description: cp14-alerts-confused-aura-desc
icons:
- sprite: _CP14/Actions/Spells/meta.rsi
state: magic_vision_shuffled

View File

@@ -37,6 +37,7 @@
- type: entity
id: CP14MagicVisionMarker
parent: CP14SpectralBase
categories: [ HideSpawnMenu ]
name: mana trace
components:

View File

@@ -23,7 +23,6 @@
- type: PhysicalComposition
materialComposition:
CP14Cloth: 40
CP14Mithril: 10
CP14BloodEssence: 1
- type: entity

View File

@@ -20,8 +20,8 @@
type: VoiceMaskBoundUserInterface
- type: PhysicalComposition
materialComposition:
CP14Iron: 10
CP14Leather: 10
CP14BloodEssence: 1
- type: entity
parent: CP14ClothingMaskVampireVoiceBase

View File

@@ -1,5 +1,7 @@
- type: entity
parent: BaseItem
parent:
- BaseItem
- CP14SpectralBase
id: CP14BloodEssence
name: blood essence
description: The essence of life, extracted by force. Only true vampires know how to use it.

View File

@@ -120,3 +120,18 @@
Quantity: 9
- ReagentId: CP14BasicEffectHealManaDepletion
Quantity: 1
- type: entity
id: CP14BasicEffectConfuseAura
parent: CP14VialSmall
name: "brad's aura confusion potion"
suffix: Aura confusion 10%
components:
- type: SolutionContainerManager
solutions:
vial:
reagents:
- ReagentId: CP14BasicEffectEmpty
Quantity: 8
- ReagentId: CP14BasicEffectConfuseAura
Quantity: 2

View File

@@ -30,6 +30,7 @@
- type: entity
id: CP14StatusEffectGlowing
name: glowing
components:
- type: StatusEffect
- type: StatusEffectAlert
@@ -50,10 +51,19 @@
- type: entity
parent: MobStatusEffectDebuff
id: CP14StatusEffectVampireForceSleep
name: vampire forced sleep
name: forced sleep
components:
- type: StatusEffectAlert
alert: CP14VampireSleeping
- type: ForcedSleepingStatusEffect
- type: StunnedStatusEffect
- type: KnockdownStatusEffect
- type: KnockdownStatusEffect
- type: entity
id: MobStatusEffectMagicAuraConfused
name: confused aura
components:
- type: StatusEffect
- type: StatusEffectAlert
alert: CP14ConfusedAura
- type: CP14HideMagicAuraStatusEffect

View File

@@ -26,6 +26,7 @@
id: CP14BaseVampirePortalGlyph
categories: [ ForkFiltered ]
abstract: true
parent: CP14SpectralBase
name: portal glyph
description: A teleportation glyph imbued with bloody magic. Any vampire from the owner clan can teleport here at any moment! To destroy a glyph, suck all the magical energy out of it.
components:
@@ -57,17 +58,6 @@
property: Energy
isLooped: true
enabled: true
- type: CP14MagicEnergyContainer
magicAlert: CP14MagicEnergy
maxEnergy: 1
energy: 1
unsafeSupport: true
- type: CP14MagicUnsafeDamage
damagePerEnergy:
types:
CP14ManaDepletion: 1
- type: Damageable
damageContainer: CP14Spectral
- type: Destructible
thresholds:
- trigger:

View File

@@ -0,0 +1,30 @@
# Entities that are entirely magical and can be destroyed by dispelling magic.
- type: entity
id: CP14SpectralBase
categories: [ ForkFiltered ]
abstract: true
components:
- type: CP14MagicEnergyContainer
magicAlert: CP14MagicEnergy
maxEnergy: 1
energy: 1
unsafeSupport: true
- type: CP14MagicUnsafeDamage
damagePerEnergy:
types:
CP14ManaDepletion: 1
- type: Damageable
damageContainer: CP14Spectral
- type: Destructible
thresholds:
- trigger:
!type:DamageTrigger
damage: 10
behaviors:
- !type:PlaySoundBehavior
sound:
path: /Audio/Effects/eye_close.ogg
params:
volume: 6
- !type:DoActsBehavior
acts: [ "Destruction" ]

View File

@@ -601,4 +601,23 @@
metabolismRate: 0.05
effects:
- !type:Jitter
pricePerUnit: 0.3 # Weakest negative effect
pricePerUnit: 0.3 # Weakest negative effect
- type: reagent
id: CP14BasicEffectConfuseAura
name: cp14-reagent-name-basic-confuse-aura
desc: cp14-reagent-desc-basic-confuse-aura
group: CP14BasicEffect
flavor: CP14Vomit
color: "#eb34b7"
physicalDesc: cp14-reagent-physical-desc-colorless
metabolisms:
Food:
metabolismRate: 0.05
effects:
- !type:ModifyStatusEffect
effectProto: MobStatusEffectMagicAuraConfused
type: Add
time: 2
refresh: false
pricePerUnit: 0.6

View File

@@ -10,7 +10,7 @@
stack: CP14ThinLeather
count: 2
- !type:StackResource
stack: CP14IronBar
stack: CP14BloodEssence
count: 1
result: CP14ClothingMaskVampireVoiceDevourers
resultCount: 1
@@ -26,9 +26,6 @@
- !type:StackResource
stack: CP14Cloth
count: 4
- !type:StackResource
stack: CP14MithrilBar
count: 1
- !type:StackResource
stack: CP14BloodEssence
count: 1

View File

@@ -10,7 +10,7 @@
stack: CP14ThinLeather
count: 2
- !type:StackResource
stack: CP14IronBar
stack: CP14BloodEssence
count: 1
result: CP14ClothingMaskVampireVoiceNightChildrens
resultCount: 1
@@ -26,9 +26,6 @@
- !type:StackResource
stack: CP14Cloth
count: 4
- !type:StackResource
stack: CP14MithrilBar
count: 1
- !type:StackResource
stack: CP14BloodEssence
count: 1

View File

@@ -10,7 +10,7 @@
stack: CP14ThinLeather
count: 2
- !type:StackResource
stack: CP14IronBar
stack: CP14BloodEssence
count: 1
result: CP14ClothingMaskVampireVoiceUnnameable
resultCount: 1
@@ -26,9 +26,6 @@
- !type:StackResource
stack: CP14Cloth
count: 4
- !type:StackResource
stack: CP14MithrilBar
count: 1
- !type:StackResource
stack: CP14BloodEssence
count: 1

View File

@@ -0,0 +1,9 @@
- type: cp14TradingPosition
id: CP14BasicEffectConfuseAura
faction: VampireMarket
uiPosition: 0
icon:
sprite: _CP14/Objects/Specific/Alchemy/vial_small.rsi
state: vial
service: !type:CP14BuyItemsService
product: CP14BasicEffectConfuseAura

View File

@@ -51,4 +51,9 @@
- type: cp14TradingFaction
id: Guards
color: "#385573"
name: cp14-trade-faction-guard
name: cp14-trade-faction-guard
- type: cp14TradingFaction
id: VampireMarket
color: "#6b1934"
name: cp14-trade-faction-vampire-market

Binary file not shown.

After

Width:  |  Height:  |  Size: 943 B

View File

@@ -33,6 +33,9 @@
},
{
"name": "magic_vision"
},
{
"name": "magic_vision_shuffled"
}
]
}