Ghost roles create new minds, better tracking of roles at round end screen (#5175)

* Ghost roles now get new Minds

* Some round start/end button stuff

* Mind tracking for better round end reports

* Make traitor kill objectives use mind CharacterName rather than actual occupied entity ("kill brain" prevention)

* Transition over to EntityUid for mind stuff because that's the only way to do it

* BrainSystem fix for PR rebase
This commit is contained in:
20kdc
2021-11-15 18:14:34 +00:00
committed by GitHub
parent c3a7548545
commit 4cce40bd9f
26 changed files with 229 additions and 68 deletions

View File

@@ -17,6 +17,14 @@ namespace Content.Server.GameTicking.Commands
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
var ticker = EntitySystem.Get<GameTicker>();
if (ticker.RunLevel != GameRunLevel.InRound)
{
shell.WriteLine("This can only be executed while the game is in a round - try restartroundnow");
return;
}
EntitySystem.Get<RoundEndSystem>().EndRound();
}
}

View File

@@ -37,7 +37,7 @@ namespace Content.Server.GameTicking
{
// Always make sure the client has player data. Mind gets assigned on spawn.
if (session.Data.ContentDataUncast == null)
session.Data.ContentDataUncast = new PlayerData(session.UserId);
session.Data.ContentDataUncast = new PlayerData(session.UserId, args.Session.Name);
// Make the player actually join the game.
// timer time must be > tick length

View File

@@ -2,6 +2,8 @@ using System;
using System.Collections.Generic;
using System.Linq;
using Content.Server.Players;
using Content.Server.Mind;
using Content.Server.Ghost;
using Content.Shared.CCVar;
using Content.Shared.Coordinates;
using Content.Shared.GameTicking;
@@ -210,29 +212,50 @@ namespace Content.Server.GameTicking
//Generate a list of basic player info to display in the end round summary.
var listOfPlayerInfo = new List<RoundEndMessageEvent.RoundEndPlayerInfo>();
foreach (var ply in _playerManager.GetAllPlayers().OrderBy(p => p.Name))
// Grab the great big book of all the Minds, we'll need them for this.
var allMinds = EntitySystem.Get<MindTrackerSystem>().AllMinds;
foreach (var mind in allMinds)
{
var mind = ply.ContentData()?.Mind;
if (mind != null)
{
_playersInLobby.TryGetValue(ply, out var status);
// Some basics assuming things fail
var userId = mind.OriginalOwnerUserId;
var playerOOCName = userId.ToString();
var connected = false;
var observer = mind.AllRoles.Any(role => role is ObserverRole);
// Continuing
if (_playerManager.TryGetSessionById(userId, out var ply))
{
connected = true;
}
PlayerData? contentPlayerData = null;
if (_playerManager.TryGetPlayerData(userId, out var playerData))
{
contentPlayerData = playerData.ContentData();
}
// Finish
var antag = mind.AllRoles.Any(role => role.Antagonist);
var playerEndRoundInfo = new RoundEndMessageEvent.RoundEndPlayerInfo()
{
PlayerOOCName = ply.Name,
PlayerICName = mind.CurrentEntity?.Name,
// Note that contentPlayerData?.Name sticks around after the player is disconnected.
// This is as opposed to ply?.Name which doesn't.
PlayerOOCName = contentPlayerData?.Name ?? "(IMPOSSIBLE: REGISTERED MIND WITH NO OWNER)",
// Character name takes precedence over current entity name
PlayerICName = mind.CharacterName ?? mind.CurrentEntity?.Name,
Role = antag
? mind.AllRoles.First(role => role.Antagonist).Name
: mind.AllRoles.FirstOrDefault()?.Name ?? Loc.GetString("game-ticker-unknown-role"),
Antag = antag,
Observer = status == LobbyPlayerStatus.Observer,
Observer = observer,
Connected = connected
};
listOfPlayerInfo.Add(playerEndRoundInfo);
}
}
// This ordering mechanism isn't great (no ordering of minds) but functions
var listOfPlayerInfoFinal = listOfPlayerInfo.OrderBy(pi => pi.PlayerOOCName).ToArray();
RaiseNetworkEvent(new RoundEndMessageEvent(gamemodeTitle, roundEndText, roundDuration, listOfPlayerInfo.Count, listOfPlayerInfo.ToArray()));
RaiseNetworkEvent(new RoundEndMessageEvent(gamemodeTitle, roundEndText, roundDuration, listOfPlayerInfoFinal.Length, listOfPlayerInfoFinal));
}
public void RestartRound()

View File

@@ -4,6 +4,7 @@ using System.Globalization;
using Content.Server.Access.Components;
using Content.Server.Access.Systems;
using Content.Server.CharacterAppearance.Components;
using Content.Server.Ghost;
using Content.Server.Ghost.Components;
using Content.Server.Hands.Components;
using Content.Server.Inventory.Components;
@@ -70,17 +71,18 @@ namespace Content.Server.GameTicking
DebugTools.AssertNotNull(data);
data!.WipeMind();
data.Mind = new Mind.Mind(player.UserId)
var newMind = new Mind.Mind(data.UserId)
{
CharacterName = character.Name
};
newMind.ChangeOwningPlayer(data.UserId);
// Pick best job best on prefs.
jobId ??= PickBestAvailableJob(character);
var jobPrototype = _prototypeManager.Index<JobPrototype>(jobId);
var job = new Job(data.Mind, jobPrototype);
data.Mind.AddRole(job);
var job = new Job(newMind, jobPrototype);
newMind.AddRole(job);
if (lateJoin)
{
@@ -92,7 +94,7 @@ namespace Content.Server.GameTicking
}
var mob = SpawnPlayerMob(job, character, lateJoin);
data.Mind.TransferTo(mob);
newMind.TransferTo(mob.Uid);
if (player.UserId == new Guid("{e887eb93-f503-4b65-95b6-2f282c014192}"))
{
@@ -150,13 +152,15 @@ namespace Content.Server.GameTicking
DebugTools.AssertNotNull(data);
data!.WipeMind();
data.Mind = new Mind.Mind(player.UserId);
var newMind = new Mind.Mind(data.UserId);
newMind.ChangeOwningPlayer(data.UserId);
newMind.AddRole(new ObserverRole(newMind));
var mob = SpawnObserverMob();
mob.Name = name;
var ghost = mob.GetComponent<GhostComponent>();
EntitySystem.Get<SharedGhostSystem>().SetCanReturnToBody(ghost, false);
data.Mind.TransferTo(mob);
newMind.TransferTo(mob.Uid);
_playersInLobby[player] = LobbyPlayerStatus.Observer;
RaiseNetworkEvent(GetStatusSingle(player, LobbyPlayerStatus.Observer));

View File

@@ -94,7 +94,7 @@ namespace Content.Server.GameTicking.Presets
if (canReturn)
mind.Visit(ghost);
else
mind.TransferTo(ghost);
mind.TransferTo(ghost.Uid);
return true;
}