Skip to content

Commit

Permalink
Mail table rework (#1477)
Browse files Browse the repository at this point in the history
* Mail table, system for smoke prank

* Format mail messages

* DelayedItemSystem cleanup, more mail table entries

* More mail table entries

* Remove hoverbike from mail pool

* Add large mail.

FIXME: mail_large.rsi has no copyright info

* Default mail isLarge to false, comment cleanup

* More mail types

* Add optional large mail flag to admin mailto cmd

* mail_large copyright

* admin cmd fix, new mail types, const cleanup

* Mail: new components, weighting, a few new items

* Fix merge conflict, add placeholder pipebomb mail

* Format mail text, separate sword mail from knives

* Mail: fix exp. welder ID, split up Dan's cigs

* Fourth muffin, decrease captain's sabre chance

* yaml fixes

* Add ShowJobIcons component to mail hud

* Reorganize mail items, add build-a-buddy mail

* Build-a-Buddy fixes, slime & vulp versions, text

* Reptillian->Reptilian

* More signatures, label necrosol bottle, bigger emp

* lowercase i

* extra premium cigars, premium liquors

* Cleanup

* Fixups And Edits

* Remove kendo hakama, jabroni comment, fix cigars

* Platinum cigars, fix sprites

* fix premium absinthe ID

* Remove cyberpen, add BibleUserImplanter, ATV mail

Also adjusts weights for TacticalMaid (missing a zero), Restraints (cut
in half)

* kendo mail order, more mail comments

* Remove Nyano mail lists & parcels, move into _NF/

* True to true, cigars aren't fragile

---------

Co-authored-by: Dvir <[email protected]>
Co-authored-by: Whatstone <[email protected]>
  • Loading branch information
3 people authored Jun 14, 2024
1 parent 44474b7 commit ed91b98
Show file tree
Hide file tree
Showing 47 changed files with 3,647 additions and 1,426 deletions.
38 changes: 21 additions & 17 deletions Content.Server/Nyanotrasen/Mail/Components/MailComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,20 @@ namespace Content.Server.Mail.Components
[RegisterComponent]
public sealed partial class MailComponent : SharedMailComponent
{
[ViewVariables(VVAccess.ReadWrite)]
[DataField("recipient")]
[DataField, ViewVariables(VVAccess.ReadWrite)]
public string Recipient = "None";

[ViewVariables(VVAccess.ReadWrite)]
[DataField("recipientJob")]
[DataField, ViewVariables(VVAccess.ReadWrite)]
public string RecipientJob = "None";

[ViewVariables(VVAccess.ReadWrite)]
[DataField("recipientStation")]
[DataField, ViewVariables(VVAccess.ReadWrite)]
public string RecipientStation = "None";

// Why do we not use LockComponent?
// Because this can't be locked again,
// and we have special conditions for unlocking,
// and we don't want to add a verb.
[ViewVariables(VVAccess.ReadWrite)]
[DataField("isLocked")]
[DataField, ViewVariables(VVAccess.ReadWrite)]
public bool IsLocked = true;

/// <summary>
Expand All @@ -36,7 +32,7 @@ public sealed partial class MailComponent : SharedMailComponent
/// This is useful for broken fragile packages and packages that were
/// not delivered in time.
/// </remarks>
[DataField("isProfitable")]
[DataField]
public bool IsProfitable = true;

/// <summary>
Expand All @@ -46,7 +42,7 @@ public sealed partial class MailComponent : SharedMailComponent
/// This can be set to true in the YAML files for a mail delivery to
/// always be Fragile, despite its contents.
/// </remarks>
[DataField("isFragile")]
[DataField]
public bool IsFragile = false;

/// <summary>
Expand All @@ -62,43 +58,51 @@ public sealed partial class MailComponent : SharedMailComponent
/// This can be set to true in the YAML files for a mail delivery to
/// always be Priority.
/// </remarks>
[DataField("isPriority")]
[DataField]
public bool IsPriority = false;

// Frontier: large mail
/// <summary>
/// Whether this parcel is large.
/// </summary>
[DataField]
public bool IsLarge = false;
// End Frontier: large mail

/// <summary>
/// What will be packaged when the mail is spawned.
/// </summary>
[DataField("contents")]
[DataField]
public List<EntitySpawnEntry> Contents = new();

/// <summary>
/// The amount that cargo will be awarded for delivering this mail.
/// </summary>
[DataField("bounty")]
[DataField]
public int Bounty = 7500; // Frontier 750<7500

/// <summary>
/// Penalty if the mail is destroyed.
/// </summary>
[DataField("penalty")]
[DataField]
public int Penalty = -250;

/// <summary>
/// The sound that's played when the mail's lock is broken.
/// </summary>
[DataField("penaltySound")]
[DataField]
public SoundSpecifier PenaltySound = new SoundPathSpecifier("/Audio/Machines/Nuke/angry_beep.ogg");

/// <summary>
/// The sound that's played when the mail's opened.
/// </summary>
[DataField("openSound")]
[DataField]
public SoundSpecifier OpenSound = new SoundPathSpecifier("/Audio/Effects/packetrip.ogg");

/// <summary>
/// The sound that's played when the mail's lock has been emagged.
/// </summary>
[DataField("emagSound")]
[DataField]
public SoundSpecifier EmagSound = new SoundCollectionSpecifier("sparks");

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public sealed partial class MailTeleporterComponent : Component
/// teleporter can deliver.
/// </summary>
[DataField("mailPool")]
public string MailPool = "RandomMailDeliveryPool";
public string MailPool = "RandomNFMailDeliveryPool"; // Frontier: use our own mail pool (TODO: migrate to frontier.yml instance?)

/// <summary>
/// How many mail candidates do we need per actual delivery sent when
Expand Down Expand Up @@ -104,5 +104,19 @@ public sealed partial class MailTeleporterComponent : Component
/// </summary>
[DataField("priorityMalus")]
public int PriorityMalus = -250;

// Frontier: Large mail
/// <summary>
/// What's the bonus for delivering a large package intact?
/// </summary>
[DataField("largeBonus")]
public int LargeBonus = 5000;

/// <summary>
/// What's the malus for failing to deliver a large package?
/// </summary>
[DataField("largeMalus")]
public int LargeMalus = -250;
// End Frontier: Large mail
}
}
20 changes: 16 additions & 4 deletions Content.Server/Nyanotrasen/Mail/MailCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public sealed class MailToCommand : IConsoleCommand
[Dependency] private readonly IEntitySystemManager _entitySystemManager = default!;

private readonly string _blankMailPrototype = "MailAdminFun";
private readonly string _blankLargeMailPrototype = "MailLargeAdminFun"; // Frontier: large mail
private readonly string _container = "storagebase";
private readonly string _mailContainer = "contents";

Expand Down Expand Up @@ -56,6 +57,16 @@ public async void Execute(IConsoleShell shell, string argStr, string[] args)
return;
}

// Frontier: Large Mail
bool isLarge = false;
if (args.Length > 4 && !Boolean.TryParse(args[4], out isLarge))
{
shell.WriteError(Loc.GetString("shell-invalid-bool"));
return;
}
var mailPrototype = isLarge ? _blankLargeMailPrototype : _blankMailPrototype;
// End Frontier


var _mailSystem = _entitySystemManager.GetEntitySystem<MailSystem>();
var _containerSystem = _entitySystemManager.GetEntitySystem<SharedContainerSystem>();
Expand All @@ -66,9 +77,9 @@ public async void Execute(IConsoleShell shell, string argStr, string[] args)
return;
}

if (!_prototypeManager.HasIndex<EntityPrototype>(_blankMailPrototype))
if (!_prototypeManager.HasIndex<EntityPrototype>(mailPrototype)) // Frontier: _blankMailPrototype<mailPrototype
{
shell.WriteLine(Loc.GetString("command-mailto-no-blankmail", ("blankMail", _blankMailPrototype)));
shell.WriteLine(Loc.GetString("command-mailto-no-blankmail", ("blankMail", mailPrototype))); // Frontier: _blankMailPrototype<mailPrototype
return;
}

Expand All @@ -90,12 +101,12 @@ public async void Execute(IConsoleShell shell, string argStr, string[] args)
return;
}

var mailUid = _entityManager.SpawnEntity(_blankMailPrototype, _entityManager.GetComponent<TransformComponent>(containerUid).Coordinates);
var mailUid = _entityManager.SpawnEntity(mailPrototype, _entityManager.GetComponent<TransformComponent>(containerUid).Coordinates); // Frontier: _blankMailPrototype<mailPrototype
var mailContents = _containerSystem.EnsureContainer<Container>(mailUid, _mailContainer);

if (!_entityManager.TryGetComponent(mailUid, out MailComponent? mailComponent))
{
shell.WriteLine(Loc.GetString("command-mailto-bogus-mail", ("blankMail", _blankMailPrototype), ("requiredMailComponent", nameof(MailComponent))));
shell.WriteLine(Loc.GetString("command-mailto-bogus-mail", ("blankMail", mailPrototype), ("requiredMailComponent", nameof(MailComponent)))); // Frontier: _blankMailPrototype<mailPrototype
return;
}

Expand All @@ -104,6 +115,7 @@ public async void Execute(IConsoleShell shell, string argStr, string[] args)

mailComponent.IsFragile = isFragile;
mailComponent.IsPriority = isPriority;
mailComponent.IsLarge = isLarge;

_mailSystem.SetupMail(mailUid, teleporterComponent, recipient.Value);

Expand Down
16 changes: 13 additions & 3 deletions Content.Server/Nyanotrasen/Mail/MailSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -245,13 +245,14 @@ private void OnAfterInteractUsing(EntityUid uid, MailComponent component, AfterI

private void OnExamined(EntityUid uid, MailComponent component, ExaminedEvent args)
{
MailEntityStrings mailEntityStrings = component.IsLarge ? MailConstants.MailLarge : MailConstants.Mail; //Frontier: mail types stored per type (large mail)
if (!args.IsInDetailsRange)
{
args.PushMarkup(Loc.GetString("mail-desc-far"));
args.PushMarkup(Loc.GetString(mailEntityStrings.DescFar)); // Frontier: mail constants struct
return;
}

args.PushMarkup(Loc.GetString("mail-desc-close", ("name", component.Recipient), ("job", component.RecipientJob), ("station", component.RecipientStation)));
args.PushMarkup(Loc.GetString(mailEntityStrings.DescClose, ("name", component.Recipient), ("job", component.RecipientJob), ("station", component.RecipientStation))); // Frontier: mail constants struct

if (component.IsFragile)
args.PushMarkup(Loc.GetString("mail-desc-fragile"));
Expand Down Expand Up @@ -469,6 +470,15 @@ public void SetupMail(EntityUid uid, MailTeleporterComponent component, MailReci
mailComp.Recipient = recipient.Name;
mailComp.RecipientStation = recipient.Ship; // Frontier

// Frontier: Large mail bonus
MailEntityStrings mailEntityStrings = mailComp.IsLarge ? MailConstants.MailLarge : MailConstants.Mail;
if (mailComp.IsLarge)
{
mailComp.Bounty += component.LargeBonus;
mailComp.Penalty += component.LargeMalus;
}
// End Frontier

if (mailComp.IsFragile)
{
mailComp.Bounty += component.FragileBonus;
Expand All @@ -491,7 +501,7 @@ public void SetupMail(EntityUid uid, MailTeleporterComponent component, MailReci

_appearanceSystem.SetData(uid, MailVisuals.JobIcon, recipient.JobIcon);

_metaDataSystem.SetEntityName(uid, Loc.GetString("mail-item-name-addressed",
_metaDataSystem.SetEntityName(uid, Loc.GetString(mailEntityStrings.NameAddressed, // Frontier: move constant to MailEntityString
("recipient", recipient.Name)));

var accessReader = EnsureComp<AccessReaderComponent>(uid);
Expand Down
16 changes: 16 additions & 0 deletions Content.Server/_NF/Mail/DelayedItemComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace Content.Server.Mail
{
/// <summary>
/// A placeholder for another entity, spawned when dropped or placed in someone's hands.
/// Useful for storing instant effect entities, e.g. smoke, in the mail.
/// </summary>
[RegisterComponent]
public sealed partial class DelayedItemComponent : Component
{
/// <summary>
/// The entity to replace this when opened or dropped.
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public string Item = "None";
}
}
56 changes: 56 additions & 0 deletions Content.Server/_NF/Mail/DelayedItemSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using Content.Shared.Damage;
using Content.Shared.Hands;
using Robust.Shared.Containers;

namespace Content.Server.Mail
{
/// <summary>
/// A placeholder for another entity, spawned when taken out of a container, with the placeholder deleted shortly after.
/// Useful for storing instant effect entities, e.g. smoke, in the mail.
/// </summary>
public sealed class DelayedItemSystem : EntitySystem
{
public override void Initialize()
{
base.Initialize();

SubscribeLocalEvent<DelayedItemComponent, DropAttemptEvent>(OnDropAttempt);
SubscribeLocalEvent<DelayedItemComponent, GotEquippedHandEvent>(OnHandEquipped);
SubscribeLocalEvent<DelayedItemComponent, DamageChangedEvent>(OnDamageChanged);
SubscribeLocalEvent<DelayedItemComponent, EntGotRemovedFromContainerMessage>(OnRemovedFromContainer);
}

/// <summary>
/// EntGotRemovedFromContainerMessage handler - spawn the intended entity after removed from a container.
/// </summary>
private void OnRemovedFromContainer(EntityUid uid, DelayedItemComponent component, ContainerModifiedMessage args)
{
Spawn(component.Item, Transform(uid).Coordinates);
}

/// <summary>
/// GotEquippedHandEvent handler - destroy the placeholder.
/// </summary>
private void OnHandEquipped(EntityUid uid, DelayedItemComponent component, EquippedHandEvent args)
{
EntityManager.DeleteEntity(uid);
}

/// <summary>
/// OnDropAttempt handler - destroy the placeholder.
/// </summary>
private void OnDropAttempt(EntityUid uid, DelayedItemComponent component, DropAttemptEvent args)
{
EntityManager.DeleteEntity(uid);
}

/// <summary>
/// OnDamageChanged handler - item has taken damage (e.g. inside the envelope), spawn the intended entity outside of any container and delete the placeholder.
/// </summary>
private void OnDamageChanged(EntityUid uid, DelayedItemComponent component, DamageChangedEvent args)
{
Spawn(component.Item, Transform(uid).Coordinates);
EntityManager.DeleteEntity(uid);
}
}
}
38 changes: 38 additions & 0 deletions Content.Server/_NF/Mail/MailConstants.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
namespace Content.Server.Mail
{
/// <summary>
/// A set of localized strings related to mail entities
/// </summary>
public struct MailEntityStrings
{
public string NameAddressed;
public string DescClose;
public string DescFar;
}

/// <summary>
/// Constants related to mail.
/// </summary>
public sealed class MailConstants : EntitySystem
{
/// <summary>
/// Locale strings related to small parcels.
/// <summary>
public static readonly MailEntityStrings Mail = new()
{
NameAddressed = "mail-item-name-addressed",
DescClose = "mail-desc-close",
DescFar = "mail-desc-far"
};

/// <summary>
/// Locale strings related to large packages.
/// <summary>
public static readonly MailEntityStrings MailLarge = new()
{
NameAddressed = "mail-large-item-name-addressed",
DescClose = "mail-large-desc-close",
DescFar = "mail-large-desc-far"
};
}
}
4 changes: 4 additions & 0 deletions Resources/Locale/en-US/_NF/mail/mail.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
mail-large-item-name-unaddressed = package
mail-large-item-name-addressed = package ({$recipient})
mail-large-desc-far = A large package.
mail-large-desc-close = A large package addressed to {CAPITALIZE($name)}, {$job}. Last known location: {$station}.
8 changes: 7 additions & 1 deletion Resources/Locale/en-US/nyanotrasen/mail.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ mail-item-name-unaddressed = mail
mail-item-name-addressed = mail ({$recipient})
command-mailto-description = Queue a parcel to be delivered to an entity. Example usage: `mailto 1234 5678 false false`. The target container's contents will be transferred to an actual mail parcel.
command-mailto-help = Usage: {$command} <recipient entityUid> <container entityUid> [is-fragile: true or false] [is-priority: true or false]
# Frontier: add is-large description
command-mailto-help = Usage: {$command} <recipient entityUid> <container entityUid> [is-fragile: true or false] [is-priority: true or false] [is-large: true or false, optional]
command-mailto-no-mailreceiver = Target recipient entity does not have a {$requiredComponent}.
command-mailto-no-blankmail = The {$blankMail} prototype doesn't exist. Something is very wrong. Contact a programmer.
command-mailto-bogus-mail = {$blankMail} did not have {$requiredMailComponent}. Something is very wrong. Contact a programmer.
Expand All @@ -29,3 +30,8 @@ command-mailto-success = Success! Mail parcel has been queued for next teleport
command-mailnow = Force all mail teleporters to deliver another round of mail as soon as possible. This will not bypass the undelivered mail limit.
command-mailnow-help = Usage: {$command}
command-mailnow-success = Success! All mail teleporters will be delivering another round of mail soon.
# Frontier: mailtestbulk
command-mailtestbulk = Sends one of each type of parcel to a given mail teleporter. Implicitly calls mailnow.
command-mailtestbulk-help = Usage: {$command} <teleporter_id>
command-mailtestbulk-success = Success! All mail teleporters will be delivering another round of mail soon.
Loading

0 comments on commit ed91b98

Please sign in to comment.