Merge remote-tracking branch 'upstream/master'
This commit is contained in:
66
Content.Server/_White/Accent/Bloodloss/BloodLossAccent.cs
Normal file
66
Content.Server/_White/Accent/Bloodloss/BloodLossAccent.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
using System.Text;
|
||||
using Content.Server.Speech;
|
||||
using Content.Shared.StatusEffect;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server._White.Accent.Bloodloss;
|
||||
|
||||
public sealed class BloodLossAccent : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly StatusEffectsSystem _statusEffectsSystem = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<BloodLossAccentComponent, AccentGetEvent>(OnAccent);
|
||||
}
|
||||
|
||||
public void StartBloodLossAccent(EntityUid uid, TimeSpan time, bool refresh, StatusEffectsComponent? status = null)
|
||||
{
|
||||
if (!Resolve(uid, ref status, false))
|
||||
return;
|
||||
|
||||
_statusEffectsSystem.TryAddStatusEffect<BloodLossAccentComponent>(uid, "BloodLoss", time, refresh, status);
|
||||
}
|
||||
|
||||
public void StopBloodLossAccent(EntityUid uid, double timeRemoved)
|
||||
{
|
||||
_statusEffectsSystem.TryRemoveTime(uid, "BloodLoss", TimeSpan.FromSeconds(timeRemoved));
|
||||
}
|
||||
|
||||
private void OnAccent(EntityUid uid, BloodLossAccentComponent component, AccentGetEvent args)
|
||||
{
|
||||
args.Message = Accentuate(args.Message, component);
|
||||
}
|
||||
|
||||
public string Accentuate(string message, BloodLossAccentComponent component)
|
||||
{
|
||||
if (string.IsNullOrEmpty(message))
|
||||
{
|
||||
return message;
|
||||
}
|
||||
|
||||
var result = new StringBuilder();
|
||||
string[] words = message.Split(' ');
|
||||
|
||||
foreach (var word in words)
|
||||
{
|
||||
if (word.Length >= 3 && _random.NextDouble() < component.ReplaceProb)
|
||||
{
|
||||
int start = Random.Shared.Next(1, word.Length - 1);
|
||||
int end = start + Random.Shared.Next(1, word.Length - start);
|
||||
|
||||
result.Append(word.Substring(0, start) + component.ToReplace + word.Substring(end));
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Append(word);
|
||||
}
|
||||
|
||||
result.Append(' ');
|
||||
}
|
||||
|
||||
return result.ToString().TrimEnd();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace Content.Server._White.Accent.Bloodloss;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class BloodLossAccentComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public float ReplaceProb = 0.6f;
|
||||
|
||||
[DataField]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public string ToReplace = "...";
|
||||
}
|
||||
@@ -12,6 +12,7 @@ using Content.Shared.Physics;
|
||||
using Content.Shared.StatusEffect;
|
||||
using Content.Shared._White.Cult;
|
||||
using Content.Shared._White.Cult.Components;
|
||||
using Content.Shared.Throwing;
|
||||
|
||||
namespace Content.Server._White.Cult.Runes.Systems;
|
||||
|
||||
@@ -34,6 +35,7 @@ public partial class CultSystem
|
||||
|
||||
SubscribeLocalEvent<WraithPhaseActionEvent>(OnWraithPhase);
|
||||
SubscribeLocalEvent<IncorporealComponent, AttackAttemptEvent>(OnAttackAttempt);
|
||||
SubscribeLocalEvent<IncorporealComponent, ThrowAttemptEvent>(OnThrowAttempt);
|
||||
|
||||
SubscribeLocalEvent<JuggernautCreateWallActionEvent>(OnJuggernautCreateWall);
|
||||
|
||||
@@ -163,6 +165,14 @@ public partial class CultSystem
|
||||
}
|
||||
}
|
||||
|
||||
private void OnThrowAttempt(Entity<IncorporealComponent> ent, ref ThrowAttemptEvent args)
|
||||
{
|
||||
if (_statusEffectsSystem.HasStatusEffect(args.Uid, "Incorporeal"))
|
||||
{
|
||||
_statusEffectsSystem.TryRemoveStatusEffect(args.Uid, "Incorporeal");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnJuggernautCreateWall(JuggernautCreateWallActionEvent ev)
|
||||
{
|
||||
if (!TrySpawnWall(ev.Performer, ev.WallPrototypeId))
|
||||
|
||||
@@ -1,20 +1,25 @@
|
||||
using System.Linq;
|
||||
using Content.Server.Actions;
|
||||
using Content.Shared._White.Wizard.Magic;
|
||||
using Content.Shared.Actions;
|
||||
using Content.Shared.Eye;
|
||||
using Content.Shared.Movement.Pulling.Components;
|
||||
using Content.Shared.Movement.Pulling.Systems;
|
||||
using Content.Shared.Movement.Systems;
|
||||
using Content.Shared.Physics;
|
||||
using Content.Shared.Stealth;
|
||||
using Content.Shared.Stealth.Components;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Physics.Systems;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server._White.IncorporealSystem;
|
||||
|
||||
public sealed class IncorporealSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly MovementSpeedModifierSystem _movement = default!;
|
||||
[Dependency] private readonly ActionsSystem _actions = default!;
|
||||
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
||||
[Dependency] private readonly VisibilitySystem _visibilitySystem = default!;
|
||||
[Dependency] private readonly SharedStealthSystem _stealth = default!;
|
||||
@@ -78,6 +83,21 @@ public sealed class IncorporealSystem : EntitySystem
|
||||
_stealth.SetVisibility(uid, 1);
|
||||
RemComp<StealthComponent>(uid);
|
||||
_movement.RefreshMovementSpeedModifiers(uid);
|
||||
if (!TryComp(uid, out ActionsContainerComponent? container))
|
||||
return;
|
||||
|
||||
var cooldown = TimeSpan.FromSeconds(3);
|
||||
|
||||
foreach (var action in container.Container.ContainedEntities.Where(HasComp<MagicComponent>))
|
||||
{
|
||||
if (!_actions.TryGetActionData(action, out var comp, false))
|
||||
continue;
|
||||
|
||||
if (comp.Cooldown.HasValue && comp.Cooldown.Value.End >= _timing.CurTime + cooldown)
|
||||
continue;
|
||||
|
||||
_actions.SetCooldown(action, cooldown);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnRefresh(EntityUid uid, IncorporealComponent component, RefreshMovementSpeedModifiersEvent args)
|
||||
|
||||
@@ -24,7 +24,7 @@ public sealed class AmaterasuSystem : EntitySystem
|
||||
|
||||
if (flammable.OnFire)
|
||||
{
|
||||
_bodySystem.GibBody(uid);
|
||||
_bodySystem.GibBody(uid, true);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -300,10 +300,10 @@ public sealed class WizardRuleSystem : GameRuleSystem<WizardRuleComponent>
|
||||
_npcFaction.AddFaction(mob, "Wizard");
|
||||
}
|
||||
|
||||
private void SpawnWizard(ICommonSession? session, WizardRuleComponent component, bool spawnGhostRoles = true)
|
||||
private EntityCoordinates WizardSpawnPoint(WizardRuleComponent component)
|
||||
{
|
||||
if (component.ShuttleMap is not {Valid: true} mapUid)
|
||||
return;
|
||||
return EntityCoordinates.Invalid;
|
||||
|
||||
var spawn = new EntityCoordinates();
|
||||
foreach (var (_, meta, xform) in EntityQuery<SpawnPointComponent, MetaDataComponent, TransformComponent>(true))
|
||||
@@ -318,13 +318,25 @@ public sealed class WizardRuleSystem : GameRuleSystem<WizardRuleComponent>
|
||||
break;
|
||||
}
|
||||
|
||||
//Fallback, spawn at the centre of the map
|
||||
// Fallback, spawn at the centre of the map
|
||||
if (spawn == new EntityCoordinates())
|
||||
{
|
||||
spawn = Transform(mapUid).Coordinates;
|
||||
_sawmill.Warning("Fell back to default spawn for wizard!");
|
||||
}
|
||||
|
||||
return spawn;
|
||||
}
|
||||
|
||||
private void SpawnWizard(ICommonSession? session, WizardRuleComponent component, bool spawnGhostRoles = true)
|
||||
{
|
||||
var spawn = WizardSpawnPoint(component);
|
||||
if (spawn == EntityCoordinates.Invalid)
|
||||
{
|
||||
_sawmill.Error("Failed to calculate wizard spawn point");
|
||||
return;
|
||||
}
|
||||
|
||||
var wizardAntag = _prototypeManager.Index(component.WizardRoleProto);
|
||||
|
||||
//If a session is available, spawn mob and transfer mind into it
|
||||
@@ -395,4 +407,62 @@ public sealed class WizardRuleSystem : GameRuleSystem<WizardRuleComponent>
|
||||
ICommonSession? session = null;
|
||||
SpawnWizard(session, component, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Makes mob a wizard through admin verb button
|
||||
/// </summary>
|
||||
public void AdminMakeWizard(EntityUid uid)
|
||||
{
|
||||
var rule = EntityQuery<WizardRuleComponent>().FirstOrDefault();
|
||||
|
||||
if (rule == null)
|
||||
{
|
||||
GameTicker.StartGameRule("Wizard", out var ruleEntity);
|
||||
rule = Comp<WizardRuleComponent>(ruleEntity);
|
||||
}
|
||||
|
||||
if (HasComp<WizardComponent>(uid))
|
||||
return;
|
||||
|
||||
MakeWizard(uid, rule, true);
|
||||
}
|
||||
|
||||
private bool MakeWizard(EntityUid wizard, WizardRuleComponent rule,
|
||||
bool giveObjectives = true)
|
||||
{
|
||||
if (!_mind.TryGetMind(wizard, out var mindId, out var mind))
|
||||
{
|
||||
Log.Info("Failed getting mind for picked wizard.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (HasComp<WizardRoleComponent>(mindId))
|
||||
{
|
||||
Log.Error($"Player {mind.CharacterName} is already a wizard.");
|
||||
return false;
|
||||
}
|
||||
|
||||
HumanoidCharacterProfile? profile = null;
|
||||
if (TryComp(wizard, out ActorComponent? actor))
|
||||
profile = _prefs.GetPreferences(actor.PlayerSession.UserId).SelectedCharacter as HumanoidCharacterProfile;
|
||||
|
||||
if (giveObjectives)
|
||||
{
|
||||
AddRole(mindId, mind, rule);
|
||||
}
|
||||
|
||||
if (!_prototypeManager.TryIndex(rule.StartingGear, out var gear))
|
||||
{
|
||||
_sawmill.Error("Failed to load wizard gear prototype");
|
||||
return false;
|
||||
}
|
||||
|
||||
SetupWizardEntity(wizard, gear, profile, false);
|
||||
|
||||
var spawnpoint = WizardSpawnPoint(rule);
|
||||
var transform = EnsureComp<TransformComponent>(wizard);
|
||||
transform.Coordinates = spawnpoint;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user