Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More features and events for SCP-1507 #2348

Merged
merged 14 commits into from
Dec 23, 2023
6 changes: 5 additions & 1 deletion Exiled.API/Features/Ragdoll.cs
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,11 @@ public static Ragdoll CreateAndSpawn(RoleTypeId roleType, string name, string de
/// <param name="ragdoll">The <see cref="BasicRagdoll"/> to get.</param>
/// <returns>A <see cref="Ragdoll"/> or <see langword="null"/> if not found.</returns>
public static Ragdoll Get(BasicRagdoll ragdoll) => ragdoll == null ? null :
BasicRagdollToRagdoll.TryGetValue(ragdoll, out Ragdoll doll) ? doll : new Ragdoll(ragdoll);
BasicRagdollToRagdoll.TryGetValue(ragdoll, out Ragdoll doll) ? doll : ragdoll switch
{
PlayerRoles.PlayableScps.Scp1507.Scp1507Ragdoll scp1507Ragdoll => new Scp1507Ragdoll(scp1507Ragdoll),
_ => new Ragdoll(ragdoll)
};

/// <summary>
/// Gets the <see cref="IEnumerable{T}"/> of <see cref="Ragdoll"/> belonging to the <see cref="Player"/>, if any.
Expand Down
5 changes: 2 additions & 3 deletions Exiled.API/Features/Roles/Role.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,12 @@ namespace Exiled.API.Features.Roles
using System;

using Enums;

using Exiled.API.Features.Core;
using Exiled.API.Features.Spawn;
using Exiled.API.Interfaces;
using Extensions;

using PlayerRoles;
using PlayerRoles.PlayableScps.Scp049.Zombies;

using UnityEngine;

using FilmmakerGameRole = PlayerRoles.Filmmaker.FilmmakerRole;
Expand All @@ -28,6 +25,7 @@ namespace Exiled.API.Features.Roles
using Scp079GameRole = PlayerRoles.PlayableScps.Scp079.Scp079Role;
using Scp096GameRole = PlayerRoles.PlayableScps.Scp096.Scp096Role;
using Scp106GameRole = PlayerRoles.PlayableScps.Scp106.Scp106Role;
using Scp1507GameRole = PlayerRoles.PlayableScps.Scp1507.Scp1507Role;
using Scp173GameRole = PlayerRoles.PlayableScps.Scp173.Scp173Role;
using Scp3114GameRole = PlayerRoles.PlayableScps.Scp3114.Scp3114Role;
using Scp939GameRole = PlayerRoles.PlayableScps.Scp939.Scp939Role;
Expand Down Expand Up @@ -229,6 +227,7 @@ public virtual void Set(RoleTypeId newRole, SpawnReason reason, RoleSpawnFlags s
SpectatorGameRole spectatorRole => new SpectatorRole(spectatorRole),
HumanGameRole humanRole => new HumanRole(humanRole),
FilmmakerGameRole filmmakerRole => new FilmMakerRole(filmmakerRole),
Scp1507GameRole scp1507Role => new Scp1507Role(scp1507Role),
_ => new NoneRole(role),
};
}
Expand Down
148 changes: 148 additions & 0 deletions Exiled.API/Features/Roles/Scp1507Role.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
// -----------------------------------------------------------------------
// <copyright file="Scp1507Role.cs" company="Exiled Team">
// Copyright (c) Exiled Team. All rights reserved.
// Licensed under the CC BY-SA 3.0 license.
// </copyright>
// -----------------------------------------------------------------------

namespace Exiled.API.Features.Roles
{
using System.Collections.Generic;
using System.Linq;

using Exiled.API.Interfaces;
using PlayerRoles;
using PlayerRoles.PlayableScps.HumeShield;
using PlayerRoles.PlayableScps.Scp1507;
using PlayerRoles.Subroutines;

using BaseRole = PlayerRoles.PlayableScps.Scp1507.Scp1507Role;

/// <summary>
/// A wrapper for <see cref="BaseRole"/>.
/// </summary>
public class Scp1507Role : Role, IWrapper<BaseRole>, ISubroutinedScpRole, IHumeShieldRole
{
/// <summary>
/// Initializes a new instance of the <see cref="Scp1507Role"/> class.
/// </summary>
/// <param name="baseRole">the base <see cref="PlayerRoleBase"/>.</param>
public Scp1507Role(BaseRole baseRole)
: base(baseRole)
{
Base = baseRole;

SubroutineModule = baseRole.SubroutineModule;
HumeShieldModule = baseRole.HumeShieldModule;

if (!SubroutineModule.TryGetSubroutine(out Scp1507AttackAbility attackAbility))
Log.Error($"Attack ability is not a subroutine for {nameof(Scp1507Role)}");

AttackAbility = attackAbility;

if (!SubroutineModule.TryGetSubroutine(out Scp1507SwarmAbility swarmAbility))
Log.Error($"Swarm ability is not a subroutine for {nameof(Scp1507Role)}");

SwarmAbility = swarmAbility;

if (!SubroutineModule.TryGetSubroutine(out Scp1507VocalizeAbility vocalizeAbility))
Log.Error($"Vocalize ability is not a subroutine for {nameof(Scp1507Role)}");

VocalizeAbility = vocalizeAbility;
}

/// <inheritdoc/>
public override RoleTypeId Type => Base._roleTypeId;

/// <inheritdoc/>
public new BaseRole Base { get; }

/// <inheritdoc/>
public SubroutineManagerModule SubroutineModule { get; }

/// <summary>
/// Gets the <see cref="Scp1507AttackAbility"/> for this role.
/// </summary>
public Scp1507AttackAbility AttackAbility { get; }

/// <summary>
/// Gets the <see cref="Scp1507SwarmAbility"/> for this role.
/// </summary>
public Scp1507SwarmAbility SwarmAbility { get; }

/// <summary>
/// Gets the <see cref="Scp1507VocalizeAbility"/> for this role.
/// </summary>
public Scp1507VocalizeAbility VocalizeAbility { get; }

/// <summary>
/// Gets or sets how much damage should deal SCP-1507.
/// </summary>
public float Damage
{
get => AttackAbility._damage;
set => AttackAbility._damage = value;
}

/// <summary>
/// Gets the delay between attacks.
/// </summary>
public float AttackDelay => AttackAbility.AttackDelay;

/// <summary>
/// Gets or sets a list with flamingos, which are close to owner.
/// </summary>
public IEnumerable<Player> NearbyFlamingos
{
get => SwarmAbility._nearbyFlamingos.Select(x => Player.Get(x._lastOwner));
set
{
SwarmAbility._nearbyFlamingos.Clear();

foreach (var player in value.Where(x => x.Role.Is<Scp1507Role>(out _)))
SwarmAbility._nearbyFlamingos.Add(player.Role.As<Scp1507Role>().Base);
}
}

/// <summary>
/// Gets or sets a list with all flamingos.
/// </summary>
public IEnumerable<Player> AllFlamingos
{
get => SwarmAbility._entireFlock.Select(x => Player.Get(x._lastOwner));
set
{
SwarmAbility._entireFlock.Clear();

foreach (var player in value.Where(x => x.Role.Is<Scp1507Role>(out _)))
SwarmAbility._entireFlock.Add(player.Role.As<Scp1507Role>().Base);

SwarmAbility._flockSize = (byte)(SwarmAbility._entireFlock.Count - 1);
}
}

/// <summary>
/// Gets or sets a multiplier for healing.
/// </summary>
public float Multiplier
{
get => SwarmAbility.Multiplier;
set => SwarmAbility.Multiplier = value;
}

/// <inheritdoc/>
public HumeShieldModuleBase HumeShieldModule { get; }

/// <summary>
/// Tries to attack door.
/// </summary>
/// <returns><see langword="true"/> if successfully. Otherwise, <see langword="false"/>.</returns>
/// <remarks>This method does not modify game logic, so if you want this method to work correctly, make sure that player is staying in front of the door.</remarks>
public bool TryAttackDoor() => AttackAbility.TryAttackDoor();

/// <summary>
/// Forces a SCP-1507 to scream.
/// </summary>
public void Scream() => VocalizeAbility.ServerScream();
}
}
74 changes: 74 additions & 0 deletions Exiled.API/Features/Scp1507Ragdoll.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// -----------------------------------------------------------------------
// <copyright file="Scp1507Ragdoll.cs" company="Exiled Team">
// Copyright (c) Exiled Team. All rights reserved.
// Licensed under the CC BY-SA 3.0 license.
// </copyright>
// -----------------------------------------------------------------------

namespace Exiled.API.Features
{
using Exiled.API.Extensions;
using Exiled.API.Features.Roles;
using Exiled.API.Interfaces;
using PlayerRoles;

using Scp1507BaseRagdoll = PlayerRoles.PlayableScps.Scp1507.Scp1507Ragdoll;

/// <summary>
/// A wrapper for <see cref="Scp1507BaseRagdoll"/>.
/// </summary>
public class Scp1507Ragdoll : Ragdoll, IWrapper<Scp1507BaseRagdoll>
{
/// <summary>
/// Initializes a new instance of the <see cref="Scp1507Ragdoll"/> class.
/// </summary>
/// <param name="ragdoll">The encapsulated <see cref="Scp1507BaseRagdoll"/>.</param>
internal Scp1507Ragdoll(Scp1507BaseRagdoll ragdoll)
: base(ragdoll)
{
Base = ragdoll;
}

/// <inheritdoc/>
public new Scp1507BaseRagdoll Base { get; }

/// <summary>
/// Gets or sets current progress of revival process.
/// </summary>
public float RevivalProgress
{
get => Base._revivalProgress;
set => Base.Network_revivalProgress = value;
}

/// <summary>
/// Gets or sets a value indicating whether or not this ragdoll has been revived.
/// </summary>
public bool IsRevived
{
get => Base._hasAlreadyRevived;
set => Base.Network_hasAlreadyRevived = value;
}

/// <summary>
/// Gets or sets amount of time when ragdoll was reset last time.
/// </summary>
public double ResetTime
{
get => Base._lastResetTime;
set => Base.Network_lastResetTime = value;
}

/// <summary>
/// Spawns a variant from available ragdolls for chosen role.
/// </summary>
/// <param name="role">Role. Can be <see cref="RoleTypeId.Flamingo"/>, <see cref="RoleTypeId.AlphaFlamingo"/> or <see cref="RoleTypeId.ZombieFlamingo"/>.</param>
public void SpawnVariant(RoleTypeId role) => Base.SpawnVariant(role);

/// <summary>
/// Vocalizes ragdoll.
/// </summary>
/// <param name="player">Player who vocalizes. If <see langword="null"/>, will be chosen random.</param>
public void Vocalize(Player player = null) => Base.OnVocalize((player ?? Player.Get(x => x.Role.Is(out Scp1507Role _)).GetRandomValue()).ReferenceHub);
}
}
22 changes: 22 additions & 0 deletions Exiled.Events/EventArgs/Interfaces/IScp1507Event.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// -----------------------------------------------------------------------
// <copyright file="IScp1507Event.cs" company="Exiled Team">
// Copyright (c) Exiled Team. All rights reserved.
// Licensed under the CC BY-SA 3.0 license.
// </copyright>
// -----------------------------------------------------------------------

namespace Exiled.Events.EventArgs.Interfaces
{
using Exiled.API.Features.Roles;

/// <summary>
/// Event args used for all <see cref="Scp1507Role"/> related events.
/// </summary>
public interface IScp1507Event : IPlayerEvent
{
/// <summary>
/// Gets the <see cref="Scp1507Role"/> triggering the event.
/// </summary>
public Scp1507Role Scp1507 { get; }
}
}
6 changes: 6 additions & 0 deletions Exiled.Events/EventArgs/Scp049/FinishingRecallEventArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public FinishingRecallEventArgs(Player target, Player scp049, BasicRagdoll ragdo
Target = target;
Ragdoll = Ragdoll.Get(ragdoll);
IsAllowed = isAllowed;
IsFlamingo = ragdoll is PlayerRoles.PlayableScps.Scp1507.Scp1507Ragdoll;
}

/// <inheritdoc/>
Expand All @@ -63,5 +64,10 @@ public FinishingRecallEventArgs(Player target, Player scp049, BasicRagdoll ragdo
/// Gets or sets a value indicating whether or not the player can be revived.
/// </summary>
public bool IsAllowed { get; set; }

/// <summary>
/// Gets or sets a value indicating whether or not revived player should become a zombie flamingo.
/// </summary>
public bool IsFlamingo { get; set; }
}
}
46 changes: 46 additions & 0 deletions Exiled.Events/EventArgs/Scp1507/AttackingDoorEventArgs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// -----------------------------------------------------------------------
// <copyright file="AttackingDoorEventArgs.cs" company="Exiled Team">
// Copyright (c) Exiled Team. All rights reserved.
// Licensed under the CC BY-SA 3.0 license.
// </copyright>
// -----------------------------------------------------------------------

namespace Exiled.Events.EventArgs.Scp1507
{
using Exiled.API.Features;
using Exiled.API.Features.Doors;
using Exiled.API.Features.Roles;
using Exiled.Events.EventArgs.Interfaces;

/// <summary>
/// Contains all information before SCP-1507 attacks door.
/// </summary>
public class AttackingDoorEventArgs : IScp1507Event, IDeniableEvent, IDoorEvent
{
/// <summary>
/// Initializes a new instance of the <see cref="AttackingDoorEventArgs"/> class.
/// </summary>
/// <param name="player"><inheritdoc cref="Player"/></param>
/// <param name="door"><inheritdoc cref="Door"/></param>
/// <param name="isAllowed"><inheritdoc cref="IsAllowed"/></param>
public AttackingDoorEventArgs(Player player, Door door, bool isAllowed = true)
{
Player = player;
Scp1507 = player.Role.As<Scp1507Role>();
Door = door;
IsAllowed = isAllowed;
}

/// <inheritdoc/>
public Player Player { get; }

/// <inheritdoc/>
public Scp1507Role Scp1507 { get; }

/// <inheritdoc/>
public bool IsAllowed { get; set; }

/// <inheritdoc/>
public Door Door { get; }
}
}
Loading
Loading