mirror of
https://github.com/WWhiteDreamProject/wwdpublic.git
synced 2026-04-19 22:49:01 +03:00
* Уэээээээ * Почти настрадались * Скоро конец.... * СКОРО * Мышки плакали, кололись, но продолжали упорно жрать кактус * Все ближе! * Это такой конец? * Книжка говна * фиксики * ОНО ЖИВОЕ * Телепорт * разное * Added byond * ивенты теперь работают * Разфикс телепорта * Свет мой зеркальце скажи, да всю правду доложи - Я ль робастней всех на свете? * Разное * Еще многа всего * Многа разнава * Скоро конец.... * ЭТО КОНЕЦ * Фикс линтера (ну, или я на это надеюсь) * Еще один фикс линтера * Победа! * фиксики * пу пу пу * Фикс подмастерья * Мисклик * Высокочастотный меч * Неймспейсы * Пул способностей мага
296 lines
11 KiB
C#
296 lines
11 KiB
C#
// SPDX-FileCopyrightText: 2025 Aiden <28298836+Aidenkrz@users.noreply.github.com>
|
|
// SPDX-FileCopyrightText: 2025 Aidenkrz <aiden@djkraz.com>
|
|
// SPDX-FileCopyrightText: 2025 Aviu00 <93730715+Aviu00@users.noreply.github.com>
|
|
// SPDX-FileCopyrightText: 2025 Ilya246 <57039557+Ilya246@users.noreply.github.com>
|
|
// SPDX-FileCopyrightText: 2025 Misandry <mary@thughunt.ing>
|
|
// SPDX-FileCopyrightText: 2025 gluesniffler <159397573+gluesniffler@users.noreply.github.com>
|
|
// SPDX-FileCopyrightText: 2025 gus <august.eymann@gmail.com>
|
|
//
|
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
using System.Linq;
|
|
using Content.Server._Shitcode.Wizard.Components;
|
|
using Content.Server.Administration.Logs;
|
|
using Content.Server.Antag;
|
|
using Content.Server.Atmos.EntitySystems;
|
|
using Content.Server.Chat.Managers;
|
|
using Content.Server.GameTicking;
|
|
using Content.Server.GameTicking.Rules;
|
|
using Content.Server.Mind;
|
|
using Content.Server.Roles;
|
|
using Content.Server.Station.Components;
|
|
using Content.Server.Station.Systems;
|
|
using Content.Shared._Shitcode.Wizard;
|
|
using Content.Shared._Shitcode.Wizard.BindSoul;
|
|
using Content.Shared.Atmos;
|
|
using Content.Shared.Chat;
|
|
using Content.Shared.Cloning;
|
|
using Content.Shared.Database;
|
|
using Content.Shared.GameTicking.Components;
|
|
using Content.Shared.Humanoid;
|
|
using Content.Shared.Mind;
|
|
using Content.Shared.Mobs;
|
|
using Content.Shared.Mobs.Components;
|
|
using Content.Shared.NPC.Prototypes;
|
|
using Content.Shared.NPC.Systems;
|
|
using Content.Shared.Parallax;
|
|
using Robust.Server.Audio;
|
|
using Robust.Shared.Player;
|
|
using Robust.Shared.Prototypes;
|
|
using Robust.Shared.Random;
|
|
using Robust.Shared.Utility;
|
|
|
|
namespace Content.Server._Shitcode.Wizard.Systems;
|
|
|
|
public sealed class WizardRuleSystem : GameRuleSystem<WizardRuleComponent>
|
|
{
|
|
[Dependency] private readonly StationSystem _station = default!;
|
|
[Dependency] private readonly AntagSelectionSystem _antag = default!;
|
|
[Dependency] private readonly MindSystem _mind = default!;
|
|
[Dependency] private readonly RoleSystem _role = default!;
|
|
[Dependency] private readonly GameTicker _gameTicker = default!;
|
|
[Dependency] private readonly IRobustRandom _random = default!;
|
|
[Dependency] private readonly AtmosphereSystem _atmos = default!;
|
|
[Dependency] private readonly AudioSystem _audio = default!;
|
|
[Dependency] private readonly NpcFactionSystem _faction = default!;
|
|
[Dependency] private readonly IAdminLogManager _log = default!;
|
|
[Dependency] private readonly IChatManager _chatManager = default!;
|
|
|
|
public static readonly ProtoId<NpcFactionPrototype> Faction = "Wizard";
|
|
|
|
public static readonly EntProtoId Role = "MindRoleWizard";
|
|
|
|
public override void Initialize()
|
|
{
|
|
base.Initialize();
|
|
|
|
SubscribeLocalEvent<WizardRuleComponent, AfterAntagEntitySelectedEvent>(OnAfterAntagSelected);
|
|
|
|
SubscribeLocalEvent<WizardRoleComponent, GetBriefingEvent>(OnWizardGetBriefing);
|
|
SubscribeLocalEvent<ApprenticeRoleComponent, GetBriefingEvent>(OnApprenticeGetBriefing);
|
|
|
|
SubscribeLocalEvent<WizardComponent, MobStateChangedEvent>(OnStateChanged);
|
|
SubscribeLocalEvent<WizardComponent, ComponentRemove>(OnRemove);
|
|
SubscribeLocalEvent<WizardComponent, CloningEvent>(OnWizardClone);
|
|
SubscribeLocalEvent<ApprenticeComponent, MobStateChangedEvent>(OnStateChanged);
|
|
SubscribeLocalEvent<ApprenticeComponent, ComponentRemove>(OnRemove);
|
|
SubscribeLocalEvent<ApprenticeComponent, CloningEvent>(OnApprenticeClone);
|
|
SubscribeLocalEvent<PhylacteryComponent, ComponentRemove>(OnRemove);
|
|
SubscribeLocalEvent<EntParentChangedMessage>(OnParentChanged);
|
|
|
|
SubscribeLocalEvent<DimensionShiftEvent>(OnDimensionShift);
|
|
}
|
|
|
|
private void OnApprenticeClone(Entity<ApprenticeComponent> ent, ref CloningEvent args)
|
|
{
|
|
EnsureComp<ApprenticeComponent>(args.Target);
|
|
RemCompDeferred<ApprenticeComponent>(ent);
|
|
_faction.ClearFactions(args.Target, false);
|
|
_faction.AddFaction(args.Target, Faction);
|
|
}
|
|
|
|
private void OnWizardClone(Entity<WizardComponent> ent, ref CloningEvent args)
|
|
{
|
|
EnsureComp<WizardComponent>(args.Target);
|
|
RemCompDeferred<WizardComponent>(ent);
|
|
_faction.ClearFactions(args.Target, false);
|
|
_faction.AddFaction(args.Target, Faction);
|
|
}
|
|
|
|
public EntityUid? GetTargetMap()
|
|
{
|
|
var rule = GameTicker.GetActiveGameRules().Where(HasComp<WizardRuleComponent>).FirstOrNull();
|
|
EntityUid? map;
|
|
if (rule != null)
|
|
{
|
|
var ruleComp = Comp<WizardRuleComponent>(rule.Value);
|
|
if (ruleComp.TargetStation == null)
|
|
map = GetRandomTargetMap();
|
|
else
|
|
{
|
|
var stationGrid = _station.GetLargestGrid(Comp<StationDataComponent>(ruleComp.TargetStation.Value));
|
|
map = stationGrid == null ? GetRandomTargetMap() : Transform(stationGrid.Value).MapUid;
|
|
}
|
|
}
|
|
else
|
|
map = GetRandomTargetMap();
|
|
|
|
return map;
|
|
}
|
|
|
|
private EntityUid? GetRandomTargetMap()
|
|
{
|
|
var grid = GetWizardTargetRandomStationGrid();
|
|
return grid == null ? null : Transform(grid.Value).MapUid;
|
|
}
|
|
|
|
private void OnDimensionShift(DimensionShiftEvent ev)
|
|
{
|
|
var map = GetTargetMap();
|
|
if (map == null)
|
|
return;
|
|
|
|
if (ev.Parallax != null)
|
|
{
|
|
var parallax = EnsureComp<ParallaxComponent>(map.Value);
|
|
parallax.Parallax = ev.Parallax;
|
|
Dirty(map.Value, parallax);
|
|
}
|
|
|
|
var moles = new float[Atmospherics.AdjustedNumberOfGases];
|
|
moles[(int) Gas.Oxygen] = ev.OxygenMoles;
|
|
moles[(int) Gas.Nitrogen] = ev.NitrogenMoles;
|
|
moles[(int) Gas.CarbonDioxide] = ev.CarbonDioxideMoles;
|
|
|
|
var mixture = new GasMixture(moles, ev.Temperature);
|
|
|
|
_atmos.SetMapAtmosphere(map.Value, false, mixture);
|
|
|
|
var message = Loc.GetString("dimension-shift-message");
|
|
var wrappedMessage = Loc.GetString("chat-manager-server-wrap-message", ("message", message));
|
|
_chatManager.ChatMessageToAll(ChatChannel.Radio, message, wrappedMessage, default, false, true, Color.Red);
|
|
_audio.PlayGlobal(ev.Sound, Filter.Broadcast(), true);
|
|
|
|
_log.Add(LogType.EventRan, LogImpact.Extreme, $"Station map changed via wizard spellbook dimension shift.");
|
|
|
|
return;
|
|
}
|
|
|
|
private void OnParentChanged(ref EntParentChangedMessage args)
|
|
{
|
|
if (args.OldMapId != args.Transform.MapUid && RecursivePhylacteryCheck(args.Entity, args.Transform))
|
|
CheckRoundShouldEnd();
|
|
}
|
|
|
|
private bool RecursivePhylacteryCheck(EntityUid entity, TransformComponent? xform = null)
|
|
{
|
|
if (HasComp<PhylacteryComponent>(entity))
|
|
return true;
|
|
|
|
if (!Resolve(entity, ref xform, false))
|
|
return false;
|
|
|
|
var enumerator = xform.ChildEnumerator;
|
|
while (enumerator.MoveNext(out var child))
|
|
{
|
|
if (RecursivePhylacteryCheck(child))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private void OnRemove(EntityUid uid, Component component, ComponentRemove args)
|
|
{
|
|
CheckRoundShouldEnd();
|
|
}
|
|
|
|
private void OnStateChanged(EntityUid uid, Component component, MobStateChangedEvent args)
|
|
{
|
|
if (args.NewMobState == MobState.Dead)
|
|
CheckRoundShouldEnd();
|
|
}
|
|
|
|
private void CheckRoundShouldEnd()
|
|
{
|
|
if (!_gameTicker.IsGameRuleActive<RuleOnWizardDeathRuleComponent>() ||
|
|
!_gameTicker.IsGameRuleActive<WizardRuleComponent>())
|
|
return;
|
|
|
|
var endRound = false;
|
|
var query = EntityQueryEnumerator<MindComponent>();
|
|
while (query.MoveNext(out var mind, out var mindComp))
|
|
{
|
|
if (!_role.MindHasRole<WizardRoleComponent>(mind) && !_role.MindHasRole<ApprenticeRoleComponent>(mind))
|
|
continue;
|
|
|
|
if (!_mind.IsCharacterDeadIc(mindComp))
|
|
return;
|
|
|
|
if (TryComp(mindComp.OwnedEntity, out MobStateComponent? mobState) &&
|
|
mobState.CurrentState != MobState.Dead)
|
|
return;
|
|
|
|
if (TryComp(mind, out SoulBoundComponent? soulBound) && Exists(soulBound.Item) &&
|
|
HasComp<PhylacteryComponent>(soulBound.Item.Value) &&
|
|
TryComp(soulBound.Item.Value, out TransformComponent? xform) && xform.MapUid != null &&
|
|
xform.MapUid == soulBound.MapId)
|
|
return;
|
|
|
|
endRound = true;
|
|
}
|
|
|
|
if (!endRound)
|
|
return;
|
|
|
|
var endQuery = EntityQueryEnumerator<RuleOnWizardDeathRuleComponent, GameRuleComponent>();
|
|
while (endQuery.MoveNext(out var uid, out var ruleOnDeath, out var gameRule))
|
|
{
|
|
_gameTicker.EndGameRule(uid, gameRule);
|
|
_gameTicker.StartGameRule(ruleOnDeath.Rule);
|
|
}
|
|
}
|
|
|
|
public IEnumerable<Entity<StationDataComponent>> GetWizardTargetStations()
|
|
{
|
|
var query = EntityQueryEnumerator<StationWizardTargetComponent, StationDataComponent>();
|
|
while (query.MoveNext(out var station, out _, out var data))
|
|
{
|
|
yield return (station, data);
|
|
}
|
|
}
|
|
|
|
public IEnumerable<EntityUid?> GetWizardTargetStationGrids()
|
|
{
|
|
return GetWizardTargetStations().Select(station => _station.GetLargestGrid(station.Comp));
|
|
}
|
|
|
|
public EntityUid? GetWizardTargetRandomStationGrid()
|
|
{
|
|
var grids = GetWizardTargetStationGrids().Where(grid => grid != null).ToList();
|
|
return grids.Count == 0 ? null : _random.Pick(grids);
|
|
}
|
|
|
|
protected override void Started(EntityUid uid,
|
|
WizardRuleComponent component,
|
|
GameRuleComponent gameRule,
|
|
GameRuleStartedEvent args)
|
|
{
|
|
var stations = GetWizardTargetStations().ToList();
|
|
if (stations.Count == 0)
|
|
return;
|
|
component.TargetStation = _random.Pick(stations);
|
|
}
|
|
|
|
private void OnWizardGetBriefing(Entity<WizardRoleComponent> ent, ref GetBriefingEvent args)
|
|
{
|
|
args.Append(Loc.GetString("wizard-role-briefing"));
|
|
}
|
|
|
|
private void OnApprenticeGetBriefing(Entity<ApprenticeRoleComponent> ent, ref GetBriefingEvent args)
|
|
{
|
|
args.Append(Loc.GetString("apprentice-role-briefing"));
|
|
}
|
|
|
|
private void OnAfterAntagSelected(Entity<WizardRuleComponent> ent, ref AfterAntagEntitySelectedEvent args)
|
|
{
|
|
MakeWizard(args.EntityUid, ent.Comp);
|
|
}
|
|
|
|
public bool MakeWizard(EntityUid target, WizardRuleComponent rule)
|
|
{
|
|
var station = (rule.TargetStation is not null) ? Name(rule.TargetStation.Value) : "the station";
|
|
|
|
_antag.SendBriefing(target, Loc.GetString("wizard-role-greeting", ("station", station)), Color.Cyan, null);
|
|
|
|
if (!TryComp(target, out HumanoidAppearanceComponent? humanoid) || humanoid.Age >= 60)
|
|
return true;
|
|
|
|
// Wizards are old
|
|
humanoid.Age = _random.Next(60, 121);
|
|
Dirty(target, humanoid);
|
|
|
|
return true;
|
|
}
|
|
}
|