Маг (#336)
* GameRule, a lot of prototypes and FTL pending * some protos * - add: Magic additions, tweaks and bugfixes. * - add: Wizard gamerule. * - tweak: Do not call shuttle. --------- Co-authored-by: melano <92106367+melanoTurbo@users.noreply.github.com>
This commit is contained in:
@@ -47,5 +47,8 @@ namespace Content.Server.Abilities.Mime
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("vowCooldown")]
|
[DataField("vowCooldown")]
|
||||||
public TimeSpan VowCooldown = TimeSpan.FromMinutes(5);
|
public TimeSpan VowCooldown = TimeSpan.FromMinutes(5);
|
||||||
|
|
||||||
|
[DataField] // WD
|
||||||
|
public bool CanBreakVow = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,6 +108,9 @@ namespace Content.Server.Abilities.Mime
|
|||||||
if (!Resolve(uid, ref mimePowers))
|
if (!Resolve(uid, ref mimePowers))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (!mimePowers.CanBreakVow) // WD
|
||||||
|
return;
|
||||||
|
|
||||||
if (mimePowers.VowBroken)
|
if (mimePowers.VowBroken)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using Content.Server._White.Carrying;
|
|||||||
using Content.Server._White.Cult.GameRule;
|
using Content.Server._White.Cult.GameRule;
|
||||||
using Content.Server._White.Mood;
|
using Content.Server._White.Mood;
|
||||||
using Content.Server._White.Other.FastAndFuriousSystem;
|
using Content.Server._White.Other.FastAndFuriousSystem;
|
||||||
|
using Content.Server._White.Wizard;
|
||||||
using Content.Server.Administration.Systems;
|
using Content.Server.Administration.Systems;
|
||||||
using Content.Server.Bible.Components;
|
using Content.Server.Bible.Components;
|
||||||
using Content.Server.Body.Components;
|
using Content.Server.Body.Components;
|
||||||
@@ -404,7 +405,7 @@ public sealed partial class ChangelingSystem
|
|||||||
if (!_ui.TryGetUi(user, TransformStingSelectorUiKey.Key, out var bui))
|
if (!_ui.TryGetUi(user, TransformStingSelectorUiKey.Key, out var bui))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (HasComp<ChangelingComponent>(target) || HasComp<SpaceNinjaComponent>(target) ||
|
if (HasComp<ChangelingComponent>(target) || HasComp<SpaceNinjaComponent>(target) || HasComp<WizardComponent>(target) ||
|
||||||
_tag.HasTag(target, "Unimplantable")) // Terminator check
|
_tag.HasTag(target, "Unimplantable")) // Terminator check
|
||||||
{
|
{
|
||||||
_popup.PopupEntity(Loc.GetString("changeling-popup-transform-not-effective"), user, user);
|
_popup.PopupEntity(Loc.GetString("changeling-popup-transform-not-effective"), user, user);
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ using Robust.Shared.Random;
|
|||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
|
using Content.Shared.Mind;
|
||||||
|
|
||||||
namespace Content.Server.GameTicking.Rules;
|
namespace Content.Server.GameTicking.Rules;
|
||||||
|
|
||||||
@@ -215,12 +216,9 @@ public sealed class NukeopsRuleSystem : GameRuleSystem<NukeopsRuleComponent>
|
|||||||
|
|
||||||
ev.AddLine(Loc.GetString("nukeops-list-start"));
|
ev.AddLine(Loc.GetString("nukeops-list-start"));
|
||||||
|
|
||||||
var nukiesQuery = EntityQueryEnumerator<NukeopsRoleComponent, MindContainerComponent>();
|
var nukiesQuery = EntityQueryEnumerator<NukeopsRoleComponent, MindComponent>();
|
||||||
while (nukiesQuery.MoveNext(out var nukeopsUid, out _, out var mindContainer))
|
while (nukiesQuery.MoveNext(out var nukeopsUid, out _, out var mind))
|
||||||
{
|
{
|
||||||
if (!_mind.TryGetMind(nukeopsUid, out _, out var mind, mindContainer))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
ev.AddLine(mind.Session != null
|
ev.AddLine(mind.Session != null
|
||||||
? Loc.GetString("nukeops-list-name-user", ("name", Name(nukeopsUid)), ("user", mind.Session.Name))
|
? Loc.GetString("nukeops-list-name-user", ("name", Name(nukeopsUid)), ("user", mind.Session.Name))
|
||||||
: Loc.GetString("nukeops-list-name", ("name", Name(nukeopsUid))));
|
: Loc.GetString("nukeops-list-name", ("name", Name(nukeopsUid))));
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Shared.Eye;
|
using Content.Shared.Eye;
|
||||||
|
using Content.Shared.Movement.Pulling.Components;
|
||||||
|
using Content.Shared.Movement.Pulling.Systems;
|
||||||
using Content.Shared.Movement.Systems;
|
using Content.Shared.Movement.Systems;
|
||||||
using Content.Shared.Physics;
|
using Content.Shared.Physics;
|
||||||
using Content.Shared.Stealth;
|
using Content.Shared.Stealth;
|
||||||
@@ -17,6 +19,7 @@ public sealed class IncorporealSystem : EntitySystem
|
|||||||
[Dependency] private readonly VisibilitySystem _visibilitySystem = default!;
|
[Dependency] private readonly VisibilitySystem _visibilitySystem = default!;
|
||||||
[Dependency] private readonly SharedStealthSystem _stealth = default!;
|
[Dependency] private readonly SharedStealthSystem _stealth = default!;
|
||||||
[Dependency] private readonly TransformSystem _transform = default!;
|
[Dependency] private readonly TransformSystem _transform = default!;
|
||||||
|
[Dependency] private readonly PullingSystem _pulling = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -48,6 +51,8 @@ public sealed class IncorporealSystem : EntitySystem
|
|||||||
Spawn("EffectEmpPulse", Transform(uid).Coordinates);
|
Spawn("EffectEmpPulse", Transform(uid).Coordinates);
|
||||||
EnsureComp<StealthComponent>(uid);
|
EnsureComp<StealthComponent>(uid);
|
||||||
_stealth.SetVisibility(uid, -1);
|
_stealth.SetVisibility(uid, -1);
|
||||||
|
if (TryComp(uid, out PullableComponent? pullable))
|
||||||
|
_pulling.TryStopPull(uid, pullable);
|
||||||
_movement.RefreshMovementSpeedModifiers(uid);
|
_movement.RefreshMovementSpeedModifiers(uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
namespace Content.Server._White.Wizard.Magic.Other;
|
||||||
|
|
||||||
|
[RegisterComponent]
|
||||||
|
public sealed partial class VariableUseDelayComponent : Component
|
||||||
|
{
|
||||||
|
[DataField]
|
||||||
|
public TimeSpan UseDelay = TimeSpan.FromSeconds(6);
|
||||||
|
|
||||||
|
[DataField]
|
||||||
|
public TimeSpan AltUseDelay = TimeSpan.FromSeconds(12);
|
||||||
|
|
||||||
|
[DataField]
|
||||||
|
public TimeSpan ChargeUseDelay = TimeSpan.FromSeconds(40);
|
||||||
|
}
|
||||||
@@ -61,6 +61,7 @@ public sealed class WizardSpellsSystem : EntitySystem
|
|||||||
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
||||||
[Dependency] private readonly InventorySystem _inventory = default!;
|
[Dependency] private readonly InventorySystem _inventory = default!;
|
||||||
[Dependency] private readonly EmpSystem _empSystem = default!;
|
[Dependency] private readonly EmpSystem _empSystem = default!;
|
||||||
|
[Dependency] private readonly SharedActionsSystem _actions = default!;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@@ -148,7 +149,8 @@ public sealed class WizardSpellsSystem : EntitySystem
|
|||||||
}
|
}
|
||||||
|
|
||||||
SetOutfitCommand.SetOutfit(msg.Target, "MimeGear", EntityManager);
|
SetOutfitCommand.SetOutfit(msg.Target, "MimeGear", EntityManager);
|
||||||
EnsureComp<MimePowersComponent>(msg.Target);
|
var powers = EnsureComp<MimePowersComponent>(msg.Target);
|
||||||
|
powers.CanBreakVow = false;
|
||||||
|
|
||||||
Spawn("AdminInstantEffectSmoke3", Transform(msg.Target).Coordinates);
|
Spawn("AdminInstantEffectSmoke3", Transform(msg.Target).Coordinates);
|
||||||
|
|
||||||
@@ -195,7 +197,8 @@ public sealed class WizardSpellsSystem : EntitySystem
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
EnsureComp<CluwneComponent>(msg.Target);
|
var cluwne = EnsureComp<CluwneComponent>(msg.Target);
|
||||||
|
cluwne.KnockChance = 0.2f;
|
||||||
|
|
||||||
Spawn("AdminInstantEffectSmoke3", Transform(msg.Target).Coordinates);
|
Spawn("AdminInstantEffectSmoke3", Transform(msg.Target).Coordinates);
|
||||||
|
|
||||||
@@ -317,6 +320,7 @@ public sealed class WizardSpellsSystem : EntitySystem
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetCooldown(msg.Action, msg.ActionUseType);
|
||||||
msg.Handled = true;
|
msg.Handled = true;
|
||||||
Speak(msg);
|
Speak(msg);
|
||||||
}
|
}
|
||||||
@@ -338,7 +342,7 @@ public sealed class WizardSpellsSystem : EntitySystem
|
|||||||
{
|
{
|
||||||
var xform = Transform(msg.Performer);
|
var xform = Transform(msg.Performer);
|
||||||
|
|
||||||
var positions = GetArenaPositions(xform, msg.ChargeLevel);
|
var positions = GetArenaPositions(xform.Coordinates, msg.ChargeLevel);
|
||||||
|
|
||||||
foreach (var position in positions)
|
foreach (var position in positions)
|
||||||
{
|
{
|
||||||
@@ -351,9 +355,7 @@ public sealed class WizardSpellsSystem : EntitySystem
|
|||||||
|
|
||||||
private void ForcewallSpellAlt(ForceWallSpellEvent msg)
|
private void ForcewallSpellAlt(ForceWallSpellEvent msg)
|
||||||
{
|
{
|
||||||
var xform = Transform(msg.TargetUid);
|
var positions = GetArenaPositions(msg.Target, 2);
|
||||||
|
|
||||||
var positions = GetArenaPositions(xform, 2);
|
|
||||||
|
|
||||||
foreach (var direction in positions)
|
foreach (var direction in positions)
|
||||||
{
|
{
|
||||||
@@ -373,6 +375,8 @@ public sealed class WizardSpellsSystem : EntitySystem
|
|||||||
if (msg.Handled || !CheckRequirements(msg.Action, msg.Performer))
|
if (msg.Handled || !CheckRequirements(msg.Action, msg.Performer))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
var result = true;
|
||||||
|
|
||||||
switch (msg.ActionUseType)
|
switch (msg.ActionUseType)
|
||||||
{
|
{
|
||||||
case ActionUseType.Default:
|
case ActionUseType.Default:
|
||||||
@@ -382,10 +386,14 @@ public sealed class WizardSpellsSystem : EntitySystem
|
|||||||
CardsSpellCharge(msg);
|
CardsSpellCharge(msg);
|
||||||
break;
|
break;
|
||||||
case ActionUseType.AltUse:
|
case ActionUseType.AltUse:
|
||||||
CardsSpellAlt(msg);
|
result = CardsSpellAlt(msg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SetCooldown(msg.Action, msg.ActionUseType);
|
||||||
msg.Handled = true;
|
msg.Handled = true;
|
||||||
Speak(msg);
|
Speak(msg);
|
||||||
}
|
}
|
||||||
@@ -417,7 +425,7 @@ public sealed class WizardSpellsSystem : EntitySystem
|
|||||||
{
|
{
|
||||||
var xform = Transform(msg.Performer);
|
var xform = Transform(msg.Performer);
|
||||||
|
|
||||||
var count = 5 * msg.ChargeLevel;
|
var count = 10 * msg.ChargeLevel;
|
||||||
var angleStep = 360f / count;
|
var angleStep = 360f / count;
|
||||||
|
|
||||||
for (var i = 0; i < count; i++)
|
for (var i = 0; i < count; i++)
|
||||||
@@ -441,14 +449,19 @@ public sealed class WizardSpellsSystem : EntitySystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CardsSpellAlt(CardsSpellEvent msg)
|
private bool CardsSpellAlt(CardsSpellEvent msg)
|
||||||
{
|
{
|
||||||
if (!HasComp<ItemComponent>(msg.TargetUid))
|
if (!HasComp<ItemComponent>(msg.TargetUid))
|
||||||
return;
|
{
|
||||||
|
_popupSystem.PopupEntity("Работает только на предметах.", msg.Performer, msg.Performer);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Del(msg.TargetUid);
|
Del(msg.TargetUid);
|
||||||
var item = Spawn(msg.Prototype);
|
var item = Spawn(msg.Prototype);
|
||||||
_handsSystem.TryPickupAnyHand(msg.Performer, item);
|
_handsSystem.TryPickupAnyHand(msg.Performer, item);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@@ -460,6 +473,8 @@ public sealed class WizardSpellsSystem : EntitySystem
|
|||||||
if (msg.Handled || !CheckRequirements(msg.Action, msg.Performer))
|
if (msg.Handled || !CheckRequirements(msg.Action, msg.Performer))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
var result = true;
|
||||||
|
|
||||||
switch (msg.ActionUseType)
|
switch (msg.ActionUseType)
|
||||||
{
|
{
|
||||||
case ActionUseType.Default:
|
case ActionUseType.Default:
|
||||||
@@ -469,10 +484,14 @@ public sealed class WizardSpellsSystem : EntitySystem
|
|||||||
FireballSpellCharge(msg);
|
FireballSpellCharge(msg);
|
||||||
break;
|
break;
|
||||||
case ActionUseType.AltUse:
|
case ActionUseType.AltUse:
|
||||||
FireballSpellAlt(msg);
|
result = FireballSpellAlt(msg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SetCooldown(msg.Action, msg.ActionUseType);
|
||||||
msg.Handled = true;
|
msg.Handled = true;
|
||||||
Speak(msg);
|
Speak(msg);
|
||||||
}
|
}
|
||||||
@@ -507,21 +526,26 @@ public sealed class WizardSpellsSystem : EntitySystem
|
|||||||
|
|
||||||
foreach (var target in targets.Where(target => target.Owner != msg.Performer))
|
foreach (var target in targets.Where(target => target.Owner != msg.Performer))
|
||||||
{
|
{
|
||||||
target.Comp.FireStacks += 3;
|
target.Comp.FireStacks += 2 + msg.ChargeLevel * 2;
|
||||||
_flammableSystem.Ignite(target, msg.Performer);
|
_flammableSystem.Ignite(target, msg.Performer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FireballSpellAlt(FireballSpellEvent msg)
|
private bool FireballSpellAlt(FireballSpellEvent msg)
|
||||||
{
|
{
|
||||||
if (!TryComp<FlammableComponent>(msg.TargetUid, out var flammableComponent))
|
if (!TryComp<FlammableComponent>(msg.TargetUid, out var flammableComponent))
|
||||||
return;
|
{
|
||||||
|
_popupSystem.PopupEntity("Это нельзя поджечь!", msg.Performer, msg.Performer);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
flammableComponent.FireStacks += 4;
|
flammableComponent.FireStacks += 4;
|
||||||
|
|
||||||
_flammableSystem.Ignite(msg.TargetUid, msg.Performer);
|
_flammableSystem.Ignite(msg.TargetUid, msg.Performer);
|
||||||
|
|
||||||
EnsureComp<AmaterasuComponent>(msg.TargetUid);
|
EnsureComp<AmaterasuComponent>(msg.TargetUid);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@@ -546,6 +570,7 @@ public sealed class WizardSpellsSystem : EntitySystem
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetCooldown(msg.Action, msg.ActionUseType);
|
||||||
msg.Handled = true;
|
msg.Handled = true;
|
||||||
Speak(msg);
|
Speak(msg);
|
||||||
}
|
}
|
||||||
@@ -574,10 +599,12 @@ public sealed class WizardSpellsSystem : EntitySystem
|
|||||||
if (msg.Handled || !CheckRequirements(msg.Action, msg.Performer))
|
if (msg.Handled || !CheckRequirements(msg.Action, msg.Performer))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
var result = true;
|
||||||
|
|
||||||
switch (msg.ActionUseType)
|
switch (msg.ActionUseType)
|
||||||
{
|
{
|
||||||
case ActionUseType.Default:
|
case ActionUseType.Default:
|
||||||
ArcSpellDefault(msg);
|
result = ArcSpellDefault(msg);
|
||||||
break;
|
break;
|
||||||
case ActionUseType.Charge:
|
case ActionUseType.Charge:
|
||||||
ArcSpellCharge(msg);
|
ArcSpellCharge(msg);
|
||||||
@@ -587,21 +614,28 @@ public sealed class WizardSpellsSystem : EntitySystem
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SetCooldown(msg.Action, msg.ActionUseType);
|
||||||
msg.Handled = true;
|
msg.Handled = true;
|
||||||
Speak(msg);
|
Speak(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ArcSpellDefault(ArcSpellEvent msg)
|
private bool ArcSpellDefault(ArcSpellEvent msg)
|
||||||
{
|
{
|
||||||
const int possibleEntitiesCount = 2;
|
const int possibleEntitiesCount = 2;
|
||||||
|
|
||||||
var entitiesInRange = _lookup.GetEntitiesInRange(msg.Target, 1);
|
var entitiesInRange = _lookup.GetEntitiesInRange(msg.Target, 1);
|
||||||
var entitiesToHit = entitiesInRange.Where(HasComp<MobStateComponent>).Take(possibleEntitiesCount);
|
var entitiesToHit = entitiesInRange.Where(HasComp<MobStateComponent>).Take(possibleEntitiesCount);
|
||||||
|
|
||||||
foreach (var entity in entitiesToHit)
|
var entityUids = entitiesToHit.ToList();
|
||||||
|
foreach (var entity in entityUids)
|
||||||
{
|
{
|
||||||
_lightning.ShootLightning(msg.Performer, entity);
|
_lightning.ShootLightning(msg.Performer, entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return entityUids.Count != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ArcSpellCharge(ArcSpellEvent msg)
|
private void ArcSpellCharge(ArcSpellEvent msg)
|
||||||
@@ -644,7 +678,23 @@ public sealed class WizardSpellsSystem : EntitySystem
|
|||||||
InGameICChatType.Speak, false);
|
InGameICChatType.Speak, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<EntityCoordinates> GetArenaPositions(TransformComponent casterXform, int arenaSize)
|
private void SetCooldown(EntityUid action, ActionUseType useType)
|
||||||
|
{
|
||||||
|
if (!TryComp(action, out VariableUseDelayComponent? variableUseDelayComponent))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var cooldown = useType switch
|
||||||
|
{
|
||||||
|
ActionUseType.Default => variableUseDelayComponent.UseDelay,
|
||||||
|
ActionUseType.AltUse => variableUseDelayComponent.AltUseDelay,
|
||||||
|
ActionUseType.Charge => variableUseDelayComponent.ChargeUseDelay,
|
||||||
|
_ => TimeSpan.FromSeconds(60)
|
||||||
|
};
|
||||||
|
|
||||||
|
_actions.SetUseDelay(action, cooldown);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<EntityCoordinates> GetArenaPositions(EntityCoordinates coords, int arenaSize)
|
||||||
{
|
{
|
||||||
var positions = new List<EntityCoordinates>();
|
var positions = new List<EntityCoordinates>();
|
||||||
|
|
||||||
@@ -655,7 +705,7 @@ public sealed class WizardSpellsSystem : EntitySystem
|
|||||||
for (var j = -arenaSize; j <= arenaSize; j++)
|
for (var j = -arenaSize; j <= arenaSize; j++)
|
||||||
{
|
{
|
||||||
var position = new Vector2(i, j);
|
var position = new Vector2(i, j);
|
||||||
var coordinates = casterXform.Coordinates.Offset(position);
|
var coordinates = coords.Offset(position);
|
||||||
positions.Add(coordinates);
|
positions.Add(coordinates);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
7
Content.Server/_White/Wizard/WizardComponent.cs
Normal file
7
Content.Server/_White/Wizard/WizardComponent.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace Content.Server._White.Wizard;
|
||||||
|
|
||||||
|
|
||||||
|
[RegisterComponent]
|
||||||
|
public sealed partial class WizardComponent : Component
|
||||||
|
{
|
||||||
|
}
|
||||||
11
Content.Server/_White/Wizard/WizardRoleComponent.cs
Normal file
11
Content.Server/_White/Wizard/WizardRoleComponent.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
using Content.Shared.Roles;
|
||||||
|
|
||||||
|
namespace Content.Server._White.Wizard;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This is used for...
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent, ExclusiveAntagonist]
|
||||||
|
public sealed partial class WizardRoleComponent : AntagonistRoleComponent
|
||||||
|
{
|
||||||
|
}
|
||||||
68
Content.Server/_White/Wizard/WizardRuleComponent.cs
Normal file
68
Content.Server/_White/Wizard/WizardRuleComponent.cs
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
using Content.Server.RoundEnd;
|
||||||
|
using Content.Shared.NPC.Prototypes;
|
||||||
|
using Content.Shared.Random;
|
||||||
|
using Content.Shared.Roles;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
|
namespace Content.Server._White.Wizard;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This is used for...
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent]
|
||||||
|
public sealed partial class WizardRuleComponent : Component
|
||||||
|
{
|
||||||
|
public readonly List<EntityUid> WizardMinds = new();
|
||||||
|
|
||||||
|
public EntityUid? TargetStation;
|
||||||
|
|
||||||
|
[DataField("minPlayers")]
|
||||||
|
public int MinPlayers = 20;
|
||||||
|
|
||||||
|
[DataField("announcementOnWizardDeath")]
|
||||||
|
public bool AnnouncementOnWizardDeath = true;
|
||||||
|
|
||||||
|
[DataField("points")]
|
||||||
|
public int Points = 10; //TODO: wizard shop prototype
|
||||||
|
|
||||||
|
[DataField("wizardRoleProto")]
|
||||||
|
public ProtoId<AntagPrototype> WizardRoleProto = "WizardRole";
|
||||||
|
|
||||||
|
[DataField("wizardSpawnPointProto")]
|
||||||
|
public EntProtoId SpawnPointProto = "SpawnPointWizard";
|
||||||
|
|
||||||
|
[DataField]
|
||||||
|
public EntProtoId GhostSpawnPointProto = "SpawnPointGhostWizard";
|
||||||
|
|
||||||
|
[DataField("startingGear")]
|
||||||
|
public ProtoId<StartingGearPrototype> StartingGear = "WizardGear";
|
||||||
|
|
||||||
|
[DataField("spawnShuttle")]
|
||||||
|
public bool SpawnShuttle = true;
|
||||||
|
|
||||||
|
[DataField]
|
||||||
|
public EntityUid? ShuttleMap;
|
||||||
|
|
||||||
|
[DataField("shuttlePath")]
|
||||||
|
public string ShuttlePath = "/Maps/White/Shuttles/wizard.yml";
|
||||||
|
|
||||||
|
[DataField]
|
||||||
|
public ProtoId<NpcFactionPrototype> Faction = "Wizard";
|
||||||
|
|
||||||
|
public RoundEndBehavior RoundEndBehavior = RoundEndBehavior.Nothing;
|
||||||
|
|
||||||
|
[DataField]
|
||||||
|
public string RoundEndTextSender = "comms-console-announcement-title-centcom";
|
||||||
|
|
||||||
|
[DataField]
|
||||||
|
public string RoundEndTextShuttleCall = "wizard-no-more-threat-announcement-shuttle-call";
|
||||||
|
|
||||||
|
[DataField]
|
||||||
|
public string RoundEndTextAnnouncement = "wizard-no-more-threat-announcement";
|
||||||
|
|
||||||
|
[DataField]
|
||||||
|
public TimeSpan EvacShuttleTime = TimeSpan.FromMinutes(5);
|
||||||
|
|
||||||
|
[DataField]
|
||||||
|
public ProtoId<WeightedRandomPrototype> ObjectiveGroup = "WizardObjectiveGroups";
|
||||||
|
}
|
||||||
397
Content.Server/_White/Wizard/WizardRuleSystem.cs
Normal file
397
Content.Server/_White/Wizard/WizardRuleSystem.cs
Normal file
@@ -0,0 +1,397 @@
|
|||||||
|
using Content.Server.GameTicking;
|
||||||
|
using Content.Server.GameTicking.Rules;
|
||||||
|
using Content.Server.GameTicking.Rules.Components;
|
||||||
|
using Content.Server.Antag;
|
||||||
|
using Content.Server.Ghost.Roles.Components;
|
||||||
|
using Content.Server.Ghost.Roles.Events;
|
||||||
|
using Content.Server.Humanoid;
|
||||||
|
using Content.Server.Mind;
|
||||||
|
using Content.Server.Preferences.Managers;
|
||||||
|
using Content.Server.RoundEnd;
|
||||||
|
using Content.Server.Spawners.Components;
|
||||||
|
using Content.Server.Station.Systems;
|
||||||
|
using Content.Shared.Humanoid;
|
||||||
|
using Content.Shared.Humanoid.Prototypes;
|
||||||
|
using Content.Shared.Mind.Components;
|
||||||
|
using Content.Shared.Mobs;
|
||||||
|
using Content.Shared.NPC.Systems;
|
||||||
|
using Content.Shared.Preferences;
|
||||||
|
using Content.Shared.Roles;
|
||||||
|
using Robust.Shared.Map;
|
||||||
|
using Robust.Shared.Player;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using System.Linq;
|
||||||
|
using Content.Server.Objectives;
|
||||||
|
using Content.Server.Station.Components;
|
||||||
|
using Content.Shared.Mind;
|
||||||
|
using Content.Shared.NPC.Components;
|
||||||
|
using Content.Shared.Objectives.Components;
|
||||||
|
using Robust.Server.GameObjects;
|
||||||
|
using Robust.Server.Maps;
|
||||||
|
using Robust.Shared.Random;
|
||||||
|
|
||||||
|
namespace Content.Server._White.Wizard;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This handles...
|
||||||
|
/// </summary>
|
||||||
|
public sealed class WizardRuleSystem : GameRuleSystem<WizardRuleComponent>
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||||
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
|
[Dependency] private readonly IServerPreferencesManager _prefs = default!;
|
||||||
|
[Dependency] private readonly ILogManager _logManager = default!;
|
||||||
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
|
[Dependency] private readonly MapLoaderSystem _map = default!;
|
||||||
|
[Dependency] private readonly HumanoidAppearanceSystem _humanoid = default!;
|
||||||
|
[Dependency] private readonly MetaDataSystem _metaData = default!;
|
||||||
|
[Dependency] private readonly MindSystem _mind = default!;
|
||||||
|
[Dependency] private readonly NpcFactionSystem _npcFaction = default!;
|
||||||
|
[Dependency] private readonly SharedRoleSystem _roles = default!;
|
||||||
|
[Dependency] private readonly StationSpawningSystem _stationSpawning = default!;
|
||||||
|
[Dependency] private readonly AntagSelectionSystem _antagSelection = default!;
|
||||||
|
[Dependency] private readonly RoundEndSystem _roundEndSystem = default!;
|
||||||
|
[Dependency] private readonly ObjectivesSystem _objectives = default!;
|
||||||
|
|
||||||
|
private ISawmill _sawmill = default!;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
SubscribeLocalEvent<RoundStartAttemptEvent>(OnStartAttempt);
|
||||||
|
SubscribeLocalEvent<RulePlayerSpawningEvent>(OnPlayersSpawning);
|
||||||
|
SubscribeLocalEvent<GameRunLevelChangedEvent>(OnRunLevelChanged);
|
||||||
|
SubscribeLocalEvent<WizardComponent, ComponentRemove>(OnComponentRemove);
|
||||||
|
SubscribeLocalEvent<WizardComponent, MobStateChangedEvent>(OnMobStateChanged);
|
||||||
|
SubscribeLocalEvent<WizardComponent, GhostRoleSpawnerUsedEvent>(OnPlayersGhostSpawning);
|
||||||
|
SubscribeLocalEvent<WizardComponent, MindAddedMessage>(OnMindAdded);
|
||||||
|
SubscribeLocalEvent<WizardRuleComponent, ObjectivesTextGetInfoEvent>(OnObjectivesTextGetInfo);
|
||||||
|
|
||||||
|
_sawmill = _logManager.GetSawmill("Wizard");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnObjectivesTextGetInfo(Entity<WizardRuleComponent> ent, ref ObjectivesTextGetInfoEvent args)
|
||||||
|
{
|
||||||
|
args.Minds = ent.Comp.WizardMinds;
|
||||||
|
args.AgentName = Loc.GetString("wizard-round-end-agent-name");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnStartAttempt(RoundStartAttemptEvent ev)
|
||||||
|
{
|
||||||
|
TryRoundStartAttempt(ev, Loc.GetString("wizard-title"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPlayersSpawning(RulePlayerSpawningEvent ev)
|
||||||
|
{
|
||||||
|
var query = QueryActiveRules();
|
||||||
|
while (query.MoveNext(out var uid, out _, out var wizardRule, out _))
|
||||||
|
{
|
||||||
|
if (!SpawnMap((uid, wizardRule)))
|
||||||
|
{
|
||||||
|
_sawmill.Info("Failed to load shuttle for wizard");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Handle there being nobody readied up
|
||||||
|
if (ev.PlayerPool.Count == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var wizardEligible =
|
||||||
|
_antagSelection.GetEligibleSessions(ev.PlayerPool, wizardRule.WizardRoleProto);
|
||||||
|
|
||||||
|
//Select wizard
|
||||||
|
var selectedWizard = _antagSelection
|
||||||
|
.ChooseAntags(1, wizardEligible, ev.PlayerPool).FirstOrDefault();
|
||||||
|
|
||||||
|
SpawnWizard(selectedWizard, wizardRule, false);
|
||||||
|
|
||||||
|
if (selectedWizard != null)
|
||||||
|
GameTicker.PlayerJoinGame(selectedWizard);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Started(
|
||||||
|
EntityUid uid,
|
||||||
|
WizardRuleComponent component,
|
||||||
|
GameRuleComponent gameRule,
|
||||||
|
GameRuleStartedEvent args)
|
||||||
|
{
|
||||||
|
base.Started(uid, component, gameRule, args);
|
||||||
|
|
||||||
|
if (GameTicker.RunLevel == GameRunLevel.InRound)
|
||||||
|
SpawnWizardGhostRole(uid, component);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnComponentRemove(EntityUid uid, WizardComponent component, ComponentRemove args)
|
||||||
|
{
|
||||||
|
CheckAnnouncement();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnMobStateChanged(EntityUid uid, WizardComponent component, MobStateChangedEvent ev)
|
||||||
|
{
|
||||||
|
if (ev.NewMobState == MobState.Dead)
|
||||||
|
CheckAnnouncement();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPlayersGhostSpawning(EntityUid uid, WizardComponent component, GhostRoleSpawnerUsedEvent args)
|
||||||
|
{
|
||||||
|
var spawner = args.Spawner;
|
||||||
|
|
||||||
|
if (!TryComp<WizardSpawnerComponent>(spawner, out var wizardSpawner))
|
||||||
|
return;
|
||||||
|
|
||||||
|
HumanoidCharacterProfile? profile = null;
|
||||||
|
if (TryComp(args.Spawned, out ActorComponent? actor))
|
||||||
|
profile = _prefs.GetPreferences(actor.PlayerSession.UserId).SelectedCharacter as HumanoidCharacterProfile;
|
||||||
|
|
||||||
|
if (!EntityQuery<WizardRuleComponent>().Any())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!_prototypeManager.TryIndex(wizardSpawner.StartingGear, out var gear))
|
||||||
|
{
|
||||||
|
_sawmill.Error("Failed to load wizard gear prototype");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetupWizardEntity(uid, wizardSpawner.Points, gear, profile);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnMindAdded(EntityUid uid, WizardComponent component, MindAddedMessage args)
|
||||||
|
{
|
||||||
|
if (!_mind.TryGetMind(uid, out var mindId, out var mind))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var query = QueryActiveRules();
|
||||||
|
while (query.MoveNext(out _, out _, out var wizardRule, out _))
|
||||||
|
{
|
||||||
|
AddRole(mindId, mind, wizardRule);
|
||||||
|
|
||||||
|
if (mind.Session is not { } playerSession)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (GameTicker.RunLevel != GameRunLevel.InRound)
|
||||||
|
return;
|
||||||
|
|
||||||
|
NotifyWizard(playerSession, component, wizardRule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddRole(EntityUid mindId, MindComponent mind, WizardRuleComponent wizardRule)
|
||||||
|
{
|
||||||
|
if (_roles.MindHasRole<WizardRoleComponent>(mindId))
|
||||||
|
return;
|
||||||
|
|
||||||
|
wizardRule.WizardMinds.Add(mindId);
|
||||||
|
|
||||||
|
var role = wizardRule.WizardRoleProto;
|
||||||
|
_roles.MindAddRole(mindId, new WizardRoleComponent {PrototypeId = role});
|
||||||
|
|
||||||
|
GiveObjectives(mindId, mind, wizardRule);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GiveObjectives(EntityUid mindId, MindComponent mind, WizardRuleComponent wizardRule)
|
||||||
|
{
|
||||||
|
_mind.TryAddObjective(mindId, mind, "WizardSurviveObjective");
|
||||||
|
|
||||||
|
var difficulty = 0f;
|
||||||
|
for (var pick = 0; pick < 6 && 8 > difficulty; pick++)
|
||||||
|
{
|
||||||
|
var objective = _objectives.GetRandomObjective(mindId, mind, wizardRule.ObjectiveGroup);
|
||||||
|
if (objective == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
_mind.AddObjective(mindId, mind, objective.Value);
|
||||||
|
var adding = Comp<ObjectiveComponent>(objective.Value).Difficulty;
|
||||||
|
difficulty += adding;
|
||||||
|
_sawmill.Debug($"Added objective {ToPrettyString(objective):objective} with {adding} difficulty");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnRunLevelChanged(GameRunLevelChangedEvent ev)
|
||||||
|
{
|
||||||
|
var query = QueryActiveRules();
|
||||||
|
while (query.MoveNext(out var uid, out _, out var wiz, out _))
|
||||||
|
{
|
||||||
|
if (ev.New == GameRunLevel.InRound)
|
||||||
|
OnRoundStart(uid, wiz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnRoundStart(EntityUid uid, WizardRuleComponent? component = null)
|
||||||
|
{
|
||||||
|
if (!Resolve(uid, ref component))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var eligible = new List<Entity<StationEventEligibleComponent, NpcFactionMemberComponent>>();
|
||||||
|
var eligibleQuery = EntityQueryEnumerator<StationEventEligibleComponent, NpcFactionMemberComponent>();
|
||||||
|
while (eligibleQuery.MoveNext(out var eligibleUid, out var eligibleComp, out var member))
|
||||||
|
{
|
||||||
|
if (!_npcFaction.IsFactionHostile(component.Faction, (eligibleUid, member)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
eligible.Add((eligibleUid, eligibleComp, member));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eligible.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
component.TargetStation = _random.Pick(eligible);
|
||||||
|
|
||||||
|
var filter = Filter.Empty();
|
||||||
|
var query = EntityQueryEnumerator<WizardComponent, ActorComponent>();
|
||||||
|
while (query.MoveNext(out _, out var wizard, out var actor))
|
||||||
|
{
|
||||||
|
NotifyWizard(actor.PlayerSession, wizard, component);
|
||||||
|
filter.AddPlayer(actor.PlayerSession);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CheckAnnouncement()
|
||||||
|
{
|
||||||
|
var query = QueryActiveRules();
|
||||||
|
while (query.MoveNext(out _, out _, out var wizard, out _))
|
||||||
|
{
|
||||||
|
_roundEndSystem.DoRoundEndBehavior(
|
||||||
|
wizard.RoundEndBehavior, wizard.EvacShuttleTime, wizard.RoundEndTextSender,
|
||||||
|
wizard.RoundEndTextShuttleCall, wizard.RoundEndTextAnnouncement);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool SpawnMap(Entity<WizardRuleComponent> ent)
|
||||||
|
{
|
||||||
|
if (!ent.Comp.SpawnShuttle
|
||||||
|
|| ent.Comp.ShuttleMap != null)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
var shuttleMap = _mapManager.CreateMap();
|
||||||
|
var options = new MapLoadOptions
|
||||||
|
{
|
||||||
|
LoadMap = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!_map.TryLoad(shuttleMap, ent.Comp.ShuttlePath, out _, options))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ent.Comp.ShuttleMap = _mapManager.GetMapEntityId(shuttleMap);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetupWizardEntity(
|
||||||
|
EntityUid mob,
|
||||||
|
int points,
|
||||||
|
StartingGearPrototype gear,
|
||||||
|
HumanoidCharacterProfile? profile)
|
||||||
|
{
|
||||||
|
EnsureComp<WizardComponent>(mob);
|
||||||
|
|
||||||
|
profile ??= HumanoidCharacterProfile.RandomWithSpecies();
|
||||||
|
|
||||||
|
_humanoid.LoadProfile(mob, profile);
|
||||||
|
|
||||||
|
_metaData.SetEntityName(mob, profile.Name);
|
||||||
|
|
||||||
|
_stationSpawning.EquipStartingGear(mob, gear, profile);
|
||||||
|
|
||||||
|
_npcFaction.RemoveFaction(mob, "NanoTrasen", false);
|
||||||
|
_npcFaction.AddFaction(mob, "Wizard");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SpawnWizard(ICommonSession? session, WizardRuleComponent component, bool spawnGhostRoles = true)
|
||||||
|
{
|
||||||
|
if (component.ShuttleMap is not {Valid: true} mapUid)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var spawn = new EntityCoordinates();
|
||||||
|
foreach (var (_, meta, xform) in EntityQuery<SpawnPointComponent, MetaDataComponent, TransformComponent>(true))
|
||||||
|
{
|
||||||
|
if (meta.EntityPrototype?.ID != component.SpawnPointProto.Id)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (xform.ParentUid != component.ShuttleMap)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
spawn = xform.Coordinates;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//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!");
|
||||||
|
}
|
||||||
|
|
||||||
|
var wizardAntag = _prototypeManager.Index(component.WizardRoleProto);
|
||||||
|
|
||||||
|
//If a session is available, spawn mob and transfer mind into it
|
||||||
|
if (session != null)
|
||||||
|
{
|
||||||
|
var profile =
|
||||||
|
_prefs.GetPreferences(session.UserId).SelectedCharacter as HumanoidCharacterProfile;
|
||||||
|
|
||||||
|
profile ??= HumanoidCharacterProfile.RandomWithSpecies();
|
||||||
|
var name = profile.Name;
|
||||||
|
|
||||||
|
if (!_prototypeManager.TryIndex(profile.Species, out SpeciesPrototype? species))
|
||||||
|
{
|
||||||
|
species = _prototypeManager.Index<SpeciesPrototype>(SharedHumanoidAppearanceSystem.DefaultSpecies);
|
||||||
|
}
|
||||||
|
|
||||||
|
var mob = Spawn(species.Prototype, spawn);
|
||||||
|
if (!_prototypeManager.TryIndex(component.StartingGear, out var gear))
|
||||||
|
{
|
||||||
|
_sawmill.Error("Failed to load wizard gear prototype");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetupWizardEntity(mob, component.Points, gear, profile);
|
||||||
|
|
||||||
|
var newMind = _mind.CreateMind(session.UserId, name);
|
||||||
|
_mind.SetUserId(newMind, session.UserId);
|
||||||
|
AddRole(newMind.Owner, newMind.Comp, component);
|
||||||
|
|
||||||
|
_mind.TransferTo(newMind, mob);
|
||||||
|
}
|
||||||
|
//Otherwise, spawn as a ghost role
|
||||||
|
else if (spawnGhostRoles)
|
||||||
|
{
|
||||||
|
var spawnPoint = Spawn(component.GhostSpawnPointProto, spawn);
|
||||||
|
var ghostRole = EnsureComp<GhostRoleComponent>(spawnPoint);
|
||||||
|
EnsureComp<GhostRoleMobSpawnerComponent>(spawnPoint);
|
||||||
|
ghostRole.RoleName = Loc.GetString(wizardAntag.Name);
|
||||||
|
ghostRole.RoleDescription = Loc.GetString(wizardAntag.Objective);
|
||||||
|
|
||||||
|
var wizardSpawner = EnsureComp<WizardSpawnerComponent>(spawnPoint);
|
||||||
|
//TODO: maybe other params
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void NotifyWizard(ICommonSession session, WizardComponent wizard, WizardRuleComponent wizardRule)
|
||||||
|
{
|
||||||
|
if (wizardRule.TargetStation is not { } station)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_antagSelection.SendBriefing(session, Loc.GetString("wizard-welcome", ("station", station)), Color.Aqua, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Spawn wizard ghost role if this gamerule was started mid round
|
||||||
|
/// </summary>
|
||||||
|
private void SpawnWizardGhostRole(EntityUid uid, WizardRuleComponent? component = null)
|
||||||
|
{
|
||||||
|
if (!Resolve(uid, ref component))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!SpawnMap((uid, component)))
|
||||||
|
{
|
||||||
|
_sawmill.Info("Failed to load map for wizard");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ICommonSession? session = null;
|
||||||
|
SpawnWizard(session, component, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
21
Content.Server/_White/Wizard/WizardSpawnerComponent.cs
Normal file
21
Content.Server/_White/Wizard/WizardSpawnerComponent.cs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
using Content.Shared.Roles;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
|
namespace Content.Server._White.Wizard;
|
||||||
|
|
||||||
|
|
||||||
|
[RegisterComponent]
|
||||||
|
public sealed partial class WizardSpawnerComponent : Component
|
||||||
|
{
|
||||||
|
[DataField("name")]
|
||||||
|
public string Name = "Ololo The Balls' Twister";
|
||||||
|
|
||||||
|
[DataField("points")]
|
||||||
|
public int Points = 10;
|
||||||
|
|
||||||
|
[DataField("startingGear")]
|
||||||
|
public ProtoId<StartingGearPrototype> StartingGear = "WizardGear";
|
||||||
|
|
||||||
|
[DataField]
|
||||||
|
public ProtoId<AntagPrototype> WizardRoleProto = "WizardRole";
|
||||||
|
}
|
||||||
@@ -154,6 +154,9 @@ public abstract partial class BaseActionComponent : Component
|
|||||||
// WD START
|
// WD START
|
||||||
[DataField]
|
[DataField]
|
||||||
public bool RemoveOnNoCharges;
|
public bool RemoveOnNoCharges;
|
||||||
|
|
||||||
|
[DataField]
|
||||||
|
public bool AlwaysPlaySound = true;
|
||||||
// WD END
|
// WD END
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -540,12 +540,18 @@ public abstract class SharedActionsSystem : EntitySystem
|
|||||||
handled = actionEvent.Handled;
|
handled = actionEvent.Handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
_audio.PlayPredicted(action.Sound, performer,predicted ? performer : null);
|
if (action.AlwaysPlaySound) // WD EDIT
|
||||||
handled |= action.Sound != null;
|
{
|
||||||
|
_audio.PlayPredicted(action.Sound, performer,predicted ? performer : null);
|
||||||
|
handled |= action.Sound != null;
|
||||||
|
}
|
||||||
|
|
||||||
if (!handled)
|
if (!handled)
|
||||||
return; // no interaction occurred.
|
return; // no interaction occurred.
|
||||||
|
|
||||||
|
if (!action.AlwaysPlaySound) // WD
|
||||||
|
_audio.PlayPvs(action.Sound, performer);
|
||||||
|
|
||||||
// reduce charges, start cooldown, and mark as dirty (if required).
|
// reduce charges, start cooldown, and mark as dirty (if required).
|
||||||
|
|
||||||
var dirty = toggledBefore == action.Toggled;
|
var dirty = toggledBefore == action.Toggled;
|
||||||
|
|||||||
17
Resources/Locale/ru-RU/_white/wizard.ftl
Normal file
17
Resources/Locale/ru-RU/_white/wizard.ftl
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
wizard-title = Wizard
|
||||||
|
wizard-description = Космический Волшебник посещает станцию, дабы продемонстрировать чудеса своей магии.
|
||||||
|
|
||||||
|
objective-issuer-wizards = [color=aqua]Федерация Космических Волшебников[/color]
|
||||||
|
|
||||||
|
wizard-not-enough-ready-players = Недостаточно игроков готовы к игре! { $readyPlayersCount } игроков из необходимых { $minimumPlayers } готовы. Нельзя начать режим: Wizard.
|
||||||
|
wizard-no-one-ready = Нет готовых игроков! Нельзя начать Wizard.
|
||||||
|
|
||||||
|
roles-antag-wizard-name = Космический волшебник
|
||||||
|
roles-antag-wizard-objective = Устройте хаос на станции
|
||||||
|
|
||||||
|
wizard-round-end-agent-name = космический волшебник
|
||||||
|
|
||||||
|
wizard-welcome = Вы - космический волшебник. Федерация Космических Волшебников отправила вас на станцию {$station}, дабы посеять хаос. Не разочаруйте их.
|
||||||
|
|
||||||
|
wizard-no-more-threat-announcement-shuttle-call = Судя по данным наших датчиков дальнего действия, магическая угроза была устранена. Эвакуационный шаттл скоро прибудет. Время прибытия: {$time} {$units}. Вы можете отозвать его, чтобы продлить смену.
|
||||||
|
wizard-no-more-threat-announcement = Судя по данным наших датчиков дальнего действия, магическая угроза была устранена. Шаттл уже вызван.
|
||||||
5023
Resources/Maps/White/Shuttles/wizard.yml
Normal file
5023
Resources/Maps/White/Shuttles/wizard.yml
Normal file
File diff suppressed because it is too large
Load Diff
@@ -150,6 +150,13 @@
|
|||||||
- RitualDagger
|
- RitualDagger
|
||||||
- CultRunicMetal20
|
- CultRunicMetal20
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: Wizard
|
||||||
|
parent: BaseGameRule
|
||||||
|
noSpawn: true
|
||||||
|
components:
|
||||||
|
- type: WizardRule
|
||||||
|
|
||||||
# variation passes
|
# variation passes
|
||||||
- type: entity
|
- type: entity
|
||||||
id: BasicRoundstartVariation
|
id: BasicRoundstartVariation
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
- type: entity
|
- type: entity
|
||||||
id: ActionKnock
|
id: ActionKnock
|
||||||
name: Knock
|
name: Knock
|
||||||
description: This spell opens nearby doors.
|
description: This spell opens nearby doors.
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
- type: InstantAction
|
- type: InstantAction
|
||||||
useDelay: 10
|
useDelay: 10
|
||||||
itemIconStyle: BigAction
|
itemIconStyle: BigAction
|
||||||
|
checkCanInteract: false
|
||||||
icon:
|
icon:
|
||||||
sprite: Objects/Magic/magicactions.rsi
|
sprite: Objects/Magic/magicactions.rsi
|
||||||
state: knock
|
state: knock
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
- type: entity
|
- type: entity
|
||||||
id: ActionElectricArcSpell
|
id: ActionElectricArcSpell
|
||||||
name: Electric arc
|
name: Electric arc
|
||||||
noSpawn: true
|
noSpawn: true
|
||||||
@@ -6,10 +6,12 @@
|
|||||||
- type: Magic
|
- type: Magic
|
||||||
requiresClothes: true
|
requiresClothes: true
|
||||||
- type: WorldTargetAction
|
- type: WorldTargetAction
|
||||||
useDelay: 60
|
|
||||||
itemIconStyle: BigAction
|
itemIconStyle: BigAction
|
||||||
|
useDelay: 60
|
||||||
checkCanAccess: false
|
checkCanAccess: false
|
||||||
|
checkCanInteract: false
|
||||||
range: 10
|
range: 10
|
||||||
|
alwaysPlaySound: false
|
||||||
sound: !type:SoundPathSpecifier
|
sound: !type:SoundPathSpecifier
|
||||||
path: /Audio/White/Magic/Arc/cast.ogg
|
path: /Audio/White/Magic/Arc/cast.ogg
|
||||||
icon:
|
icon:
|
||||||
@@ -26,6 +28,10 @@
|
|||||||
speech: "KUH, ABAH'RAH"
|
speech: "KUH, ABAH'RAH"
|
||||||
prototype: ProjectileTeslaBall
|
prototype: ProjectileTeslaBall
|
||||||
posData: !type:TargetCasterPos
|
posData: !type:TargetCasterPos
|
||||||
|
- type: VariableUseDelay
|
||||||
|
useDelay: 6
|
||||||
|
altUseDelay: 12
|
||||||
|
chargeUseDelay: 40
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: ActionForceSpell
|
id: ActionForceSpell
|
||||||
@@ -35,10 +41,12 @@
|
|||||||
- type: Magic
|
- type: Magic
|
||||||
requiresClothes: true
|
requiresClothes: true
|
||||||
- type: WorldTargetAction
|
- type: WorldTargetAction
|
||||||
useDelay: 60
|
|
||||||
itemIconStyle: BigAction
|
itemIconStyle: BigAction
|
||||||
|
useDelay: 60
|
||||||
checkCanAccess: false
|
checkCanAccess: false
|
||||||
|
checkCanInteract: false
|
||||||
range: 10
|
range: 10
|
||||||
|
alwaysPlaySound: false
|
||||||
sound: !type:SoundPathSpecifier
|
sound: !type:SoundPathSpecifier
|
||||||
path: /Audio/White/Magic/Force/cast.ogg
|
path: /Audio/White/Magic/Force/cast.ogg
|
||||||
icon:
|
icon:
|
||||||
@@ -53,6 +61,10 @@
|
|||||||
isAltEnabled: true
|
isAltEnabled: true
|
||||||
event: !type:ForceSpellEvent
|
event: !type:ForceSpellEvent
|
||||||
speech: "EL DRITCH!"
|
speech: "EL DRITCH!"
|
||||||
|
- type: VariableUseDelay
|
||||||
|
useDelay: 6
|
||||||
|
altUseDelay: 12
|
||||||
|
chargeUseDelay: 40
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: ActionFireballSpell
|
id: ActionFireballSpell
|
||||||
@@ -62,13 +74,15 @@
|
|||||||
- type: Magic
|
- type: Magic
|
||||||
requiresClothes: true
|
requiresClothes: true
|
||||||
- type: WorldTargetAction
|
- type: WorldTargetAction
|
||||||
useDelay: 60
|
|
||||||
itemIconStyle: BigAction
|
itemIconStyle: BigAction
|
||||||
|
useDelay: 60
|
||||||
checkCanAccess: false
|
checkCanAccess: false
|
||||||
|
checkCanInteract: false
|
||||||
range: 45
|
range: 45
|
||||||
isChargeEnabled: true
|
isChargeEnabled: true
|
||||||
chargeProto: MagicFollowerFireEntity
|
chargeProto: MagicFollowerFireEntity
|
||||||
isAltEnabled: true
|
isAltEnabled: true
|
||||||
|
alwaysPlaySound: false
|
||||||
sound: !type:SoundPathSpecifier
|
sound: !type:SoundPathSpecifier
|
||||||
path: /Audio/Magic/fireball.ogg
|
path: /Audio/Magic/fireball.ogg
|
||||||
icon:
|
icon:
|
||||||
@@ -78,6 +92,10 @@
|
|||||||
prototype: ProjectileFireball
|
prototype: ProjectileFireball
|
||||||
posData: !type:TargetCasterPos
|
posData: !type:TargetCasterPos
|
||||||
speech: action-speech-spell-fireball
|
speech: action-speech-spell-fireball
|
||||||
|
- type: VariableUseDelay
|
||||||
|
useDelay: 6
|
||||||
|
altUseDelay: 12
|
||||||
|
chargeUseDelay: 40
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: ActionCardSpell
|
id: ActionCardSpell
|
||||||
@@ -87,9 +105,10 @@
|
|||||||
- type: Magic
|
- type: Magic
|
||||||
requiresClothes: true
|
requiresClothes: true
|
||||||
- type: WorldTargetAction
|
- type: WorldTargetAction
|
||||||
useDelay: 60
|
|
||||||
itemIconStyle: BigAction
|
itemIconStyle: BigAction
|
||||||
|
useDelay: 60
|
||||||
checkCanAccess: false
|
checkCanAccess: false
|
||||||
|
checkCanInteract: false
|
||||||
range: 45
|
range: 45
|
||||||
isChargeEnabled: true
|
isChargeEnabled: true
|
||||||
chargingSound:
|
chargingSound:
|
||||||
@@ -98,6 +117,7 @@
|
|||||||
maxChargedSound:
|
maxChargedSound:
|
||||||
path: /Audio/White/Magic/Cards/max.ogg
|
path: /Audio/White/Magic/Cards/max.ogg
|
||||||
isAltEnabled: true
|
isAltEnabled: true
|
||||||
|
alwaysPlaySound: false
|
||||||
sound: !type:SoundPathSpecifier
|
sound: !type:SoundPathSpecifier
|
||||||
path: /Audio/White/Magic/Cards/cast.ogg
|
path: /Audio/White/Magic/Cards/cast.ogg
|
||||||
icon:
|
icon:
|
||||||
@@ -107,6 +127,10 @@
|
|||||||
prototype: ThrowingCard
|
prototype: ThrowingCard
|
||||||
posData: !type:TargetCasterPos
|
posData: !type:TargetCasterPos
|
||||||
speech: "SHIZO NERO!"
|
speech: "SHIZO NERO!"
|
||||||
|
- type: VariableUseDelay
|
||||||
|
useDelay: 6
|
||||||
|
altUseDelay: 1
|
||||||
|
chargeUseDelay: 40
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: ActionForcewallSpell
|
id: ActionForcewallSpell
|
||||||
@@ -116,10 +140,12 @@
|
|||||||
- type: Magic
|
- type: Magic
|
||||||
requiresClothes: true
|
requiresClothes: true
|
||||||
- type: WorldTargetAction
|
- type: WorldTargetAction
|
||||||
useDelay: 60
|
|
||||||
itemIconStyle: BigAction
|
itemIconStyle: BigAction
|
||||||
|
useDelay: 60
|
||||||
checkCanAccess: false
|
checkCanAccess: false
|
||||||
|
checkCanInteract: false
|
||||||
range: 10
|
range: 10
|
||||||
|
alwaysPlaySound: false
|
||||||
sound: !type:SoundPathSpecifier
|
sound: !type:SoundPathSpecifier
|
||||||
path: /Audio/White/Magic/Force/cast.ogg
|
path: /Audio/White/Magic/Force/cast.ogg
|
||||||
icon:
|
icon:
|
||||||
@@ -135,6 +161,10 @@
|
|||||||
event: !type:ForceWallSpellEvent
|
event: !type:ForceWallSpellEvent
|
||||||
speech: "TARCOL MINTI ZHERI!"
|
speech: "TARCOL MINTI ZHERI!"
|
||||||
prototype: WallForce
|
prototype: WallForce
|
||||||
|
- type: VariableUseDelay
|
||||||
|
useDelay: 10
|
||||||
|
altUseDelay: 20
|
||||||
|
chargeUseDelay: 60
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: ActionBlinkSpell
|
id: ActionBlinkSpell
|
||||||
@@ -142,8 +172,9 @@
|
|||||||
noSpawn: true
|
noSpawn: true
|
||||||
components:
|
components:
|
||||||
- type: InstantAction
|
- type: InstantAction
|
||||||
useDelay: 60
|
useDelay: 6
|
||||||
itemIconStyle: BigAction
|
itemIconStyle: BigAction
|
||||||
|
checkCanInteract: false
|
||||||
icon:
|
icon:
|
||||||
sprite: Objects/Magic/magicactions.rsi
|
sprite: Objects/Magic/magicactions.rsi
|
||||||
state: blink
|
state: blink
|
||||||
@@ -158,8 +189,9 @@
|
|||||||
- type: Magic
|
- type: Magic
|
||||||
requiresClothes: true
|
requiresClothes: true
|
||||||
- type: InstantAction
|
- type: InstantAction
|
||||||
useDelay: 60
|
useDelay: 30
|
||||||
itemIconStyle: BigAction
|
itemIconStyle: BigAction
|
||||||
|
checkCanInteract: false
|
||||||
icon:
|
icon:
|
||||||
sprite: Objects/Magic/magicactions.rsi
|
sprite: Objects/Magic/magicactions.rsi
|
||||||
state: jaunt
|
state: jaunt
|
||||||
@@ -174,8 +206,9 @@
|
|||||||
- type: Magic
|
- type: Magic
|
||||||
requiresClothes: true
|
requiresClothes: true
|
||||||
- type: InstantAction
|
- type: InstantAction
|
||||||
useDelay: 60
|
useDelay: 40
|
||||||
itemIconStyle: BigAction
|
itemIconStyle: BigAction
|
||||||
|
checkCanInteract: false
|
||||||
icon:
|
icon:
|
||||||
sprite: Objects/Magic/magicactions.rsi
|
sprite: Objects/Magic/magicactions.rsi
|
||||||
state: emp_new
|
state: emp_new
|
||||||
@@ -192,7 +225,7 @@
|
|||||||
- type: EntityTargetAction
|
- type: EntityTargetAction
|
||||||
canTargetSelf: false
|
canTargetSelf: false
|
||||||
range: 2
|
range: 2
|
||||||
useDelay: 300
|
useDelay: 400
|
||||||
itemIconStyle: BigAction
|
itemIconStyle: BigAction
|
||||||
icon:
|
icon:
|
||||||
sprite: Objects/Magic/magicactions.rsi
|
sprite: Objects/Magic/magicactions.rsi
|
||||||
@@ -210,7 +243,7 @@
|
|||||||
- type: EntityTargetAction
|
- type: EntityTargetAction
|
||||||
canTargetSelf: false
|
canTargetSelf: false
|
||||||
range: 2
|
range: 2
|
||||||
useDelay: 300
|
useDelay: 200
|
||||||
itemIconStyle: BigAction
|
itemIconStyle: BigAction
|
||||||
icon:
|
icon:
|
||||||
sprite: Objects/Magic/magicactions.rsi
|
sprite: Objects/Magic/magicactions.rsi
|
||||||
@@ -228,7 +261,7 @@
|
|||||||
- type: EntityTargetAction
|
- type: EntityTargetAction
|
||||||
canTargetSelf: false
|
canTargetSelf: false
|
||||||
range: 2
|
range: 2
|
||||||
useDelay: 300
|
useDelay: 200
|
||||||
itemIconStyle: BigAction
|
itemIconStyle: BigAction
|
||||||
icon:
|
icon:
|
||||||
sprite: Objects/Magic/magicactions.rsi
|
sprite: Objects/Magic/magicactions.rsi
|
||||||
|
|||||||
@@ -340,6 +340,17 @@
|
|||||||
allowRepeatedMorphs: true
|
allowRepeatedMorphs: true
|
||||||
inventory: Transfer
|
inventory: Transfer
|
||||||
|
|
||||||
|
- type: polymorph
|
||||||
|
id: MobHumanSpaceWiz
|
||||||
|
configuration:
|
||||||
|
entity: MobHuman
|
||||||
|
forced: true
|
||||||
|
revertOnCrit: false
|
||||||
|
revertOnDeath: false
|
||||||
|
transferDamage: true
|
||||||
|
allowRepeatedMorphs: true
|
||||||
|
inventory: Transfer
|
||||||
|
|
||||||
- type: polymorph
|
- type: polymorph
|
||||||
id: MobHumanGhost
|
id: MobHumanGhost
|
||||||
configuration:
|
configuration:
|
||||||
|
|||||||
26
Resources/Prototypes/_White/Wizard/objective_groups.yml
Normal file
26
Resources/Prototypes/_White/Wizard/objective_groups.yml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
- type: weightedRandom
|
||||||
|
id: WizardObjectiveGroups
|
||||||
|
weights:
|
||||||
|
WizardObjectiveGroupSteal: 1
|
||||||
|
WizardObjectiveGroupKill: 1
|
||||||
|
|
||||||
|
- type: weightedRandom
|
||||||
|
id: WizardObjectiveGroupSteal
|
||||||
|
weights:
|
||||||
|
CaptainIDStealObjectiveWiz: 1
|
||||||
|
CMOHyposprayStealObjectiveWiz: 1
|
||||||
|
RDHardsuitStealObjectiveWiz: 1
|
||||||
|
NukeDiskStealObjectiveWiz: 1
|
||||||
|
MagbootsStealObjectiveWiz: 1
|
||||||
|
CorgiMeatStealObjectiveWiz: 1
|
||||||
|
ClipboardStealObjectiveWiz: 1
|
||||||
|
CaptainGunStealObjectiveWiz: 0.5
|
||||||
|
CaptainJetpackStealObjectiveWiz: 0.5
|
||||||
|
HandTeleporterStealObjectiveWiz: 0.5
|
||||||
|
SecretDocumentsStealObjectiveWiz: 0.5
|
||||||
|
|
||||||
|
- type: weightedRandom
|
||||||
|
id: WizardObjectiveGroupKill
|
||||||
|
weights:
|
||||||
|
KillRandomPersonObjectiveWiz: 1
|
||||||
|
KillRandomHeadObjectiveWiz: 0.25
|
||||||
219
Resources/Prototypes/_White/Wizard/objectives.yml
Normal file
219
Resources/Prototypes/_White/Wizard/objectives.yml
Normal file
@@ -0,0 +1,219 @@
|
|||||||
|
#survive
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
abstract: true
|
||||||
|
parent: BaseObjective
|
||||||
|
id: BaseWizardObjective
|
||||||
|
components:
|
||||||
|
- type: Objective
|
||||||
|
issuer: wizards
|
||||||
|
- type: RoleRequirement
|
||||||
|
roles:
|
||||||
|
components:
|
||||||
|
- WizardRole
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
noSpawn: true
|
||||||
|
parent: [BaseWizardObjective, BaseSurviveObjective]
|
||||||
|
id: WizardSurviveObjective
|
||||||
|
name: Survive the shift, causing as much chaos as possible.
|
||||||
|
description: Space Wizards Federation sent you to the Nanotrasen station to wreak havoc. Don't disappoint them.
|
||||||
|
components:
|
||||||
|
- type: Objective
|
||||||
|
difficulty: 2
|
||||||
|
icon:
|
||||||
|
sprite: Objects/Fun/figurines.rsi
|
||||||
|
state: wizard
|
||||||
|
|
||||||
|
#steal
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
abstract: true
|
||||||
|
parent: [BaseWizardObjective, BaseStealObjective]
|
||||||
|
id: BaseWizardStealObjective
|
||||||
|
components:
|
||||||
|
- type: StealCondition
|
||||||
|
verifyMapExistence: false
|
||||||
|
- type: Objective
|
||||||
|
difficulty: 2.75
|
||||||
|
|
||||||
|
## cmo
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
noSpawn: true
|
||||||
|
parent: BaseWizardStealObjective
|
||||||
|
id: CMOHyposprayStealObjectiveWiz
|
||||||
|
components:
|
||||||
|
- type: NotJobRequirement
|
||||||
|
job: ChiefMedicalOfficer
|
||||||
|
- type: StealCondition
|
||||||
|
stealGroup: Hypospray
|
||||||
|
owner: job-name-cmo
|
||||||
|
|
||||||
|
## rd
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
noSpawn: true
|
||||||
|
parent: BaseWizardStealObjective
|
||||||
|
id: RDHardsuitStealObjectiveWiz
|
||||||
|
components:
|
||||||
|
- type: NotJobRequirement
|
||||||
|
job: ResearchDirector
|
||||||
|
- type: StealCondition
|
||||||
|
stealGroup: ClothingOuterHardsuitRd
|
||||||
|
owner: job-name-rd
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
noSpawn: true
|
||||||
|
parent: BaseWizardStealObjective
|
||||||
|
id: HandTeleporterStealObjectiveWiz
|
||||||
|
components:
|
||||||
|
- type: NotJobRequirement
|
||||||
|
job: ResearchDirector
|
||||||
|
- type: StealCondition
|
||||||
|
stealGroup: HandTeleporter
|
||||||
|
owner: job-name-rd
|
||||||
|
|
||||||
|
## hos
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
noSpawn: true
|
||||||
|
parent: BaseWizardStealObjective
|
||||||
|
id: SecretDocumentsStealObjectiveWiz
|
||||||
|
components:
|
||||||
|
- type: Objective
|
||||||
|
# hos has a gun ce does not, higher difficulty than most
|
||||||
|
difficulty: 3
|
||||||
|
- type: NotJobRequirement
|
||||||
|
job: HeadOfSecurity
|
||||||
|
- type: StealCondition
|
||||||
|
stealGroup: BookSecretDocuments
|
||||||
|
owner: job-name-hos
|
||||||
|
|
||||||
|
## ce
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
noSpawn: true
|
||||||
|
parent: BaseWizardStealObjective
|
||||||
|
id: MagbootsStealObjectiveWiz
|
||||||
|
components:
|
||||||
|
- type: NotJobRequirement
|
||||||
|
job: ChiefEngineer
|
||||||
|
- type: StealCondition
|
||||||
|
stealGroup: ClothingShoesBootsMagAdv
|
||||||
|
owner: job-name-ce
|
||||||
|
|
||||||
|
## qm
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
noSpawn: true
|
||||||
|
parent: BaseWizardStealObjective
|
||||||
|
id: ClipboardStealObjectiveWiz
|
||||||
|
components:
|
||||||
|
- type: NotJobRequirement
|
||||||
|
job: Quartermaster
|
||||||
|
- type: StealCondition
|
||||||
|
stealGroup: BoxFolderQmClipboard
|
||||||
|
owner: job-name-qm
|
||||||
|
|
||||||
|
## hop
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
noSpawn: true
|
||||||
|
parent: BaseWizardStealObjective
|
||||||
|
id: CorgiMeatStealObjectiveWiz
|
||||||
|
components:
|
||||||
|
- type: NotJobRequirement
|
||||||
|
job: HeadOfPersonnel
|
||||||
|
- type: ObjectiveLimit
|
||||||
|
limit: 3 # ian only has 2 slices, 3 obj for drama
|
||||||
|
- type: StealCondition
|
||||||
|
stealGroup: FoodMeatCorgi
|
||||||
|
owner: objective-condition-steal-Ian
|
||||||
|
|
||||||
|
## cap
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
abstract: true
|
||||||
|
parent: BaseWizardStealObjective
|
||||||
|
id: BaseCaptainObjectiveWiz
|
||||||
|
components:
|
||||||
|
- type: Objective
|
||||||
|
# sorry ce but your jordans are not as high security as the caps gear
|
||||||
|
difficulty: 3.5
|
||||||
|
- type: NotJobRequirement
|
||||||
|
job: Captain
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
noSpawn: true
|
||||||
|
parent: BaseCaptainObjectiveWiz
|
||||||
|
id: CaptainIDStealObjectiveWiz
|
||||||
|
components:
|
||||||
|
- type: StealCondition
|
||||||
|
stealGroup: CaptainIDCard
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
noSpawn: true
|
||||||
|
parent: BaseCaptainObjectiveWiz
|
||||||
|
id: CaptainJetpackStealObjectiveWiz
|
||||||
|
components:
|
||||||
|
- type: StealCondition
|
||||||
|
stealGroup: JetpackCaptainFilled
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
noSpawn: true
|
||||||
|
parent: BaseCaptainObjectiveWiz
|
||||||
|
id: CaptainGunStealObjectiveWiz
|
||||||
|
components:
|
||||||
|
- type: StealCondition
|
||||||
|
stealGroup: WeaponAntiqueLaser
|
||||||
|
owner: job-name-captain
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
noSpawn: true
|
||||||
|
parent: BaseCaptainObjectiveWiz
|
||||||
|
id: NukeDiskStealObjectiveWiz
|
||||||
|
components:
|
||||||
|
- type: Objective
|
||||||
|
# high difficulty since the hardest item both to steal, and to not get caught down the road,
|
||||||
|
# since anyone with a pinpointer can track you down and kill you
|
||||||
|
# it's close to being a stealth loneop
|
||||||
|
difficulty: 4
|
||||||
|
- type: NotCommandRequirement
|
||||||
|
- type: StealCondition
|
||||||
|
stealGroup: NukeDisk
|
||||||
|
owner: objective-condition-steal-station
|
||||||
|
|
||||||
|
# kill
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
noSpawn: true
|
||||||
|
parent: [BaseWizardObjective, BaseKillObjective]
|
||||||
|
id: KillRandomPersonObjectiveWiz
|
||||||
|
description: Do it however you like, just make sure they don't make it to centcom.
|
||||||
|
components:
|
||||||
|
- type: Objective
|
||||||
|
difficulty: 1.75
|
||||||
|
unique: false
|
||||||
|
- type: TargetObjective
|
||||||
|
title: objective-condition-kill-person-title
|
||||||
|
- type: PickRandomPerson
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
noSpawn: true
|
||||||
|
parent: [BaseWizardObjective, BaseKillObjective]
|
||||||
|
id: KillRandomHeadObjectiveWiz
|
||||||
|
description: We need this head gone and you probably know why. Good luck, agent.
|
||||||
|
components:
|
||||||
|
- type: Objective
|
||||||
|
# technically its still possible for KillRandomPersonObjective to roll a head but this is guaranteed, so higher difficulty
|
||||||
|
difficulty: 3.0
|
||||||
|
# killing 1 head is enough
|
||||||
|
unique: true
|
||||||
|
- type: TargetObjective
|
||||||
|
title: objective-condition-kill-head-title
|
||||||
|
- type: PickRandomHead
|
||||||
|
- type: KillPersonCondition
|
||||||
|
# don't count missing evac as killing as heads are higher profile, so you really need to do the dirty work
|
||||||
|
# if ce flies a shittle to centcom you better find a way onto it
|
||||||
|
requireDead: true
|
||||||
56
Resources/Prototypes/_White/Wizard/wizard.yml
Normal file
56
Resources/Prototypes/_White/Wizard/wizard.yml
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
- type: antag
|
||||||
|
id: WizardRole
|
||||||
|
name: roles-antag-wizard-name
|
||||||
|
antagonist: true
|
||||||
|
setPreference: true
|
||||||
|
objective: roles-antag-wizard-objective
|
||||||
|
requirements:
|
||||||
|
- !type:OverallPlaytimeRequirement
|
||||||
|
time: 18000 # 5h
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: SpawnPointWizard
|
||||||
|
parent: MarkerBase
|
||||||
|
name: wizard spawn point
|
||||||
|
components:
|
||||||
|
- type: SpawnPoint
|
||||||
|
- type: Sprite
|
||||||
|
layers:
|
||||||
|
- state: green
|
||||||
|
- sprite: Objects/Fun/figurines.rsi
|
||||||
|
state: wizard
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: SpawnPointGhostWizard
|
||||||
|
parent: MarkerBase
|
||||||
|
name: wizard spawn point (ghost role)
|
||||||
|
components:
|
||||||
|
- type: GhostRole
|
||||||
|
- type: GhostRoleMobSpawner
|
||||||
|
prototype: MobHumanSpaceWiz
|
||||||
|
- type: Sprite
|
||||||
|
layers:
|
||||||
|
- state: green
|
||||||
|
- sprite: Objects/Fun/figurines.rsi
|
||||||
|
state: wizard_fake
|
||||||
|
|
||||||
|
- type: startingGear
|
||||||
|
id: WizardGear
|
||||||
|
equipment:
|
||||||
|
jumpsuit: ClothingUniformJumpsuitColorDarkBlue
|
||||||
|
back: ClothingBackpackFilled
|
||||||
|
head: ClothingHeadHatRealWizardBlue
|
||||||
|
outerClothing: ClothingOuterRealWizardBlue
|
||||||
|
shoes: ClothingShoesWizard
|
||||||
|
innerClothingSkirt: ClothingUniformJumpskirtColorDarkBlue
|
||||||
|
satchel: ClothingBackpackSatchelFilled
|
||||||
|
duffelbag: ClothingBackpackDuffelFilled
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
noSpawn: true
|
||||||
|
name: Space Wizard
|
||||||
|
parent: MobHuman
|
||||||
|
id: MobHumanSpaceWiz
|
||||||
|
components:
|
||||||
|
- type: Wizard
|
||||||
|
- type: RandomHumanoidAppearance
|
||||||
@@ -16,6 +16,7 @@
|
|||||||
- Xeno
|
- Xeno
|
||||||
- Zombie
|
- Zombie
|
||||||
- Revolutionary
|
- Revolutionary
|
||||||
|
- Wizard
|
||||||
|
|
||||||
- type: npcFaction
|
- type: npcFaction
|
||||||
id: Mouse
|
id: Mouse
|
||||||
@@ -54,6 +55,7 @@
|
|||||||
- Xeno
|
- Xeno
|
||||||
- PetsNT
|
- PetsNT
|
||||||
- Zombie
|
- Zombie
|
||||||
|
- Wizard
|
||||||
|
|
||||||
- type: npcFaction
|
- type: npcFaction
|
||||||
id: Xeno
|
id: Xeno
|
||||||
@@ -75,6 +77,7 @@
|
|||||||
- Passive
|
- Passive
|
||||||
- PetsNT
|
- PetsNT
|
||||||
- Revolutionary
|
- Revolutionary
|
||||||
|
- Wizard
|
||||||
|
|
||||||
- type: npcFaction
|
- type: npcFaction
|
||||||
id: Revolutionary
|
id: Revolutionary
|
||||||
@@ -83,6 +86,7 @@
|
|||||||
- Zombie
|
- Zombie
|
||||||
- SimpleHostile
|
- SimpleHostile
|
||||||
- Dragon
|
- Dragon
|
||||||
|
- Wizard
|
||||||
|
|
||||||
# WD EDIT STARt
|
# WD EDIT STARt
|
||||||
- type: npcFaction
|
- type: npcFaction
|
||||||
@@ -93,4 +97,14 @@
|
|||||||
- Xeno
|
- Xeno
|
||||||
- PetsNT
|
- PetsNT
|
||||||
- Syndicate
|
- Syndicate
|
||||||
|
- Wizard
|
||||||
|
|
||||||
|
- type: npcFaction
|
||||||
|
id: Wizard
|
||||||
|
hostile:
|
||||||
|
- NanoTrasen
|
||||||
|
- Syndicate
|
||||||
|
- Cultist
|
||||||
|
- Revolutionary
|
||||||
|
- Zombie
|
||||||
# WD EDIT END
|
# WD EDIT END
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
- RampingStationEventScheduler
|
- RampingStationEventScheduler
|
||||||
- Changeling
|
- Changeling
|
||||||
- Cult
|
- Cult
|
||||||
|
- Wizard
|
||||||
- BasicRoundstartVariation
|
- BasicRoundstartVariation
|
||||||
|
|
||||||
- type: gamePreset
|
- type: gamePreset
|
||||||
@@ -197,4 +198,19 @@
|
|||||||
- SubGamemodesRule
|
- SubGamemodesRule
|
||||||
- BasicStationEventScheduler
|
- BasicStationEventScheduler
|
||||||
- BasicRoundstartVariation
|
- BasicRoundstartVariation
|
||||||
|
|
||||||
|
- type: gamePreset
|
||||||
|
id: Wizard
|
||||||
|
alias:
|
||||||
|
- wizard
|
||||||
|
- wiz
|
||||||
|
name: wizard-title
|
||||||
|
description: wizard-description
|
||||||
|
showInVote: true
|
||||||
|
minPlayers: 20
|
||||||
|
rules:
|
||||||
|
- Wizard
|
||||||
|
- SubGamemodesRule
|
||||||
|
- BasicStationEventScheduler
|
||||||
|
- BasicRoundstartVariation
|
||||||
#WD EDIT END
|
#WD EDIT END
|
||||||
|
|||||||
Reference in New Issue
Block a user