* sync * sync * no more squiggles.. * last build error * updated maps for testing * some issue with receiving arrivals setup * networkpayload refactor. TODO: accurate timings * timings accurate. TODO: backport old bugfix * all set? * cleaned up source. TODO: diff arrivals methods * cleaned component. TODO: escape polish, docs * first documentation pass * escape timers work * no more magic numbers * removed dead code leads * sync sync * Automatic changelog update * shuttle timer groundwork no more squiggles.. last build error updated maps for testing some issue with receiving arrivals setup networkpayload refactor. TODO: accurate timings timings accurate. TODO: backport old bugfix all set? cleaned up source. TODO: diff arrivals methods cleaned component. TODO: escape polish, docs first documentation pass escape timers work no more magic numbers * BBQ rib sandwich (#21180) * Fix missing toggle fullscreen loc string (#21264) * Cave Decoration pack (#21265) * add chromite chasm * add desert chasm * snow chasm * finish * fixes and tweaks (#21172) * Automatic changelog update * Fix ItemPlacer (#21160) This is going to lead to many entities being ticked unnecessarily and performance problems. * headrev spawn music (#21119) * headrev spawn music * :trollface: * skill issue * double skill issue * :trollface: * :trollface: * :trollface: * Automatic changelog update * Techfab resprite + department fab sprites (#21136) * Fix popup messages appearing when someone tries to open a door without a tool. (#21099) * The fixTM * typo fix * addressing review * Show "departed and moved on" for when a ghost role is taken (#21092) * fix ghost role not counting for "departed and moved on" * I don't think that bit was needed so away it goes * hopefully finish the upsream merge * Automatic changelog update * Implant whitelist/blacklisting (#20678) * add whitelist and blacklist to implant and implanter components * handle whitelist and blacklist in systems * move hardcoded whitelist/blacklist to base implanter + add admeme implanter * give implants sensible whitelists * cleaner CheckTarget and fix * remove unused imports * network lists --------- Co-authored-by: deltanedas <@deltanedas:kde.org> * Automatic changelog update * Ion storm event (#20277) * ion storm event prototype + locale * add lawsets * use lawsets, make borgs ion storm targets * ion storm rule and ion storm target * lawset prototype * use lawsets * update silicon law system to use lawsets and support ion storm event * new toys * fix * more fix * fixy * ion storm admin logging * assigning laws makes borg provide its own laws, other stuff * 1h reoccurence * 50% chance * better call saul * emagLaws is required * add announcment audio * fixy * family friendly gaming * fixy * address reviews * fixy * more fixy and no erp * pro --------- Co-authored-by: deltanedas <@deltanedas:kde.org> * Automatic changelog update * A return to foam (foam rework) (#20831) * Automatic changelog update * ERT Loadout overhaul + Real deathsquad mobs + ERT fixes (#21230) * "assist with medical efforts" * CentComm official description change * give cburn ert mask * Ert medic hardsuit uses blood-red medic values * description changes, they all used to use the blood-red description * ert engineer hardsuit uses cburn values, good for handling all possible engineering problems. * janitor hardsuit uses cburn values for extreme messes, otherwise we'd send the non eva variant. * spawn suffix changes * shorten suffix * drop armor from ert jumpsuits * drop armor from DS jumpsuit * add more armor to death squad to make up for removed armor in the uniform. * give sec gas masks armor, give syndicate gas masks armor. ERT gas mask uses syndicate mask values * add nanotrasen * removed duplicate * give centcom IDs their hud icon * replace all ert bulletproof armor with basic universal armor * replace all oxygen tanks with air tanks; species is random. * remove gun and meds from ert engineer kit * give ert engineer materials * remove weapons and meds from janitor ert * give ert janitor light replacer * remove ert sec pulse weapons, admins will assign loadout. Either the lecter or enforcer, probably. * Give ert sec the security pistol kit * typo * give eva ert sec pistol * give eva janitor ert gas mask * give jani purple gloves * medical gloves for medical ert * replicate security loadout to leader * quick ert lecter spawns for lazy admins * better suffixes to find them easier * add cburn to ertspawn * Replace "Spawn" with "role" * Add death squad. Give ert engineer gas analyzer. * death squad using wrong equipment * typo * missing ghost roles on lecter loadouts * add freedom implanter to deathsquad * deathsquad ghost role text * Operative sounds better * give Ds flashbang box (why isn't it entirely filled?) * fix typo. add energy shield to DS * fix typos * all centcomm roles are now mindshielded. These cannot be removed. * Rider didnt include some of the changes ? * give zipties instead of cuffs for mass arrests! * upgrade ERT survival boxes to extended capacity * give cburn extended oxygen too * Automatic changelog update * Restore Leviathan's 80 pop cap (#21281) * Un-revert IPlayerManager refactor (#21244) * Update engine to v172.0.0 (#21288) * Bandaid tests (#21292) * rename the rocks (#21275) * Make crystals noRot (#21279) IDK might be better. Ideally the anchoring would be offset 0-0 but this is the world we live in atm. * Fix nukies sound not played (#21268) * Play sound and sending greeting message works for nukies now!!!!! * oops * silly change * Automatic changelog update * Fix hijack objective (#21241) * Fix hijack * Max difficulty * Remove GridModifiedEvent (#21291) * Update submodule to 173.0.0 (#21296) * Fix namespace error (#21298) * Update yaml sequence option in editorconfig (#21297) * Fix namespace (#21299) * fix cburn bag issue, make new bag entity for them and filled bag entity (#21295) * Health analyzer UI improve (#17280) * Automatic changelog update * User accessible playtime (#21242) Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com> * Automatic changelog update * Moves cloning comp & cloning event to shared (#21253) * Generalizes solution overflow & slightly increases space lube yield (#21094) * generalize SolutionSpikeOverflowEvent * let reactions overflow * spacelube: 3 -> 5 * restore TryMixAndOverflow threshold cap * Automatic changelog update * Move ActorComponent to shared (#21293) * Update engine to v174.0.0 (#21311) * Fix planet command help message (#21312) * Wearable bee plush (#20623) * add * fix * temporary change, needs fixing * mayb fix * actually fix FR * yes * Automatic changelog update * remove pulse rifle from ert medic (#21310) * Content audio (#20862) * Automatic changelog update * Update submodule to 175.0.0 (#21318) * Revert "Update submodule to 175.0.0 (#21318)" (#21319) * Atomic bomb add uranium (#21143) * fix: Incendiary bullets no longer deal cold, acid, or shock damage that ignores all armor. * Atomic bomb * Action bugfixes (#21321) * Disable OOC during round (#21323) * Fix PDA notifications when creating a news entry using the Mass-Media console. (#21320) * Automatic changelog update * Update belt.yml (#21317) changes the chief engineer's belt to remove the lv wires (they take up a lot of space and are easy to get anyways) in exchange for a holofan, a t-ray, and a gas analyzer (first time coding ever this might have to be edited) * New foam sprites (edge sprites) (#21308) * New foam sprites (icon smoothing) * changed to edge sprites for foam * fix * edges for metal foams * fix * Fix bola stam damage, bring back old construction requirements (#21340) * Automatic changelog update * Added thermal insulation to flannel jackets (#21273) * Automatic changelog update * Space Asshole Gear (#21243) * Add Space Asshole Coat * Add sledgehammer * Adjust sledgehammer damage values * Add copyright string to sledgehammer * Fix broken slot highlight in midnight theme. (#21331) * removed dead code leads removed redundant ensurecomps * textscreen documentation * remove redundant ensurecomps * Add hint for the examine trigger effect (#21166) * examine locale * examine trigger desc Automatic changelog update cornmeal is actually obtainable now (#21162) * do the thing * lets find out * Update Resources/Prototypes/Entities/Objects/Consumable/Food/produce.yml Co-authored-by: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com> --------- Co-authored-by: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com> Automatic changelog update Healing skeletons by pouring milk over them (and clean pie remains off their skulls) (#21231) * mvp done - skellies can heal by spillink regular milk on themselves and clean themselves off creaming with water * added other types of healing milk, also made a separate reaction to oat milk - it has almost no calcium in it * fixed indent error, made a dumb mistake Automatic changelog update Fix anomaly locators frantically beeping when entering detection range. (#21178) * reset beep timer when out of range * prevent deficit from impacting beep timing Automatic changelog update Remove "mk --> mmm, okay" and "u --> you" to chatsan anti slang (#21177) Automatic changelog update Adds AttemptEntity(Uns|S)tickEvent. (#20728) * try-stick * convert spider charge to attempt-stick-events Change ListContainer to send null when selected is removed from the data (#20595) fix feeding unremovable items (#21234) Automatic changelog update Power switchable refactor (#20419) Co-authored-by: deltanedas <@deltanedas:kde.org> simple space mobs cant be flashed (#20784) Co-authored-by: deltanedas <@deltanedas:kde.org> give roundstart borgs names (#20081) Co-authored-by: deltanedas <@deltanedas:kde.org> fix searching on vending machines (#21233) syndicate snack box (#21024) Co-authored-by: deltanedas <@deltanedas:kde.org> Fix DockingControl (#21238) Shadow Dimension visual pack (#21237) Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Potato battery update + potato AI (#21142) Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com> [TEST MERGE] Slot-based Storage (#21212) Automatic changelog update Some mild item size balancing + fixes (#21250) Automatic changelog update Revert "Storage TEST MERGE" (#21258) Add missing changelog for storage refactor revert (#21259) * sync sync * Automatic changelog update shuttle timer groundwork no more squiggles.. last build error updated maps for testing some issue with receiving arrivals setup networkpayload refactor. TODO: accurate timings timings accurate. TODO: backport old bugfix all set? cleaned up source. TODO: diff arrivals methods cleaned component. TODO: escape polish, docs first documentation pass escape timers work no more magic numbers BBQ rib sandwich (#21180) Fix missing toggle fullscreen loc string (#21264) Cave Decoration pack (#21265) * add chromite chasm * add desert chasm * snow chasm * finish fixes and tweaks (#21172) Automatic changelog update Fix ItemPlacer (#21160) This is going to lead to many entities being ticked unnecessarily and performance problems. headrev spawn music (#21119) * headrev spawn music * :trollface: * skill issue * double skill issue * :trollface: * :trollface: * :trollface: Automatic changelog update Techfab resprite + department fab sprites (#21136) Fix popup messages appearing when someone tries to open a door without a tool. (#21099) * The fixTM * typo fix * addressing review Show "departed and moved on" for when a ghost role is taken (#21092) * fix ghost role not counting for "departed and moved on" * I don't think that bit was needed so away it goes * hopefully finish the upsream merge Automatic changelog update Implant whitelist/blacklisting (#20678) * add whitelist and blacklist to implant and implanter components * handle whitelist and blacklist in systems * move hardcoded whitelist/blacklist to base implanter + add admeme implanter * give implants sensible whitelists * cleaner CheckTarget and fix * remove unused imports * network lists --------- Co-authored-by: deltanedas <@deltanedas:kde.org> Automatic changelog update Ion storm event (#20277) * ion storm event prototype + locale * add lawsets * use lawsets, make borgs ion storm targets * ion storm rule and ion storm target * lawset prototype * use lawsets * update silicon law system to use lawsets and support ion storm event * new toys * fix * more fix * fixy * ion storm admin logging * assigning laws makes borg provide its own laws, other stuff * 1h reoccurence * 50% chance * better call saul * emagLaws is required * add announcment audio * fixy * family friendly gaming * fixy * address reviews * fixy * more fixy and no erp * pro --------- Co-authored-by: deltanedas <@deltanedas:kde.org> Automatic changelog update A return to foam (foam rework) (#20831) Automatic changelog update ERT Loadout overhaul + Real deathsquad mobs + ERT fixes (#21230) * "assist with medical efforts" * CentComm official description change * give cburn ert mask * Ert medic hardsuit uses blood-red medic values * description changes, they all used to use the blood-red description * ert engineer hardsuit uses cburn values, good for handling all possible engineering problems. * janitor hardsuit uses cburn values for extreme messes, otherwise we'd send the non eva variant. * spawn suffix changes * shorten suffix * drop armor from ert jumpsuits * drop armor from DS jumpsuit * add more armor to death squad to make up for removed armor in the uniform. * give sec gas masks armor, give syndicate gas masks armor. ERT gas mask uses syndicate mask values * add nanotrasen * removed duplicate * give centcom IDs their hud icon * replace all ert bulletproof armor with basic universal armor * replace all oxygen tanks with air tanks; species is random. * remove gun and meds from ert engineer kit * give ert engineer materials * remove weapons and meds from janitor ert * give ert janitor light replacer * remove ert sec pulse weapons, admins will assign loadout. Either the lecter or enforcer, probably. * Give ert sec the security pistol kit * typo * give eva ert sec pistol * give eva janitor ert gas mask * give jani purple gloves * medical gloves for medical ert * replicate security loadout to leader * quick ert lecter spawns for lazy admins * better suffixes to find them easier * add cburn to ertspawn * Replace "Spawn" with "role" * Add death squad. Give ert engineer gas analyzer. * death squad using wrong equipment * typo * missing ghost roles on lecter loadouts * add freedom implanter to deathsquad * deathsquad ghost role text * Operative sounds better * give Ds flashbang box (why isn't it entirely filled?) * fix typo. add energy shield to DS * fix typos * all centcomm roles are now mindshielded. These cannot be removed. * Rider didnt include some of the changes ? * give zipties instead of cuffs for mass arrests! * upgrade ERT survival boxes to extended capacity * give cburn extended oxygen too Automatic changelog update Restore Leviathan's 80 pop cap (#21281) Un-revert IPlayerManager refactor (#21244) Update engine to v172.0.0 (#21288) Bandaid tests (#21292) rename the rocks (#21275) Make crystals noRot (#21279) IDK might be better. Ideally the anchoring would be offset 0-0 but this is the world we live in atm. Fix nukies sound not played (#21268) * Play sound and sending greeting message works for nukies now!!!!! * oops * silly change Automatic changelog update Fix hijack objective (#21241) * Fix hijack * Max difficulty Remove GridModifiedEvent (#21291) Update submodule to 173.0.0 (#21296) Fix namespace error (#21298) Update yaml sequence option in editorconfig (#21297) Fix namespace (#21299) fix cburn bag issue, make new bag entity for them and filled bag entity (#21295) Health analyzer UI improve (#17280) Automatic changelog update User accessible playtime (#21242) Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com> Automatic changelog update Moves cloning comp & cloning event to shared (#21253) Generalizes solution overflow & slightly increases space lube yield (#21094) * generalize SolutionSpikeOverflowEvent * let reactions overflow * spacelube: 3 -> 5 * restore TryMixAndOverflow threshold cap Automatic changelog update Move ActorComponent to shared (#21293) Update engine to v174.0.0 (#21311) Fix planet command help message (#21312) Wearable bee plush (#20623) * add * fix * temporary change, needs fixing * mayb fix * actually fix FR * yes Automatic changelog update remove pulse rifle from ert medic (#21310) Content audio (#20862) Automatic changelog update Update submodule to 175.0.0 (#21318) Revert "Update submodule to 175.0.0 (#21318)" (#21319) Atomic bomb add uranium (#21143) * fix: Incendiary bullets no longer deal cold, acid, or shock damage that ignores all armor. * Atomic bomb Action bugfixes (#21321) Disable OOC during round (#21323) Fix PDA notifications when creating a news entry using the Mass-Media console. (#21320) Automatic changelog update Update belt.yml (#21317) changes the chief engineer's belt to remove the lv wires (they take up a lot of space and are easy to get anyways) in exchange for a holofan, a t-ray, and a gas analyzer (first time coding ever this might have to be edited) New foam sprites (edge sprites) (#21308) * New foam sprites (icon smoothing) * changed to edge sprites for foam * fix * edges for metal foams * fix Fix bola stam damage, bring back old construction requirements (#21340) Automatic changelog update Added thermal insulation to flannel jackets (#21273) Automatic changelog update Space Asshole Gear (#21243) * Add Space Asshole Coat * Add sledgehammer * Adjust sledgehammer damage values * Add copyright string to sledgehammer Fix broken slot highlight in midnight theme. (#21331) * removed old ensurecomps, stubs removed dead code leads removed redundant ensurecomps sync sync no more squiggles.. last build error updated maps for testing some issue with receiving arrivals setup networkpayload refactor. TODO: accurate timings timings accurate. TODO: backport old bugfix all set? cleaned up source. TODO: diff arrivals methods cleaned component. TODO: escape polish, docs first documentation pass escape timers work no more magic numbers removed dead code leads textscreen documentation remove redundant ensurecomps * sync * new shuttletimer sprite/offset * sync * sync * sync * sync * sync * builds * sync * sync * sync * offset adjustments * timer pattern implemented * arrivals timer system seems to work * sync * sync * sync * sync * sync * sync * sync * sync * sync * sync * implements shuttletimers * centcomm timers * set color to tg 1097fb * textscreen -> signalscreen, shuttletimer -> screen * move screens out of timer.yml * pruned unused properties/imports * license+copyright for screen.rsi * forgor change signaltimer event handler doc * roundstart arrivals ftl logic * block signaltimer screentext updates during timing * merged robust 185 * centcomm carpet uid collision PLEASE MERGE MY PR * remove arrivalssystem entitymanager dependency * refactored magic strings, added roundend getters * specific vgstation sprite commit licensing ---------
322 lines
12 KiB
C#
322 lines
12 KiB
C#
using System.Linq;
|
|
using System.Numerics;
|
|
using Content.Shared.TextScreen;
|
|
using Robust.Client.GameObjects;
|
|
using Robust.Shared.Timing;
|
|
using Robust.Shared.Utility;
|
|
|
|
namespace Content.Client.TextScreen;
|
|
|
|
/// overview:
|
|
/// Data is passed from server to client through <see cref="SharedAppearanceSystem.SetData"/>,
|
|
/// calling <see cref="OnAppearanceChange"/>, which calls almost everything else.
|
|
|
|
/// Data for the (at most one) timer is stored in <see cref="TextScreenTimerComponent"/>.
|
|
|
|
/// All screens have <see cref="TextScreenVisualsComponent"/>, but:
|
|
/// the update method only updates the timers, so the timercomp is added/removed by appearance changes/timing out.
|
|
|
|
/// Because the sprite component stores layers in a dict with no nesting, individual layers
|
|
/// have to be mapped to unique ids e.g. {"textMapKey01" : <first row, second char layerstate>}
|
|
/// in either the visuals or timer component.
|
|
|
|
|
|
/// <summary>
|
|
/// The TextScreenSystem draws text in the game world using 3x5 sprite states for each character.
|
|
/// </summary>
|
|
public sealed class TextScreenSystem : VisualizerSystem<TextScreenVisualsComponent>
|
|
{
|
|
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
|
|
|
/// <summary>
|
|
/// Contains char/state Key/Value pairs. <br/>
|
|
/// The states in Textures/Effects/text.rsi that special character should be replaced with.
|
|
/// </summary>
|
|
private static readonly Dictionary<char, string> CharStatePairs = new()
|
|
{
|
|
{ ':', "colon" },
|
|
{ '!', "exclamation" },
|
|
{ '?', "question" },
|
|
{ '*', "star" },
|
|
{ '+', "plus" },
|
|
{ '-', "dash" },
|
|
{ ' ', "blank" }
|
|
};
|
|
|
|
private const string DefaultState = "blank";
|
|
|
|
/// <summary>
|
|
/// A string prefix for all text layers.
|
|
/// </summary>
|
|
private const string TextMapKey = "textMapKey";
|
|
/// <summary>
|
|
/// A string prefix for all timer layers.
|
|
/// </summary>
|
|
private const string TimerMapKey = "timerMapKey";
|
|
private const string TextPath = "Effects/text.rsi";
|
|
private const int CharWidth = 4;
|
|
|
|
public override void Initialize()
|
|
{
|
|
base.Initialize();
|
|
|
|
SubscribeLocalEvent<TextScreenVisualsComponent, ComponentInit>(OnInit);
|
|
SubscribeLocalEvent<TextScreenTimerComponent, ComponentInit>(OnTimerInit);
|
|
}
|
|
|
|
private void OnInit(EntityUid uid, TextScreenVisualsComponent component, ComponentInit args)
|
|
{
|
|
if (!TryComp(uid, out SpriteComponent? sprite))
|
|
return;
|
|
|
|
// awkward to specify a textoffset of e.g. 0.1875 in the prototype
|
|
component.TextOffset = Vector2.Multiply(TextScreenVisualsComponent.PixelSize, component.TextOffset);
|
|
component.TimerOffset = Vector2.Multiply(TextScreenVisualsComponent.PixelSize, component.TimerOffset);
|
|
|
|
ResetText(uid, component, sprite);
|
|
BuildTextLayers(uid, component, sprite);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Instantiates <see cref="SpriteComponent.Layers"/> with {<see cref="TimerMapKey"/> + int : <see cref="DefaultState"/>} pairs.
|
|
/// </summary>
|
|
private void OnTimerInit(EntityUid uid, TextScreenTimerComponent timer, ComponentInit args)
|
|
{
|
|
if (!TryComp<SpriteComponent>(uid, out var sprite) || !TryComp<TextScreenVisualsComponent>(uid, out var screen))
|
|
return;
|
|
|
|
for (var i = 0; i < screen.RowLength; i++)
|
|
{
|
|
sprite.LayerMapReserveBlank(TimerMapKey + i);
|
|
timer.LayerStatesToDraw.Add(TimerMapKey + i, null);
|
|
sprite.LayerSetRSI(TimerMapKey + i, new ResPath(TextPath));
|
|
sprite.LayerSetColor(TimerMapKey + i, screen.Color);
|
|
sprite.LayerSetState(TimerMapKey + i, DefaultState);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called by <see cref="SharedAppearanceSystem.SetData"/> to handle text updates,
|
|
/// and spawn a <see cref="TextScreenTimerComponent"/> if necessary
|
|
/// </summary>
|
|
protected override void OnAppearanceChange(EntityUid uid, TextScreenVisualsComponent component, ref AppearanceChangeEvent args)
|
|
{
|
|
if (!Resolve(uid, ref args.Sprite))
|
|
return;
|
|
|
|
var appearance = args.Component;
|
|
|
|
if (AppearanceSystem.TryGetData(uid, TextScreenVisuals.TargetTime, out TimeSpan time, appearance))
|
|
{
|
|
if (time > _gameTiming.CurTime)
|
|
{
|
|
var timer = EnsureComp<TextScreenTimerComponent>(uid);
|
|
timer.Target = time;
|
|
BuildTimerLayers(uid, timer, component);
|
|
DrawLayers(uid, timer.LayerStatesToDraw);
|
|
}
|
|
else
|
|
{
|
|
OnTimerFinish(uid, component);
|
|
}
|
|
}
|
|
|
|
if (AppearanceSystem.TryGetData(uid, TextScreenVisuals.ScreenText, out string?[] text, appearance))
|
|
{
|
|
component.TextToDraw = text;
|
|
ResetText(uid, component);
|
|
BuildTextLayers(uid, component, args.Sprite);
|
|
DrawLayers(uid, component.LayerStatesToDraw);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Removes the timer component, clears the sprite layer dict,
|
|
/// and draws <see cref="TextScreenVisualsComponent.Text"/>
|
|
/// </summary>
|
|
private void OnTimerFinish(EntityUid uid, TextScreenVisualsComponent screen)
|
|
{
|
|
screen.TextToDraw = screen.Text;
|
|
|
|
if (!TryComp<TextScreenTimerComponent>(uid, out var timer) || !TryComp<SpriteComponent>(uid, out var sprite))
|
|
return;
|
|
|
|
foreach (var key in timer.LayerStatesToDraw.Keys)
|
|
sprite.RemoveLayer(key);
|
|
|
|
RemComp<TextScreenTimerComponent>(uid);
|
|
|
|
ResetText(uid, screen);
|
|
BuildTextLayers(uid, screen, sprite);
|
|
DrawLayers(uid, screen.LayerStatesToDraw);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clears <see cref="TextScreenVisualsComponent.LayerStatesToDraw"/>, and instantiates new blank defaults.
|
|
/// </summary>
|
|
public void ResetText(EntityUid uid, TextScreenVisualsComponent component, SpriteComponent? sprite = null)
|
|
{
|
|
if (!Resolve(uid, ref sprite))
|
|
return;
|
|
|
|
foreach (var key in component.LayerStatesToDraw.Keys)
|
|
sprite.RemoveLayer(key);
|
|
|
|
component.LayerStatesToDraw.Clear();
|
|
|
|
for (var row = 0; row < component.Rows; row++)
|
|
for (var i = 0; i < component.RowLength; i++)
|
|
{
|
|
sprite.LayerMapReserveBlank(TextMapKey + row + i);
|
|
component.LayerStatesToDraw.Add(TextMapKey + row + i, null);
|
|
sprite.LayerSetRSI(TextMapKey + row + i, new ResPath(TextPath));
|
|
sprite.LayerSetColor(TextMapKey + row + i, component.Color);
|
|
sprite.LayerSetState(TextMapKey + row + i, DefaultState);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the states in the <see cref="TextScreenVisualsComponent.LayerStatesToDraw"/> to match the component
|
|
/// <see cref="TextScreenVisualsComponent.TextToDraw"/> string?[].
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Remember to set <see cref="TextScreenVisualsComponent.TextToDraw"/> to a string?[] first.
|
|
/// </remarks>
|
|
public void BuildTextLayers(EntityUid uid, TextScreenVisualsComponent component, SpriteComponent? sprite = null)
|
|
{
|
|
if (!Resolve(uid, ref sprite))
|
|
return;
|
|
|
|
for (var rowIdx = 0; rowIdx < Math.Min(component.TextToDraw.Length, component.Rows); rowIdx++)
|
|
{
|
|
var row = component.TextToDraw[rowIdx];
|
|
if (row == null)
|
|
continue;
|
|
var min = Math.Min(row.Length, component.RowLength);
|
|
|
|
for (var chr = 0; chr < min; chr++)
|
|
{
|
|
component.LayerStatesToDraw[TextMapKey + rowIdx + chr] = GetStateFromChar(row[chr]);
|
|
sprite.LayerSetOffset(
|
|
TextMapKey + rowIdx + chr,
|
|
Vector2.Multiply(
|
|
new Vector2((chr - min / 2f + 0.5f) * CharWidth, -rowIdx * component.RowOffset),
|
|
TextScreenVisualsComponent.PixelSize
|
|
) + component.TextOffset
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Populates timer.LayerStatesToDraw & the sprite component's layer dict with calculated offsets.
|
|
/// </summary>
|
|
public void BuildTimerLayers(EntityUid uid, TextScreenTimerComponent timer, TextScreenVisualsComponent screen)
|
|
{
|
|
if (!TryComp<SpriteComponent>(uid, out var sprite))
|
|
return;
|
|
|
|
string time = TimeToString(
|
|
(_gameTiming.CurTime - timer.Target).Duration(),
|
|
false,
|
|
screen.HourFormat, screen.MinuteFormat, screen.SecondFormat
|
|
);
|
|
|
|
int min = Math.Min(time.Length, screen.RowLength);
|
|
|
|
for (int i = 0; i < min; i++)
|
|
{
|
|
timer.LayerStatesToDraw[TimerMapKey + i] = GetStateFromChar(time[i]);
|
|
sprite.LayerSetOffset(
|
|
TimerMapKey + i,
|
|
Vector2.Multiply(
|
|
new Vector2((i - min / 2f + 0.5f) * CharWidth, 0f),
|
|
TextScreenVisualsComponent.PixelSize
|
|
) + screen.TimerOffset
|
|
);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Draws a LayerStates dict by setting the sprite states individually.
|
|
/// </summary>
|
|
private void DrawLayers(EntityUid uid, Dictionary<string, string?> layerStates, SpriteComponent? sprite = null)
|
|
{
|
|
if (!Resolve(uid, ref sprite))
|
|
return;
|
|
|
|
foreach (var (key, state) in layerStates.Where(pairs => pairs.Value != null))
|
|
sprite.LayerSetState(key, state);
|
|
}
|
|
|
|
public override void Update(float frameTime)
|
|
{
|
|
base.Update(frameTime);
|
|
|
|
var query = EntityQueryEnumerator<TextScreenTimerComponent, TextScreenVisualsComponent>();
|
|
while (query.MoveNext(out var uid, out var timer, out var screen))
|
|
{
|
|
if (timer.Target < _gameTiming.CurTime)
|
|
{
|
|
OnTimerFinish(uid, screen);
|
|
continue;
|
|
}
|
|
|
|
BuildTimerLayers(uid, timer, screen);
|
|
DrawLayers(uid, timer.LayerStatesToDraw);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the <paramref name="timeSpan"/> converted to a string in either HH:MM, MM:SS or potentially SS:mm format.
|
|
/// </summary>
|
|
/// <param name="timeSpan">TimeSpan to convert into string.</param>
|
|
/// <param name="getMilliseconds">Should the string be ss:ms if minutes are less than 1?</param>
|
|
/// <remarks>
|
|
/// hours, minutes, seconds, and centiseconds are each set to 2 decimal places by default.
|
|
/// </remarks>
|
|
public static string TimeToString(TimeSpan timeSpan, bool getMilliseconds = true, string hours = "D2", string minutes = "D2", string seconds = "D2", string cs = "D2")
|
|
{
|
|
string firstString;
|
|
string lastString;
|
|
|
|
if (timeSpan.TotalHours >= 1)
|
|
{
|
|
firstString = timeSpan.Hours.ToString(hours);
|
|
lastString = timeSpan.Minutes.ToString(minutes);
|
|
}
|
|
else if (timeSpan.TotalMinutes >= 1 || !getMilliseconds)
|
|
{
|
|
firstString = timeSpan.Minutes.ToString(minutes);
|
|
lastString = timeSpan.Seconds.ToString(seconds);
|
|
}
|
|
else
|
|
{
|
|
firstString = timeSpan.Seconds.ToString(seconds);
|
|
var centiseconds = timeSpan.Milliseconds / 10;
|
|
lastString = centiseconds.ToString(cs);
|
|
}
|
|
|
|
return firstString + ':' + lastString;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the Effects/text.rsi state string based on <paramref name="character"/>, or null if none available.
|
|
/// </summary>
|
|
public static string? GetStateFromChar(char? character)
|
|
{
|
|
if (character == null)
|
|
return null;
|
|
|
|
// First checks if its one of our special characters
|
|
if (CharStatePairs.ContainsKey(character.Value))
|
|
return CharStatePairs[character.Value];
|
|
|
|
// Or else it checks if its a normal letter or digit
|
|
if (char.IsLetterOrDigit(character.Value))
|
|
return character.Value.ToString().ToLower();
|
|
|
|
return null;
|
|
}
|
|
}
|