Librarian gameplay (DND, but in SS14) (#17041)

* D&D character sheets

* Tabletop improvements

* Grass battlemap

* You can now put shit inside of the board

* change variable name

* make the grass tabletop better, again

* update the damn thing AGAIN

* update the shit AGAIN

* You can now take stuff out of tabletops

* Make it use parenting to avoid zany bugs

* MORE battlemaps! Battlemaps for everyone!

* You can now dump out pieces + cleanup

* All (most) non-game pieces should fall to the ground

* make the verb a bit more responsive

* Librarian content officially done

* fix tests i think

* i forgot the sheet

* Smidgen of refactoring

* You can no longer put high risk items inside of boards

* no boardgame defusal

* minor refactoring

* hoplogrma

* doc

* fix rt
This commit is contained in:
eclips_e
2023-07-17 17:03:18 +08:00
committed by GitHub
parent 73c7ed67fa
commit 01a0e2002a
44 changed files with 720 additions and 83 deletions

View File

@@ -1,4 +1,5 @@
using System.Numerics;
using Vector2 = System.Numerics.Vector2;
namespace Content.Server.Tabletop.Components
{
@@ -8,18 +9,33 @@ namespace Content.Server.Tabletop.Components
[RegisterComponent, Access(typeof(TabletopSystem))]
public sealed class TabletopGameComponent : Component
{
/// <summary>
/// The localized name of the board. Shown in the UI.
/// </summary>
[DataField("boardName")]
public string BoardName { get; } = "tabletop-default-board-name";
/// <summary>
/// The type of method used to set up a tabletop.
/// </summary>
[DataField("setup", required: true)]
public TabletopSetup Setup { get; } = new TabletopChessSetup();
/// <summary>
/// The size of the viewport being opened. Must match the board dimensions otherwise you'll get the space parallax (unless that's what you want).
/// </summary>
[DataField("size")]
public Vector2i Size { get; } = (300, 300);
/// <summary>
/// The zoom of the viewport camera.
/// </summary>
[DataField("cameraZoom")]
public Vector2 CameraZoom { get; } = Vector2.One;
/// <summary>
/// The specific session of this tabletop.
/// </summary>
[ViewVariables]
public TabletopSession? Session { get; set; } = null;
}

View File

@@ -5,8 +5,6 @@ namespace Content.Server.Tabletop
[UsedImplicitly]
public sealed class TabletopBackgammonSetup : TabletopSetup
{
[DataField("boardPrototype")]
public string BackgammonBoardPrototype { get; } = "BackgammonBoardTabletop";
[DataField("whitePiecePrototype")]
public string WhitePiecePrototype { get; } = "WhiteTabletopPiece";
@@ -15,7 +13,7 @@ namespace Content.Server.Tabletop
public string BlackPiecePrototype { get; } = "BlackTabletopPiece";
public override void SetupTabletop(TabletopSession session, IEntityManager entityManager)
{
var board = entityManager.SpawnEntity(BackgammonBoardPrototype, session.Position);
var board = entityManager.SpawnEntity(BoardPrototype, session.Position);
const float borderLengthX = 7.35f; //BORDER
const float borderLengthY = 5.60f; //BORDER

View File

@@ -8,14 +8,12 @@ namespace Content.Server.Tabletop
[UsedImplicitly]
public sealed class TabletopCheckerSetup : TabletopSetup
{
[DataField("boardPrototype", customTypeSerializer:typeof(PrototypeIdSerializer<EntityPrototype>))]
public string CheckerBoardPrototype { get; } = "CheckerBoardTabletop";
// TODO: Un-hardcode the rest of entity prototype IDs, probably.
public override void SetupTabletop(TabletopSession session, IEntityManager entityManager)
{
var checkerboard = entityManager.SpawnEntity(CheckerBoardPrototype, session.Position.Offset(-1, 0));
var checkerboard = entityManager.SpawnEntity(BoardPrototype, session.Position.Offset(-1, 0));
session.Entities.Add(checkerboard);

View File

@@ -8,14 +8,12 @@ namespace Content.Server.Tabletop
[UsedImplicitly]
public sealed class TabletopChessSetup : TabletopSetup
{
[DataField("boardPrototype", customTypeSerializer:typeof(PrototypeIdSerializer<EntityPrototype>))]
public string ChessBoardPrototype { get; } = "ChessBoardTabletop";
// TODO: Un-hardcode the rest of entity prototype IDs, probably.
public override void SetupTabletop(TabletopSession session, IEntityManager entityManager)
{
var chessboard = entityManager.SpawnEntity(ChessBoardPrototype, session.Position.Offset(-1, 0));
var chessboard = entityManager.SpawnEntity(BoardPrototype, session.Position.Offset(-1, 0));
session.Entities.Add(chessboard);

View File

@@ -0,0 +1,14 @@
using JetBrains.Annotations;
namespace Content.Server.Tabletop
{
[UsedImplicitly]
public sealed class TabletopEmptySetup : TabletopSetup
{
public override void SetupTabletop(TabletopSession session, IEntityManager entityManager)
{
var board = entityManager.SpawnEntity(BoardPrototype, session.Position.Offset(0, 0));
session.Entities.Add(board);
}
}
}

View File

@@ -0,0 +1,10 @@
namespace Content.Server.Tabletop;
/// <summary>
/// This is used for tracking pieces that are simply "holograms" shown on the tabletop
/// </summary>
[RegisterComponent]
public sealed class TabletopHologramComponent : Component
{
}

View File

@@ -7,8 +7,6 @@ namespace Content.Server.Tabletop
[UsedImplicitly]
public sealed class TabletopParchisSetup : TabletopSetup
{
[DataField("boardPrototype", customTypeSerializer:typeof(PrototypeIdSerializer<EntityPrototype>))]
public string ParchisBoardPrototype { get; } = "ParchisBoardTabletop";
[DataField("redPiecePrototype", customTypeSerializer:typeof(PrototypeIdSerializer<EntityPrototype>))]
public string RedPiecePrototype { get; } = "RedTabletopPiece";
@@ -24,7 +22,7 @@ namespace Content.Server.Tabletop
public override void SetupTabletop(TabletopSession session, IEntityManager entityManager)
{
var board = entityManager.SpawnEntity(ParchisBoardPrototype, session.Position);
var board = entityManager.SpawnEntity(BoardPrototype, session.Position);
const float x1 = 6.25f;
const float x2 = 4.25f;

View File

@@ -1,3 +1,6 @@
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
namespace Content.Server.Tabletop
{
[ImplicitDataDefinitionForInheritors]
@@ -10,5 +13,8 @@ namespace Content.Server.Tabletop
/// <param name="session">Tabletop session to set up. You'll want to grab the tabletop center position here for spawning entities.</param>
/// <param name="entityManager">Dependency that can be used for spawning entities.</param>
public abstract void SetupTabletop(TabletopSession session, IEntityManager entityManager);
[DataField("boardPrototype", customTypeSerializer:typeof(PrototypeIdSerializer<EntityPrototype>))]
public string BoardPrototype = default!;
}
}

View File

@@ -1,6 +1,11 @@
using Content.Server.Popups;
using Content.Server.Tabletop.Components;
using Content.Shared.Examine;
using Content.Shared.Hands.Components;
using Content.Shared.Interaction;
using Content.Shared.Item;
using Content.Shared.Tabletop;
using Content.Shared.Tabletop.Components;
using Content.Shared.Tabletop.Events;
using Content.Shared.Verbs;
using JetBrains.Annotations;
@@ -16,7 +21,9 @@ namespace Content.Server.Tabletop
public sealed partial class TabletopSystem : SharedTabletopSystem
{
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly ViewSubscriberSystem _viewSubscriberSystem = default!;
[Dependency] private readonly PopupSystem _popupSystem = default!;
public override void Initialize()
{
@@ -27,10 +34,73 @@ namespace Content.Server.Tabletop
SubscribeLocalEvent<TabletopGamerComponent, PlayerDetachedEvent>(OnPlayerDetached);
SubscribeLocalEvent<TabletopGamerComponent, ComponentShutdown>(OnGamerShutdown);
SubscribeLocalEvent<TabletopGameComponent, GetVerbsEvent<ActivationVerb>>(AddPlayGameVerb);
SubscribeLocalEvent<TabletopGameComponent, InteractUsingEvent>(OnInteractUsing);
SubscribeNetworkEvent<TabletopRequestTakeOut>(OnTabletopRequestTakeOut);
InitializeMap();
}
private void OnTabletopRequestTakeOut(TabletopRequestTakeOut msg, EntitySessionEventArgs args)
{
if (args.SenderSession is not IPlayerSession playerSession)
return;
if (!TryComp(msg.TableUid, out TabletopGameComponent? tabletop) || tabletop.Session is not { } session)
return;
if (!msg.Entity.IsValid())
return;
if (!TryComp(msg.Entity, out TabletopHologramComponent? hologram))
{
_popupSystem.PopupEntity(Loc.GetString("tabletop-error-remove-non-hologram"), msg.TableUid, args.SenderSession);
return;
}
// Check if player is actually playing at this table
if (!session.Players.ContainsKey(playerSession))
return;
// Find the entity, remove it from the session and set it's position to the tabletop
session.Entities.TryGetValue(msg.Entity, out var result);
session.Entities.Remove(result);
_entityManager.QueueDeleteEntity(result);
}
private void OnInteractUsing(EntityUid uid, TabletopGameComponent component, InteractUsingEvent args)
{
if (!EntityManager.TryGetComponent(args.User, out HandsComponent? hands))
return;
if (component.Session is not { } session)
return;
if (hands.ActiveHand == null)
return;
if (hands.ActiveHand.HeldEntity == null)
return;
var handEnt = hands.ActiveHand.HeldEntity.Value;
if (!TryComp<ItemComponent>(handEnt, out var item))
return;
var meta = MetaData(handEnt);
var protoId = meta.EntityPrototype?.ID;
var hologram = _entityManager.SpawnEntity(protoId, session.Position.Offset(-1, 0));
// Make sure the entity can be dragged and can be removed, move it into the board game world and add it to the Entities hashmap
EnsureComp<TabletopDraggableComponent>(hologram);
EnsureComp<TabletopHologramComponent>(hologram);
session.Entities.Add(hologram);
_popupSystem.PopupEntity(Loc.GetString("tabletop-added-piece"), uid, args.User);
}
protected override void OnTabletopMove(TabletopMoveEvent msg, EntitySessionEventArgs args)
{
if (args.SenderSession is not IPlayerSession playerSession)
@@ -57,11 +127,14 @@ namespace Content.Server.Tabletop
if (!EntityManager.TryGetComponent<ActorComponent?>(args.User, out var actor))
return;
ActivationVerb verb = new();
verb.Text = Loc.GetString("tabletop-verb-play-game");
verb.Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/die.svg.192dpi.png"));
verb.Act = () => OpenSessionFor(actor.PlayerSession, uid);
args.Verbs.Add(verb);
var playVerb = new ActivationVerb()
{
Text = Loc.GetString("tabletop-verb-play-game"),
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/die.svg.192dpi.png")),
Act = () => OpenSessionFor(actor.PlayerSession, uid)
};
args.Verbs.Add(playVerb);
}
private void OnTabletopActivate(EntityUid uid, TabletopGameComponent component, ActivateInWorldEvent args)