Examine prediction (#23565)
* Initial prediction * new group handling * groups for all examines that use multiple rn * compile * why was it doing this?? * handle newlines with sorting properly
This commit is contained in:
@@ -81,27 +81,30 @@ namespace Content.Client.Construction
|
|||||||
|
|
||||||
private void HandleConstructionGhostExamined(EntityUid uid, ConstructionGhostComponent component, ExaminedEvent args)
|
private void HandleConstructionGhostExamined(EntityUid uid, ConstructionGhostComponent component, ExaminedEvent args)
|
||||||
{
|
{
|
||||||
if (component.Prototype == null) return;
|
if (component.Prototype == null)
|
||||||
|
|
||||||
args.PushMarkup(Loc.GetString(
|
|
||||||
"construction-ghost-examine-message",
|
|
||||||
("name", component.Prototype.Name)));
|
|
||||||
|
|
||||||
if (!_prototypeManager.TryIndex(component.Prototype.Graph, out ConstructionGraphPrototype? graph))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var startNode = graph.Nodes[component.Prototype.StartNode];
|
using (args.PushGroup(nameof(ConstructionGhostComponent)))
|
||||||
|
|
||||||
if (!graph.TryPath(component.Prototype.StartNode, component.Prototype.TargetNode, out var path) ||
|
|
||||||
!startNode.TryGetEdge(path[0].Name, out var edge))
|
|
||||||
{
|
{
|
||||||
return;
|
args.PushMarkup(Loc.GetString(
|
||||||
}
|
"construction-ghost-examine-message",
|
||||||
|
("name", component.Prototype.Name)));
|
||||||
|
|
||||||
foreach (ConstructionGraphStep step in edge.Steps)
|
if (!_prototypeManager.TryIndex(component.Prototype.Graph, out ConstructionGraphPrototype? graph))
|
||||||
{
|
return;
|
||||||
args.Message.PushNewline();
|
|
||||||
step.DoExamine(args);
|
var startNode = graph.Nodes[component.Prototype.StartNode];
|
||||||
|
|
||||||
|
if (!graph.TryPath(component.Prototype.StartNode, component.Prototype.TargetNode, out var path) ||
|
||||||
|
!startNode.TryGetEdge(path[0].Name, out var edge))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var step in edge.Steps)
|
||||||
|
{
|
||||||
|
step.DoExamine(args);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -366,13 +366,14 @@ namespace Content.Client.Examine
|
|||||||
var canSeeClearly = !HasComp<BlurryVisionComponent>(playerEnt);
|
var canSeeClearly = !HasComp<BlurryVisionComponent>(playerEnt);
|
||||||
|
|
||||||
OpenTooltip(playerEnt.Value, entity, centeredOnCursor, false, knowTarget: canSeeClearly);
|
OpenTooltip(playerEnt.Value, entity, centeredOnCursor, false, knowTarget: canSeeClearly);
|
||||||
if (IsClientSide(entity)
|
|
||||||
|| _client.RunLevel == ClientRunLevel.SinglePlayerGame) // i.e. a replay
|
// Always update tooltip info from client first.
|
||||||
{
|
// If we get it wrong, server will correct us later anyway.
|
||||||
message = GetExamineText(entity, playerEnt);
|
// This will usually be correct (barring server-only components, which generally only adds, not replaces text)
|
||||||
UpdateTooltipInfo(playerEnt.Value, entity, message);
|
message = GetExamineText(entity, playerEnt);
|
||||||
}
|
UpdateTooltipInfo(playerEnt.Value, entity, message);
|
||||||
else
|
|
||||||
|
if (!IsClientSide(entity))
|
||||||
{
|
{
|
||||||
// Ask server for extra examine info.
|
// Ask server for extra examine info.
|
||||||
if (entity != _lastExaminedEntity)
|
if (entity != _lastExaminedEntity)
|
||||||
@@ -383,7 +384,6 @@ namespace Content.Client.Examine
|
|||||||
}
|
}
|
||||||
|
|
||||||
RaiseLocalEvent(entity, new ClientExaminedEvent(entity, playerEnt.Value));
|
RaiseLocalEvent(entity, new ClientExaminedEvent(entity, playerEnt.Value));
|
||||||
|
|
||||||
_lastExaminedEntity = entity;
|
_lastExaminedEntity = entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -110,6 +110,7 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
|
|
||||||
private void OnExamined(EntityUid uid, GasTankComponent component, ExaminedEvent args)
|
private void OnExamined(EntityUid uid, GasTankComponent component, ExaminedEvent args)
|
||||||
{
|
{
|
||||||
|
using(args.PushGroup(nameof(GasTankComponent)));
|
||||||
if (args.IsInDetailsRange)
|
if (args.IsInDetailsRange)
|
||||||
args.PushMarkup(Loc.GetString("comp-gas-tank-examine", ("pressure", Math.Round(component.Air?.Pressure ?? 0))));
|
args.PushMarkup(Loc.GetString("comp-gas-tank-examine", ("pressure", Math.Round(component.Air?.Pressure ?? 0))));
|
||||||
if (component.IsConnected)
|
if (component.IsConnected)
|
||||||
|
|||||||
@@ -51,20 +51,23 @@ namespace Content.Server.Atmos.Piping.Binary.EntitySystems
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (comp.Reacting)
|
using (args.PushGroup(nameof(GasRecyclerComponent)))
|
||||||
{
|
{
|
||||||
args.PushMarkup(Loc.GetString("gas-recycler-reacting"));
|
if (comp.Reacting)
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (inlet.Air.Pressure < comp.MinPressure)
|
|
||||||
{
|
{
|
||||||
args.PushMarkup(Loc.GetString("gas-recycler-low-pressure"));
|
args.PushMarkup(Loc.GetString("gas-recycler-reacting"));
|
||||||
}
|
}
|
||||||
|
else
|
||||||
if (inlet.Air.Temperature < comp.MinTemp)
|
|
||||||
{
|
{
|
||||||
args.PushMarkup(Loc.GetString("gas-recycler-low-temperature"));
|
if (inlet.Air.Pressure < comp.MinPressure)
|
||||||
|
{
|
||||||
|
args.PushMarkup(Loc.GetString("gas-recycler-low-pressure"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inlet.Air.Temperature < comp.MinTemp)
|
||||||
|
{
|
||||||
|
args.PushMarkup(Loc.GetString("gas-recycler-low-temperature"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,10 +90,13 @@ public sealed partial class BotanySystem : EntitySystem
|
|||||||
if (!TryGetSeed(component, out var seed))
|
if (!TryGetSeed(component, out var seed))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var name = Loc.GetString(seed.DisplayName);
|
using (args.PushGroup(nameof(SeedComponent)))
|
||||||
args.PushMarkup(Loc.GetString($"seed-component-description", ("seedName", name)));
|
{
|
||||||
args.PushMarkup(Loc.GetString($"seed-component-plant-yield-text", ("seedYield", seed.Yield)));
|
var name = Loc.GetString(seed.DisplayName);
|
||||||
args.PushMarkup(Loc.GetString($"seed-component-plant-potency-text", ("seedPotency", seed.Potency)));
|
args.PushMarkup(Loc.GetString($"seed-component-description", ("seedName", name)));
|
||||||
|
args.PushMarkup(Loc.GetString($"seed-component-plant-yield-text", ("seedYield", seed.Yield)));
|
||||||
|
args.PushMarkup(Loc.GetString($"seed-component-plant-potency-text", ("seedPotency", seed.Potency)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#region SeedPrototype prototype stuff
|
#region SeedPrototype prototype stuff
|
||||||
|
|||||||
@@ -77,59 +77,62 @@ public sealed class PlantHolderSystem : EntitySystem
|
|||||||
|
|
||||||
var (_, component) = entity;
|
var (_, component) = entity;
|
||||||
|
|
||||||
if (component.Seed == null)
|
using (args.PushGroup(nameof(PlantHolderComponent)))
|
||||||
{
|
{
|
||||||
args.PushMarkup(Loc.GetString("plant-holder-component-nothing-planted-message"));
|
if (component.Seed == null)
|
||||||
}
|
{
|
||||||
else if (!component.Dead)
|
args.PushMarkup(Loc.GetString("plant-holder-component-nothing-planted-message"));
|
||||||
{
|
}
|
||||||
var displayName = Loc.GetString(component.Seed.DisplayName);
|
else if (!component.Dead)
|
||||||
args.PushMarkup(Loc.GetString("plant-holder-component-something-already-growing-message",
|
{
|
||||||
|
var displayName = Loc.GetString(component.Seed.DisplayName);
|
||||||
|
args.PushMarkup(Loc.GetString("plant-holder-component-something-already-growing-message",
|
||||||
("seedName", displayName),
|
("seedName", displayName),
|
||||||
("toBeForm", displayName.EndsWith('s') ? "are" : "is")));
|
("toBeForm", displayName.EndsWith('s') ? "are" : "is")));
|
||||||
|
|
||||||
if (component.Health <= component.Seed.Endurance / 2)
|
if (component.Health <= component.Seed.Endurance / 2)
|
||||||
{
|
{
|
||||||
args.PushMarkup(Loc.GetString(
|
args.PushMarkup(Loc.GetString(
|
||||||
"plant-holder-component-something-already-growing-low-health-message",
|
"plant-holder-component-something-already-growing-low-health-message",
|
||||||
("healthState",
|
("healthState",
|
||||||
Loc.GetString(component.Age > component.Seed.Lifespan
|
Loc.GetString(component.Age > component.Seed.Lifespan
|
||||||
? "plant-holder-component-plant-old-adjective"
|
? "plant-holder-component-plant-old-adjective"
|
||||||
: "plant-holder-component-plant-unhealthy-adjective"))));
|
: "plant-holder-component-plant-unhealthy-adjective"))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
args.PushMarkup(Loc.GetString("plant-holder-component-dead-plant-matter-message"));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
args.PushMarkup(Loc.GetString("plant-holder-component-dead-plant-matter-message"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (component.WeedLevel >= 5)
|
if (component.WeedLevel >= 5)
|
||||||
args.PushMarkup(Loc.GetString("plant-holder-component-weed-high-level-message"));
|
args.PushMarkup(Loc.GetString("plant-holder-component-weed-high-level-message"));
|
||||||
|
|
||||||
if (component.PestLevel >= 5)
|
if (component.PestLevel >= 5)
|
||||||
args.PushMarkup(Loc.GetString("plant-holder-component-pest-high-level-message"));
|
args.PushMarkup(Loc.GetString("plant-holder-component-pest-high-level-message"));
|
||||||
|
|
||||||
args.PushMarkup(Loc.GetString($"plant-holder-component-water-level-message",
|
args.PushMarkup(Loc.GetString($"plant-holder-component-water-level-message",
|
||||||
("waterLevel", (int) component.WaterLevel)));
|
("waterLevel", (int) component.WaterLevel)));
|
||||||
args.PushMarkup(Loc.GetString($"plant-holder-component-nutrient-level-message",
|
args.PushMarkup(Loc.GetString($"plant-holder-component-nutrient-level-message",
|
||||||
("nutritionLevel", (int) component.NutritionLevel)));
|
("nutritionLevel", (int) component.NutritionLevel)));
|
||||||
|
|
||||||
if (component.DrawWarnings)
|
if (component.DrawWarnings)
|
||||||
{
|
{
|
||||||
if (component.Toxins > 40f)
|
if (component.Toxins > 40f)
|
||||||
args.PushMarkup(Loc.GetString("plant-holder-component-toxins-high-warning"));
|
args.PushMarkup(Loc.GetString("plant-holder-component-toxins-high-warning"));
|
||||||
|
|
||||||
if (component.ImproperLight)
|
if (component.ImproperLight)
|
||||||
args.PushMarkup(Loc.GetString("plant-holder-component-light-improper-warning"));
|
args.PushMarkup(Loc.GetString("plant-holder-component-light-improper-warning"));
|
||||||
|
|
||||||
if (component.ImproperHeat)
|
if (component.ImproperHeat)
|
||||||
args.PushMarkup(Loc.GetString("plant-holder-component-heat-improper-warning"));
|
args.PushMarkup(Loc.GetString("plant-holder-component-heat-improper-warning"));
|
||||||
|
|
||||||
if (component.ImproperPressure)
|
if (component.ImproperPressure)
|
||||||
args.PushMarkup(Loc.GetString("plant-holder-component-pressure-improper-warning"));
|
args.PushMarkup(Loc.GetString("plant-holder-component-pressure-improper-warning"));
|
||||||
|
|
||||||
if (component.MissingGas > 0)
|
if (component.MissingGas > 0)
|
||||||
args.PushMarkup(Loc.GetString("plant-holder-component-gas-missing-warning"));
|
args.PushMarkup(Loc.GetString("plant-holder-component-gas-missing-warning"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ namespace Content.Server.Construction.Conditions
|
|||||||
if (entityManager.EntitySysManager.GetEntitySystem<MachineFrameSystem>().IsComplete(machineFrame))
|
if (entityManager.EntitySysManager.GetEntitySystem<MachineFrameSystem>().IsComplete(machineFrame))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
args.Message.AddMarkup(Loc.GetString("construction-condition-machine-frame-requirement-label") + "\n");
|
args.PushMarkup(Loc.GetString("construction-condition-machine-frame-requirement-label"));
|
||||||
foreach (var (part, required) in machineFrame.Requirements)
|
foreach (var (part, required) in machineFrame.Requirements)
|
||||||
{
|
{
|
||||||
var amount = required - machineFrame.Progress[part];
|
var amount = required - machineFrame.Progress[part];
|
||||||
@@ -54,10 +54,9 @@ namespace Content.Server.Construction.Conditions
|
|||||||
if(amount == 0)
|
if(amount == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
args.Message.AddMarkup(Loc.GetString("construction-condition-machine-frame-required-element-entry",
|
args.PushMarkup(Loc.GetString("construction-condition-machine-frame-required-element-entry",
|
||||||
("amount", amount),
|
("amount", amount),
|
||||||
("elementName", Loc.GetString(part)))
|
("elementName", Loc.GetString(part))));
|
||||||
+ "\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var (material, required) in machineFrame.MaterialRequirements)
|
foreach (var (material, required) in machineFrame.MaterialRequirements)
|
||||||
@@ -67,10 +66,9 @@ namespace Content.Server.Construction.Conditions
|
|||||||
if(amount == 0)
|
if(amount == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
args.Message.AddMarkup(Loc.GetString("construction-condition-machine-frame-required-element-entry",
|
args.PushMarkup(Loc.GetString("construction-condition-machine-frame-required-element-entry",
|
||||||
("amount", amount),
|
("amount", amount),
|
||||||
("elementName", Loc.GetString(material)))
|
("elementName", Loc.GetString(material))));
|
||||||
+ "\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var (compName, info) in machineFrame.ComponentRequirements)
|
foreach (var (compName, info) in machineFrame.ComponentRequirements)
|
||||||
@@ -80,10 +78,9 @@ namespace Content.Server.Construction.Conditions
|
|||||||
if(amount == 0)
|
if(amount == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
args.Message.AddMarkup(Loc.GetString("construction-condition-machine-frame-required-element-entry",
|
args.PushMarkup(Loc.GetString("construction-condition-machine-frame-required-element-entry",
|
||||||
("amount", info.Amount),
|
("amount", info.Amount),
|
||||||
("elementName", Loc.GetString(info.ExamineName)))
|
("elementName", Loc.GetString(info.ExamineName))));
|
||||||
+ "\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var (tagName, info) in machineFrame.TagRequirements)
|
foreach (var (tagName, info) in machineFrame.TagRequirements)
|
||||||
@@ -93,10 +90,10 @@ namespace Content.Server.Construction.Conditions
|
|||||||
if(amount == 0)
|
if(amount == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
args.Message.AddMarkup(Loc.GetString("construction-condition-machine-frame-required-element-entry",
|
args.PushMarkup(Loc.GetString("construction-condition-machine-frame-required-element-entry",
|
||||||
("amount", info.Amount),
|
("amount", info.Amount),
|
||||||
("elementName", Loc.GetString(info.ExamineName)))
|
("elementName", Loc.GetString(info.ExamineName)))
|
||||||
+ "\n");
|
+ "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -67,46 +67,50 @@ namespace Content.Server.Construction
|
|||||||
|
|
||||||
private void HandleConstructionExamined(EntityUid uid, ConstructionComponent component, ExaminedEvent args)
|
private void HandleConstructionExamined(EntityUid uid, ConstructionComponent component, ExaminedEvent args)
|
||||||
{
|
{
|
||||||
if (GetTargetNode(uid, component) is {} target)
|
using (args.PushGroup(nameof(ConstructionComponent)))
|
||||||
{
|
{
|
||||||
if (target.Name == component.DeconstructionNode)
|
if (GetTargetNode(uid, component) is {} target)
|
||||||
{
|
{
|
||||||
args.PushMarkup(Loc.GetString("deconstruction-header-text") + "\n");
|
if (target.Name == component.DeconstructionNode)
|
||||||
|
{
|
||||||
|
args.PushMarkup(Loc.GetString("deconstruction-header-text") + "\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
args.PushMarkup(Loc.GetString(
|
||||||
|
"construction-component-to-create-header",
|
||||||
|
("targetName", target.Name)) + "\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if (component.EdgeIndex == null && GetTargetEdge(uid, component) is {} targetEdge)
|
||||||
{
|
{
|
||||||
args.PushMarkup(Loc.GetString(
|
var preventStepExamine = false;
|
||||||
"construction-component-to-create-header",
|
|
||||||
("targetName", target.Name)) + "\n");
|
foreach (var condition in targetEdge.Conditions)
|
||||||
|
{
|
||||||
|
preventStepExamine |= condition.DoExamine(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!preventStepExamine)
|
||||||
|
targetEdge.Steps[0].DoExamine(args);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetCurrentEdge(uid, component) is {} edge)
|
||||||
|
{
|
||||||
|
var preventStepExamine = false;
|
||||||
|
|
||||||
|
foreach (var condition in edge.Conditions)
|
||||||
|
{
|
||||||
|
preventStepExamine |= condition.DoExamine(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!preventStepExamine && component.StepIndex < edge.Steps.Count)
|
||||||
|
edge.Steps[component.StepIndex].DoExamine(args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (component.EdgeIndex == null && GetTargetEdge(uid, component) is {} targetEdge)
|
|
||||||
{
|
|
||||||
var preventStepExamine = false;
|
|
||||||
|
|
||||||
foreach (var condition in targetEdge.Conditions)
|
|
||||||
{
|
|
||||||
preventStepExamine |= condition.DoExamine(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!preventStepExamine)
|
|
||||||
targetEdge.Steps[0].DoExamine(args);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GetCurrentEdge(uid, component) is {} edge)
|
|
||||||
{
|
|
||||||
var preventStepExamine = false;
|
|
||||||
|
|
||||||
foreach (var condition in edge.Conditions)
|
|
||||||
{
|
|
||||||
preventStepExamine |= condition.DoExamine(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!preventStepExamine && component.StepIndex < edge.Steps.Count)
|
|
||||||
edge.Steps[component.StepIndex].DoExamine(args);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -66,26 +66,29 @@ public sealed class DefusableSystem : SharedDefusableSystem
|
|||||||
if (!args.IsInDetailsRange)
|
if (!args.IsInDetailsRange)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!comp.Usable)
|
using (args.PushGroup(nameof(DefusableComponent)))
|
||||||
{
|
{
|
||||||
args.PushMarkup(Loc.GetString("defusable-examine-defused", ("name", uid)));
|
if (!comp.Usable)
|
||||||
}
|
|
||||||
else if (comp.Activated && TryComp<ActiveTimerTriggerComponent>(uid, out var activeComp))
|
|
||||||
{
|
|
||||||
if (comp.DisplayTime)
|
|
||||||
{
|
{
|
||||||
args.PushMarkup(Loc.GetString("defusable-examine-live", ("name", uid),
|
args.PushMarkup(Loc.GetString("defusable-examine-defused", ("name", uid)));
|
||||||
("time", MathF.Floor(activeComp.TimeRemaining))));
|
}
|
||||||
|
else if (comp.Activated && TryComp<ActiveTimerTriggerComponent>(uid, out var activeComp))
|
||||||
|
{
|
||||||
|
if (comp.DisplayTime)
|
||||||
|
{
|
||||||
|
args.PushMarkup(Loc.GetString("defusable-examine-live", ("name", uid),
|
||||||
|
("time", MathF.Floor(activeComp.TimeRemaining))));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
args.PushMarkup(Loc.GetString("defusable-examine-live-display-off", ("name", uid)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
args.PushMarkup(Loc.GetString("defusable-examine-live-display-off", ("name", uid)));
|
args.PushMarkup(Loc.GetString("defusable-examine-inactive", ("name", uid)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
args.PushMarkup(Loc.GetString("defusable-examine-inactive", ("name", uid)));
|
|
||||||
}
|
|
||||||
|
|
||||||
args.PushMarkup(Loc.GetString("defusable-examine-bolts", ("down", comp.Bolted)));
|
args.PushMarkup(Loc.GetString("defusable-examine-bolts", ("down", comp.Bolted)));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ public sealed class DrainSystem : SharedDrainSystem
|
|||||||
var text = drainSolution.AvailableVolume != 0
|
var text = drainSolution.AvailableVolume != 0
|
||||||
? Loc.GetString("drain-component-examine-volume", ("volume", drainSolution.AvailableVolume))
|
? Loc.GetString("drain-component-examine-volume", ("volume", drainSolution.AvailableVolume))
|
||||||
: Loc.GetString("drain-component-examine-hint-full");
|
: Loc.GetString("drain-component-examine-hint-full");
|
||||||
args.Message.AddMarkup($"\n\n{text}");
|
args.PushMarkup(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnInteract(Entity<DrainComponent> entity, ref AfterInteractUsingEvent args)
|
private void OnInteract(Entity<DrainComponent> entity, ref AfterInteractUsingEvent args)
|
||||||
|
|||||||
@@ -43,10 +43,13 @@ public sealed partial class PuddleSystem
|
|||||||
|
|
||||||
private void OnExamined(Entity<SpillableComponent> entity, ref ExaminedEvent args)
|
private void OnExamined(Entity<SpillableComponent> entity, ref ExaminedEvent args)
|
||||||
{
|
{
|
||||||
args.PushMarkup(Loc.GetString("spill-examine-is-spillable"));
|
using (args.PushGroup(nameof(SpillableComponent)))
|
||||||
|
{
|
||||||
|
args.PushMarkup(Loc.GetString("spill-examine-is-spillable"));
|
||||||
|
|
||||||
if (HasComp<MeleeWeaponComponent>(entity))
|
if (HasComp<MeleeWeaponComponent>(entity))
|
||||||
args.PushMarkup(Loc.GetString("spill-examine-spillable-weapon"));
|
args.PushMarkup(Loc.GetString("spill-examine-spillable-weapon"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnOverflow(Entity<SpillableComponent> entity, ref SolutionContainerOverflowEvent args)
|
private void OnOverflow(Entity<SpillableComponent> entity, ref SolutionContainerOverflowEvent args)
|
||||||
|
|||||||
@@ -361,23 +361,27 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
|
|||||||
|
|
||||||
private void HandlePuddleExamined(Entity<PuddleComponent> entity, ref ExaminedEvent args)
|
private void HandlePuddleExamined(Entity<PuddleComponent> entity, ref ExaminedEvent args)
|
||||||
{
|
{
|
||||||
if (TryComp<StepTriggerComponent>(entity, out var slippery) && slippery.Active)
|
using (args.PushGroup(nameof(PuddleComponent)))
|
||||||
{
|
{
|
||||||
args.PushMarkup(Loc.GetString("puddle-component-examine-is-slipper-text"));
|
if (TryComp<StepTriggerComponent>(entity, out var slippery) && slippery.Active)
|
||||||
}
|
{
|
||||||
|
args.PushMarkup(Loc.GetString("puddle-component-examine-is-slipper-text"));
|
||||||
|
}
|
||||||
|
|
||||||
if (HasComp<EvaporationComponent>(entity) &&
|
if (HasComp<EvaporationComponent>(entity) &&
|
||||||
_solutionContainerSystem.ResolveSolution(entity.Owner, entity.Comp.SolutionName, ref entity.Comp.Solution, out var solution))
|
_solutionContainerSystem.ResolveSolution(entity.Owner, entity.Comp.SolutionName,
|
||||||
{
|
ref entity.Comp.Solution, out var solution))
|
||||||
if (CanFullyEvaporate(solution))
|
{
|
||||||
args.PushMarkup(Loc.GetString("puddle-component-examine-evaporating"));
|
if (CanFullyEvaporate(solution))
|
||||||
else if (solution.GetTotalPrototypeQuantity(EvaporationReagents) > FixedPoint2.Zero)
|
args.PushMarkup(Loc.GetString("puddle-component-examine-evaporating"));
|
||||||
args.PushMarkup(Loc.GetString("puddle-component-examine-evaporating-partial"));
|
else if (solution.GetTotalPrototypeQuantity(EvaporationReagents) > FixedPoint2.Zero)
|
||||||
|
args.PushMarkup(Loc.GetString("puddle-component-examine-evaporating-partial"));
|
||||||
|
else
|
||||||
|
args.PushMarkup(Loc.GetString("puddle-component-examine-evaporating-no"));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
args.PushMarkup(Loc.GetString("puddle-component-examine-evaporating-no"));
|
args.PushMarkup(Loc.GetString("puddle-component-examine-evaporating-no"));
|
||||||
}
|
}
|
||||||
else
|
|
||||||
args.PushMarkup(Loc.GetString("puddle-component-examine-evaporating-no"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnAnchorChanged(Entity<PuddleComponent> entity, ref AnchorStateChangedEvent args)
|
private void OnAnchorChanged(Entity<PuddleComponent> entity, ref AnchorStateChangedEvent args)
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ public sealed class ToggleableGhostRoleSystem : EntitySystem
|
|||||||
{
|
{
|
||||||
if (!args.IsInDetailsRange)
|
if (!args.IsInDetailsRange)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (TryComp<MindContainerComponent>(uid, out var mind) && mind.HasMind)
|
if (TryComp<MindContainerComponent>(uid, out var mind) && mind.HasMind)
|
||||||
{
|
{
|
||||||
args.PushMarkup(Loc.GetString(component.ExamineTextMindPresent));
|
args.PushMarkup(Loc.GetString(component.ExamineTextMindPresent));
|
||||||
|
|||||||
@@ -44,8 +44,7 @@ public sealed class RandomGiftSystem : EntitySystem
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var name = _prototype.Index<EntityPrototype>(component.SelectedEntity).Name;
|
var name = _prototype.Index<EntityPrototype>(component.SelectedEntity).Name;
|
||||||
args.Message.PushNewline();
|
args.PushText(Loc.GetString("gift-packin-contains", ("name", name)));
|
||||||
args.Message.AddText(Loc.GetString("gift-packin-contains", ("name", name)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnUseInHand(EntityUid uid, RandomGiftComponent component, UseInHandEvent args)
|
private void OnUseInHand(EntityUid uid, RandomGiftComponent component, UseInHandEvent args)
|
||||||
|
|||||||
@@ -25,11 +25,14 @@ public sealed class HolosignSystem : EntitySystem
|
|||||||
var charges = UsesRemaining(component, battery);
|
var charges = UsesRemaining(component, battery);
|
||||||
var maxCharges = MaxUses(component, battery);
|
var maxCharges = MaxUses(component, battery);
|
||||||
|
|
||||||
args.PushMarkup(Loc.GetString("limited-charges-charges-remaining", ("charges", charges)));
|
using (args.PushGroup(nameof(HolosignProjectorComponent)))
|
||||||
|
|
||||||
if (charges > 0 && charges == maxCharges)
|
|
||||||
{
|
{
|
||||||
args.PushMarkup(Loc.GetString("limited-charges-max-charges"));
|
args.PushMarkup(Loc.GetString("limited-charges-charges-remaining", ("charges", charges)));
|
||||||
|
|
||||||
|
if (charges > 0 && charges == maxCharges)
|
||||||
|
{
|
||||||
|
args.PushMarkup(Loc.GetString("limited-charges-max-charges"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -100,25 +100,28 @@ namespace Content.Server.Labels
|
|||||||
if (comp.LabelSlot.Item is not {Valid: true} item)
|
if (comp.LabelSlot.Item is not {Valid: true} item)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!args.IsInDetailsRange)
|
using (args.PushGroup(nameof(PaperLabelComponent)))
|
||||||
{
|
{
|
||||||
args.PushMarkup(Loc.GetString("comp-paper-label-has-label-cant-read"));
|
if (!args.IsInDetailsRange)
|
||||||
return;
|
{
|
||||||
|
args.PushMarkup(Loc.GetString("comp-paper-label-has-label-cant-read"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!EntityManager.TryGetComponent(item, out PaperComponent? paper))
|
||||||
|
// Assuming yaml has the correct entity whitelist, this should not happen.
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(paper.Content))
|
||||||
|
{
|
||||||
|
args.PushMarkup(Loc.GetString("comp-paper-label-has-label-blank"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
args.PushMarkup(Loc.GetString("comp-paper-label-has-label"));
|
||||||
|
var text = paper.Content;
|
||||||
|
args.PushMarkup(text.TrimEnd());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!EntityManager.TryGetComponent(item, out PaperComponent? paper))
|
|
||||||
// Assuming yaml has the correct entity whitelist, this should not happen.
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(paper.Content))
|
|
||||||
{
|
|
||||||
args.PushMarkup(Loc.GetString("comp-paper-label-has-label-blank"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
args.PushMarkup(Loc.GetString("comp-paper-label-has-label"));
|
|
||||||
var text = paper.Content;
|
|
||||||
args.PushMarkup(text.TrimEnd());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnContainerModified(EntityUid uid, PaperLabelComponent label, ContainerModifiedMessage args)
|
private void OnContainerModified(EntityUid uid, PaperLabelComponent label, ContainerModifiedMessage args)
|
||||||
|
|||||||
@@ -47,28 +47,31 @@ public sealed class EmergencyLightSystem : SharedEmergencyLightSystem
|
|||||||
|
|
||||||
private void OnEmergencyExamine(EntityUid uid, EmergencyLightComponent component, ExaminedEvent args)
|
private void OnEmergencyExamine(EntityUid uid, EmergencyLightComponent component, ExaminedEvent args)
|
||||||
{
|
{
|
||||||
args.PushMarkup(
|
using (args.PushGroup(nameof(EmergencyLightComponent)))
|
||||||
Loc.GetString("emergency-light-component-on-examine",
|
{
|
||||||
("batteryStateText",
|
args.PushMarkup(
|
||||||
Loc.GetString(component.BatteryStateText[component.State]))));
|
Loc.GetString("emergency-light-component-on-examine",
|
||||||
|
("batteryStateText",
|
||||||
|
Loc.GetString(component.BatteryStateText[component.State]))));
|
||||||
|
|
||||||
// Show alert level on the light itself.
|
// Show alert level on the light itself.
|
||||||
if (!TryComp<AlertLevelComponent>(_station.GetOwningStation(uid), out var alerts))
|
if (!TryComp<AlertLevelComponent>(_station.GetOwningStation(uid), out var alerts))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (alerts.AlertLevels == null)
|
if (alerts.AlertLevels == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var name = alerts.CurrentLevel;
|
var name = alerts.CurrentLevel;
|
||||||
|
|
||||||
var color = Color.White;
|
var color = Color.White;
|
||||||
if (alerts.AlertLevels.Levels.TryGetValue(alerts.CurrentLevel, out var details))
|
if (alerts.AlertLevels.Levels.TryGetValue(alerts.CurrentLevel, out var details))
|
||||||
color = details.Color;
|
color = details.Color;
|
||||||
|
|
||||||
args.PushMarkup(
|
args.PushMarkup(
|
||||||
Loc.GetString("emergency-light-component-on-examine-alert",
|
Loc.GetString("emergency-light-component-on-examine-alert",
|
||||||
("color", color.ToHex()),
|
("color", color.ToHex()),
|
||||||
("level", name)));
|
("level", name)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnEmergencyLightEvent(EntityUid uid, EmergencyLightComponent component, EmergencyLightEvent args)
|
private void OnEmergencyLightEvent(EntityUid uid, EmergencyLightComponent component, EmergencyLightEvent args)
|
||||||
|
|||||||
@@ -33,23 +33,27 @@ public sealed class LightReplacerSystem : EntitySystem
|
|||||||
|
|
||||||
private void OnExamined(EntityUid uid, LightReplacerComponent component, ExaminedEvent args)
|
private void OnExamined(EntityUid uid, LightReplacerComponent component, ExaminedEvent args)
|
||||||
{
|
{
|
||||||
if (!component.InsertedBulbs.ContainedEntities.Any())
|
using (args.PushGroup(nameof(LightReplacerComponent)))
|
||||||
{
|
{
|
||||||
args.PushMarkup(Loc.GetString("comp-light-replacer-no-lights"));
|
if (!component.InsertedBulbs.ContainedEntities.Any())
|
||||||
return;
|
{
|
||||||
}
|
args.PushMarkup(Loc.GetString("comp-light-replacer-no-lights"));
|
||||||
args.PushMarkup(Loc.GetString("comp-light-replacer-has-lights"));
|
return;
|
||||||
var groups = new Dictionary<string, int>();
|
}
|
||||||
var metaQuery = GetEntityQuery<MetaDataComponent>();
|
|
||||||
foreach (var bulb in component.InsertedBulbs.ContainedEntities)
|
|
||||||
{
|
|
||||||
var metaData = metaQuery.GetComponent(bulb);
|
|
||||||
groups[metaData.EntityName] = groups.GetValueOrDefault(metaData.EntityName) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var (name, amount) in groups)
|
args.PushMarkup(Loc.GetString("comp-light-replacer-has-lights"));
|
||||||
{
|
var groups = new Dictionary<string, int>();
|
||||||
args.PushMarkup(Loc.GetString("comp-light-replacer-light-listing", ("amount", amount), ("name", name)));
|
var metaQuery = GetEntityQuery<MetaDataComponent>();
|
||||||
|
foreach (var bulb in component.InsertedBulbs.ContainedEntities)
|
||||||
|
{
|
||||||
|
var metaData = metaQuery.GetComponent(bulb);
|
||||||
|
groups[metaData.EntityName] = groups.GetValueOrDefault(metaData.EntityName) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var (name, amount) in groups)
|
||||||
|
{
|
||||||
|
args.PushMarkup(Loc.GetString("comp-light-replacer-light-listing", ("amount", amount), ("name", name)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -208,10 +208,13 @@ public sealed partial class CryoPodSystem : SharedCryoPodSystem
|
|||||||
var container = _itemSlotsSystem.GetItemOrNull(entity.Owner, entity.Comp.SolutionContainerName);
|
var container = _itemSlotsSystem.GetItemOrNull(entity.Owner, entity.Comp.SolutionContainerName);
|
||||||
if (args.IsInDetailsRange && container != null && _solutionContainerSystem.TryGetFitsInDispenser(container.Value, out _, out var containerSolution))
|
if (args.IsInDetailsRange && container != null && _solutionContainerSystem.TryGetFitsInDispenser(container.Value, out _, out var containerSolution))
|
||||||
{
|
{
|
||||||
args.PushMarkup(Loc.GetString("cryo-pod-examine", ("beaker", Name(container.Value))));
|
using (args.PushGroup(nameof(CryoPodComponent)))
|
||||||
if (containerSolution.Volume == 0)
|
|
||||||
{
|
{
|
||||||
args.PushMarkup(Loc.GetString("cryo-pod-empty-beaker"));
|
args.PushMarkup(Loc.GetString("cryo-pod-examine", ("beaker", Name(container.Value))));
|
||||||
|
if (containerSolution.Volume == 0)
|
||||||
|
{
|
||||||
|
args.PushMarkup(Loc.GetString("cryo-pod-empty-beaker"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,17 +47,24 @@ public sealed class CrematoriumSystem : EntitySystem
|
|||||||
if (!TryComp<AppearanceComponent>(uid, out var appearance))
|
if (!TryComp<AppearanceComponent>(uid, out var appearance))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_appearance.TryGetData<bool>(uid, CrematoriumVisuals.Burning, out var isBurning, appearance) && isBurning)
|
using (args.PushGroup(nameof(CrematoriumComponent)))
|
||||||
{
|
{
|
||||||
args.PushMarkup(Loc.GetString("crematorium-entity-storage-component-on-examine-details-is-burning", ("owner", uid)));
|
if (_appearance.TryGetData<bool>(uid, CrematoriumVisuals.Burning, out var isBurning, appearance) &&
|
||||||
}
|
isBurning)
|
||||||
if (_appearance.TryGetData<bool>(uid, StorageVisuals.HasContents, out var hasContents, appearance) && hasContents)
|
{
|
||||||
{
|
args.PushMarkup(Loc.GetString("crematorium-entity-storage-component-on-examine-details-is-burning",
|
||||||
args.PushMarkup(Loc.GetString("crematorium-entity-storage-component-on-examine-details-has-contents"));
|
("owner", uid)));
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
if (_appearance.TryGetData<bool>(uid, StorageVisuals.HasContents, out var hasContents, appearance) &&
|
||||||
args.PushMarkup(Loc.GetString("crematorium-entity-storage-component-on-examine-details-empty"));
|
hasContents)
|
||||||
|
{
|
||||||
|
args.PushMarkup(Loc.GetString("crematorium-entity-storage-component-on-examine-details-has-contents"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
args.PushMarkup(Loc.GetString("crematorium-entity-storage-component-on-examine-details-empty"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -135,19 +135,19 @@ public sealed class DrinkSystem : EntitySystem
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// put Empty / Xu after Opened, or start a new line
|
// put Empty / Xu after Opened, or start a new line
|
||||||
args.Message.AddMarkup(hasOpenable ? " - " : "\n");
|
args.AddMarkup(hasOpenable ? " - " : "\n");
|
||||||
|
|
||||||
var empty = IsEmpty(entity, entity.Comp);
|
var empty = IsEmpty(entity, entity.Comp);
|
||||||
if (empty)
|
if (empty)
|
||||||
{
|
{
|
||||||
args.Message.AddMarkup(Loc.GetString("drink-component-on-examine-is-empty"));
|
args.AddMarkup(Loc.GetString("drink-component-on-examine-is-empty"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TryComp<ExaminableSolutionComponent>(entity, out var comp))
|
if (TryComp<ExaminableSolutionComponent>(entity, out var comp))
|
||||||
{
|
{
|
||||||
//provide exact measurement for beakers
|
//provide exact measurement for beakers
|
||||||
args.Message.AddMarkup(Loc.GetString("drink-component-on-examine-exact-volume", ("amount", DrinkVolume(entity, entity.Comp))));
|
args.AddMarkup(Loc.GetString("drink-component-on-examine-exact-volume", ("amount", DrinkVolume(entity, entity.Comp))));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -159,7 +159,7 @@ public sealed class DrinkSystem : EntitySystem
|
|||||||
> 33 => HalfEmptyOrHalfFull(args),
|
> 33 => HalfEmptyOrHalfFull(args),
|
||||||
_ => "drink-component-on-examine-is-mostly-empty",
|
_ => "drink-component-on-examine-is-mostly-empty",
|
||||||
};
|
};
|
||||||
args.Message.AddMarkup(Loc.GetString(remainingString));
|
args.AddMarkup(Loc.GetString(remainingString));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -79,20 +79,24 @@ namespace Content.Server.Paper
|
|||||||
if (!args.IsInDetailsRange)
|
if (!args.IsInDetailsRange)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (paperComp.Content != "")
|
using (args.PushGroup(nameof(PaperComponent)))
|
||||||
args.PushMarkup(
|
|
||||||
Loc.GetString(
|
|
||||||
"paper-component-examine-detail-has-words", ("paper", uid)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (paperComp.StampedBy.Count > 0)
|
|
||||||
{
|
{
|
||||||
var commaSeparated = string.Join(", ", paperComp.StampedBy.Select(s => Loc.GetString(s.StampedName)));
|
if (paperComp.Content != "")
|
||||||
args.PushMarkup(
|
args.PushMarkup(
|
||||||
Loc.GetString(
|
Loc.GetString(
|
||||||
"paper-component-examine-detail-stamped-by", ("paper", uid), ("stamps", commaSeparated))
|
"paper-component-examine-detail-has-words", ("paper", uid)
|
||||||
);
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (paperComp.StampedBy.Count > 0)
|
||||||
|
{
|
||||||
|
var commaSeparated =
|
||||||
|
string.Join(", ", paperComp.StampedBy.Select(s => Loc.GetString(s.StampedName)));
|
||||||
|
args.PushMarkup(
|
||||||
|
Loc.GetString(
|
||||||
|
"paper-component-examine-detail-stamped-by", ("paper", uid), ("stamps", commaSeparated))
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -121,19 +121,22 @@ public sealed class PayloadSystem : EntitySystem
|
|||||||
|
|
||||||
private void OnExamined(EntityUid uid, PayloadCaseComponent component, ExaminedEvent args)
|
private void OnExamined(EntityUid uid, PayloadCaseComponent component, ExaminedEvent args)
|
||||||
{
|
{
|
||||||
if (!args.IsInDetailsRange)
|
using (args.PushGroup(nameof(PayloadCaseComponent)))
|
||||||
{
|
{
|
||||||
args.PushMarkup(Loc.GetString("payload-case-not-close-enough", ("ent", uid)));
|
if (!args.IsInDetailsRange)
|
||||||
return;
|
{
|
||||||
}
|
args.PushMarkup(Loc.GetString("payload-case-not-close-enough", ("ent", uid)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (GetAllPayloads(uid).Any())
|
if (GetAllPayloads(uid).Any())
|
||||||
{
|
{
|
||||||
args.PushMarkup(Loc.GetString("payload-case-has-payload", ("ent", uid)));
|
args.PushMarkup(Loc.GetString("payload-case-has-payload", ("ent", uid)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
args.PushMarkup(Loc.GetString("payload-case-does-not-have-payload", ("ent", uid)));
|
args.PushMarkup(Loc.GetString("payload-case-does-not-have-payload", ("ent", uid)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -172,8 +172,13 @@ public sealed class RadioDeviceSystem : EntitySystem
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var proto = _protoMan.Index<RadioChannelPrototype>(component.BroadcastChannel);
|
var proto = _protoMan.Index<RadioChannelPrototype>(component.BroadcastChannel);
|
||||||
args.PushMarkup(Loc.GetString("handheld-radio-component-on-examine", ("frequency", proto.Frequency)));
|
|
||||||
args.PushMarkup(Loc.GetString("handheld-radio-component-chennel-examine", ("channel", proto.LocalizedName)));
|
using (args.PushGroup(nameof(RadioMicrophoneComponent)))
|
||||||
|
{
|
||||||
|
args.PushMarkup(Loc.GetString("handheld-radio-component-on-examine", ("frequency", proto.Frequency)));
|
||||||
|
args.PushMarkup(Loc.GetString("handheld-radio-component-chennel-examine",
|
||||||
|
("channel", proto.LocalizedName)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnListen(EntityUid uid, RadioMicrophoneComponent component, ListenEvent args)
|
private void OnListen(EntityUid uid, RadioMicrophoneComponent component, ListenEvent args)
|
||||||
|
|||||||
@@ -64,22 +64,26 @@ public sealed class ThrusterSystem : EntitySystem
|
|||||||
// Powered is already handled by other power components
|
// Powered is already handled by other power components
|
||||||
var enabled = Loc.GetString(component.Enabled ? "thruster-comp-enabled" : "thruster-comp-disabled");
|
var enabled = Loc.GetString(component.Enabled ? "thruster-comp-enabled" : "thruster-comp-disabled");
|
||||||
|
|
||||||
args.PushMarkup(enabled);
|
using (args.PushGroup(nameof(ThrusterComponent)))
|
||||||
|
|
||||||
if (component.Type == ThrusterType.Linear &&
|
|
||||||
EntityManager.TryGetComponent(uid, out TransformComponent? xform) &&
|
|
||||||
xform.Anchored)
|
|
||||||
{
|
{
|
||||||
var nozzleDir = Loc.GetString("thruster-comp-nozzle-direction",
|
args.PushMarkup(enabled);
|
||||||
("direction", xform.LocalRotation.Opposite().ToWorldVec().GetDir().ToString().ToLowerInvariant()));
|
|
||||||
|
|
||||||
args.PushMarkup(nozzleDir);
|
if (component.Type == ThrusterType.Linear &&
|
||||||
|
EntityManager.TryGetComponent(uid, out TransformComponent? xform) &&
|
||||||
|
xform.Anchored)
|
||||||
|
{
|
||||||
|
var nozzleDir = Loc.GetString("thruster-comp-nozzle-direction",
|
||||||
|
("direction", xform.LocalRotation.Opposite().ToWorldVec().GetDir().ToString().ToLowerInvariant()));
|
||||||
|
|
||||||
var exposed = NozzleExposed(xform);
|
args.PushMarkup(nozzleDir);
|
||||||
|
|
||||||
var nozzleText = Loc.GetString(exposed ? "thruster-comp-nozzle-exposed" : "thruster-comp-nozzle-not-exposed");
|
var exposed = NozzleExposed(xform);
|
||||||
|
|
||||||
args.PushMarkup(nozzleText);
|
var nozzleText =
|
||||||
|
Loc.GetString(exposed ? "thruster-comp-nozzle-exposed" : "thruster-comp-nozzle-not-exposed");
|
||||||
|
|
||||||
|
args.PushMarkup(nozzleText);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ namespace Content.Server.Stunnable.Systems
|
|||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
SubscribeLocalEvent<BatteryComponent, ExaminedEvent>(OnExamined);
|
SubscribeLocalEvent<StunbatonComponent, ExaminedEvent>(OnExamined);
|
||||||
SubscribeLocalEvent<StunbatonComponent, SolutionContainerChangedEvent>(OnSolutionChange);
|
SubscribeLocalEvent<StunbatonComponent, SolutionContainerChangedEvent>(OnSolutionChange);
|
||||||
SubscribeLocalEvent<StunbatonComponent, StaminaDamageOnHitAttemptEvent>(OnStaminaHitAttempt);
|
SubscribeLocalEvent<StunbatonComponent, StaminaDamageOnHitAttemptEvent>(OnStaminaHitAttempt);
|
||||||
SubscribeLocalEvent<StunbatonComponent, ItemToggleActivateAttemptEvent>(TryTurnOn);
|
SubscribeLocalEvent<StunbatonComponent, ItemToggleActivateAttemptEvent>(TryTurnOn);
|
||||||
@@ -47,16 +47,12 @@ namespace Content.Server.Stunnable.Systems
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnExamined(Entity<BatteryComponent> entity, ref ExaminedEvent args)
|
private void OnExamined(Entity<StunbatonComponent> entity, ref ExaminedEvent args)
|
||||||
{
|
{
|
||||||
var onMsg = _itemToggle.IsActivated(entity.Owner)
|
var onMsg = _itemToggle.IsActivated(entity.Owner)
|
||||||
? Loc.GetString("comp-stunbaton-examined-on")
|
? Loc.GetString("comp-stunbaton-examined-on")
|
||||||
: Loc.GetString("comp-stunbaton-examined-off");
|
: Loc.GetString("comp-stunbaton-examined-off");
|
||||||
args.PushMarkup(onMsg);
|
args.PushMarkup(onMsg);
|
||||||
|
|
||||||
var chargeMessage = Loc.GetString("stunbaton-component-on-examine-charge",
|
|
||||||
("charge", (int) (entity.Comp.CurrentCharge / entity.Comp.MaxCharge * 100)));
|
|
||||||
args.PushMarkup(chargeMessage);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ToggleDone(Entity<StunbatonComponent> entity, ref ItemToggledEvent args)
|
private void ToggleDone(Entity<StunbatonComponent> entity, ref ItemToggledEvent args)
|
||||||
|
|||||||
@@ -99,24 +99,27 @@ namespace Content.Server.Tools
|
|||||||
|
|
||||||
private void OnWelderExamine(Entity<WelderComponent> entity, ref ExaminedEvent args)
|
private void OnWelderExamine(Entity<WelderComponent> entity, ref ExaminedEvent args)
|
||||||
{
|
{
|
||||||
if (_itemToggle.IsActivated(entity.Owner))
|
using (args.PushGroup(nameof(WelderComponent)))
|
||||||
{
|
{
|
||||||
args.PushMarkup(Loc.GetString("welder-component-on-examine-welder-lit-message"));
|
if (_itemToggle.IsActivated(entity.Owner))
|
||||||
}
|
{
|
||||||
else
|
args.PushMarkup(Loc.GetString("welder-component-on-examine-welder-lit-message"));
|
||||||
{
|
}
|
||||||
args.PushMarkup(Loc.GetString("welder-component-on-examine-welder-not-lit-message"));
|
else
|
||||||
}
|
{
|
||||||
|
args.PushMarkup(Loc.GetString("welder-component-on-examine-welder-not-lit-message"));
|
||||||
|
}
|
||||||
|
|
||||||
if (args.IsInDetailsRange)
|
if (args.IsInDetailsRange)
|
||||||
{
|
{
|
||||||
var (fuel, capacity) = GetWelderFuelAndCapacity(entity.Owner, entity.Comp);
|
var (fuel, capacity) = GetWelderFuelAndCapacity(entity.Owner, entity.Comp);
|
||||||
|
|
||||||
args.PushMarkup(Loc.GetString("welder-component-on-examine-detailed-message",
|
args.PushMarkup(Loc.GetString("welder-component-on-examine-detailed-message",
|
||||||
("colorName", fuel < capacity / FixedPoint2.New(4f) ? "darkorange" : "orange"),
|
("colorName", fuel < capacity / FixedPoint2.New(4f) ? "darkorange" : "orange"),
|
||||||
("fuelLeft", fuel),
|
("fuelLeft", fuel),
|
||||||
("fuelCapacity", capacity),
|
("fuelCapacity", capacity),
|
||||||
("status", string.Empty))); // Lit status is handled above
|
("status", string.Empty))); // Lit status is handled above
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -73,7 +73,8 @@ public sealed class TraversalDistorterSystem : EntitySystem
|
|||||||
examine = Loc.GetString("traversal-distorter-desc-out");
|
examine = Loc.GetString("traversal-distorter-desc-out");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
args.Message.AddMarkup(examine);
|
|
||||||
|
args.PushMarkup(examine);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnRefreshParts(EntityUid uid, TraversalDistorterComponent component, RefreshPartsEvent args)
|
private void OnRefreshParts(EntityUid uid, TraversalDistorterComponent component, RefreshPartsEvent args)
|
||||||
|
|||||||
@@ -17,11 +17,13 @@ public abstract class SharedChargesSystem : EntitySystem
|
|||||||
if (!args.IsInDetailsRange)
|
if (!args.IsInDetailsRange)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
args.PushMarkup(Loc.GetString("limited-charges-charges-remaining", ("charges", comp.Charges)));
|
using (args.PushGroup(nameof(LimitedChargesComponent)))
|
||||||
if (comp.Charges == comp.MaxCharges)
|
|
||||||
{
|
{
|
||||||
args.PushMarkup(Loc.GetString("limited-charges-max-charges"));
|
args.PushMarkup(Loc.GetString("limited-charges-charges-remaining", ("charges", comp.Charges)));
|
||||||
return;
|
if (comp.Charges == comp.MaxCharges)
|
||||||
|
{
|
||||||
|
args.PushMarkup(Loc.GetString("limited-charges-max-charges"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -742,61 +742,65 @@ public abstract partial class SharedSolutionContainerSystem : EntitySystem
|
|||||||
.ToHexNoAlpha(); //TODO: If the chem has a dark color, the examine text becomes black on a black background, which is unreadable.
|
.ToHexNoAlpha(); //TODO: If the chem has a dark color, the examine text becomes black on a black background, which is unreadable.
|
||||||
var messageString = "shared-solution-container-component-on-examine-main-text";
|
var messageString = "shared-solution-container-component-on-examine-main-text";
|
||||||
|
|
||||||
args.PushMarkup(Loc.GetString(messageString,
|
using (args.PushGroup(nameof(ExaminableSolutionComponent)))
|
||||||
("color", colorHex),
|
|
||||||
("wordedAmount", Loc.GetString(solution.Contents.Count == 1
|
|
||||||
? "shared-solution-container-component-on-examine-worded-amount-one-reagent"
|
|
||||||
: "shared-solution-container-component-on-examine-worded-amount-multiple-reagents")),
|
|
||||||
("desc", primary.LocalizedPhysicalDescription)));
|
|
||||||
|
|
||||||
var reagentPrototypes = solution.GetReagentPrototypes(PrototypeManager);
|
|
||||||
|
|
||||||
// Sort the reagents by amount, descending then alphabetically
|
|
||||||
var sortedReagentPrototypes = reagentPrototypes
|
|
||||||
.OrderByDescending(pair => pair.Value.Value)
|
|
||||||
.ThenBy(pair => pair.Key.LocalizedName);
|
|
||||||
|
|
||||||
// Add descriptions of immediately recognizable reagents, like water or beer
|
|
||||||
var recognized = new List<ReagentPrototype>();
|
|
||||||
foreach (var keyValuePair in sortedReagentPrototypes)
|
|
||||||
{
|
{
|
||||||
var proto = keyValuePair.Key;
|
args.PushMarkup(Loc.GetString(messageString,
|
||||||
if (!proto.Recognizable)
|
("color", colorHex),
|
||||||
|
("wordedAmount", Loc.GetString(solution.Contents.Count == 1
|
||||||
|
? "shared-solution-container-component-on-examine-worded-amount-one-reagent"
|
||||||
|
: "shared-solution-container-component-on-examine-worded-amount-multiple-reagents")),
|
||||||
|
("desc", primary.LocalizedPhysicalDescription)));
|
||||||
|
|
||||||
|
var reagentPrototypes = solution.GetReagentPrototypes(PrototypeManager);
|
||||||
|
|
||||||
|
// Sort the reagents by amount, descending then alphabetically
|
||||||
|
var sortedReagentPrototypes = reagentPrototypes
|
||||||
|
.OrderByDescending(pair => pair.Value.Value)
|
||||||
|
.ThenBy(pair => pair.Key.LocalizedName);
|
||||||
|
|
||||||
|
// Add descriptions of immediately recognizable reagents, like water or beer
|
||||||
|
var recognized = new List<ReagentPrototype>();
|
||||||
|
foreach (var keyValuePair in sortedReagentPrototypes)
|
||||||
{
|
{
|
||||||
continue;
|
var proto = keyValuePair.Key;
|
||||||
|
if (!proto.Recognizable)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
recognized.Add(proto);
|
||||||
}
|
}
|
||||||
|
|
||||||
recognized.Add(proto);
|
// Skip if there's nothing recognizable
|
||||||
|
if (recognized.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var msg = new StringBuilder();
|
||||||
|
foreach (var reagent in recognized)
|
||||||
|
{
|
||||||
|
string part;
|
||||||
|
if (reagent == recognized[0])
|
||||||
|
{
|
||||||
|
part = "examinable-solution-recognized-first";
|
||||||
|
}
|
||||||
|
else if (reagent == recognized[^1])
|
||||||
|
{
|
||||||
|
// this loc specifically requires space to be appended, fluent doesnt support whitespace
|
||||||
|
msg.Append(' ');
|
||||||
|
part = "examinable-solution-recognized-last";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
part = "examinable-solution-recognized-next";
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.Append(Loc.GetString(part, ("color", reagent.SubstanceColor.ToHexNoAlpha()),
|
||||||
|
("chemical", reagent.LocalizedName)));
|
||||||
|
}
|
||||||
|
|
||||||
|
args.PushMarkup(Loc.GetString("examinable-solution-has-recognizable-chemicals",
|
||||||
|
("recognizedString", msg.ToString())));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip if there's nothing recognizable
|
|
||||||
if (recognized.Count == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var msg = new StringBuilder();
|
|
||||||
foreach (var reagent in recognized)
|
|
||||||
{
|
|
||||||
string part;
|
|
||||||
if (reagent == recognized[0])
|
|
||||||
{
|
|
||||||
part = "examinable-solution-recognized-first";
|
|
||||||
}
|
|
||||||
else if (reagent == recognized[^1])
|
|
||||||
{
|
|
||||||
// this loc specifically requires space to be appended, fluent doesnt support whitespace
|
|
||||||
msg.Append(' ');
|
|
||||||
part = "examinable-solution-recognized-last";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
part = "examinable-solution-recognized-next";
|
|
||||||
}
|
|
||||||
|
|
||||||
msg.Append(Loc.GetString(part, ("color", reagent.SubstanceColor.ToHexNoAlpha()),
|
|
||||||
("chemical", reagent.LocalizedName)));
|
|
||||||
}
|
|
||||||
|
|
||||||
args.PushMarkup(Loc.GetString("examinable-solution-has-recognizable-chemicals", ("recognizedString", msg.ToString())));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnSolutionExaminableVerb(Entity<ExaminableSolutionComponent> entity, ref GetVerbsEvent<ExamineVerb> args)
|
private void OnSolutionExaminableVerb(Entity<ExaminableSolutionComponent> entity, ref GetVerbsEvent<ExamineVerb> args)
|
||||||
|
|||||||
@@ -28,33 +28,37 @@ namespace Content.Shared.Construction
|
|||||||
{
|
{
|
||||||
if (!args.IsInDetailsRange)
|
if (!args.IsInDetailsRange)
|
||||||
return;
|
return;
|
||||||
args.PushMarkup(Loc.GetString("machine-board-component-on-examine-label"));
|
|
||||||
foreach (var (part, amount) in component.Requirements)
|
|
||||||
{
|
|
||||||
args.PushMarkup(Loc.GetString("machine-board-component-required-element-entry-text",
|
|
||||||
("amount", amount),
|
|
||||||
("requiredElement", Loc.GetString(_prototype.Index<MachinePartPrototype>(part).Name))));
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var (material, amount) in component.MaterialRequirements)
|
using (args.PushGroup(nameof(MachineBoardComponent)))
|
||||||
{
|
{
|
||||||
args.PushMarkup(Loc.GetString("machine-board-component-required-element-entry-text",
|
args.PushMarkup(Loc.GetString("machine-board-component-on-examine-label"));
|
||||||
("amount", amount),
|
foreach (var (part, amount) in component.Requirements)
|
||||||
("requiredElement", Loc.GetString(material.Name))));
|
{
|
||||||
}
|
args.PushMarkup(Loc.GetString("machine-board-component-required-element-entry-text",
|
||||||
|
("amount", amount),
|
||||||
|
("requiredElement", Loc.GetString(_prototype.Index<MachinePartPrototype>(part).Name))));
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var (_, info) in component.ComponentRequirements)
|
foreach (var (material, amount) in component.MaterialRequirements)
|
||||||
{
|
{
|
||||||
args.PushMarkup(Loc.GetString("machine-board-component-required-element-entry-text",
|
args.PushMarkup(Loc.GetString("machine-board-component-required-element-entry-text",
|
||||||
("amount", info.Amount),
|
("amount", amount),
|
||||||
("requiredElement", Loc.GetString(info.ExamineName))));
|
("requiredElement", Loc.GetString(material.Name))));
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var (_, info) in component.TagRequirements)
|
foreach (var (_, info) in component.ComponentRequirements)
|
||||||
{
|
{
|
||||||
args.PushMarkup(Loc.GetString("machine-board-component-required-element-entry-text",
|
args.PushMarkup(Loc.GetString("machine-board-component-required-element-entry-text",
|
||||||
("amount", info.Amount),
|
("amount", info.Amount),
|
||||||
("requiredElement", Loc.GetString(info.ExamineName))));
|
("requiredElement", Loc.GetString(info.ExamineName))));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var (_, info) in component.TagRequirements)
|
||||||
|
{
|
||||||
|
args.PushMarkup(Loc.GetString("machine-board-component-required-element-entry-text",
|
||||||
|
("amount", info.Amount),
|
||||||
|
("requiredElement", Loc.GetString(info.ExamineName))));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,9 +66,14 @@ namespace Content.Shared.Construction
|
|||||||
{
|
{
|
||||||
if (!args.IsInDetailsRange)
|
if (!args.IsInDetailsRange)
|
||||||
return;
|
return;
|
||||||
args.PushMarkup(Loc.GetString("machine-part-component-on-examine-rating-text", ("rating", component.Rating)));
|
|
||||||
args.PushMarkup(Loc.GetString("machine-part-component-on-examine-type-text", ("type",
|
using (args.PushGroup(nameof(MachinePartComponent)))
|
||||||
Loc.GetString(_prototype.Index<MachinePartPrototype>(component.PartType).Name))));
|
{
|
||||||
|
args.PushMarkup(Loc.GetString("machine-part-component-on-examine-rating-text",
|
||||||
|
("rating", component.Rating)));
|
||||||
|
args.PushMarkup(Loc.GetString("machine-part-component-on-examine-type-text", ("type",
|
||||||
|
Loc.GetString(_prototype.Index<MachinePartPrototype>(component.PartType).Name))));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Dictionary<string, int> GetMachineBoardMaterialCost(Entity<MachineBoardComponent> entity, int coefficient = 1)
|
public Dictionary<string, int> GetMachineBoardMaterialCost(Entity<MachineBoardComponent> entity, int coefficient = 1)
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ namespace Content.Shared.Construction.Steps
|
|||||||
if (string.IsNullOrEmpty(Name))
|
if (string.IsNullOrEmpty(Name))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
examinedEvent.Message.AddMarkup(Loc.GetString("construction-insert-arbitrary-entity", ("stepName", Name)));
|
examinedEvent.PushMarkup(Loc.GetString("construction-insert-arbitrary-entity", ("stepName", Name)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override ConstructionGuideEntry GenerateGuideEntry()
|
public override ConstructionGuideEntry GenerateGuideEntry()
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ namespace Content.Shared.Construction.Steps
|
|||||||
|
|
||||||
public override void DoExamine(ExaminedEvent examinedEvent)
|
public override void DoExamine(ExaminedEvent examinedEvent)
|
||||||
{
|
{
|
||||||
examinedEvent.Message.AddMarkup(string.IsNullOrEmpty(Name)
|
examinedEvent.PushMarkup(string.IsNullOrEmpty(Name)
|
||||||
? Loc.GetString(
|
? Loc.GetString(
|
||||||
"construction-insert-entity-with-component",
|
"construction-insert-entity-with-component",
|
||||||
("componentName", Component))// Terrible.
|
("componentName", Component))// Terrible.
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ namespace Content.Shared.Construction.Steps
|
|||||||
{
|
{
|
||||||
var material = IoCManager.Resolve<IPrototypeManager>().Index<StackPrototype>(MaterialPrototypeId);
|
var material = IoCManager.Resolve<IPrototypeManager>().Index<StackPrototype>(MaterialPrototypeId);
|
||||||
|
|
||||||
examinedEvent.Message.AddMarkup(Loc.GetString("construction-insert-material-entity", ("amount", Amount), ("materialName", material.Name)));
|
examinedEvent.PushMarkup(Loc.GetString("construction-insert-material-entity", ("amount", Amount), ("materialName", material.Name)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool EntityValid(EntityUid uid, IEntityManager entityManager, IComponentFactory compFactory)
|
public override bool EntityValid(EntityUid uid, IEntityManager entityManager, IComponentFactory compFactory)
|
||||||
|
|||||||
@@ -48,8 +48,12 @@ public abstract class SharedDiceSystem : EntitySystem
|
|||||||
private void OnExamined(EntityUid uid, DiceComponent dice, ExaminedEvent args)
|
private void OnExamined(EntityUid uid, DiceComponent dice, ExaminedEvent args)
|
||||||
{
|
{
|
||||||
//No details check, since the sprite updates to show the side.
|
//No details check, since the sprite updates to show the side.
|
||||||
args.PushMarkup(Loc.GetString("dice-component-on-examine-message-part-1", ("sidesAmount", dice.Sides)));
|
using (args.PushGroup(nameof(DiceComponent)))
|
||||||
args.PushMarkup(Loc.GetString("dice-component-on-examine-message-part-2", ("currentSide", dice.CurrentValue)));
|
{
|
||||||
|
args.PushMarkup(Loc.GetString("dice-component-on-examine-message-part-1", ("sidesAmount", dice.Sides)));
|
||||||
|
args.PushMarkup(Loc.GetString("dice-component-on-examine-message-part-2",
|
||||||
|
("currentSide", dice.CurrentValue)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetCurrentSide(EntityUid uid, int side, DiceComponent? die = null)
|
public void SetCurrentSide(EntityUid uid, int side, DiceComponent? die = null)
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
using Content.Shared.Eye.Blinding.Components;
|
using Content.Shared.Eye.Blinding.Components;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Mobs.Components;
|
using Content.Shared.Mobs.Components;
|
||||||
@@ -238,42 +241,60 @@ namespace Content.Shared.Examine
|
|||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
var doNewline = false;
|
var hasDescription = false;
|
||||||
|
|
||||||
//Add an entity description if one is declared
|
//Add an entity description if one is declared
|
||||||
if (!string.IsNullOrEmpty(EntityManager.GetComponent<MetaDataComponent>(entity).EntityDescription))
|
if (!string.IsNullOrEmpty(EntityManager.GetComponent<MetaDataComponent>(entity).EntityDescription))
|
||||||
{
|
{
|
||||||
message.AddText(EntityManager.GetComponent<MetaDataComponent>(entity).EntityDescription);
|
message.AddText(EntityManager.GetComponent<MetaDataComponent>(entity).EntityDescription);
|
||||||
doNewline = true;
|
hasDescription = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
message.PushColor(Color.DarkGray);
|
message.PushColor(Color.DarkGray);
|
||||||
|
|
||||||
// Raise the event and let things that subscribe to it change the message...
|
// Raise the event and let things that subscribe to it change the message...
|
||||||
var isInDetailsRange = IsInDetailsRange(examiner.Value, entity);
|
var isInDetailsRange = IsInDetailsRange(examiner.Value, entity);
|
||||||
var examinedEvent = new ExaminedEvent(message, entity, examiner.Value, isInDetailsRange, doNewline);
|
var examinedEvent = new ExaminedEvent(message, entity, examiner.Value, isInDetailsRange, hasDescription);
|
||||||
RaiseLocalEvent(entity, examinedEvent, true);
|
RaiseLocalEvent(entity, examinedEvent);
|
||||||
|
|
||||||
message.Pop();
|
var newMessage = examinedEvent.GetTotalMessage();
|
||||||
|
|
||||||
return message;
|
// pop color tag
|
||||||
|
newMessage.Pop();
|
||||||
|
|
||||||
|
return newMessage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Raised when an entity is examined.
|
/// Raised when an entity is examined.
|
||||||
|
/// If you're pushing multiple messages that should be grouped together (or ordered in some way),
|
||||||
|
/// call <see cref="PushGroup"/> before pushing and <see cref="PopGroup"/> when finished.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class ExaminedEvent : EntityEventArgs
|
public sealed class ExaminedEvent : EntityEventArgs
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The message that will be displayed as the examine text.
|
/// The message that will be displayed as the examine text.
|
||||||
/// For most use cases, you probably want to use <see cref="PushMarkup"/> and similar instead to modify this,
|
/// You should use <see cref="PushMarkup"/> and similar instead to modify this,
|
||||||
/// since it handles newlines and such correctly.
|
/// since it handles newlines/priority and such correctly.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <seealso cref="PushMessage"/>
|
/// <seealso cref="PushMessage"/>
|
||||||
/// <seealso cref="PushMarkup"/>
|
/// <seealso cref="PushMarkup"/>
|
||||||
/// <seealso cref="PushText"/>
|
/// <seealso cref="PushText"/>
|
||||||
public FormattedMessage Message { get; }
|
/// <seealso cref="AddMessage"/>
|
||||||
|
/// <seealso cref="AddMarkup"/>
|
||||||
|
/// <seealso cref="AddText"/>
|
||||||
|
private FormattedMessage Message { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parts of the examine message that will later be sorted by priority and pushed onto <see cref="Message"/>.
|
||||||
|
/// </summary>
|
||||||
|
private List<ExamineMessagePart> Parts { get; } = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the examiner is in range of the entity to get some extra details.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsInDetailsRange { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The entity performing the examining.
|
/// The entity performing the examining.
|
||||||
@@ -285,62 +306,206 @@ namespace Content.Shared.Examine
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public EntityUid Examined { get; }
|
public EntityUid Examined { get; }
|
||||||
|
|
||||||
/// <summary>
|
private bool _hasDescription;
|
||||||
/// Whether the examiner is in range of the entity to get some extra details.
|
|
||||||
/// </summary>
|
|
||||||
public bool IsInDetailsRange { get; }
|
|
||||||
|
|
||||||
private bool _doNewLine;
|
private ExamineMessagePart? _currentGroupPart;
|
||||||
|
|
||||||
public ExaminedEvent(FormattedMessage message, EntityUid examined, EntityUid examiner, bool isInDetailsRange, bool doNewLine)
|
public ExaminedEvent(FormattedMessage message, EntityUid examined, EntityUid examiner, bool isInDetailsRange, bool hasDescription)
|
||||||
{
|
{
|
||||||
Message = message;
|
Message = message;
|
||||||
Examined = examined;
|
Examined = examined;
|
||||||
Examiner = examiner;
|
Examiner = examiner;
|
||||||
IsInDetailsRange = isInDetailsRange;
|
IsInDetailsRange = isInDetailsRange;
|
||||||
_doNewLine = doNewLine;
|
_hasDescription = hasDescription;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns <see cref="Message"/> with all <see cref="Parts"/> appended according to their priority.
|
||||||
|
/// </summary>
|
||||||
|
public FormattedMessage GetTotalMessage()
|
||||||
|
{
|
||||||
|
int Comparison(ExamineMessagePart a, ExamineMessagePart b)
|
||||||
|
{
|
||||||
|
// Try sort by priority, then group, then by string contents
|
||||||
|
if (a.Priority != b.Priority)
|
||||||
|
{
|
||||||
|
// negative so that expected behavior is consistent with what makes sense
|
||||||
|
// i.e. a negative priority should mean its at the bottom of the list, right?
|
||||||
|
return -a.Priority.CompareTo(b.Priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a.Group != b.Group)
|
||||||
|
{
|
||||||
|
return string.Compare(a.Group, b.Group, StringComparison.Ordinal);
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Compare(a.Message.ToString(), b.Message.ToString(), StringComparison.Ordinal);
|
||||||
|
}
|
||||||
|
|
||||||
|
// tolist/clone formatted message so calling this multiple times wont fuck shit up
|
||||||
|
// (if that happens for some reason)
|
||||||
|
var parts = Parts.ToList();
|
||||||
|
var totalMessage = new FormattedMessage(Message);
|
||||||
|
parts.Sort(Comparison);
|
||||||
|
|
||||||
|
if (_hasDescription)
|
||||||
|
{
|
||||||
|
totalMessage.PushNewline();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var part in parts)
|
||||||
|
{
|
||||||
|
totalMessage.AddMessage(part.Message);
|
||||||
|
if (part.DoNewLine && parts.Last() != part)
|
||||||
|
totalMessage.PushNewline();
|
||||||
|
}
|
||||||
|
|
||||||
|
return totalMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Message group handling. Call this if you want the next set of examine messages that you're adding to have
|
||||||
|
/// a consistent order with regards to each other. This is done so that client & server will always
|
||||||
|
/// sort messages the same as well as grouped together properly, even if subscriptions are different.
|
||||||
|
/// You should wrap it in a using() block so popping automatically occurs.
|
||||||
|
/// </summary>
|
||||||
|
public ExamineGroupDisposable PushGroup(string groupName, int priority=0)
|
||||||
|
{
|
||||||
|
// Ensure that other examine events correctly ended their groups.
|
||||||
|
DebugTools.Assert(_currentGroupPart == null);
|
||||||
|
_currentGroupPart = new ExamineMessagePart(new FormattedMessage(), priority, false, groupName);
|
||||||
|
return new ExamineGroupDisposable(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ends the current group and pushes its groups contents to the message.
|
||||||
|
/// This will be called automatically if in using a `using` block with <see cref="PushGroup"/>.
|
||||||
|
/// </summary>
|
||||||
|
private void PopGroup()
|
||||||
|
{
|
||||||
|
DebugTools.Assert(_currentGroupPart != null);
|
||||||
|
if (_currentGroupPart != null)
|
||||||
|
Parts.Add(_currentGroupPart);
|
||||||
|
|
||||||
|
_currentGroupPart = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Push another message into this examine result, on its own line.
|
/// Push another message into this examine result, on its own line.
|
||||||
|
/// End message will be grouped by <see cref="priority"/>, then by group if one was started
|
||||||
|
/// then by ordinal comparison.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <seealso cref="PushMarkup"/>
|
/// <seealso cref="PushMarkup"/>
|
||||||
/// <seealso cref="PushText"/>
|
/// <seealso cref="PushText"/>
|
||||||
public void PushMessage(FormattedMessage message)
|
public void PushMessage(FormattedMessage message, int priority=0)
|
||||||
{
|
{
|
||||||
if (message.Nodes.Count == 0)
|
if (message.Nodes.Count == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_doNewLine)
|
if (_currentGroupPart != null)
|
||||||
Message.AddText("\n");
|
{
|
||||||
|
message.PushNewline();
|
||||||
Message.AddMessage(message);
|
_currentGroupPart.Message.AddMessage(message);
|
||||||
_doNewLine = true;
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Parts.Add(new ExamineMessagePart(message, priority, true, null));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Push another message parsed from markup into this examine result, on its own line.
|
/// Push another message parsed from markup into this examine result, on its own line.
|
||||||
|
/// End message will be grouped by <see cref="priority"/>, then by group if one was started
|
||||||
|
/// then by ordinal comparison.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <seealso cref="PushText"/>
|
/// <seealso cref="PushText"/>
|
||||||
/// <seealso cref="PushMessage"/>
|
/// <seealso cref="PushMessage"/>
|
||||||
public void PushMarkup(string markup)
|
public void PushMarkup(string markup, int priority=0)
|
||||||
{
|
{
|
||||||
PushMessage(FormattedMessage.FromMarkup(markup));
|
PushMessage(FormattedMessage.FromMarkup(markup), priority);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Push another message containing raw text into this examine result, on its own line.
|
/// Push another message containing raw text into this examine result, on its own line.
|
||||||
|
/// End message will be grouped by <see cref="priority"/>, then by group if one was started
|
||||||
|
/// then by ordinal comparison.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <seealso cref="PushMarkup"/>
|
/// <seealso cref="PushMarkup"/>
|
||||||
/// <seealso cref="PushMessage"/>
|
/// <seealso cref="PushMessage"/>
|
||||||
public void PushText(string text)
|
public void PushText(string text, int priority=0)
|
||||||
{
|
{
|
||||||
var msg = new FormattedMessage();
|
var msg = new FormattedMessage();
|
||||||
msg.AddText(text);
|
msg.AddText(text);
|
||||||
PushMessage(msg);
|
PushMessage(msg, priority);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a message directly without starting a newline after.
|
||||||
|
/// End message will be grouped by <see cref="priority"/>, then by group if one was started
|
||||||
|
/// then by ordinal comparison.
|
||||||
|
/// </summary>
|
||||||
|
/// <seealso cref="AddMarkup"/>
|
||||||
|
/// <seealso cref="AddText"/>
|
||||||
|
public void AddMessage(FormattedMessage message, int priority = 0)
|
||||||
|
{
|
||||||
|
if (message.Nodes.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_currentGroupPart != null)
|
||||||
|
{
|
||||||
|
_currentGroupPart.Message.AddMessage(message);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Parts.Add(new ExamineMessagePart(message, priority, false, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds markup directly without starting a newline after.
|
||||||
|
/// End message will be grouped by <see cref="priority"/>, then by group if one was started
|
||||||
|
/// then by ordinal comparison.
|
||||||
|
/// </summary>
|
||||||
|
/// <seealso cref="AddText"/>
|
||||||
|
/// <seealso cref="AddMessage"/>
|
||||||
|
public void AddMarkup(string markup, int priority=0)
|
||||||
|
{
|
||||||
|
AddMessage(FormattedMessage.FromMarkup(markup), priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds text directly without starting a newline after.
|
||||||
|
/// End message will be grouped by <see cref="priority"/>, then by group if one was started
|
||||||
|
/// then by ordinal comparison.
|
||||||
|
/// </summary>
|
||||||
|
/// <seealso cref="AddMarkup"/>
|
||||||
|
/// <seealso cref="AddMessage"/>
|
||||||
|
public void AddText(string text, int priority=0)
|
||||||
|
{
|
||||||
|
var msg = new FormattedMessage();
|
||||||
|
msg.AddText(text);
|
||||||
|
AddMessage(msg, priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct ExamineGroupDisposable : IDisposable
|
||||||
|
{
|
||||||
|
private ExaminedEvent _event;
|
||||||
|
|
||||||
|
public ExamineGroupDisposable(ExaminedEvent @event)
|
||||||
|
{
|
||||||
|
_event = @event;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_event.PopGroup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private record ExamineMessagePart(FormattedMessage Message, int Priority, bool DoNewLine, string? Group);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Event raised directed at an entity that someone is attempting to examine
|
/// Event raised directed at an entity that someone is attempting to examine
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -185,19 +185,22 @@ public abstract partial class SharedHandsSystem : EntitySystem
|
|||||||
var held = EnumerateHeld(uid, handsComp)
|
var held = EnumerateHeld(uid, handsComp)
|
||||||
.Where(x => !HasComp<HandVirtualItemComponent>(x)).ToList();
|
.Where(x => !HasComp<HandVirtualItemComponent>(x)).ToList();
|
||||||
|
|
||||||
if (!held.Any())
|
using (args.PushGroup(nameof(HandsComponent)))
|
||||||
{
|
{
|
||||||
args.PushText(Loc.GetString("comp-hands-examine-empty",
|
if (!held.Any())
|
||||||
("user", Identity.Entity(uid, EntityManager))));
|
{
|
||||||
return;
|
args.PushText(Loc.GetString("comp-hands-examine-empty",
|
||||||
|
("user", Identity.Entity(uid, EntityManager))));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var heldList = ContentLocalizationManager.FormatList(held
|
||||||
|
.Select(x => Loc.GetString("comp-hands-examine-wrapper",
|
||||||
|
("item", Identity.Entity(x, EntityManager)))).ToList());
|
||||||
|
|
||||||
|
args.PushMarkup(Loc.GetString("comp-hands-examine",
|
||||||
|
("user", Identity.Entity(uid, EntityManager)),
|
||||||
|
("items", heldList)));
|
||||||
}
|
}
|
||||||
|
|
||||||
var heldList = ContentLocalizationManager.FormatList(held
|
|
||||||
.Select(x => Loc.GetString("comp-hands-examine-wrapper",
|
|
||||||
("item", Identity.Entity(x, EntityManager)))).ToList());
|
|
||||||
|
|
||||||
args.PushMarkup(Loc.GetString("comp-hands-examine",
|
|
||||||
("user", Identity.Entity(uid, EntityManager)),
|
|
||||||
("items", heldList)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -112,8 +112,9 @@ public abstract class SharedItemSystem : EntitySystem
|
|||||||
|
|
||||||
private void OnExamine(EntityUid uid, ItemComponent component, ExaminedEvent args)
|
private void OnExamine(EntityUid uid, ItemComponent component, ExaminedEvent args)
|
||||||
{
|
{
|
||||||
|
// show at end of message generally
|
||||||
args.PushMarkup(Loc.GetString("item-component-on-examine-size",
|
args.PushMarkup(Loc.GetString("item-component-on-examine-size",
|
||||||
("size", GetItemSizeLocale(component.Size))));
|
("size", GetItemSizeLocale(component.Size))), priority: -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ItemSizePrototype GetSizePrototype(ProtoId<ItemSizePrototype> id)
|
public ItemSizePrototype GetSizePrototype(ProtoId<ItemSizePrototype> id)
|
||||||
|
|||||||
@@ -265,16 +265,20 @@ public abstract partial class SharedGunSystem
|
|||||||
var (count, _) = GetChamberMagazineCountCapacity(uid, component);
|
var (count, _) = GetChamberMagazineCountCapacity(uid, component);
|
||||||
string boltState;
|
string boltState;
|
||||||
|
|
||||||
if (component.BoltClosed != null)
|
using (args.PushGroup(nameof(ChamberMagazineAmmoProviderComponent)))
|
||||||
{
|
{
|
||||||
if (component.BoltClosed == true)
|
if (component.BoltClosed != null)
|
||||||
boltState = Loc.GetString("gun-chamber-bolt-open-state");
|
{
|
||||||
else
|
if (component.BoltClosed == true)
|
||||||
boltState = Loc.GetString("gun-chamber-bolt-closed-state");
|
boltState = Loc.GetString("gun-chamber-bolt-open-state");
|
||||||
args.PushMarkup(Loc.GetString("gun-chamber-bolt", ("bolt", boltState), ("color", component.BoltClosed.Value ? Color.FromHex("#94e1f2") : Color.FromHex("#f29d94"))));
|
else
|
||||||
}
|
boltState = Loc.GetString("gun-chamber-bolt-closed-state");
|
||||||
|
args.PushMarkup(Loc.GetString("gun-chamber-bolt", ("bolt", boltState),
|
||||||
|
("color", component.BoltClosed.Value ? Color.FromHex("#94e1f2") : Color.FromHex("#f29d94"))));
|
||||||
|
}
|
||||||
|
|
||||||
args.PushMarkup(Loc.GetString("gun-magazine-examine", ("color", AmmoExamineColor), ("count", count)));
|
args.PushMarkup(Loc.GetString("gun-magazine-examine", ("color", AmmoExamineColor), ("count", count)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool TryTakeChamberEntity(EntityUid uid, [NotNullWhen(true)] out EntityUid? entity)
|
private bool TryTakeChamberEntity(EntityUid uid, [NotNullWhen(true)] out EntityUid? entity)
|
||||||
|
|||||||
@@ -14,8 +14,13 @@ public abstract partial class SharedGunSystem
|
|||||||
if (!args.IsInDetailsRange || !component.ShowExamineText)
|
if (!args.IsInDetailsRange || !component.ShowExamineText)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
args.PushMarkup(Loc.GetString("gun-selected-mode-examine", ("color", ModeExamineColor), ("mode", GetLocSelector(component.SelectedMode))));
|
using (args.PushGroup(nameof(GunComponent)))
|
||||||
args.PushMarkup(Loc.GetString("gun-fire-rate-examine", ("color", FireRateExamineColor), ("fireRate", $"{component.FireRate:0.0}")));
|
{
|
||||||
|
args.PushMarkup(Loc.GetString("gun-selected-mode-examine", ("color", ModeExamineColor),
|
||||||
|
("mode", GetLocSelector(component.SelectedMode))));
|
||||||
|
args.PushMarkup(Loc.GetString("gun-fire-rate-examine", ("color", FireRateExamineColor),
|
||||||
|
("fireRate", $"{component.FireRate:0.0}")));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetLocSelector(SelectiveFire mode)
|
private string GetLocSelector(SelectiveFire mode)
|
||||||
|
|||||||
@@ -15,18 +15,21 @@ public abstract class SharedWiresSystem : EntitySystem
|
|||||||
|
|
||||||
private void OnExamine(EntityUid uid, WiresPanelComponent component, ExaminedEvent args)
|
private void OnExamine(EntityUid uid, WiresPanelComponent component, ExaminedEvent args)
|
||||||
{
|
{
|
||||||
if (!component.Open)
|
using (args.PushGroup(nameof(WiresPanelComponent)))
|
||||||
{
|
{
|
||||||
args.PushMarkup(Loc.GetString("wires-panel-component-on-examine-closed"));
|
if (!component.Open)
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
args.PushMarkup(Loc.GetString("wires-panel-component-on-examine-open"));
|
|
||||||
|
|
||||||
if (TryComp<WiresPanelSecurityComponent>(uid, out var wiresPanelSecurity) &&
|
|
||||||
wiresPanelSecurity.Examine != null)
|
|
||||||
{
|
{
|
||||||
args.PushMarkup(Loc.GetString(wiresPanelSecurity.Examine));
|
args.PushMarkup(Loc.GetString("wires-panel-component-on-examine-closed"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
args.PushMarkup(Loc.GetString("wires-panel-component-on-examine-open"));
|
||||||
|
|
||||||
|
if (TryComp<WiresPanelSecurityComponent>(uid, out var wiresPanelSecurity) &&
|
||||||
|
wiresPanelSecurity.Examine != null)
|
||||||
|
{
|
||||||
|
args.PushMarkup(Loc.GetString(wiresPanelSecurity.Examine));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user