Skip to content
This repository has been archived by the owner on Oct 23, 2024. It is now read-only.

Gamemode Blood Family #38

Closed
wants to merge 12 commits into from

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using Content.Shared.Mind;
using Content.Shared.Preferences;
using Content.Shared.Roles;
using Robust.Server.Player;
using Robust.Shared.Audio;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;

namespace Content.Server.EstacaoPirata.GameTicking.Rules.Components;

/// <summary>
/// This is used for...
/// </summary>
[RegisterComponent, Access(typeof(BloodFamilyRuleSystem))]
public sealed partial class BloodFamilyRuleComponent : Component
{
public readonly List<EntityUid> BloodFamilyMinds = new();

// Mind + team
public readonly Dictionary<EntityUid, int> BloodFamilyTeams = new();

public Dictionary<IPlayerSession, (EntityUid,MindComponent, int)> BloodFamilyQueue = new();

[DataField("bloodFamilyPrototypeId", customTypeSerializer: typeof(PrototypeIdSerializer<AntagPrototype>))]
public string BloodFamilyPrototypeId = "BloodFamily";

public int TotalBloodFamilyMembers => BloodFamilyMinds.Count; // Alterar isto

// TODO: colocar os valores certos

/// <summary>
/// Max amount members in a family
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public int MaxBloodFamily = 3;

/// <summary>
/// For every X players, 1 will be a family member
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public int PlayersPerFamilyMember = 8;

/// <summary>
/// Min number of players who selected Blood Family in character creation. (MUDAR PARA Min amount of members in a family?)
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public int MinBloodFamily = 2;

/// <summary>
/// Maximum amount of random objectives a blood family member will have
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public int MaxRandomObjectives = 2;

/// <summary>
/// Minimum players in game for the game rule to be selected
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public int MinPlayers = 5;

/// <summary>
/// Maximum players to be selected as a blood family member
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public int MaxPlayers = 20;

public enum SelectionState
{
WaitingForSpawn = 0,
ReadyToSelect = 1,
SelectionMade = 2,
Error = 3,
}

public SelectionState SelectionStatus = SelectionState.WaitingForSpawn;
public TimeSpan AnnounceAt = TimeSpan.Zero;
public Dictionary<IPlayerSession, HumanoidCharacterProfile> StartCandidates = new();

/// <summary>
/// Path to antagonist alert sound.
/// </summary>
[DataField("greetSoundNotification")]
public SoundSpecifier GreetSoundNotification = new SoundPathSpecifier("/Audio/Ambience/Antag/traitor_start.ogg");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Content.Server.EstacaoPirata.Objectives.Systems;

namespace Content.Server.EstacaoPirata.Objectives.Components;

/// <summary>
/// This is used for...
/// </summary>
[RegisterComponent, Access(typeof(KeepGroupAliveConditionSystem))]
public sealed partial class FamilyAliveComponent : Component
{

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using Content.Server.EstacaoPirata.Objectives.Systems;

namespace Content.Server.EstacaoPirata.Objectives.Components;

/// <summary>
/// This is used for...
/// </summary>
[RegisterComponent, Access(typeof(GroupTargetObjectiveSystem))]
public sealed partial class GroupTargetObjectiveComponent : Component
{
/// <summary>
/// Locale id for the objective title.
/// It is passed "targetName" and "job" arguments.
/// </summary>
[DataField(required: true), ViewVariables(VVAccess.ReadWrite)]
public string Title = string.Empty;

/// <summary>
/// List of targets' uids
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public List<EntityUid> Targets = new List<EntityUid>();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Content.Server.EstacaoPirata.Objectives.Systems;

namespace Content.Server.EstacaoPirata.Objectives.Components;

/// <summary>
/// This is used for...
/// </summary>
[RegisterComponent, Access(typeof(KeepGroupAliveConditionSystem))]
public sealed partial class KeepGroupAliveConditionComponent : Component
{

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Content.Server.Objectives.Systems;

namespace Content.Server.EstacaoPirata.Objectives.Components;

/// <summary>
/// This is used for picking a random head exluding members of the blood family to be killed for an objective
/// </summary>
[RegisterComponent, Access(typeof(KillPersonConditionSystem))]
public sealed partial class PickRandomHeadFamilyComponent : Component
{

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Content.Server.Objectives.Systems;

namespace Content.Server.EstacaoPirata.Objectives.Components;

/// <summary>
/// This is used for picking a random person exluding members of the blood family to be killed for an objective
/// </summary>
[RegisterComponent, Access(typeof(KillPersonConditionSystem))]
public sealed partial class PickRandomPersonFamilyComponent : Component
{

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text;
using Content.Server.EstacaoPirata.Objectives.Components;
using Content.Server.Objectives.Components;
using Content.Shared.Mind;
using Content.Shared.Objectives.Components;
using Content.Shared.Roles.Jobs;

namespace Content.Server.EstacaoPirata.Objectives.Systems;

/// <summary>
/// This handles...
/// </summary>
public sealed class GroupTargetObjectiveSystem : EntitySystem
{
[Dependency] private readonly MetaDataSystem _metaData = default!;

/// <inheritdoc/>
public override void Initialize()
{

SubscribeLocalEvent<GroupTargetObjectiveComponent, ObjectiveAfterAssignEvent>(OnAfterAssign);
}

private void OnAfterAssign(EntityUid uid, GroupTargetObjectiveComponent component, ref ObjectiveAfterAssignEvent args)
{
if (!GetTargets(uid, out var targets, component))
return;

_metaData.SetEntityName(uid, GetTitle(targets, component.Title), args.Meta);
}

public void SetTargets(EntityUid uid, List<EntityUid> targets, GroupTargetObjectiveComponent? comp = null)
{
if (!Resolve(uid, ref comp))
return;

foreach (var target in targets)
{
comp.Targets.Add(target);
}

}

/// <summary>
/// Gets the targets from the component.
/// </summary>
/// <remarks>
/// If it is null then the prototype is invalid, just return.
/// </remarks>
public bool GetTargets(EntityUid uid, [NotNullWhen(true)] out List<EntityUid>? targets, GroupTargetObjectiveComponent? comp = null)
{
targets = Resolve(uid, ref comp) ? comp.Targets : null;
return targets != null;
}

private string GetTitle(List<EntityUid> targets, string title)
{
var targetsNames = new StringBuilder("");
int index = 0;
foreach (var target in targets)
{
var targetName = "Unknown";
if (TryComp<MindComponent>(target, out var mind) && mind.CharacterName != null)
{
targetName = mind.CharacterName;
}

if(index > 0 && index < targets.Count)
targetsNames.Append("e ");

targetsNames.Append(targetName);
targetsNames.Append(' ');

index++;
}
return Loc.GetString(title, ("targetsNames", targetsNames));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
using System.Linq;
using Content.Server.EstacaoPirata.GameTicking.Rules;
using Content.Server.EstacaoPirata.GameTicking.Rules.Components;
using Content.Server.EstacaoPirata.Objectives.Components;
using Content.Server.GameTicking.Rules;
using Content.Server.Objectives.Components;
using Content.Server.Objectives.Systems;
using Content.Shared.Mind;
using Content.Shared.Objectives.Components;

namespace Content.Server.EstacaoPirata.Objectives.Systems;

/// <summary>
/// Handles keep alive condition logic for blood family
/// </summary>
public sealed class KeepGroupAliveConditionSystem : EntitySystem
{
[Dependency] private readonly SharedMindSystem _mind = default!;
[Dependency] private readonly GroupTargetObjectiveSystem _groupTarget = default!;
[Dependency] private readonly BloodFamilyRuleSystem _bloodFamilyRule = default!;

/// <inheritdoc/>
public override void Initialize()
{
SubscribeLocalEvent<KeepGroupAliveConditionComponent, ObjectiveGetProgressEvent>(OnGetProgress);

SubscribeLocalEvent<FamilyAliveComponent, ObjectiveAssignedEvent>(OnAssigned);
}

private void OnAssigned(EntityUid uid, FamilyAliveComponent component, ref ObjectiveAssignedEvent args)
{
// invalid prototype
if (!TryComp<GroupTargetObjectiveComponent>(uid, out var comp))
{
args.Cancelled = true;
return;
}

var family = Enumerable.ToList<(EntityUid Id, MindComponent Mind)>(_bloodFamilyRule.GetOtherBloodFamilyMindsAliveAndConnectedSameTeam(args.Mind));

// You are the first/only family member.
if (family.Count == 0)
{
args.Cancelled = true;
return;
}

var targets = new List<EntityUid>();
foreach (var player in family)
{
targets.Add(player.Id);
}

_groupTarget.SetTargets(uid, targets, comp);
}

private void OnGetProgress(EntityUid uid, KeepGroupAliveConditionComponent component, ref ObjectiveGetProgressEvent args)
{
if (!_groupTarget.GetTargets(uid, out var targets))
return;

args.Progress = GetProgress(targets);
}

private float GetProgress(List<EntityUid> targets)
{
foreach (var target in targets)
{
if (!TryComp<MindComponent>(target, out var mind))
return 0f;

if (_mind.IsCharacterDeadIc(mind))
return 0f;
}

return 1f;
}
}
12 changes: 12 additions & 0 deletions Content.Server/EstacaoPirata/Roles/BloodFamilyRoleComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Content.Shared.Roles;

namespace Content.Server.EstacaoPirata.Roles;

/// <summary>
/// This is used for...
/// </summary>
[RegisterComponent]
public sealed partial class BloodFamilyRoleComponent : AntagonistRoleComponent
{

}
7 changes: 7 additions & 0 deletions Content.Server/GameTicking/Rules/TraitorRuleSystem.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Linq;
using Content.Server.Chat.Managers;
using Content.Server.EstacaoPirata.Roles;
using Content.Server.GameTicking.Rules.Components;
using Content.Server.Mind;
using Content.Server.NPC.Systems;
Expand Down Expand Up @@ -230,6 +231,12 @@ public bool MakeTraitor(ICommonSession traitor, bool giveUplink = true, bool giv
return false;
}

if (HasComp<BloodFamilyRoleComponent>(mindId))
{
Log.Error($"Player {traitor.Name} is already a blood family member.");
return false;
}

if (mind.OwnedEntity is not { } entity)
{
Log.Error("Mind picked for traitor did not have an attached entity.");
Expand Down
Loading
Loading