forked from SpaceStation14-Shenanigans/Monolith
Compare commits
197 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| da767f3e0f | |||
| 5eeaf3a4e3 | |||
| c5f5cbc8ee | |||
| 50d4130f75 | |||
| 74cd863daf | |||
| 424dd518e0 | |||
| 03d32fc523 | |||
| d325a536b1 | |||
| 44da153488 | |||
| df87fc784a | |||
| 7a73c806de | |||
| 2bbfb35ecc | |||
| ed4e303bf3 | |||
| c6cd221511 | |||
| 906f32b00b | |||
| 099b943c30 | |||
| 1c961e5300 | |||
| e74ffc3178 | |||
| c6c036a27f | |||
| 28e3584a67 | |||
| 78c94ddbc4 | |||
| cef95a03bf | |||
| bd3a35ee64 | |||
| 0b50c919e4 | |||
| 7c5ab0b1cd | |||
| eb5e54d485 | |||
| 59f1950bce | |||
| 617eca8397 | |||
| afcf994545 | |||
| 5aaee26a09 | |||
| fb3c49bd09 | |||
| 2c381cbcd0 | |||
| aa354fd8d7 | |||
| f4e3ac2478 | |||
| 31de4af5e2 | |||
| 5e67e63032 | |||
| 274b9d0a68 | |||
| 2c2edc8460 | |||
| d98c2dd0a7 | |||
| a65d7b6a5d | |||
| f3919fafc1 | |||
| 974b78863b | |||
| 1654bd5cf8 | |||
| d353667f97 | |||
| 47116d8ba7 | |||
| 9bd6d5f3f2 | |||
| 1dc696deb6 | |||
| f2df23dc81 | |||
| 76d6ea96e0 | |||
| 93ba265e00 | |||
| 16f73ec031 | |||
| 9d3b0778b3 | |||
| 32b15951e2 | |||
| 7a0f0d04c5 | |||
| bcce8e67a3 | |||
| 5afcdd9379 | |||
| 01c7ea464a | |||
| 55f6108312 | |||
| 8be27c1658 | |||
| 4df38cc9cc | |||
| 8c0d2a50df | |||
| 2d8105de13 | |||
| 01bb73bf56 | |||
| fb09b866f2 | |||
| 0458a500ff | |||
| 4334b07093 | |||
| ad2dd99a9b | |||
| f11c83a96e | |||
| 36d1740829 | |||
| 1e201bb8d2 | |||
| c7a34dfc22 | |||
| e366c4d7cc | |||
| bc0151e540 | |||
| b2307660de | |||
| 5d5f6b4654 | |||
| 165f9950b5 | |||
| ef9858936d | |||
| d0a95f5d8b | |||
| ee386b0633 | |||
| de38cc18ef | |||
| ca928bdc83 | |||
| cee6ce9566 | |||
| 984a2c9b71 | |||
| 548e9eccb6 | |||
| cd817abd2c | |||
| f276df8fe9 | |||
| dd323be01d | |||
| 0cf9b35f08 | |||
| 114a09f290 | |||
| dc4b50e71e | |||
| c405c32c89 | |||
| 34ff30a736 | |||
| c8e162baa1 | |||
| ffcbc32c43 | |||
| 351b225102 | |||
| 496432881e | |||
| 9fd2a7b5af | |||
| 8972408ec1 | |||
| 5798b57788 | |||
| ec88162ac0 | |||
| 3992aa846f | |||
| 4b62f35f10 | |||
| cc1c91f39f | |||
| c5241854ce | |||
| d02895a50f | |||
| c41d005cf4 | |||
| 013f57a73d | |||
| c3f687a493 | |||
| f837710be1 | |||
| 7b00d623e0 | |||
| dafbb5f3d8 | |||
| d4487d9a5a | |||
| 7b9f602c55 | |||
| 97509dd3b6 | |||
| 55c2a03ea4 | |||
| 543c19645f | |||
| da8b19dd05 | |||
| 4fc44d3a9c | |||
| 55688cc9e0 | |||
| 5357469644 | |||
| 6040135534 | |||
| 52649a871e | |||
| fef33511d8 | |||
| fec5bfce0a | |||
| 11f82f95d3 | |||
| 3dbad97455 | |||
| a193ab828e | |||
| c75083140d | |||
| 106f9b6d28 | |||
| fe24fc22bc | |||
| 85c9636003 | |||
| a1d2f4dcbc | |||
| 3381fe165c | |||
| a913c35b21 | |||
| 0706b759d4 | |||
| 73a91c0b0a | |||
| 9e390680bd | |||
| d3d391f5a0 | |||
| a6506c7f46 | |||
| 958421b6c9 | |||
| c513938ed9 | |||
| a6431c9bab | |||
| f3390a81cc | |||
| 6ba80381cc | |||
| ef095aec88 | |||
| d02738089c | |||
| b9f0de8576 | |||
| 5a6d4b74b1 | |||
| 1ac13bf597 | |||
| 90ee912816 | |||
| 27665829e6 | |||
| e1459b0d43 | |||
| 395d334dd7 | |||
| 75e166e9b3 | |||
| d987cfe88d | |||
| a942f3e7b1 | |||
| 4108933834 | |||
| 6af6f3b386 | |||
| 9a590069d2 | |||
| a60321f201 | |||
| dfabb71045 | |||
| ce034c3f19 | |||
| 79c9dee112 | |||
| 6a048def33 | |||
| e41ef48441 | |||
| 27e7b2f70a | |||
| 2bd317dadb | |||
| 1145822797 | |||
| 27dca32ef3 | |||
| 4bdad8f6ee | |||
| 38ebc2699c | |||
| 82f75ff37f | |||
| c84cde54cb | |||
| f0c6624762 | |||
| 277ad91140 | |||
| b9419b25a1 | |||
| e1a5488f14 | |||
| d9b46ca6dc | |||
| a672e9bd28 | |||
| 2a5fe8fe6a | |||
| e069f2ba9d | |||
| db3675b3e8 | |||
| 79bf0fec68 | |||
| 41b3fb9113 | |||
| 7cd749dfa6 | |||
| eb44deeeda | |||
| 7035e752a9 | |||
| 2fdd1cd573 | |||
| 6c4101e0c0 | |||
| 5f90433697 | |||
| 9f54374593 | |||
| 5272291275 | |||
| 4a0f4cec3a | |||
| 5d68716090 | |||
| a4b1a5317c | |||
| ee48853724 | |||
| a8651f6457 |
@@ -1,5 +1,5 @@
|
||||
name: PR Changelogs
|
||||
concurrency: commit_action
|
||||
concurrency: commit_action-${{ github.event.pull_request.base.ref }} # Mono
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [closed]
|
||||
@@ -16,11 +16,11 @@ jobs:
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Checkout Master
|
||||
- name: Checkout Base Branch # Mono
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
token: ${{ secrets.BOT_TOKEN }}
|
||||
ref: "${{ vars.CHANGELOG_BRANCH }}"
|
||||
ref: "${{ github.event.pull_request.base.ref }}" # Mono
|
||||
|
||||
- name: Setup Git
|
||||
run: |
|
||||
@@ -47,9 +47,9 @@ jobs:
|
||||
|
||||
- name: Commit Changelog
|
||||
run: |
|
||||
git pull origin main
|
||||
git pull origin "${{ github.event.pull_request.base.ref }}"
|
||||
git add "${{ env.CHANGELOG_DIR }}"
|
||||
git commit -m "Automated Changelog (#${{ env.PR_NUMBER }})"
|
||||
git push
|
||||
git push origin "${{ github.event.pull_request.base.ref }}"
|
||||
shell: bash
|
||||
continue-on-error: true
|
||||
|
||||
Vendored
+53
-7
@@ -13,6 +13,26 @@
|
||||
"console": "internalConsole",
|
||||
"stopAtEntry": false
|
||||
},
|
||||
{
|
||||
"name": "Client - Tools",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build - Tools",
|
||||
"program": "${workspaceFolder}/bin/Content.Client/Content.Client.dll",
|
||||
"args": [],
|
||||
"console": "internalConsole",
|
||||
"stopAtEntry": false
|
||||
},
|
||||
{
|
||||
"name": "Client - Release",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build - Release",
|
||||
"program": "${workspaceFolder}/bin/Content.Client/Content.Client.dll",
|
||||
"args": [],
|
||||
"console": "internalConsole",
|
||||
"stopAtEntry": false
|
||||
},
|
||||
{
|
||||
"name": "Client (Compatibility renderer)",
|
||||
"type": "coreclr",
|
||||
@@ -31,6 +51,26 @@
|
||||
"console": "integratedTerminal",
|
||||
"stopAtEntry": false
|
||||
},
|
||||
{
|
||||
"name": "Server - Tools",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build - Tools",
|
||||
"program": "${workspaceFolder}/bin/Content.Server/Content.Server.dll",
|
||||
"args": [""],
|
||||
"console": "integratedTerminal",
|
||||
"stopAtEntry": false
|
||||
},
|
||||
{
|
||||
"name": "Server - Release",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build - Release",
|
||||
"program": "${workspaceFolder}/bin/Content.Server/Content.Server.dll",
|
||||
"args": [""],
|
||||
"console": "integratedTerminal",
|
||||
"stopAtEntry": false
|
||||
},
|
||||
{
|
||||
"name": "YAML Linter",
|
||||
"type": "coreclr",
|
||||
@@ -40,7 +80,7 @@
|
||||
"cwd": "${workspaceFolder}/Content.YAMLLinter",
|
||||
"console": "internalConsole",
|
||||
"stopAtEntry": false
|
||||
}
|
||||
},
|
||||
],
|
||||
"compounds": [
|
||||
{
|
||||
@@ -51,14 +91,21 @@
|
||||
],
|
||||
"preLaunchTask": "build"
|
||||
},
|
||||
// Frontier begin
|
||||
{
|
||||
"name": "Server/Client (Release)",
|
||||
"name": "Server/Client - Tools",
|
||||
"configurations": [
|
||||
"Server",
|
||||
"Client"
|
||||
"Server - Tools",
|
||||
"Client - Tools"
|
||||
],
|
||||
"preLaunchTask": "build-release"
|
||||
"preLaunchTask": "build - Tools"
|
||||
},
|
||||
{
|
||||
"name": "Server/Client - Release",
|
||||
"configurations": [
|
||||
"Server - Release",
|
||||
"Client - Release"
|
||||
],
|
||||
"preLaunchTask": "build - Release"
|
||||
},
|
||||
{
|
||||
"name": "Server/Client (No Build)",
|
||||
@@ -67,6 +114,5 @@
|
||||
"Client"
|
||||
]
|
||||
}
|
||||
// Frontier end
|
||||
]
|
||||
}
|
||||
|
||||
Vendored
+26
-6
@@ -21,26 +21,46 @@
|
||||
},
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
// Frontier begin
|
||||
{
|
||||
"label": "build-release",
|
||||
"label": "build - Tools",
|
||||
"command": "dotnet",
|
||||
"type": "shell",
|
||||
"args": [
|
||||
"build",
|
||||
"--configuration=Release", // Build in release mode. Note: --, not /. /configuration doesn't work, because Microsoft.
|
||||
"--configuration",
|
||||
"Tools",
|
||||
"/property:GenerateFullPaths=true", // Ask dotnet build to generate full paths for file names.
|
||||
"/consoleloggerparameters:NoSummary" // Do not generate summary otherwise it leads to duplicate errors in Problems panel
|
||||
"/consoleloggerparameters:'ForceNoAlign;NoSummary'", // Do not generate summary otherwise it leads to duplicate errors in Problems panel
|
||||
],
|
||||
"group": {
|
||||
"kind": "build"
|
||||
"kind": "build",
|
||||
"isDefault": false
|
||||
},
|
||||
"presentation": {
|
||||
"reveal": "silent"
|
||||
},
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "build - Release",
|
||||
"command": "dotnet",
|
||||
"type": "shell",
|
||||
"args": [
|
||||
"build",
|
||||
"--configuration",
|
||||
"Release",
|
||||
"/property:GenerateFullPaths=true", // Ask dotnet build to generate full paths for file names.
|
||||
"/consoleloggerparameters:'ForceNoAlign;NoSummary'", // Do not generate summary otherwise it leads to duplicate errors in Problems panel
|
||||
],
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": false
|
||||
},
|
||||
"presentation": {
|
||||
"reveal": "silent"
|
||||
},
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
// Frontier end
|
||||
{
|
||||
"label": "build-yaml-linter",
|
||||
"command": "dotnet",
|
||||
|
||||
@@ -32,6 +32,10 @@ public sealed class CharacterInfoSystem : EntitySystem
|
||||
private void OnCharacterInfoEvent(CharacterInfoEvent msg, EntitySessionEventArgs args)
|
||||
{
|
||||
var entity = GetEntity(msg.NetEntity);
|
||||
// Mono - fix
|
||||
if (TerminatingOrDeleted(entity))
|
||||
return;
|
||||
|
||||
var data = new CharacterData(entity, msg.JobTitle, msg.Objectives, msg.Briefing, Name(entity));
|
||||
|
||||
OnCharacterUpdate?.Invoke(data);
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<Control xmlns="https://spacestation14.io">
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<Label Name="TitleLabel" Access="Public" />
|
||||
<Label Name="ExampleLabel" Access="Public" />
|
||||
<ColorSelectorSliders Name="Slider" Access="Public" HorizontalExpand="True" />
|
||||
</BoxContainer>
|
||||
</Control>
|
||||
@@ -0,0 +1,31 @@
|
||||
using Content.Client.Options.UI;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface;
|
||||
|
||||
namespace Content.Client.Options.UI;
|
||||
|
||||
/// <summary>
|
||||
/// Standard UI control used for color sliders in the options menu. Intended for use with <see cref="OptionsTabControlRow"/>.
|
||||
/// </summary>
|
||||
/// <seealso cref="OptionsTabControlRow.AddOptionColorSlider"/>
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class OptionColorSlider : Control
|
||||
{
|
||||
/// <summary>
|
||||
/// The text describing what this slider affects.
|
||||
/// </summary>
|
||||
public string? Title
|
||||
{
|
||||
get => TitleLabel.Text;
|
||||
set => TitleLabel.Text = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The example text showing the current color of the slider.
|
||||
/// </summary>
|
||||
public string? Example
|
||||
{
|
||||
get => ExampleLabel.Text;
|
||||
set => ExampleLabel.Text = value;
|
||||
}
|
||||
}
|
||||
@@ -143,6 +143,19 @@ public sealed partial class OptionsTabControlRow : Control
|
||||
return AddOption(new OptionSliderIntCVar(this, _cfg, cVar, slider, min, max, format ?? FormatInt));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a color slider option, backed by a simple string CVar.
|
||||
/// </summary>
|
||||
/// <param name="cVar">The CVar represented by the slider.</param>
|
||||
/// <param name="slider">The UI control for the option.</param>
|
||||
/// <returns>The option instance backing the added option.</returns>
|
||||
public OptionColorSliderCVar AddOptionColorSlider(
|
||||
CVarDef<string> cVar,
|
||||
OptionColorSlider slider)
|
||||
{
|
||||
return AddOption(new OptionColorSliderCVar(this, _cfg, cVar, slider));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a drop-down option, backed by a CVar.
|
||||
/// </summary>
|
||||
@@ -518,6 +531,54 @@ public sealed class OptionSliderFloatCVar : BaseOptionCVar<float>
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class OptionColorSliderCVar : BaseOptionCVar<string>
|
||||
{
|
||||
private readonly OptionColorSlider _slider;
|
||||
|
||||
protected override string Value
|
||||
{
|
||||
get => _slider.Slider.Color.ToHex();
|
||||
set
|
||||
{
|
||||
_slider.Slider.Color = Color.FromHex(value);
|
||||
UpdateLabelColor();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of this type.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// It is generally more convenient to call overloads on <see cref="OptionsTabControlRow"/>
|
||||
/// such as <see cref="OptionsTabControlRow.AddOptionPercentSlider"/> instead of instantiating this type directly.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <param name="controller">The control row that owns this option.</param>
|
||||
/// <param name="cfg">The configuration manager to get and set values from.</param>
|
||||
/// <param name="cVar">The CVar that is being controlled by this option.</param>
|
||||
/// <param name="slider">The UI control for the option.</param>
|
||||
public OptionColorSliderCVar(
|
||||
OptionsTabControlRow controller,
|
||||
IConfigurationManager cfg,
|
||||
CVarDef<string> cVar,
|
||||
OptionColorSlider slider) : base(controller, cfg, cVar)
|
||||
{
|
||||
_slider = slider;
|
||||
|
||||
slider.Slider.OnColorChanged += _ =>
|
||||
{
|
||||
ValueChanged();
|
||||
UpdateLabelColor();
|
||||
};
|
||||
}
|
||||
|
||||
private void UpdateLabelColor()
|
||||
{
|
||||
_slider.ExampleLabel.FontColorOverride = Color.FromHex(Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implementation of a CVar option that simply corresponds with an integer <see cref="OptionSlider"/>.
|
||||
/// </summary>
|
||||
|
||||
@@ -12,6 +12,10 @@
|
||||
<ui:OptionSlider Name="SpeechBubbleTextOpacitySlider" Title="{Loc 'ui-options-speech-bubble-text-opacity'}" />
|
||||
<ui:OptionSlider Name="SpeechBubbleSpeakerOpacitySlider" Title="{Loc 'ui-options-speech-bubble-speaker-opacity'}" />
|
||||
<ui:OptionSlider Name="SpeechBubbleBackgroundOpacitySlider" Title="{Loc 'ui-options-speech-bubble-background-opacity'}" />
|
||||
<CheckBox Name="AutoFillHighlightsCheckBox" Text="{Loc 'ui-options-auto-fill-highlights'}" />
|
||||
<ui:OptionColorSlider Name="HighlightsColorSlider"
|
||||
Title="{Loc 'ui-options-highlights-color'}"
|
||||
Example="{Loc 'ui-options-highlights-color-example'}"/>
|
||||
</BoxContainer>
|
||||
</ScrollContainer>
|
||||
<ui:OptionsTabControlRow Name="Control" Access="Public" />
|
||||
|
||||
@@ -20,6 +20,8 @@ public sealed partial class AccessibilityTab : Control
|
||||
Control.AddOptionPercentSlider(CCVars.SpeechBubbleTextOpacity, SpeechBubbleTextOpacitySlider);
|
||||
Control.AddOptionPercentSlider(CCVars.SpeechBubbleSpeakerOpacity, SpeechBubbleSpeakerOpacitySlider);
|
||||
Control.AddOptionPercentSlider(CCVars.SpeechBubbleBackgroundOpacity, SpeechBubbleBackgroundOpacitySlider);
|
||||
Control.AddOptionCheckBox(CCVars.ChatAutoFillHighlights, AutoFillHighlightsCheckBox);
|
||||
Control.AddOptionColorSlider(CCVars.ChatHighlightsColor, HighlightsColorSlider);
|
||||
|
||||
Control.Initialize();
|
||||
}
|
||||
|
||||
@@ -33,9 +33,22 @@ public sealed partial class BorgSelectTypeMenu : FancyWindow
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
foreach (var borgType in _prototypeManager.EnumeratePrototypes<BorgTypePrototype>().OrderBy(PrototypeName))
|
||||
// Goobstation: Customizable borgs sprites
|
||||
ConfirmTypeButton.OnPressed += ConfirmButtonPressed;
|
||||
HelpGuidebookIds = GuidebookEntries;
|
||||
|
||||
SubtypeSelection.SubtypeSelected += () =>
|
||||
ConfirmTypeButton.Disabled = false;
|
||||
}
|
||||
|
||||
// foreach (var borgType in _prototypeManager.EnumeratePrototypes<BorgTypePrototype>().OrderBy(PrototypeName))
|
||||
// Mono: Selectable borg whitelist
|
||||
public void Populate(IReadOnlyList<ProtoId<BorgTypePrototype>> whitelist)
|
||||
{
|
||||
IEnumerable<BorgTypePrototype> types = whitelist.Select(id => _prototypeManager.Index(id)).OrderBy(PrototypeName);
|
||||
foreach (var borgType in types)
|
||||
// Mono: Selectable borg whitelist end
|
||||
{
|
||||
// Goobstation-Start: Customizable borgs sprites
|
||||
var chassisList = new EntityPrototypeView
|
||||
{
|
||||
Scale = new Vector2(2, 2),
|
||||
@@ -49,13 +62,6 @@ public sealed partial class BorgSelectTypeMenu : FancyWindow
|
||||
};
|
||||
SelectionsContainer.AddChild(chassisList);
|
||||
}
|
||||
|
||||
ConfirmTypeButton.OnPressed += ConfirmButtonPressed;
|
||||
HelpGuidebookIds = GuidebookEntries;
|
||||
|
||||
|
||||
SubtypeSelection.SubtypeSelected += () =>
|
||||
ConfirmTypeButton.Disabled = false;
|
||||
// Goobstation-End: Customizable borgs sprites
|
||||
}
|
||||
|
||||
|
||||
@@ -23,8 +23,12 @@ public sealed class BorgSelectTypeUserInterface : BoundUserInterface
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
//Mono: Selectable borg whitelist
|
||||
EntMan.TryGetComponent<BorgSwitchableTypeComponent>(Owner, out var comp);
|
||||
var whitelist = comp?.TypeWhitelist ?? [];
|
||||
|
||||
_menu = this.CreateWindow<BorgSelectTypeMenu>();
|
||||
_menu.Populate(whitelist); //Mono
|
||||
_menu.ConfirmedBorgType += (prototype, subtype) => SendPredictedMessage(new BorgSelectTypeMessage(prototype, subtype));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,18 +46,15 @@ public sealed class BorgSwitchableTypeSystem : SharedBorgSwitchableTypeSystem
|
||||
{
|
||||
if (TryComp(entity, out SpriteComponent? sprite))
|
||||
{
|
||||
_sprite.LayerSetRsiState((entity, sprite), BorgVisualLayers.Body, prototype.SpriteBodyState);
|
||||
_sprite.LayerSetRsiState((entity, sprite), BorgVisualLayers.Light, prototype.SpriteBodyState);
|
||||
_sprite.LayerSetRsiState((entity, sprite), BorgVisualLayers.LightStatus, prototype.SpriteBodyState);
|
||||
|
||||
var rsiPath = SpriteSpecifierSerializer.TextureRoot / subtypePrototype.SpritePath;
|
||||
if (_resourceCache.TryGetResource<RSIResource>(rsiPath, out var resource))
|
||||
{
|
||||
_sprite.LayerSetRsi((entity, sprite), BorgVisualLayers.Body, resource.RSI);
|
||||
_sprite.LayerSetRsi((entity, sprite), BorgVisualLayers.Light, resource.RSI);
|
||||
_sprite.LayerSetRsi((entity, sprite), BorgVisualLayers.LightStatus, resource.RSI);
|
||||
_sprite.LayerSetRsi((entity, sprite), BorgVisualLayers.Body, resource.RSI, prototype.SpriteBodyState);
|
||||
_sprite.LayerSetRsi((entity, sprite), BorgVisualLayers.Light, resource.RSI, prototype.SpriteBodyState);
|
||||
_sprite.LayerSetRsi((entity, sprite), BorgVisualLayers.LightStatus, resource.RSI, prototype.SpriteToggleLightState);
|
||||
}
|
||||
_sprite.LayerSetRsiState((entity, sprite), BorgVisualLayers.Body, prototype.SpriteBodyState);
|
||||
_sprite.LayerSetRsiState((entity, sprite), BorgVisualLayers.LightStatus, prototype.SpriteBodyState);
|
||||
_sprite.LayerSetRsiState((entity, sprite), BorgVisualLayers.LightStatus, prototype.SpriteToggleLightState);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,264 @@
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controllers;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Client.CharacterInfo;
|
||||
using static Content.Client.CharacterInfo.CharacterInfoSystem;
|
||||
|
||||
namespace Content.Client.UserInterface.Systems.Chat;
|
||||
|
||||
public sealed partial class ChatUIController : IOnSystemChanged<CharacterInfoSystem>
|
||||
{
|
||||
[Dependency] private readonly ILocalizationManager _loc = default!;
|
||||
[UISystemDependency] private readonly CharacterInfoSystem _characterInfo = default!;
|
||||
|
||||
private static readonly Regex StartDoubleQuote = new("\"$");
|
||||
private static readonly Regex EndDoubleQuote = new("^\"|(?<=^@)\"");
|
||||
private static readonly Regex StartAtSign = new("^@");
|
||||
|
||||
|
||||
private readonly List<string> _highlights = new();
|
||||
private readonly List<string> _autoFillRawKeywords = new();
|
||||
|
||||
private string? _highlightsColor;
|
||||
private bool _autoFillHighlightsEnabled;
|
||||
private bool _charInfoIsAttach = false;
|
||||
private string? _currentCharacterName;
|
||||
|
||||
|
||||
public event Action<string>? HighlightsUpdated;
|
||||
public event Action<string>? AutoFillUpdated;
|
||||
|
||||
private void InitializeHighlights()
|
||||
{
|
||||
_config.OnValueChanged(CCVars.ChatAutoFillHighlights, (value) => { _autoFillHighlightsEnabled = value; }, true);
|
||||
_config.OnValueChanged(CCVars.ChatHighlightsColor, (value) => { _highlightsColor = value; }, true);
|
||||
|
||||
var cvar = _config.GetCVar(CCVars.ChatHighlights);
|
||||
}
|
||||
|
||||
public void OnSystemLoaded(CharacterInfoSystem system)
|
||||
{
|
||||
system.OnCharacterUpdate += OnCharacterUpdated;
|
||||
}
|
||||
|
||||
public void OnSystemUnloaded(CharacterInfoSystem system)
|
||||
{
|
||||
system.OnCharacterUpdate -= OnCharacterUpdated;
|
||||
}
|
||||
|
||||
private void UpdateAutoFillHighlights()
|
||||
{
|
||||
_currentCharacterName = null;
|
||||
_autoFillRawKeywords.Clear();
|
||||
_highlights.Clear();
|
||||
AutoFillUpdated?.Invoke("");
|
||||
HighlightsUpdated?.Invoke("");
|
||||
|
||||
_charInfoIsAttach = true;
|
||||
_characterInfo.RequestCharacterInfo();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves the user's custom keywords for the given character into the CVar,
|
||||
/// then rebuilds the active highlight list.
|
||||
/// Called when the user submits keywords from the popup.
|
||||
/// </summary>
|
||||
public void UpdateHighlights(string customKeywords)
|
||||
{
|
||||
if (_currentCharacterName == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SaveCustomKeywords(_currentCharacterName, customKeywords);
|
||||
RebuildHighlightsList(customKeywords);
|
||||
HighlightsUpdated?.Invoke(customKeywords);
|
||||
}
|
||||
|
||||
private void OnCharacterUpdated(CharacterData data)
|
||||
{
|
||||
|
||||
if (!_charInfoIsAttach)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var (_, job, _, _, entityName) = data;
|
||||
_currentCharacterName = entityName;
|
||||
|
||||
|
||||
_autoFillRawKeywords.Clear();
|
||||
var autoFillDisplay = "";
|
||||
|
||||
if (_autoFillHighlightsEnabled)
|
||||
{
|
||||
|
||||
// Special rules for names can be added here
|
||||
|
||||
var nameHighlights = "@" + entityName;
|
||||
|
||||
// Split on spaces first (handles any number of space-separated words).
|
||||
if (nameHighlights.Contains(' '))
|
||||
nameHighlights = nameHighlights.Replace(" ", "\n@");
|
||||
|
||||
// Handle hyphenated tokens: single hyphen splits normally (e.g. "First-Last"),
|
||||
// multiple hyphens use the lizard rule — keep only first and last part (e.g. "Eats-The-Food" → @Eats @Food).
|
||||
var dashParts = nameHighlights.Split('-');
|
||||
if (dashParts.Length == 2)
|
||||
nameHighlights = nameHighlights.Replace("-", "\n@");
|
||||
else if (dashParts.Length > 2)
|
||||
nameHighlights = dashParts[0] + "\n@" + dashParts[^1];
|
||||
|
||||
|
||||
foreach (var token in nameHighlights.Split('\n', StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
_autoFillRawKeywords.Add(token);
|
||||
}
|
||||
|
||||
var jobKey = job.Replace(' ', '-').ToLower();
|
||||
|
||||
if (_loc.TryGetString($"highlights-{jobKey}", out var jobMatches))
|
||||
{
|
||||
foreach (var jobWord in jobMatches.Replace(", ", "\n").Split('\n', StringSplitOptions.RemoveEmptyEntries))
|
||||
_autoFillRawKeywords.Add(jobWord);
|
||||
}
|
||||
autoFillDisplay = string.Join("\n", _autoFillRawKeywords);
|
||||
}
|
||||
|
||||
var customKeywords = LoadCustomKeywords(entityName);
|
||||
|
||||
RebuildHighlightsList(customKeywords);
|
||||
|
||||
AutoFillUpdated?.Invoke(autoFillDisplay);
|
||||
HighlightsUpdated?.Invoke(customKeywords);
|
||||
_charInfoIsAttach = false;
|
||||
}
|
||||
|
||||
|
||||
private string LoadCustomKeywords(string characterName)
|
||||
{
|
||||
var cvar = _config.GetCVar(CCVars.ChatHighlights);
|
||||
if (string.IsNullOrEmpty(cvar))
|
||||
return "";
|
||||
|
||||
// Shouldn't be needed as no-one should have data by the time this rolls out but we never know
|
||||
if (!cvar.Contains("||"))
|
||||
{
|
||||
return cvar;
|
||||
}
|
||||
|
||||
foreach (var line in cvar.Split('\n', StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
var sep = line.IndexOf("||", StringComparison.Ordinal);
|
||||
if (sep < 0)
|
||||
continue;
|
||||
|
||||
if (line[..sep] == characterName)
|
||||
return DecodeKeywords(line[(sep + 2)..]);
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
private void SaveCustomKeywords(string characterName, string customKeywords)
|
||||
{
|
||||
var cvar = _config.GetCVar(CCVars.ChatHighlights);
|
||||
|
||||
var entries = new Dictionary<string, string>();
|
||||
if (!string.IsNullOrEmpty(cvar) && cvar.Contains("||"))
|
||||
{
|
||||
foreach (var line in cvar.Split('\n', StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
var sep = line.IndexOf("||", StringComparison.Ordinal);
|
||||
if (sep < 0)
|
||||
continue;
|
||||
entries[line[..sep]] = line[(sep + 2)..];
|
||||
}
|
||||
}
|
||||
|
||||
entries[characterName] = EncodeKeywords(customKeywords);
|
||||
|
||||
var sb = new StringBuilder();
|
||||
foreach (var (name, encoded) in entries)
|
||||
sb.Append(name).Append("||").Append(encoded).Append('\n');
|
||||
|
||||
var newValue = sb.ToString().TrimEnd('\n');
|
||||
_config.SetCVar(CCVars.ChatHighlights, newValue);
|
||||
_config.SaveToFile();
|
||||
}
|
||||
|
||||
private static string EncodeKeywords(string raw)
|
||||
{
|
||||
return raw
|
||||
.Replace(@"\", @"\\")
|
||||
.Replace("|", @"\|")
|
||||
.Replace("\n", @"\n");
|
||||
}
|
||||
|
||||
private static string DecodeKeywords(string encoded)
|
||||
{
|
||||
var sb = new StringBuilder(encoded.Length);
|
||||
for (var i = 0; i < encoded.Length; i++)
|
||||
{
|
||||
if (encoded[i] == '\\' && i + 1 < encoded.Length)
|
||||
{
|
||||
switch (encoded[i + 1])
|
||||
{
|
||||
case 'n': sb.Append('\n'); i++; break;
|
||||
case '|': sb.Append('|'); i++; break;
|
||||
case '\\': sb.Append('\\'); i++; break;
|
||||
default: sb.Append(encoded[i]); break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append(encoded[i]);
|
||||
}
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private void RebuildHighlightsList(string customRaw)
|
||||
{
|
||||
_highlights.Clear();
|
||||
|
||||
foreach (var raw in _autoFillRawKeywords)
|
||||
_highlights.Add(ProcessKeyword(raw));
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(customRaw))
|
||||
{
|
||||
foreach (var raw in customRaw.Split('\n', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
|
||||
_highlights.Add(ProcessKeyword(raw));
|
||||
}
|
||||
|
||||
_highlights.Sort((x, y) => y.Length.CompareTo(x.Length));
|
||||
}
|
||||
|
||||
private string ProcessKeyword(string raw)
|
||||
{
|
||||
// Replace every "\" to prevent "\n", "\0", etc. in regex.
|
||||
var keyword = raw.Replace(@"\", @"\\");
|
||||
|
||||
// Escape special regex characters.
|
||||
keyword = Regex.Escape(keyword);
|
||||
|
||||
// Re-escape "[" for markup-adjacent positions.
|
||||
keyword = keyword.Replace(@"\[", @"\\\[");
|
||||
|
||||
// words in double quotes will only be hightlighted as unique, not within another word
|
||||
if (keyword.Any(c => c == '"'))
|
||||
{
|
||||
keyword = StartDoubleQuote.Replace(keyword, "(?!\\w)");
|
||||
keyword = EndDoubleQuote.Replace(keyword, "(?<!\\w)");
|
||||
}
|
||||
|
||||
// Make it so it doesn't hightlight your own name when you are talking
|
||||
keyword = StartAtSign.Replace(keyword, @"(?<=\[BubbleContent\].*)");
|
||||
|
||||
return keyword;
|
||||
}
|
||||
}
|
||||
@@ -44,7 +44,7 @@ using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client.UserInterface.Systems.Chat;
|
||||
|
||||
public sealed class ChatUIController : UIController
|
||||
public sealed partial class ChatUIController : UIController
|
||||
{
|
||||
[Dependency] private readonly IClientAdminManager _admin = default!;
|
||||
[Dependency] private readonly IChatManager _manager = default!;
|
||||
@@ -248,6 +248,8 @@ public sealed class ChatUIController : UIController
|
||||
|
||||
_config.OnValueChanged(CCVars.ChatWindowOpacity, OnChatWindowOpacityChanged);
|
||||
|
||||
InitializeHighlights();
|
||||
|
||||
}
|
||||
|
||||
public void OnScreenLoad()
|
||||
@@ -434,6 +436,7 @@ public sealed class ChatUIController : UIController
|
||||
private void OnAttachedChanged(EntityUid uid)
|
||||
{
|
||||
UpdateChannelPermissions();
|
||||
UpdateAutoFillHighlights();
|
||||
}
|
||||
|
||||
private void AddSpeechBubble(ChatMessage msg, SpeechBubble.SpeechType speechType)
|
||||
@@ -877,6 +880,11 @@ public sealed class ChatUIController : UIController
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var highlight in _highlights)
|
||||
{
|
||||
msg.WrappedMessage = SharedChatSystem.InjectTagAroundString(msg, highlight, "color", _highlightsColor);
|
||||
}
|
||||
|
||||
// Log all incoming chat to repopulate when filter is un-toggled
|
||||
if (!msg.HideChat)
|
||||
{
|
||||
@@ -912,7 +920,6 @@ public sealed class ChatUIController : UIController
|
||||
case ChatChannel.Dead:
|
||||
if (_ghost is not {IsGhost: true})
|
||||
break;
|
||||
|
||||
AddSpeechBubble(msg, SpeechBubble.SpeechType.Say);
|
||||
break;
|
||||
|
||||
|
||||
@@ -1,10 +1,30 @@
|
||||
<controls:ChannelFilterPopup
|
||||
xmlns="https://spacestation14.io"
|
||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Systems.Chat.Controls">
|
||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Systems.Chat.Controls"
|
||||
xmlns:graphics="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client">
|
||||
<PanelContainer Name="FilterPopupPanel" StyleClasses="BorderedWindowPanel">
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Control MinSize="4 0"/>
|
||||
<BoxContainer Name="FilterVBox" MinWidth="110" Margin="0 10" Orientation="Vertical" SeparationOverride="4"/>
|
||||
<BoxContainer Name="HighlightsVBox" MinWidth="120" Margin="0 10" Orientation="Vertical" SeparationOverride="4">
|
||||
<BoxContainer Name="AutoFillVBox" Orientation="Vertical" SeparationOverride="2" Visible="False">
|
||||
<Label Text="{Loc 'hud-chatbox-autofill-highlights'}"/>
|
||||
<PanelContainer>
|
||||
<PanelContainer.PanelOverride>
|
||||
<graphics:StyleBoxFlat BackgroundColor="#262736"/>
|
||||
</PanelContainer.PanelOverride>
|
||||
<RichTextLabel Name="AutoFillLabel" Margin="5 5"/>
|
||||
</PanelContainer>
|
||||
</BoxContainer>
|
||||
<Label Text="{Loc 'hud-chatbox-highlights'}"/>
|
||||
<PanelContainer>
|
||||
<PanelContainer.PanelOverride>
|
||||
<graphics:StyleBoxFlat BackgroundColor="#323446"/>
|
||||
</PanelContainer.PanelOverride>
|
||||
<TextEdit Name="HighlightEdit" MinHeight="150" Margin="5 5"/>
|
||||
</PanelContainer>
|
||||
<Button Name="HighlightButton" Text="{Loc 'hud-chatbox-highlights-button'}" ToolTip="{Loc 'hud-chatbox-highlights-tooltip'}"/>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
</controls:ChannelFilterPopup>
|
||||
|
||||
@@ -2,6 +2,7 @@ using Content.Shared.Chat;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Utility;
|
||||
using static Robust.Client.UserInterface.Controls.BaseButton;
|
||||
|
||||
namespace Content.Client.UserInterface.Systems.Chat.Controls;
|
||||
@@ -30,10 +31,13 @@ public sealed partial class ChannelFilterPopup : Popup
|
||||
private readonly Dictionary<ChatChannel, ChannelFilterCheckbox> _filterStates = new();
|
||||
|
||||
public event Action<ChatChannel, bool>? OnChannelFilter;
|
||||
public event Action<string>? OnNewHighlights;
|
||||
|
||||
public ChannelFilterPopup()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
HighlightButton.OnPressed += HighlightsEntered;
|
||||
HighlightEdit.Placeholder = new Rope.Leaf(Loc.GetString("hud-chatbox-highlights-placeholder"));
|
||||
}
|
||||
|
||||
public bool IsActive(ChatChannel channel)
|
||||
@@ -95,4 +99,36 @@ public sealed partial class ChannelFilterPopup : Popup
|
||||
if (_filterStates.TryGetValue(channel, out var checkbox))
|
||||
checkbox.UpdateUnreadCount(unread);
|
||||
}
|
||||
|
||||
// Highlight
|
||||
|
||||
/// <summary>
|
||||
/// Updates the read-only auto-fill section with name/job tokens.
|
||||
/// </summary>
|
||||
public void UpdateAutoFill(string autoFillKeywords)
|
||||
{
|
||||
AutoFillVBox.Visible = !string.IsNullOrEmpty(autoFillKeywords);
|
||||
if (string.IsNullOrEmpty(autoFillKeywords))
|
||||
return;
|
||||
|
||||
var msg = new FormattedMessage();
|
||||
var lines = autoFillKeywords.Split('\n', StringSplitOptions.RemoveEmptyEntries);
|
||||
for (var i = 0; i < lines.Length; i++)
|
||||
{
|
||||
if (i > 0) msg.PushNewline();
|
||||
msg.AddText(lines[i]);
|
||||
}
|
||||
AutoFillLabel.SetMessage(msg);
|
||||
}
|
||||
|
||||
public void UpdateHighlights(string highlights)
|
||||
{
|
||||
HighlightEdit.TextRope = new Rope.Leaf(highlights);
|
||||
}
|
||||
|
||||
private void HighlightsEntered(ButtonEventArgs _args)
|
||||
{
|
||||
OnNewHighlights?.Invoke(Rope.Collapse(HighlightEdit.TextRope));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -47,9 +47,12 @@ public partial class ChatBox : UIWidget
|
||||
ChatInput.Input.OnFocusExit += OnFocusExit;
|
||||
ChatInput.ChannelSelector.OnChannelSelect += OnChannelSelect;
|
||||
ChatInput.FilterButton.Popup.OnChannelFilter += OnChannelFilter;
|
||||
ChatInput.FilterButton.Popup.OnNewHighlights += OnNewHighlights;
|
||||
|
||||
_controller = UserInterfaceManager.GetUIController<ChatUIController>();
|
||||
_controller.MessageAdded += OnMessageAdded;
|
||||
_controller.HighlightsUpdated += OnHighlightsUpdated;
|
||||
_controller.AutoFillUpdated += OnAutoFillUpdated;
|
||||
_controller.RegisterChat(this);
|
||||
|
||||
// WD EDIT START
|
||||
@@ -133,6 +136,21 @@ public partial class ChatBox : UIWidget
|
||||
}
|
||||
}
|
||||
|
||||
private void OnNewHighlights(string highlighs)
|
||||
{
|
||||
_controller.UpdateHighlights(highlighs);
|
||||
}
|
||||
|
||||
private void OnHighlightsUpdated(string highlights)
|
||||
{
|
||||
ChatInput.FilterButton.Popup.UpdateHighlights(highlights);
|
||||
}
|
||||
|
||||
private void OnAutoFillUpdated(string autoFillKeywords)
|
||||
{
|
||||
ChatInput.FilterButton.Popup.UpdateAutoFill(autoFillKeywords);
|
||||
}
|
||||
|
||||
public void AddLine(string message, Color color, int repeat = 0) // WD EDIT
|
||||
{
|
||||
var formatted = new FormattedMessage(4); // WD EDIT // specifying size beforehand smells like a useless microoptimisation, but i'll give them the benefit of doubt
|
||||
|
||||
@@ -64,7 +64,11 @@ namespace Content.Client.Voting.UI
|
||||
var entry = _vote.Entries[i];
|
||||
if (_vote.DisplayVotes)
|
||||
{
|
||||
_voteButtons[i].Text = Loc.GetString("ui-vote-button", ("text", entry.Text), ("votes", entry.Votes));
|
||||
// Mono
|
||||
if (entry.RealVotes != entry.Votes)
|
||||
_voteButtons[i].Text = Loc.GetString("ui-vote-button-weighted", ("text", entry.Text), ("votes", entry.Votes), ("realvotes", entry.RealVotes));
|
||||
else
|
||||
_voteButtons[i].Text = Loc.GetString("ui-vote-button", ("text", entry.Text), ("votes", entry.Votes));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -192,6 +192,7 @@ namespace Content.Client.Voting
|
||||
for (var i = 0; i < message.Options.Length; i++)
|
||||
{
|
||||
existingVote.Entries[i].Votes = message.Options[i].votes;
|
||||
existingVote.Entries[i].RealVotes = message.Options[i].realVotes; // Mono
|
||||
}
|
||||
|
||||
if (@new && _popupContainer != null)
|
||||
@@ -259,6 +260,7 @@ namespace Content.Client.Voting
|
||||
{
|
||||
public string Text { get; }
|
||||
public int Votes { get; set; }
|
||||
public int RealVotes; // Mono
|
||||
|
||||
public VoteEntry(string text)
|
||||
{
|
||||
|
||||
@@ -39,6 +39,8 @@ namespace Content.MapRenderer.Painters
|
||||
// Seriously whoever made MapPainter use GameMapPrototype I wish you step on a lego one time.
|
||||
Map = map,
|
||||
});
|
||||
pair.ServerLogHandler.FailureLevel = LogLevel.Fatal;
|
||||
pair.ClientLogHandler.FailureLevel = LogLevel.Fatal;
|
||||
|
||||
await foreach (var image in RenderPair(stopwatch, pair))
|
||||
yield return image;
|
||||
@@ -56,6 +58,8 @@ namespace Content.MapRenderer.Painters
|
||||
Connected = true,
|
||||
Fresh = false,
|
||||
});
|
||||
pair.ServerLogHandler.FailureLevel = LogLevel.Fatal;
|
||||
pair.ClientLogHandler.FailureLevel = LogLevel.Fatal;
|
||||
|
||||
var server = pair.Server;
|
||||
var client = pair.Client;
|
||||
@@ -69,6 +73,14 @@ namespace Content.MapRenderer.Painters
|
||||
|
||||
foreach (var grid in sMapManager.GetAllGrids(mapId))
|
||||
sEntityManager.QueueDeleteEntity(grid);
|
||||
});
|
||||
|
||||
await pair.RunTicksSync(10);
|
||||
await Task.WhenAll(client.WaitIdleAsync(), server.WaitIdleAsync());
|
||||
|
||||
await server.WaitPost(() =>
|
||||
{
|
||||
var mapId = sEntityManager.System<GameTicker>().DefaultMap;
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
@@ -178,7 +178,7 @@ public sealed class AmeNodeGroup : BaseNodeGroup
|
||||
// return MathF.Max(200000f * MathF.Log10(2 * fuel * MathF.Pow(cores, (float)-0.5)), 0); // Frontier: preferring old calculation for now
|
||||
// return 200000f * MathF.Log10(fuel * fuel) * MathF.Pow(0.75f, cores - 1); // Frontier: preferring old calculation for now
|
||||
if (cores > 0 && fuel > 0) // Mono - default zero power unless conditions are met
|
||||
return 200000f * MathF.Log10(fuel * fuel) * MathF.Pow( 1.11111f, cores - 1); // Mono - Added positive returns from extra cores. Running AME at 2 fuel per core yields roughly the same power per core at all sizes
|
||||
return 200000f * MathF.Log10(fuel * fuel) * MathF.Pow( 1.11111f, fuel / 2f - 1); // Mono - Exponential scaling at high injection
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -61,4 +61,16 @@ public sealed partial class ThermalRegulatorComponent : Component
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float ThermalRegulationTemperatureThreshold;
|
||||
|
||||
/// <summary>
|
||||
/// Process regulation while they're dead if there is a MobStateComponent? - Mono Hydrakin
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool ProcessWhileDead = false;
|
||||
|
||||
/// <summary>
|
||||
/// Process regulation in critical condition if there is a MobStateComponent? - Mono Hydrakin
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool ProcessWhileCrit = true;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ using Content.Server.Body.Components;
|
||||
using Content.Server.Temperature.Components;
|
||||
using Content.Server.Temperature.Systems;
|
||||
using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.Mobs; // Mono
|
||||
using Content.Shared.Mobs.Components; // Mono
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server.Body.Systems;
|
||||
@@ -51,6 +53,14 @@ public sealed class ThermalRegulatorSystem : EntitySystem
|
||||
if (!Resolve(ent, ref ent.Comp2, logMissing: false))
|
||||
return;
|
||||
|
||||
// mono begin
|
||||
if (ent.Comp1.ProcessWhileDead == false && TryComp<MobStateComponent>(ent, out var mobComp1) && mobComp1.CurrentState == MobState.Dead)
|
||||
return;
|
||||
|
||||
if (ent.Comp1.ProcessWhileCrit == false && TryComp<MobStateComponent>(ent, out var mobComp2) && mobComp2.CurrentState == MobState.Critical)
|
||||
return;
|
||||
// mono end
|
||||
|
||||
var totalMetabolismTempChange = ent.Comp1.MetabolismHeat - ent.Comp1.RadiatedHeat;
|
||||
|
||||
// implicit heat regulation
|
||||
|
||||
@@ -28,8 +28,6 @@ public sealed partial class BotanySystem : EntitySystem
|
||||
[Dependency] private readonly SharedSolutionContainerSystem _solutionContainerSystem = default!;
|
||||
[Dependency] private readonly MetaDataSystem _metaData = default!;
|
||||
[Dependency] private readonly RandomHelperSystem _randomHelper = default!;
|
||||
[Dependency] private readonly ContrabandTurnInSystem _contraband = default!; // Frontier
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -100,7 +98,6 @@ public sealed partial class BotanySystem : EntitySystem
|
||||
public EntityUid SpawnSeedPacket(SeedData proto, EntityCoordinates coords, EntityUid user, float? healthOverride = null)
|
||||
{
|
||||
var seed = SpawnAtPosition(proto.PacketPrototype, coords); // Frontier: Spawn<SpawnAtPosition
|
||||
_contraband.ClearContrabandValue(seed); // Frontier
|
||||
var seedComp = EnsureComp<SeedComponent>(seed);
|
||||
seedComp.Seed = proto;
|
||||
seedComp.HealthOverride = healthOverride;
|
||||
@@ -160,7 +157,6 @@ public sealed partial class BotanySystem : EntitySystem
|
||||
var product = _robustRandom.Pick(proto.ProductPrototypes);
|
||||
|
||||
var entity = SpawnAtPosition(product, position); // Frontier: Spawn<SpawnAtPosition
|
||||
_contraband.ClearContrabandValue(entity); // Frontier
|
||||
_randomHelper.RandomOffset(entity, 0.25f);
|
||||
products.Add(entity);
|
||||
|
||||
|
||||
@@ -171,7 +171,7 @@ namespace Content.Server.EntityEffects.Effects
|
||||
interruptsDoAfters: false,
|
||||
// Shitmed Change Start
|
||||
targetPart: TargetBodyPart.All,
|
||||
partMultiplier: 0.5f,
|
||||
partMultiplier: 1.00f, // Mono, 0.5f->1.00f
|
||||
canSever: false);
|
||||
// Shitmed Change End
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Content.Server._Mono.Planets;
|
||||
using Content.Server.Administration.Logs;
|
||||
using Content.Server.Body.Systems;
|
||||
using Content.Server.Explosion.Components;
|
||||
@@ -39,6 +40,7 @@ using Content.Shared.Projectiles; // Frontier: embed triggers
|
||||
using Content.Shared.Mind;
|
||||
using Content.Shared.Mind.Components;
|
||||
using Content.Shared.Roles;
|
||||
using Robust.Shared.Map.Components;
|
||||
|
||||
namespace Content.Server.Explosion.EntitySystems
|
||||
{
|
||||
@@ -83,6 +85,7 @@ namespace Content.Server.Explosion.EntitySystems
|
||||
[Dependency] private readonly InventorySystem _inventory = default!;
|
||||
[Dependency] private readonly ElectrocutionSystem _electrocution = default!;
|
||||
[Dependency] private readonly StationSystem _station = default!; // Frontier: medical insurance
|
||||
[Dependency] private readonly SharedMapSystem _map = default!; // Frontier: medical insurance
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -252,19 +255,19 @@ namespace Content.Server.Explosion.EntitySystems
|
||||
var posText = $"({x}, {y})";
|
||||
|
||||
// Frontier: Gets station location of the implant
|
||||
var station = _station.GetOwningStation(uid);
|
||||
var stationText = station is null ? null : $"{Name(station.Value)} ";
|
||||
var grid = ownerXform.GridUid;
|
||||
var gridText = grid is null ? "" : MetaData(grid.Value).EntityName;
|
||||
|
||||
if (stationText == null)
|
||||
stationText = "";
|
||||
if (HasComp<MapComponent>(grid) && !HasComp<PlanetMapComponent>(grid))
|
||||
gridText = "";
|
||||
|
||||
// Frontier: Gets species of the implant user
|
||||
var speciesText = $"";
|
||||
if (TryComp<HumanoidAppearanceComponent>(implanted.ImplantedEntity, out var species))
|
||||
speciesText = $" ({species!.Species})";
|
||||
speciesText = $" ({species.Species})";
|
||||
|
||||
var critMessage = Loc.GetString(component.CritMessage, ("user", implanted.ImplantedEntity.Value), ("specie", speciesText), ("grid", stationText!), ("position", posText));
|
||||
var deathMessage = Loc.GetString(component.DeathMessage, ("user", implanted.ImplantedEntity.Value), ("specie", speciesText), ("grid", stationText!), ("position", posText));
|
||||
var critMessage = Loc.GetString(component.CritMessage, ("user", implanted.ImplantedEntity.Value), ("specie", speciesText), ("grid", gridText), ("position", posText));
|
||||
var deathMessage = Loc.GetString(component.DeathMessage, ("user", implanted.ImplantedEntity.Value), ("specie", speciesText), ("grid", gridText), ("position", posText));
|
||||
|
||||
if (!TryComp<MobStateComponent>(implanted.ImplantedEntity, out var mobstate))
|
||||
return;
|
||||
|
||||
@@ -130,6 +130,10 @@ public sealed partial class GameTicker
|
||||
if (MetaData(ruleEntity).EntityPrototype?.ID is not { } id) // you really fucked up
|
||||
return false;
|
||||
|
||||
// Mono - ensure delayed start rules don't trigger ahead of time.
|
||||
if (TryComp<DelayedStartRuleComponent>(ruleEntity, out var delayComp) && delayComp.RuleStartTime > _gameTiming.CurTime)
|
||||
return false;
|
||||
|
||||
// If we already have it, then we just skip the delay as it has already happened.
|
||||
if (!RemComp<DelayedStartRuleComponent>(ruleEntity) && ruleData.Delay != null)
|
||||
{
|
||||
|
||||
@@ -42,5 +42,11 @@ namespace Content.Server.GameTicking.Presets
|
||||
/// </summary>
|
||||
[DataField("supportedMaps", customTypeSerializer: typeof(PrototypeIdSerializer<GameMapPoolPrototype>))]
|
||||
public string? MapPool;
|
||||
|
||||
/// <summary>
|
||||
/// Mono - as how much votes should each player click count.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float Weight = 1f;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,6 @@ namespace Content.Server.Lathe
|
||||
[Dependency] private readonly SharedSolutionContainerSystem _solution = default!;
|
||||
[Dependency] private readonly StackSystem _stack = default!;
|
||||
[Dependency] private readonly TransformSystem _transform = default!;
|
||||
[Dependency] private readonly ContrabandTurnInSystem _contraband = default!; // Frontier
|
||||
[Dependency] private readonly DeviceLinkSystem _deviceLink = default!; // Mono
|
||||
|
||||
/// <summary>
|
||||
@@ -326,11 +325,7 @@ namespace Content.Server.Lathe
|
||||
|
||||
// Frontier: adjust price before merge (stack prices changed once)
|
||||
if (result.Valid)
|
||||
{
|
||||
ModifyPrintedEntityPrice(uid, comp, result);
|
||||
|
||||
_contraband.ClearContrabandValue(result);
|
||||
}
|
||||
// End Frontier
|
||||
|
||||
_stack.TryMergeToContacts(result);
|
||||
|
||||
@@ -21,6 +21,7 @@ namespace Content.Server.Preferences.Managers
|
||||
IEnumerable<KeyValuePair<NetUserId, ICharacterProfile>> GetSelectedProfilesForPlayers(List<NetUserId> userIds);
|
||||
bool HavePreferencesLoaded(ICommonSession session);
|
||||
Task RefreshPreferencesAsync(ICommonSession session, CancellationToken cancel);
|
||||
Task SetProfile(NetUserId userId, int slot, ICharacterProfile profile);
|
||||
Task SetProfile(NetUserId userId, int slot, ICharacterProfile profile,
|
||||
bool authoritative = true); // Mono
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,10 +87,11 @@ namespace Content.Server.Preferences.Managers
|
||||
if (message.Profile == null)
|
||||
_sawmill.Error($"User {userId} sent a {nameof(MsgUpdateCharacter)} with a null profile in slot {message.Slot}.");
|
||||
else
|
||||
await SetProfile(userId, message.Slot, message.Profile);
|
||||
await SetProfile(userId, message.Slot, message.Profile, false);
|
||||
}
|
||||
|
||||
public async Task SetProfile(NetUserId userId, int slot, ICharacterProfile profile)
|
||||
public async Task SetProfile(NetUserId userId, int slot, ICharacterProfile profile,
|
||||
bool authoritative = true) // Mono
|
||||
{
|
||||
if (!_cachedPlayerPrefs.TryGetValue(userId, out var prefsData) || !prefsData.PrefsLoaded)
|
||||
{
|
||||
@@ -105,6 +106,14 @@ namespace Content.Server.Preferences.Managers
|
||||
var session = _playerManager.GetSessionById(userId);
|
||||
|
||||
profile.EnsureValid(session, _dependencies);
|
||||
// Mono
|
||||
if (!authoritative && profile is HumanoidCharacterProfile humanoid)
|
||||
{
|
||||
if (curPrefs.Characters.TryGetValue(slot, out var oldProfile) && oldProfile is HumanoidCharacterProfile oldHumanoid)
|
||||
profile = humanoid.WithBankBalance(oldHumanoid.BankBalance);
|
||||
else
|
||||
profile = humanoid.WithBankBalance(HumanoidCharacterProfile.DefaultBalance);
|
||||
}
|
||||
|
||||
var profiles = new Dictionary<int, ICharacterProfile>(curPrefs.Characters)
|
||||
|
||||
|
||||
@@ -69,6 +69,8 @@ public sealed partial class ResearchSystem
|
||||
if (serverComponent.Clients.Contains(client))
|
||||
return;
|
||||
|
||||
UnregisterClient(client, clientComponent); // Mono Research Fix, unregister a client if applicable before registering to a new server
|
||||
|
||||
serverComponent.Clients.Add(client);
|
||||
clientComponent.Server = server;
|
||||
SyncClientWithServer(client, clientComponent: clientComponent);
|
||||
|
||||
@@ -22,6 +22,7 @@ using Robust.Shared.Timing;
|
||||
using Content.Shared.DeviceNetwork.Components;
|
||||
using Timer = Robust.Shared.Timing.Timer;
|
||||
using Content.Server._NF.SectorServices; // Frontier
|
||||
using Content.Shared.GameTicking.Components; // Mono
|
||||
|
||||
namespace Content.Server.RoundEnd
|
||||
{
|
||||
@@ -354,9 +355,17 @@ namespace Content.Server.RoundEnd
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
// Check if we should auto-call.
|
||||
int mins = _autoCalledBefore ? _cfg.GetCVar(CCVars.EmergencyShuttleAutoCallExtensionTime)
|
||||
: _cfg.GetCVar(CCVars.EmergencyShuttleAutoCallTime);
|
||||
if (mins != 0 && _gameTiming.CurTime - AutoCallStartTime > TimeSpan.FromMinutes(mins))
|
||||
var mins = TimeSpan.FromMinutes(_autoCalledBefore ? _cfg.GetCVar(CCVars.EmergencyShuttleAutoCallExtensionTime)
|
||||
: _cfg.GetCVar(CCVars.EmergencyShuttleAutoCallTime));
|
||||
|
||||
// Mono
|
||||
var query = EntityQueryEnumerator<RoundEndTimeRuleComponent, ActiveGameRuleComponent>();
|
||||
while (query.MoveNext(out _, out var endTimeComp, out _))
|
||||
{
|
||||
mins = endTimeComp.EndAt;
|
||||
}
|
||||
|
||||
if (mins.TotalSeconds != 0 && _gameTiming.CurTime - AutoCallStartTime > mins)
|
||||
{
|
||||
if (!_shuttle.EmergencyShuttleArrived && ExpectedCountdownEnd is null)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
|
||||
namespace Content.Server.RoundEnd;
|
||||
|
||||
/// <summary>
|
||||
/// If a gamerule with this component is present, override the roundend time to the time set in it.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class RoundEndTimeRuleComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public TimeSpan EndAt;
|
||||
}
|
||||
@@ -71,7 +71,7 @@ namespace Content.Server.Shuttles.Components
|
||||
public string MachinePartThrust = "Capacitor";
|
||||
|
||||
[DataField("partRatingThrustMultiplier")]
|
||||
public float PartRatingThrustMultiplier = 1.15f; // Frontier - PR #1292 1.5f<1.15f
|
||||
public float PartRatingThrustMultiplier = 1.25f; // Mono: 1.15->1.25 (frontier: 1.5->1.15)
|
||||
|
||||
/// <summary>
|
||||
/// Frontier - Amount of charge this needs from an APC per second to function.
|
||||
|
||||
@@ -69,6 +69,12 @@ public sealed partial class StationEventComponent : Component
|
||||
[DataField]
|
||||
public ProtoId<RadioChannelPrototype> EndRadioAnnouncementChannel = "Supply"; // Frontier
|
||||
|
||||
/// <summary>
|
||||
/// Mono - sender of start/warn/end announcements.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public LocId? AnnounceSender = null;
|
||||
|
||||
/// <summary>
|
||||
/// In minutes, when is the first round time this event can start
|
||||
/// </summary>
|
||||
|
||||
@@ -50,7 +50,7 @@ public abstract class StationEventSystem<T> : GameRuleSystem<T> where T : ICompo
|
||||
Filter allPlayersInGame = Filter.Empty().AddWhere(GameTicker.UserHasJoinedGame);
|
||||
|
||||
if (stationEvent.StartAnnouncement != null)
|
||||
ChatSystem.DispatchFilteredAnnouncement(allPlayersInGame, Loc.GetString(stationEvent.StartAnnouncement), playSound: false, colorOverride: stationEvent.StartAnnouncementColor);
|
||||
ChatSystem.DispatchFilteredAnnouncement(allPlayersInGame, Loc.GetString(stationEvent.StartAnnouncement), sender: stationEvent.AnnounceSender is { } send ? Loc.GetString(send) : null, playSound: false, colorOverride: stationEvent.StartAnnouncementColor);
|
||||
|
||||
// Frontier
|
||||
if (stationEvent.StartRadioAnnouncement != null)
|
||||
@@ -97,7 +97,7 @@ public abstract class StationEventSystem<T> : GameRuleSystem<T> where T : ICompo
|
||||
Filter allPlayersInGame = Filter.Empty().AddWhere(GameTicker.UserHasJoinedGame);
|
||||
|
||||
if (stationEvent.EndAnnouncement != null)
|
||||
ChatSystem.DispatchFilteredAnnouncement(allPlayersInGame, Loc.GetString(stationEvent.EndAnnouncement), playSound: false, colorOverride: stationEvent.EndAnnouncementColor);
|
||||
ChatSystem.DispatchFilteredAnnouncement(allPlayersInGame, Loc.GetString(stationEvent.EndAnnouncement), sender: stationEvent.AnnounceSender is { } send ? Loc.GetString(send) : null, playSound: false, colorOverride: stationEvent.EndAnnouncementColor);
|
||||
|
||||
// Frontier: radio announcements
|
||||
if (stationEvent.EndRadioAnnouncement != null)
|
||||
@@ -139,7 +139,7 @@ public abstract class StationEventSystem<T> : GameRuleSystem<T> where T : ICompo
|
||||
{
|
||||
Filter allPlayersInGame = Filter.Empty().AddWhere(GameTicker.UserHasJoinedGame); // we don't want to send to players who aren't in game (i.e. in the lobby)
|
||||
if (stationEvent.WarningAnnouncement != null)
|
||||
ChatSystem.DispatchFilteredAnnouncement(allPlayersInGame, Loc.GetString(stationEvent.WarningAnnouncement), playSound: false, colorOverride: stationEvent.WarningAnnouncementColor);
|
||||
ChatSystem.DispatchFilteredAnnouncement(allPlayersInGame, Loc.GetString(stationEvent.WarningAnnouncement), sender: stationEvent.AnnounceSender is { } send ? Loc.GetString(send) : null, playSound: false, colorOverride: stationEvent.WarningAnnouncementColor);
|
||||
if (stationEvent.WarningRadioAnnouncement != null)
|
||||
{
|
||||
var message = Loc.GetString(stationEvent.WarningRadioAnnouncement);
|
||||
|
||||
@@ -58,7 +58,6 @@ namespace Content.Server.VendingMachines
|
||||
[Dependency] private readonly BankSystem _bankSystem = default!; // Frontier
|
||||
[Dependency] private readonly PopupSystem _popupSystem = default!; // Frontier
|
||||
[Dependency] private readonly IAdminLogManager _adminLogger = default!; // Frontier
|
||||
[Dependency] private readonly ContrabandTurnInSystem _contraband = default!; // Frontier
|
||||
[Dependency] private readonly StackSystem _stack = default!; // Frontier
|
||||
[Dependency] private readonly VendingMachinePurchaseSystem _vendingPurchase = default!; // Mono
|
||||
|
||||
@@ -545,8 +544,6 @@ namespace Content.Server.VendingMachines
|
||||
|
||||
var ent = Spawn(vendComponent.NextItemToEject, spawnCoordinates);
|
||||
|
||||
_contraband.ClearContrabandValue(ent); // Frontier
|
||||
|
||||
// Mono: Track vending machine purchases for pricing modifications
|
||||
// Only track if this was a paid purchase (not a random eject or force eject)
|
||||
if (!forceEject && vendComponent.LastPurchasePrice.HasValue)
|
||||
|
||||
@@ -233,7 +233,9 @@ namespace Content.Server.Voting.Managers
|
||||
|
||||
foreach (var (k, v) in presets)
|
||||
{
|
||||
options.Options.Add((Loc.GetString(v), k));
|
||||
options.Options.Add((Loc.GetString(v.Name), k));
|
||||
if (v.Weight != 1f)
|
||||
options.Weights.Add(k, v.Weight);
|
||||
}
|
||||
|
||||
WirePresetVoteInitiator(options, initiator);
|
||||
@@ -247,13 +249,13 @@ namespace Content.Server.Voting.Managers
|
||||
{
|
||||
picked = (string) _random.Pick(args.Winners);
|
||||
_chatManager.DispatchServerAnnouncement(
|
||||
Loc.GetString("ui-vote-gamemode-tie", ("picked", Loc.GetString(presets[picked]))));
|
||||
Loc.GetString("ui-vote-gamemode-tie", ("picked", Loc.GetString(presets[picked].Name))));
|
||||
}
|
||||
else
|
||||
{
|
||||
picked = (string) args.Winner;
|
||||
_chatManager.DispatchServerAnnouncement(
|
||||
Loc.GetString("ui-vote-gamemode-win", ("winner", Loc.GetString(presets[picked]))));
|
||||
Loc.GetString("ui-vote-gamemode-win", ("winner", Loc.GetString(presets[picked].Name))));
|
||||
}
|
||||
_adminLogger.Add(LogType.Vote, LogImpact.Medium, $"Preset vote finished: {picked}");
|
||||
var ticker = _entityManager.EntitySysManager.GetEntitySystem<GameTicker>();
|
||||
@@ -585,9 +587,9 @@ namespace Content.Server.Voting.Managers
|
||||
DirtyCanCallVoteAll();
|
||||
}
|
||||
|
||||
private Dictionary<string, string> GetGamePresets()
|
||||
private Dictionary<string, (string Name, float Weight)> GetGamePresets() // Mono - add weight
|
||||
{
|
||||
var presets = new Dictionary<string, string>();
|
||||
var presets = new Dictionary<string, (string, float)>();
|
||||
|
||||
foreach (var preset in _prototypeManager.EnumeratePrototypes<GamePresetPrototype>())
|
||||
{
|
||||
@@ -600,7 +602,7 @@ namespace Content.Server.Voting.Managers
|
||||
if(_playerManager.PlayerCount > (preset.MaxPlayers ?? int.MaxValue))
|
||||
continue;
|
||||
|
||||
presets[preset.ID] = preset.ModeTitle;
|
||||
presets[preset.ID] = (preset.ModeTitle, preset.Weight);
|
||||
}
|
||||
return presets;
|
||||
}
|
||||
|
||||
@@ -206,7 +206,8 @@ namespace Content.Server.Voting.Managers
|
||||
{
|
||||
var id = _nextVoteId++;
|
||||
|
||||
var entries = options.Options.Select(o => new VoteEntry(o.data, o.text)).ToArray();
|
||||
// Mono - added weight
|
||||
var entries = options.Options.Select(o => new VoteEntry(o.data, o.text, options.Weights.TryGetValue(o.data, out var weight) ? weight : 1f)).ToArray();
|
||||
|
||||
var start = _timing.RealTime;
|
||||
var end = start + options.Duration;
|
||||
@@ -286,11 +287,12 @@ namespace Content.Server.Voting.Managers
|
||||
msg.DisplayVotes = true;
|
||||
}
|
||||
|
||||
msg.Options = new (ushort votes, string name)[v.Entries.Length];
|
||||
msg.Options = new (ushort votes, string name, ushort realVotes)[v.Entries.Length];
|
||||
for (var i = 0; i < msg.Options.Length; i++)
|
||||
{
|
||||
ref var entry = ref v.Entries[i];
|
||||
msg.Options[i] = (msg.DisplayVotes ? (ushort) entry.Votes : (ushort) 0, entry.Text);
|
||||
var votes = msg.DisplayVotes ? (ushort) entry.Votes : (ushort) 0; // Mono
|
||||
msg.Options[i] = (votes, entry.Text, (ushort) (votes * entry.Weight)); // Mono - account for weight
|
||||
}
|
||||
|
||||
player.Channel.SendMessage(msg);
|
||||
@@ -394,7 +396,7 @@ namespace Content.Server.Voting.Managers
|
||||
|
||||
// Find winner or stalemate.
|
||||
var winners = v.Entries
|
||||
.GroupBy(e => e.Votes)
|
||||
.GroupBy(e => e.Votes * e.Weight) // Mono - add weight
|
||||
.OrderByDescending(g => g.Key)
|
||||
.First()
|
||||
.Select(e => e.Data)
|
||||
@@ -536,12 +538,15 @@ namespace Content.Server.Voting.Managers
|
||||
public object Data;
|
||||
public string Text;
|
||||
public int Votes;
|
||||
public float Weight; // Mono
|
||||
|
||||
public VoteEntry(object data, string text)
|
||||
public VoteEntry(object data, string text,
|
||||
float weight = 1f) // Mono
|
||||
{
|
||||
Data = data;
|
||||
Text = text;
|
||||
Votes = 0;
|
||||
Weight = weight; // Mono
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,9 @@ namespace Content.Server.Voting
|
||||
/// </summary>
|
||||
public List<(string text, object data)> Options { get; set; } = new();
|
||||
|
||||
// Mono - this is evil but allows seamless integration with the code
|
||||
public Dictionary<object, float> Weights = new();
|
||||
|
||||
/// <summary>
|
||||
/// Which sessions may send a vote. Used when only a subset of players should be able to vote. Defaults to all.
|
||||
/// </summary>
|
||||
@@ -50,7 +53,7 @@ namespace Content.Server.Voting
|
||||
public bool DisplayVotes = true;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the vote should have an entity attached to it, to be used for things like letting ghosts follow it.
|
||||
/// Whether the vote should have an entity attached to it, to be used for things like letting ghosts follow it.
|
||||
/// </summary>
|
||||
public NetEntity? TargetEntity = null;
|
||||
|
||||
|
||||
+12
@@ -1,3 +1,7 @@
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Damage.Prototypes;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._EinsteinEngines.Silicon.Death;
|
||||
|
||||
/// <summary>
|
||||
@@ -14,4 +18,12 @@ public sealed partial class SiliconDownOnDeadComponent : Component
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public bool Dead;
|
||||
|
||||
/// <summary>
|
||||
/// Mono - applies modifier when silicon is out of charge.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public ProtoId<DamageModifierSetPrototype>? ModifierOnDead = "IPCWeakened";
|
||||
|
||||
public ProtoId<DamageModifierSetPrototype>? OriginalModifier;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using Content.Shared.Bed.Sleep;
|
||||
using Content.Server._EinsteinEngines.Silicon.Charge;
|
||||
using Content.Server._EinsteinEngines.Power.Components;
|
||||
using Content.Server.Humanoid;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Humanoid;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Hands.EntitySystems; //Monolith IPC rework
|
||||
@@ -15,7 +16,7 @@ public sealed class SiliconDeathSystem : EntitySystem
|
||||
[Dependency] private readonly SleepingSystem _sleep = default!;
|
||||
[Dependency] private readonly SiliconChargeSystem _silicon = default!;
|
||||
[Dependency] private readonly HumanoidAppearanceSystem _humanoidAppearanceSystem = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _hands = default!; //Monolith IPC rework
|
||||
[Dependency] private readonly DamageableSystem _damage = default!; // mono
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -46,16 +47,15 @@ public sealed class SiliconDeathSystem : EntitySystem
|
||||
var deadEvent = new SiliconChargeDyingEvent(uid, batteryComp, batteryUid);
|
||||
RaiseLocalEvent(uid, deadEvent);
|
||||
|
||||
if (deadEvent.Cancelled)
|
||||
if (deadEvent.Cancelled
|
||||
|| siliconDeadComp.ModifierOnDead == null
|
||||
|| !TryComp<DamageableComponent>(uid, out var damageComp))
|
||||
return;
|
||||
|
||||
/*EntityManager.EnsureComponent<SleepingComponent>(uid); Monolith IPC rework edit start
|
||||
EntityManager.EnsureComponent<ForcedSleepingComponent>(uid);*/
|
||||
|
||||
if(!TryComp<HandsComponent>(uid, out var handsComp))
|
||||
return;
|
||||
_hands.RemoveHands(uid, handsComp); // edit end
|
||||
|
||||
siliconDeadComp.OriginalModifier = damageComp.DamageModifierSetId;
|
||||
_damage.SetDamageModifierSetId(uid, siliconDeadComp.ModifierOnDead.Value);
|
||||
|
||||
if (TryComp(uid, out HumanoidAppearanceComponent? humanoidAppearanceComponent))
|
||||
{
|
||||
@@ -73,8 +73,8 @@ public sealed class SiliconDeathSystem : EntitySystem
|
||||
/*RemComp<ForcedSleepingComponent>(uid); Monolith IPC rework edit start
|
||||
_sleep.TryWaking(uid, true, null);*/
|
||||
|
||||
_hands.AddHand(uid, "right hand", HandLocation.Right);
|
||||
_hands.AddHand(uid, "left hand", HandLocation.Left); // edit end
|
||||
if (siliconDeadComp.OriginalModifier != null)
|
||||
_damage.SetDamageModifierSetId(uid, siliconDeadComp.OriginalModifier.Value);
|
||||
|
||||
siliconDeadComp.Dead = false;
|
||||
|
||||
|
||||
@@ -37,10 +37,18 @@ public sealed class ClawsSystem : SharedClawsSystem
|
||||
if (TryGetStage<Declawed>(comp, out var declawed))
|
||||
UpdateDeclaw(uid, declawed, comp, _updateCooldown);
|
||||
|
||||
if (HasComp<ClawsGrowthSuppressionComponent>(uid))
|
||||
{
|
||||
comp.AccumulatedBonusGrowth = TimeSpan.Zero;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!_protoMan.TryIndex(comp.ClawStage, out var claw) || !claw.CanGrow)
|
||||
continue;
|
||||
|
||||
comp.GrowTimer += TimeSpan.FromSeconds(_updateCooldown);
|
||||
comp.GrowTimer += TimeSpan.FromSeconds(_updateCooldown) + comp.AccumulatedBonusGrowth;
|
||||
|
||||
comp.AccumulatedBonusGrowth = TimeSpan.Zero;
|
||||
|
||||
if (comp.GrowTimer < claw.GrowCooldown)
|
||||
{
|
||||
|
||||
@@ -9,7 +9,6 @@ using Content.Shared.Weapons.Ranged.Components;
|
||||
using Content.Shared.Weapons.Ranged.Systems;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Timing;
|
||||
using System;
|
||||
|
||||
namespace Content.Server._Mono.Detection;
|
||||
|
||||
@@ -21,18 +20,22 @@ public sealed class ThermalSignatureSystem : EntitySystem
|
||||
[Dependency] private readonly SharedPowerReceiverSystem _power = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
|
||||
private float _updateInterval = 0.5f;
|
||||
private float _updateAccumulator = 0f;
|
||||
private EntityQuery<MapGridComponent> _gridQuery;
|
||||
private const float UpdateIntervalSeconds = 1f;
|
||||
private static readonly TimeSpan UpdateInterval = TimeSpan.FromSeconds(UpdateIntervalSeconds);
|
||||
private TimeSpan _nextUpdateTime;
|
||||
|
||||
private const float HeatChangeThreshold = 1.02f;
|
||||
|
||||
private EntityQuery<ThermalSignatureComponent> _sigQuery;
|
||||
private EntityQuery<GunComponent> _gunQuery;
|
||||
|
||||
private Dictionary<EntityUid, ThermalSignatureComponent> _gridCompMap = new();
|
||||
private EntityQuery<MapGridComponent> _mapGridQuery;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<GridInitializeEvent>(OnGridInitialized);
|
||||
|
||||
// some of this could also be handled in shared but there's no point since PVS is a thing
|
||||
SubscribeLocalEvent<MachineThermalSignatureComponent, GetThermalSignatureEvent>(OnMachineGetSignature);
|
||||
SubscribeLocalEvent<PassiveThermalSignatureComponent, GetThermalSignatureEvent>(OnPassiveGetSignature);
|
||||
@@ -42,9 +45,14 @@ public sealed class ThermalSignatureSystem : EntitySystem
|
||||
SubscribeLocalEvent<ThrusterComponent, GetThermalSignatureEvent>(OnThrusterGetSignature);
|
||||
SubscribeLocalEvent<FTLDriveComponent, GetThermalSignatureEvent>(OnFTLGetSignature);
|
||||
|
||||
_gridQuery = GetEntityQuery<MapGridComponent>();
|
||||
_sigQuery = GetEntityQuery<ThermalSignatureComponent>();
|
||||
_gunQuery = GetEntityQuery<GunComponent>();
|
||||
_mapGridQuery = GetEntityQuery<MapGridComponent>();
|
||||
}
|
||||
|
||||
private void OnGridInitialized(GridInitializeEvent args)
|
||||
{
|
||||
EnsureComp<ThermalSignatureComponent>(args.EntityUid);
|
||||
}
|
||||
|
||||
private void OnGunShot(Entity<ThermalSignatureComponent> ent, ref GunShotEvent args)
|
||||
@@ -87,48 +95,45 @@ public sealed class ThermalSignatureSystem : EntitySystem
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
_updateAccumulator += frameTime;
|
||||
if (_updateAccumulator < _updateInterval)
|
||||
if (_timing.CurTime < _nextUpdateTime)
|
||||
return;
|
||||
_updateAccumulator -= _updateInterval;
|
||||
|
||||
var interval = _updateInterval;
|
||||
_nextUpdateTime = _timing.CurTime + UpdateInterval;
|
||||
|
||||
_gridCompMap.Clear();
|
||||
|
||||
var gridQuery = EntityQueryEnumerator<MapGridComponent>();
|
||||
while (gridQuery.MoveNext(out var uid, out _))
|
||||
var gridQuery = EntityQueryEnumerator<MapGridComponent, ThermalSignatureComponent>();
|
||||
while (gridQuery.MoveNext(out _, out _, out var gridSigComp))
|
||||
{
|
||||
if (!_sigQuery.TryComp(uid, out var sigComp))
|
||||
sigComp = EnsureComp<ThermalSignatureComponent>(uid);
|
||||
|
||||
sigComp.TotalHeat = 0f;
|
||||
_gridCompMap.Add(uid, sigComp);
|
||||
gridSigComp.TotalHeat = 0f;
|
||||
}
|
||||
|
||||
var query = EntityQueryEnumerator<ThermalSignatureComponent>();
|
||||
while (query.MoveNext(out var uid, out var sigComp))
|
||||
{
|
||||
var ev = new GetThermalSignatureEvent(interval);
|
||||
var ev = new GetThermalSignatureEvent();
|
||||
RaiseLocalEvent(uid, ref ev);
|
||||
sigComp.StoredHeat += ev.Signature * interval;
|
||||
sigComp.StoredHeat *= MathF.Pow(sigComp.HeatDissipation, interval);
|
||||
if (_gridCompMap.ContainsKey(uid))
|
||||
|
||||
sigComp.StoredHeat += ev.Signature * UpdateIntervalSeconds;
|
||||
sigComp.StoredHeat *= MathF.Pow(sigComp.HeatDissipation, UpdateIntervalSeconds);
|
||||
|
||||
if (_mapGridQuery.HasComp(uid))
|
||||
{
|
||||
sigComp.TotalHeat += sigComp.StoredHeat;
|
||||
|
||||
// don't sync it if it didn't change heat much since last time, we don't need to sync 500 cold asteroids every system update
|
||||
if (sigComp.TotalHeat <= sigComp.LastUpdateHeat * HeatChangeThreshold
|
||||
&& sigComp.TotalHeat >= sigComp.LastUpdateHeat / HeatChangeThreshold)
|
||||
continue;
|
||||
|
||||
sigComp.LastUpdateHeat = sigComp.TotalHeat;
|
||||
Dirty(uid, sigComp);
|
||||
}
|
||||
else
|
||||
{
|
||||
var xform = Transform(uid);
|
||||
sigComp.TotalHeat = sigComp.StoredHeat;
|
||||
if (xform.GridUid != null && _gridCompMap.TryGetValue(xform.GridUid.Value, out var gridSig))
|
||||
if (xform.GridUid != null && _sigQuery.TryGetComponent(xform.GridUid.Value, out var gridSig))
|
||||
gridSig.TotalHeat += sigComp.StoredHeat;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var (uid, sigComp) in _gridCompMap)
|
||||
{
|
||||
Dirty(uid, sigComp); // sync to client
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ namespace Content.Server._Mono.EntityEffects.Effects
|
||||
IgnoreResistances,
|
||||
interruptsDoAfters: false,
|
||||
targetPart: TargetBodyPart.All,
|
||||
partMultiplier: 0.5f,
|
||||
partMultiplier: 1.00f, // Mono, 0.5f->1.00f
|
||||
canSever: false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Linq;
|
||||
using Content.Server.Damage.Systems;
|
||||
using Content.Server.NPC.HTN;
|
||||
using Content.Server.Spreader;
|
||||
using Content.Shared._Mono;
|
||||
using Content.Shared.Damage.Components;
|
||||
@@ -68,7 +69,7 @@ public sealed class GridGodModeSystem : EntitySystem
|
||||
/// </summary>
|
||||
private void ProcessEntityOnGrid(EntityUid gridUid, EntityUid entityUid, GridGodModeComponent component)
|
||||
{
|
||||
// Don't apply GodMode to organic entities, ghosts, or kudzu
|
||||
// Don't apply GodMode to organic entities, ghosts, npcs, or kudzu
|
||||
if (IsOrganic(entityUid) || HasComp<GhostComponent>(entityUid) || HasComp<KudzuComponent>(entityUid))
|
||||
return;
|
||||
|
||||
@@ -122,6 +123,12 @@ public sealed class GridGodModeSystem : EntitySystem
|
||||
return true;
|
||||
}
|
||||
|
||||
// Also check for anything with HTN such as NPCs, such as turrets.
|
||||
if (HasComp<HTNComponent>(entityUid))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,7 +107,8 @@ public sealed partial class RadarBlipSystem : EntitySystem
|
||||
if (blipGrid != null)
|
||||
{
|
||||
var gridXform = Transform(blipGrid.Value);
|
||||
blipVelocity -= _physics.GetLinearVelocity(blipGrid.Value, coord.Position);
|
||||
if (TryComp<PhysicsComponent>(blipGrid.Value, out var gridBody)) // prevent log spam
|
||||
blipVelocity -= _physics.GetLinearVelocity(blipGrid.Value, coord.Position, gridBody);
|
||||
// it's local-frame velocity so rotate it too
|
||||
blipVelocity = (-gridXform.LocalRotation).RotateVec(blipVelocity);
|
||||
// and also offset the rotation
|
||||
|
||||
@@ -16,7 +16,7 @@ public sealed partial class GridSpawnerComponent : Component
|
||||
[DataField]
|
||||
public ProtoId<LocalizedDatasetPrototype>? NameDataset = null;
|
||||
|
||||
[DataField]
|
||||
[DataField, AlwaysPushInheritance]
|
||||
public ComponentRegistry AddComponents = new();
|
||||
|
||||
[DataField]
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
namespace Content.Server._Mono.StationEvents;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class BlankRuleComponent : Component;
|
||||
@@ -0,0 +1,9 @@
|
||||
using Content.Server.StationEvents.Events;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Content.Server._Mono.StationEvents;
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed class FalseAlarmRule : StationEventSystem<BlankRuleComponent>
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using Content.Shared._Mono.Humanoid;
|
||||
using Content.Shared._Mono.Traits.Physical;
|
||||
|
||||
namespace Content.Server._Mono.Traits.Physical;
|
||||
|
||||
/// <summary>
|
||||
/// Applies the Will To Live trait effects by modifying the death health threshold.
|
||||
/// </summary>
|
||||
public sealed class MobThresholdOffsetSystem : EntitySystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<MobThresholdOffsetComponent, QueryMobThresholdsEvent>(OnQueryMobThresholds);
|
||||
}
|
||||
|
||||
private void OnQueryMobThresholds(Entity<MobThresholdOffsetComponent> ent, ref QueryMobThresholdsEvent ev)
|
||||
{
|
||||
ev.DeathOffset += ent.Comp.DeadOffset;
|
||||
ev.CritOffset += ent.Comp.CritOffset;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
using Content.Shared._Mono.Traits.Physical;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Mobs;
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
|
||||
namespace Content.Server._Mono.Traits.Physical;
|
||||
|
||||
/// <summary>
|
||||
/// Applies the Will To Die trait effects by decreasing the death health threshold.
|
||||
/// </summary>
|
||||
public sealed class WillToDieSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly MobThresholdSystem _mobThresholds = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<WillToDieComponent, ComponentStartup>(OnStartup);
|
||||
SubscribeLocalEvent<WillToDieComponent, ComponentShutdown>(OnShutdown);
|
||||
}
|
||||
|
||||
private void OnStartup(Entity<WillToDieComponent> ent, ref ComponentStartup args)
|
||||
{
|
||||
AdjustDeathThreshold(ent.Owner, -ent.Comp.DeadDecrease);
|
||||
}
|
||||
|
||||
private void OnShutdown(Entity<WillToDieComponent> ent, ref ComponentShutdown args)
|
||||
{
|
||||
AdjustDeathThreshold(ent.Owner, ent.Comp.DeadDecrease);
|
||||
}
|
||||
|
||||
private void AdjustDeathThreshold(EntityUid uid, int deltaPoints, MobThresholdsComponent? thresholdsComp = null)
|
||||
{
|
||||
if (!_mobThresholds.TryGetThresholdForState(uid, MobState.Dead, out var current, thresholdsComp))
|
||||
return;
|
||||
|
||||
var newValue = FixedPoint2.Max(0, current.Value + deltaPoints);
|
||||
|
||||
_mobThresholds.SetMobStateThreshold(uid, newValue, MobState.Dead, thresholdsComp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
using Content.Shared._Mono.Traits.Physical;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Mobs;
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
|
||||
namespace Content.Server._Mono.Traits.Physical;
|
||||
|
||||
/// <summary>
|
||||
/// Applies the Will To Live trait effects by increasing the death health threshold.
|
||||
/// </summary>
|
||||
public sealed class WillToLiveSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly MobThresholdSystem _mobThresholds = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<WillToLiveComponent, ComponentStartup>(OnStartup);
|
||||
SubscribeLocalEvent<WillToLiveComponent, ComponentShutdown>(OnShutdown);
|
||||
}
|
||||
|
||||
private void OnStartup(Entity<WillToLiveComponent> ent, ref ComponentStartup args)
|
||||
{
|
||||
AdjustDeathThreshold(ent.Owner, ent.Comp.DeadIncrease);
|
||||
}
|
||||
|
||||
private void OnShutdown(Entity<WillToLiveComponent> ent, ref ComponentShutdown args)
|
||||
{
|
||||
AdjustDeathThreshold(ent.Owner, -ent.Comp.DeadIncrease);
|
||||
}
|
||||
|
||||
private void AdjustDeathThreshold(EntityUid uid, int deltaPoints, MobThresholdsComponent? thresholdsComp = null)
|
||||
{
|
||||
if (!_mobThresholds.TryGetThresholdForState(uid, MobState.Dead, out var current, thresholdsComp))
|
||||
return;
|
||||
|
||||
var newValue = FixedPoint2.Max(0, current.Value + deltaPoints);
|
||||
|
||||
_mobThresholds.SetMobStateThreshold(uid, newValue, MobState.Dead, thresholdsComp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -38,7 +38,6 @@ public sealed class VendingMachinePurchaseSystem : EntitySystem
|
||||
var purchaseComponent = AddComp<VendingMachinePurchaseComponent>(purchasedEntity);
|
||||
purchaseComponent.PurchaseGrid = vendingTransform.GridUid.Value;
|
||||
purchaseComponent.OriginalPurchasePrice = purchasePrice;
|
||||
purchaseComponent.VendingMachine = vendingMachine;
|
||||
|
||||
Dirty(purchasedEntity, purchaseComponent);
|
||||
}
|
||||
|
||||
@@ -296,9 +296,7 @@ public sealed partial class MarketSystem
|
||||
else
|
||||
{
|
||||
var maxQuantityToWithdraw = marketData.GetMaxQuantityToWithdraw(prototype);
|
||||
var toWithdraw = args.Amount;
|
||||
if (args.Amount > maxQuantityToWithdraw)
|
||||
toWithdraw = maxQuantityToWithdraw;
|
||||
var toWithdraw = MathHelper.Clamp(args.Amount, 1, maxQuantityToWithdraw);
|
||||
|
||||
var existing = FindMarketDataByPrototype(marketData, args.ItemPrototype!);
|
||||
if (existing == null)
|
||||
|
||||
@@ -177,7 +177,7 @@ public sealed class LinkedLifecycleGridSystem : EntitySystem
|
||||
// Deletes a grid, reparenting every humanoid and player character that's on it.
|
||||
public void UnparentPlayersFromGrid(EntityUid grid, bool deleteGrid, bool ignoreLifeStage = false)
|
||||
{
|
||||
if (!ignoreLifeStage && MetaData(grid).EntityLifeStage >= EntityLifeStage.Terminating)
|
||||
if (!ignoreLifeStage && TerminatingOrDeleted(grid))
|
||||
return;
|
||||
|
||||
var reparentEntities = GetEntitiesToReparent(grid);
|
||||
|
||||
@@ -150,7 +150,7 @@ public sealed class SurgerySystem : SharedSurgerySystem
|
||||
if (HasComp<ForcedSleepingComponent>(args.Body))
|
||||
damageChange = damageChange * ent.Comp.SleepModifier;
|
||||
|
||||
SetDamage(args.Body, damageChange, 0.5f, args.User, args.Part);
|
||||
SetDamage(args.Body, damageChange, 1f, args.User, args.Part); // 0.5-> 1.0f part damage - Mono
|
||||
}
|
||||
|
||||
private void OnSurgerySpecialDamageChange(Entity<SurgerySpecialDamageChangeEffectComponent> ent, ref SurgeryStepDamageChangeEvent args)
|
||||
|
||||
@@ -15,7 +15,7 @@ public sealed partial class PerishableComponent : Component
|
||||
/// How long it takes after death to start rotting.
|
||||
/// </summary>
|
||||
[DataField("rotAfter"), ViewVariables(VVAccess.ReadWrite)]
|
||||
public TimeSpan RotAfter = TimeSpan.FromMinutes(20);
|
||||
public TimeSpan RotAfter = TimeSpan.FromMinutes(60); // Mono: Tripled default (20 > 60)
|
||||
|
||||
/// <summary>
|
||||
/// How much rotting has occured
|
||||
|
||||
@@ -43,7 +43,7 @@ public sealed partial class BlockingSystem : SharedBlockingSystem // Mono
|
||||
|
||||
private void OnUserDamageModified(EntityUid uid, BlockingUserComponent component, DamageModifyEvent args)
|
||||
{
|
||||
if (TryComp<ItemToggleComponent>(component.BlockingItem, out var toggleComponent) && TryComp<BlockingComponent>(component.BlockingItem, out var blocking)) // Mono
|
||||
if (TryComp<BlockingComponent>(component.BlockingItem, out var blocking)) // Mono
|
||||
{
|
||||
if (args.Damage.GetTotal() <= 0)
|
||||
return;
|
||||
@@ -52,7 +52,7 @@ public sealed partial class BlockingSystem : SharedBlockingSystem // Mono
|
||||
if (!TryComp<DamageableComponent>(component.BlockingItem, out var dmgComp))
|
||||
return;
|
||||
|
||||
if (!toggleComponent.Activated) // Mono
|
||||
if (TryComp<ItemToggleComponent>(component.BlockingItem, out var toggleComponent) && !toggleComponent.Activated) // Mono
|
||||
return;
|
||||
|
||||
var blockFraction = blocking.IsBlocking ? blocking.ActiveBlockFraction : blocking.PassiveBlockFraction;
|
||||
|
||||
@@ -65,4 +65,15 @@ public sealed partial class CCVars
|
||||
"",
|
||||
CVar.SERVER | CVar.SERVERONLY | CVar.ARCHIVE,
|
||||
"A message broadcast to each player that joins the lobby.");
|
||||
|
||||
public static readonly CVarDef<string> ChatHighlights =
|
||||
CVarDef.Create("chat.words_highlights", "", CVar.CLIENTONLY | CVar.ARCHIVE,
|
||||
"Per-character custom highlight keywords. Format: one entry per line, 'CharacterName||encoded_keywords'. " +
|
||||
"Encoded keywords use \\n for newlines, \\| for pipes, \\\\ for backslashes.");
|
||||
|
||||
public static readonly CVarDef<bool> ChatAutoFillHighlights =
|
||||
CVarDef.Create("chat.auto_fill_highlights", false, CVar.CLIENTONLY | CVar.ARCHIVE, "Toggles automatically filling the highlights with the character's information.");
|
||||
|
||||
public static readonly CVarDef<string> ChatHighlightsColor =
|
||||
CVarDef.Create("chat.highlights_color", "#17FFC1FF", CVar.CLIENTONLY | CVar.ARCHIVE, "The color in which the highlights will be displayed.");
|
||||
}
|
||||
|
||||
@@ -77,6 +77,10 @@ public sealed partial class HumanoidAppearanceComponent : Component
|
||||
[DataField, AutoNetworkedField]
|
||||
public float Width = 1.0f;
|
||||
|
||||
[DataField, AutoNetworkedField] // Mono - Prescaled radial fixture sizes.
|
||||
public Dictionary<string, float> DefaultFixtures = [];
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Hair color of this humanoid. Used to avoid looping through all markings
|
||||
/// </summary>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Content.Shared._Mono.Humanoid; // Mono Fixture Adjustment
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Humanoid.Markings;
|
||||
using Content.Shared._Shitmed.Humanoid.Events; // Shitmed Change
|
||||
@@ -38,6 +39,7 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem
|
||||
[Dependency] private readonly ISerializationManager _serManager = default!;
|
||||
[Dependency] private readonly MarkingManager _markingManager = default!;
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||
[Dependency] private readonly HumanoidPhysicsScalingSystem _scaling = default!;
|
||||
|
||||
[ValidatePrototypeId<SpeciesPrototype>]
|
||||
public const string DefaultSpecies = "Human";
|
||||
@@ -444,6 +446,9 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem
|
||||
_appearance.SetData(uid, ScaleVisuals.Scale, new Vector2(profile.Appearance.Width, profile.Appearance.Height), appearance);
|
||||
}
|
||||
|
||||
// Update physics hitbox to match the new height and width - Mono
|
||||
_scaling.UpdatePhysicsHitbox(uid, humanoid);
|
||||
|
||||
RaiseLocalEvent(uid, new ProfileLoadFinishedEvent()); // Shitmed Change
|
||||
Dirty(uid, humanoid);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Content.Shared._Mono.Humanoid;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Content.Shared.Mobs.Events;
|
||||
using Content.Shared.Sprite;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Mobs.Systems;
|
||||
@@ -335,9 +337,27 @@ public sealed class MobThresholdSystem : EntitySystem
|
||||
private void CheckThresholds(EntityUid target, MobStateComponent mobStateComponent,
|
||||
MobThresholdsComponent thresholdsComponent, DamageableComponent damageableComponent, EntityUid? origin = null)
|
||||
{
|
||||
|
||||
var ev = new QueryMobThresholdsEvent();
|
||||
RaiseLocalEvent(target, ref ev);
|
||||
Log.Debug($"ThresholdEvent for {ToPrettyString(target)}: Scale={ev.Scale:F2}, Crit={ev.CritOffset:F2}, Death={ev.DeathOffset:F2}");
|
||||
|
||||
foreach (var (threshold, mobState) in thresholdsComponent.Thresholds.Reverse())
|
||||
{
|
||||
if (damageableComponent.TotalDamage < threshold)
|
||||
// Mono Begin
|
||||
|
||||
float scale = 1;
|
||||
if (ev.Scale != 0) // To scale from being zeroed out from no response i.e. comp not initialized yet.
|
||||
scale = ev.Scale;
|
||||
float offset = 0;
|
||||
if (mobState == MobState.Dead)
|
||||
offset += ev.DeathOffset;
|
||||
if (mobState == MobState.Critical)
|
||||
offset += ev.CritOffset;
|
||||
|
||||
// Mono End
|
||||
|
||||
if (damageableComponent.TotalDamage < (threshold + (FixedPoint2)offset) * scale) // Mono - Add threshold scale and offset.
|
||||
continue;
|
||||
|
||||
TriggerThreshold(target, mobState, mobStateComponent, thresholdsComponent, origin);
|
||||
@@ -474,9 +494,11 @@ public sealed class MobThresholdSystem : EntitySystem
|
||||
UpdateAllEffects((ent, ent, null, null), args.NewMobState);
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Event that triggers when an entity with a mob threshold is checked
|
||||
/// </summary>
|
||||
|
||||
@@ -131,6 +131,10 @@ namespace Content.Shared.Movement.Systems
|
||||
|
||||
private void OnMoverGetState(Entity<InputMoverComponent> entity, ref ComponentGetState args)
|
||||
{
|
||||
// Mono
|
||||
if (TerminatingOrDeleted(entity.Comp.RelativeEntity))
|
||||
entity.Comp.RelativeEntity = null;
|
||||
|
||||
args.State = new InputMoverComponentState()
|
||||
{
|
||||
CanMove = entity.Comp.CanMove,
|
||||
|
||||
@@ -29,6 +29,13 @@ public sealed partial class NpcFactionPrototype : IPrototype
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool DefaultHostile = false;
|
||||
|
||||
/// <summary>
|
||||
/// Mono - Is this faction checked for default hostility?
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool DefaultHostileIncluded = true;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -348,6 +348,7 @@ public sealed partial class NpcFactionSystem : EntitySystem
|
||||
{
|
||||
if (iteratedFaction.Neutral.Contains(faction) ||
|
||||
iteratedFaction.Friendly.Contains(faction) ||
|
||||
!faction.DefaultHostileIncluded || // Mono
|
||||
faction.ID == iteratedFaction.ID)
|
||||
continue;
|
||||
|
||||
|
||||
@@ -75,6 +75,8 @@ public enum CollisionGroup
|
||||
SlipLayer = MidImpassable | LowImpassable,
|
||||
ItemMask = Impassable | HighImpassable,
|
||||
ThrownItem = Impassable | HighImpassable | BulletImpassable,
|
||||
DiagonalWallLayer = Opaque | HighImpassable | MidImpassable | LowImpassable | BulletImpassable, // Mono
|
||||
DiagonalGlassLayer = HighImpassable | MidImpassable | LowImpassable | BulletImpassable, // Mono
|
||||
WallLayer = Opaque | Impassable | HighImpassable | MidImpassable | LowImpassable | BulletImpassable | InteractImpassable,
|
||||
GlassLayer = Impassable | HighImpassable | MidImpassable | LowImpassable | BulletImpassable | InteractImpassable,
|
||||
HalfWallLayer = MidImpassable | LowImpassable,
|
||||
|
||||
@@ -45,6 +45,9 @@ public sealed partial class BorgSwitchableTypeComponent : Component
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public ProtoId<RadioChannelPrototype>[] InherentRadioChannels = [];
|
||||
//Mono: Selectable borg whitelist
|
||||
[DataField(required: true), AutoNetworkedField]
|
||||
public List<ProtoId<BorgTypePrototype>> TypeWhitelist = new();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -79,6 +79,14 @@ public abstract class SharedBorgSwitchableTypeSystem : EntitySystem
|
||||
|
||||
if (!Prototypes.HasIndex(args.Prototype) || !Prototypes.HasIndex(args.Subtype))
|
||||
return;
|
||||
//Mono: Selectable borg whitelist - Validation
|
||||
if (ent.Comp.TypeWhitelist.Count == 0)
|
||||
{
|
||||
Log.Error("Empty whitelist on selectable cyborg chassis");
|
||||
return;
|
||||
}
|
||||
if (!ent.Comp.TypeWhitelist.Contains(args.Prototype))
|
||||
return;
|
||||
|
||||
SelectBorgModule(ent, args.Prototype, args.Subtype);
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Content.Shared.Voting
|
||||
public string VoteInitiator = string.Empty;
|
||||
public TimeSpan StartTime; // Server RealTime.
|
||||
public TimeSpan EndTime; // Server RealTime.
|
||||
public (ushort votes, string name)[] Options = default!;
|
||||
public (ushort votes, string name, ushort realVotes)[] Options = default!; // Mono - account for vote weight
|
||||
public bool IsYourVoteDirty;
|
||||
public byte? YourVote;
|
||||
public bool DisplayVotes;
|
||||
@@ -36,10 +36,10 @@ namespace Content.Shared.Voting
|
||||
DisplayVotes = buffer.ReadBoolean();
|
||||
TargetEntity = buffer.ReadVariableInt32();
|
||||
|
||||
Options = new (ushort votes, string name)[buffer.ReadByte()];
|
||||
Options = new (ushort votes, string name, ushort realvotes)[buffer.ReadByte()];
|
||||
for (var i = 0; i < Options.Length; i++)
|
||||
{
|
||||
Options[i] = (buffer.ReadUInt16(), buffer.ReadString());
|
||||
Options[i] = (buffer.ReadUInt16(), buffer.ReadString(), buffer.ReadUInt16());
|
||||
}
|
||||
|
||||
IsYourVoteDirty = buffer.ReadBoolean();
|
||||
@@ -66,10 +66,11 @@ namespace Content.Shared.Voting
|
||||
buffer.WriteVariableInt32(TargetEntity);
|
||||
|
||||
buffer.Write((byte) Options.Length);
|
||||
foreach (var (votes, name) in Options)
|
||||
foreach (var (votes, name, realVotes) in Options)
|
||||
{
|
||||
buffer.Write(votes);
|
||||
buffer.Write(name);
|
||||
buffer.Write(realVotes); // Mono
|
||||
}
|
||||
|
||||
buffer.Write(IsYourVoteDirty);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Weapons.Hitscan.Components;
|
||||
using Content.Shared.Weapons.Hitscan.Events;
|
||||
using Content.Shared.Weapons.Ranged.Events;
|
||||
@@ -8,6 +9,7 @@ namespace Content.Shared.Weapons.Hitscan.Systems;
|
||||
|
||||
public sealed class HitscanReflectSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly DamageableSystem _damage = default!; // Mono
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -23,8 +25,14 @@ public sealed class HitscanReflectSystem : EntitySystem
|
||||
if (hitscan.Comp.CurrentReflections >= hitscan.Comp.MaxReflections)
|
||||
return;
|
||||
|
||||
// Mono - Added null as default DamageSpecifier? Damage parameter
|
||||
var ev = new HitScanReflectAttemptEvent(args.Shooter ?? args.Gun, args.Gun, hitscan.Comp.ReflectiveType, args.ShotDirection, false, null);
|
||||
// Mono begin
|
||||
DamageSpecifier damage = new();
|
||||
if (EntityManager.TryGetComponent<HitscanBasicDamageComponent>(hitscan, out var hitscanDamage))
|
||||
damage = hitscanDamage.Damage * _damage.UniversalHitscanDamageModifier;
|
||||
|
||||
// Mono - Use hitscan damage component if available
|
||||
var ev = new HitScanReflectAttemptEvent(args.Shooter ?? args.Gun, args.Gun, hitscan.Comp.ReflectiveType, args.ShotDirection, false, damage);
|
||||
// Mono End
|
||||
RaiseLocalEvent(args.HitEntity.Value, ref ev);
|
||||
|
||||
if (!ev.Reflected)
|
||||
|
||||
@@ -30,6 +30,9 @@ public sealed partial class ReflectComponent : Component
|
||||
public SoundSpecifier? SoundOnReflect = new SoundPathSpecifier("/Audio/Weapons/Guns/Hits/laser_sear_wall.ogg");
|
||||
|
||||
// WD START
|
||||
/// <summary>
|
||||
/// How much damage does the reflecting item take on reflect?
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public float DamageOnReflectModifier;
|
||||
// WD END
|
||||
|
||||
@@ -232,7 +232,7 @@ public sealed class ReflectSystem : EntitySystem
|
||||
if (reflect.DamageOnReflectModifier != 0)
|
||||
{
|
||||
_damageable.TryChangeDamage(reflector, projectileComp.Damage * reflect.DamageOnReflectModifier,
|
||||
projectileComp.IgnoreResistances, origin: projectileComp.Shooter);
|
||||
projectileComp.IgnoreResistances, armorPenetration: projectileComp.ArmorPenetration, origin: projectileComp.Shooter); // Mono - Added armorpen
|
||||
}
|
||||
// WD EDIT END
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
using Content.Shared._Mono.Claws.Components;
|
||||
using Content.Shared._Mono.Claws;
|
||||
using Content.Shared.EntityEffects;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.EntityEffects.Effects
|
||||
{
|
||||
public sealed partial class ClawsGrowth : EntityEffect
|
||||
{
|
||||
/// <summary>
|
||||
/// Bonus Claws growth in seconds. X seconds of additional growth per second.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public double Growth;
|
||||
|
||||
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
|
||||
=> Loc.GetString("reagent-effect-guidebook-claws-growth",
|
||||
("chance", Probability),
|
||||
("amount", Growth));
|
||||
|
||||
public override void Effect(EntityEffectBaseArgs args)
|
||||
{
|
||||
if (args.EntityManager.TryGetComponent<ClawsComponent>(args.TargetEntity, out var claws))
|
||||
{
|
||||
var sys = args.EntityManager.EntitySysManager.GetEntitySystem<SharedClawsSystem>();
|
||||
var growth = Growth;
|
||||
|
||||
if (args is EntityEffectReagentArgs reagentArgs)
|
||||
{
|
||||
growth *= reagentArgs.Scale.Float();
|
||||
}
|
||||
|
||||
sys.GrowClaws(TimeSpan.FromSeconds(growth), claws);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,12 +7,13 @@ using Content.Shared.Popups;
|
||||
using Content.Shared.Weapons.Melee.Events;
|
||||
|
||||
namespace Content.Shared._Mono.Claws;
|
||||
|
||||
public abstract partial class SharedClawsSystem
|
||||
{
|
||||
public void UpdateDeclaw(EntityUid uid, Declawed declawed, ClawsComponent claws, float updateTime)
|
||||
{
|
||||
if (!_state.IsAlive(uid))
|
||||
return;
|
||||
return;
|
||||
|
||||
var hands = _hands.EnumerateHands(uid).ToArray();
|
||||
if (!_hands.EnumerateHeld(uid).Any())
|
||||
@@ -43,7 +44,7 @@ public abstract partial class SharedClawsSystem
|
||||
|
||||
claws.DeclawItemHoldTimer = TimeSpan.Zero;
|
||||
|
||||
Dirty(uid,claws);
|
||||
Dirty(uid, claws);
|
||||
}
|
||||
|
||||
public void Declaw(EntityUid uid, ClawsComponent claws)
|
||||
|
||||
@@ -43,7 +43,7 @@ public abstract partial class SharedClawsSystem
|
||||
public bool TryClipNails(NailClipperComponent component, EntityUid nailClipper, EntityUid user, EntityUid? target = null)
|
||||
{
|
||||
target ??= user;
|
||||
|
||||
|
||||
if (!TryComp<ClawsComponent>(target, out var claws))
|
||||
{
|
||||
return false;
|
||||
@@ -89,7 +89,7 @@ public abstract partial class SharedClawsSystem
|
||||
|
||||
if (nailClipper.DeclawChance > _random.NextFloat())
|
||||
{
|
||||
Declaw(uid,component);
|
||||
Declaw(uid, component);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -97,6 +97,9 @@ public abstract partial class SharedClawsSystem
|
||||
Math.Clamp(TryGetStageNumber(component) - nailClipper.StageReduction, 0, int.MaxValue));
|
||||
_popup.PopupClient(Loc.GetString("claws-clipping-success"), Transform(uid).Coordinates, uid);
|
||||
|
||||
// Reset current growth progress
|
||||
component.GrowTimer = TimeSpan.Zero;
|
||||
|
||||
UpdateClaws(uid, component);
|
||||
Dirty(uid, component);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Content.Shared._Mono.Claws.Components;
|
||||
/// <summary>
|
||||
/// This is claw component used for <see cref="SharedClawsSystem"/> System.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, AutoGenerateComponentPause]
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||
public sealed partial class ClawsComponent : Component
|
||||
{
|
||||
[DataField, AutoNetworkedField]
|
||||
@@ -18,9 +18,12 @@ public sealed partial class ClawsComponent : Component
|
||||
[DataField]
|
||||
public LocId? ClawGrowthNotification;
|
||||
|
||||
[DataField, AutoPausedField]
|
||||
[DataField]
|
||||
public TimeSpan GrowTimer = TimeSpan.Zero;
|
||||
|
||||
[AutoPausedField]
|
||||
[DataField]
|
||||
public TimeSpan AccumulatedBonusGrowth = TimeSpan.Zero;
|
||||
|
||||
[DataField]
|
||||
public TimeSpan DeclawItemHoldTimer = TimeSpan.Zero;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._Mono.Claws.Components;
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class ClawsGrowthSuppressionComponent : Component;
|
||||
@@ -104,6 +104,11 @@ public abstract partial class SharedClawsSystem : EntitySystem
|
||||
gunAccuracyComp.SpreadMultiplier = stage.GunSpreadMultiplier;
|
||||
}
|
||||
|
||||
public void GrowClaws(TimeSpan bonusGrowth, ClawsComponent component)
|
||||
{
|
||||
component.AccumulatedBonusGrowth += bonusGrowth;
|
||||
}
|
||||
|
||||
protected bool TryGetStage<T>(ClawsComponent comp, [NotNullWhen(true)] out T? stage) where T : ClawType
|
||||
{
|
||||
if (!_protoMan.TryIndex(comp.ClawStage, out var clawProto) ||
|
||||
|
||||
@@ -9,6 +9,9 @@ namespace Content.Shared._Mono.Detection;
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||
public sealed partial class ThermalSignatureComponent : Component
|
||||
{
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public float LastUpdateHeat = 0f;
|
||||
|
||||
[DataField]
|
||||
public float StoredHeat = 0f;
|
||||
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
using System.Linq;
|
||||
using Content.Shared._Mono.Traits.Physical;
|
||||
using Content.Shared._Shitmed.Humanoid.Events;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Ghost;
|
||||
using Content.Shared.Humanoid;
|
||||
using Content.Shared.Mobs;
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
using Content.Shared.Sprite;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Physics.Collision.Shapes;
|
||||
using Robust.Shared.Physics.Systems;
|
||||
|
||||
namespace Content.Shared._Mono.Humanoid;
|
||||
|
||||
/// <summary>
|
||||
/// System that adjusts physics hitboxes of humanoid entities based on their height and weight (width).
|
||||
/// </summary>
|
||||
public sealed class HumanoidPhysicsScalingSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
// Listen for when a humanoid appearance is loaded (character creation/spawning)
|
||||
SubscribeLocalEvent<HumanoidAppearanceComponent, ComponentStartup>(OnComponentStartup);
|
||||
|
||||
// Listen for when humanoid appearance changes (admin commands, mutations, etc.)
|
||||
SubscribeLocalEvent<HumanoidAppearanceComponent, ComponentRemove>(OnHumanoidShutdown);
|
||||
|
||||
SubscribeLocalEvent<HumanoidAppearanceComponent, QueryMobThresholdsEvent>(OnQueryMobThresholds);
|
||||
}
|
||||
|
||||
private void OnComponentStartup(EntityUid uid, HumanoidAppearanceComponent component, ComponentStartup args)
|
||||
{
|
||||
AssignDefaultHitboxes(uid, component);
|
||||
UpdatePhysicsHitbox(uid, component);
|
||||
}
|
||||
|
||||
private void OnHumanoidShutdown(EntityUid uid, HumanoidAppearanceComponent component, ComponentRemove args)
|
||||
{
|
||||
// Reset hitbox to default when component is removed
|
||||
if (TryComp<FixturesComponent>(uid, out var fixtures))
|
||||
{
|
||||
ResetToDefaultHitbox(uid, component, fixtures);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Public method to manually update a humanoid's hitbox
|
||||
/// </summary>
|
||||
/// <param name="uid">The entity to update</param>
|
||||
public void UpdateHitbox(EntityUid uid)
|
||||
{
|
||||
if (TryComp<HumanoidAppearanceComponent>(uid, out var humanoid))
|
||||
{
|
||||
UpdatePhysicsHitbox(uid, humanoid);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Public method to set specific height and width then update hitbox.
|
||||
/// </summary>
|
||||
/// <param name="uid">The entity to update</param>
|
||||
/// <param name="height">Height multiplier (1.0 = default)</param>
|
||||
/// <param name="width">Width multiplier (1.0 = default)</param>
|
||||
public void UpdateHitbox(EntityUid uid, float height, float width)
|
||||
{
|
||||
if (TryComp<HumanoidAppearanceComponent>(uid, out var humanoid))
|
||||
{
|
||||
humanoid.Height = height;
|
||||
humanoid.Width = width;
|
||||
UpdatePhysicsHitbox(uid, humanoid);
|
||||
}
|
||||
}
|
||||
|
||||
public void AssignDefaultHitboxes(EntityUid uid, HumanoidAppearanceComponent humanoid)
|
||||
{
|
||||
if (!TryComp<FixturesComponent>(uid, out var fixtures))
|
||||
return;
|
||||
|
||||
foreach (var (fixtureId, fixture) in fixtures.Fixtures)
|
||||
{
|
||||
if (fixture.Shape is PhysShapeCircle)
|
||||
{
|
||||
var oldRadius = fixture.Shape.Radius;
|
||||
humanoid.DefaultFixtures[fixtureId] = oldRadius;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the physics hitbox based on the humanoid's height and width.
|
||||
/// </summary>
|
||||
/// <param name="uid">The entity to update</param>
|
||||
/// <param name="humanoid">The humanoid appearance component</param>
|
||||
public void UpdatePhysicsHitbox(EntityUid uid, HumanoidAppearanceComponent humanoid)
|
||||
{
|
||||
if (!TryComp<FixturesComponent>(uid, out var fixtures))
|
||||
return;
|
||||
|
||||
// Calculate the new radius based on height and width
|
||||
// We take the average of height and width for a circular hitbox
|
||||
var scale = CalculateScale(humanoid);
|
||||
// Update all circular fixtures (most humanoids should have just one main fixture)
|
||||
foreach (var (fixtureId, fixture) in fixtures.Fixtures)
|
||||
{
|
||||
if (fixture.Shape is PhysShapeCircle circle && humanoid.DefaultFixtures.TryGetValue(fixtureId, out var oldRadius))
|
||||
{
|
||||
var newRadius = oldRadius * scale;
|
||||
_physics.SetRadius(uid, fixtureId, fixture, circle, newRadius, fixtures);
|
||||
|
||||
// Log the change for debugging
|
||||
Log.Debug($"Updated physics hitbox for {ToPrettyString(uid)}: Fixture={fixtureId:F2} Height={humanoid.Height:F2}, Width={humanoid.Width:F2}, Radius={newRadius:F2}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnQueryMobThresholds(Entity<HumanoidAppearanceComponent> ent, ref QueryMobThresholdsEvent args)
|
||||
{
|
||||
args.Scale = CalculateScale(ent.Comp);
|
||||
Log.Debug($"Updated damage scale for {ToPrettyString(ent)}: Scale={args.Scale:F2} Height={ent.Comp.Height:F2}, Width={ent.Comp.Width:F2}");
|
||||
}
|
||||
|
||||
public float CalculateScale(HumanoidAppearanceComponent humanoid)
|
||||
{
|
||||
return MathF.Sqrt(MathF.Pow(humanoid.Height, 2) + MathF.Pow(humanoid.Width, 2)) / MathF.Sqrt(2.0f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets a humanoid's hitbox to the default size.
|
||||
/// </summary>
|
||||
/// <param name="uid">The entity to reset</param>
|
||||
/// <param name="fixtures">The fixtures component</param>
|
||||
private void ResetToDefaultHitbox(EntityUid uid, HumanoidAppearanceComponent humanoid, FixturesComponent fixtures)
|
||||
{
|
||||
foreach (var (fixtureId, fixture) in fixtures.Fixtures)
|
||||
{
|
||||
if (fixture.Shape is PhysShapeCircle circle && humanoid.DefaultFixtures.TryGetValue(fixtureId, out var oldRadius))
|
||||
{
|
||||
_physics.SetRadius(uid, fixtureId, fixture, circle, oldRadius, fixtures);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
[ByRefEvent]
|
||||
public record struct QueryMobThresholdsEvent(float Scale = 1.0f, float DeathOffset = 0, float CritOffset = 0);
|
||||
@@ -0,0 +1,20 @@
|
||||
namespace Content.Shared._Mono.Traits.Physical;
|
||||
|
||||
/// <summary>
|
||||
/// Offsets the threshold required to reach mob thresholds.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class MobThresholdOffsetComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// How much to increase the Dead damage threshold by.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public int DeadOffset = 0;
|
||||
|
||||
/// <summary>
|
||||
/// How much to increase the Crit damage threshold by.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public int CritOffset = 0;
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
namespace Content.Shared._Mono.Traits.Physical;
|
||||
|
||||
/// <summary>
|
||||
/// Decreases the damage threshold required to enter the Dead state.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class WillToDieComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// How much to decrease the Dead damage threshold by.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public int DeadDecrease = 15;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
namespace Content.Shared._Mono.Traits.Physical;
|
||||
|
||||
/// <summary>
|
||||
/// Increases the damage threshold required to enter the Dead state.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class WillToLiveComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// How much to increase the Dead damage threshold by.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public int DeadIncrease = 10;
|
||||
}
|
||||
@@ -22,11 +22,4 @@ public sealed partial class VendingMachinePurchaseComponent : Component
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public double OriginalPurchasePrice;
|
||||
|
||||
/// <summary>
|
||||
/// The entity ID of the vending machine this was purchased from.
|
||||
/// Stored for reference and potential future features.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public EntityUid VendingMachine;
|
||||
}
|
||||
|
||||
@@ -177,7 +177,7 @@ public abstract partial class SharedSurgerySystem
|
||||
if (!HasComp<SanitizedComponent>(args.User))
|
||||
{
|
||||
var sepsis = new DamageSpecifier(_prototypes.Index<DamageTypePrototype>("Poison"), 15);
|
||||
var ev = new SurgeryStepDamageEvent(args.User, args.Body, args.Part, args.Surgery, sepsis, 0.5f);
|
||||
var ev = new SurgeryStepDamageEvent(args.User, args.Body, args.Part, args.Surgery, sepsis, 1.0f); // Mono - 0.5->1.0f - Mono Part surgery damage increase
|
||||
RaiseLocalEvent(args.Body, ref ev);
|
||||
}
|
||||
}
|
||||
@@ -360,7 +360,7 @@ public abstract partial class SharedSurgerySystem
|
||||
foreach (var type in group)
|
||||
adjustedDamage.DamageDict[type] -= bonus;
|
||||
|
||||
var ev = new SurgeryStepDamageEvent(args.User, args.Body, args.Part, args.Surgery, adjustedDamage, 0.5f);
|
||||
var ev = new SurgeryStepDamageEvent(args.User, args.Body, args.Part, args.Surgery, adjustedDamage, 2.5f); // 0.5 -> 2.5f part damage, buffed wound surgery tending - Mono
|
||||
RaiseLocalEvent(args.Body, ref ev);
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ public abstract class SharedLayingDownSystem : EntitySystem
|
||||
{
|
||||
if (session?.AttachedEntity == null ||
|
||||
!HasComp<LayingDownComponent>(session.AttachedEntity) ||
|
||||
_gravity.IsWeightless(session.AttachedEntity.Value))
|
||||
!CanLieDown(session.AttachedEntity.Value)) // Mono
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -112,7 +112,7 @@ public abstract class SharedLayingDownSystem : EntitySystem
|
||||
// If the entity is not on a grid, try to make it stand up to avoid issues
|
||||
if (!TryComp<StandingStateComponent>(uid, out var standingState)
|
||||
|| standingState.CurrentState is StandingState.Standing
|
||||
|| Transform(uid).GridUid != null)
|
||||
|| CanLieDown(uid)) // Mono
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -150,7 +150,8 @@ public abstract class SharedLayingDownSystem : EntitySystem
|
||||
{
|
||||
if (!Resolve(uid, ref standingState, false) ||
|
||||
!Resolve(uid, ref layingDown, false) ||
|
||||
standingState.CurrentState is not StandingState.Standing)
|
||||
standingState.CurrentState is not StandingState.Standing ||
|
||||
!CanLieDown(uid)) // Mono
|
||||
{
|
||||
if (behavior == DropHeldItemsBehavior.AlwaysDrop)
|
||||
{
|
||||
@@ -163,6 +164,12 @@ public abstract class SharedLayingDownSystem : EntitySystem
|
||||
_standing.Down(uid, true, behavior != DropHeldItemsBehavior.NoDrop, false, standingState);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Mono
|
||||
private bool CanLieDown(EntityUid uid)
|
||||
{
|
||||
return _gravity.EntityOnGravitySupportingGridOrMap(uid);
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
|
||||
@@ -24,7 +24,7 @@ We provide some scripts shown below to make the job easier.
|
||||
### Build dependencies
|
||||
|
||||
> - Git
|
||||
> - .NET SDK 9.0.101
|
||||
> - .NET SDK 10.0
|
||||
|
||||
|
||||
### Windows
|
||||
|
||||
@@ -18716,3 +18716,483 @@ Entries:
|
||||
id: 2064
|
||||
time: '2026-03-22T19:49:14.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3499
|
||||
- author: tonotom1
|
||||
changes:
|
||||
- type: Tweak
|
||||
message: >-
|
||||
Cables no longer drop an item when destroyed, ever. Hopefully this will
|
||||
reduce ram lag. Cable HP also standardized to 200 for all types.
|
||||
id: 2065
|
||||
time: '2026-03-22T22:41:10.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3520
|
||||
- author: Redrover1760
|
||||
changes:
|
||||
- type: Tweak
|
||||
message: Hydrakin no longer heat up in criticial.
|
||||
- type: Fix
|
||||
message: People no longer thermal regulate while dead.
|
||||
id: 2066
|
||||
time: '2026-03-22T22:54:10.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3530
|
||||
- author: Redrover1760
|
||||
changes:
|
||||
- type: Fix
|
||||
message: Part damage easier to heal/injure with surgery/chems
|
||||
id: 2067
|
||||
time: '2026-03-22T23:22:33.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3533
|
||||
- author: Redrover1760
|
||||
changes:
|
||||
- type: Tweak
|
||||
message: Built research datafarms now work
|
||||
id: 2068
|
||||
time: '2026-03-23T03:42:15.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3536
|
||||
- author: Kiithnaras
|
||||
changes:
|
||||
- type: Tweak
|
||||
message: Added roofing mask and emergency lighting to CDM Comet.
|
||||
id: 2069
|
||||
time: '2026-03-23T04:00:28.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3381
|
||||
- author: Redrover1760
|
||||
changes:
|
||||
- type: Tweak
|
||||
message: >-
|
||||
Tending surgery heals bodyparts 2.5x the amount tended, previous value
|
||||
was 0.5x
|
||||
- type: Tweak
|
||||
message: >-
|
||||
Other surgery based damage increased to 1.0x part damage instead of 0.5x
|
||||
(i.e sepsis)
|
||||
id: 2070
|
||||
time: '2026-03-23T06:04:49.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3534
|
||||
- author: Redrover1760
|
||||
changes:
|
||||
- type: Tweak
|
||||
message: Research datafarms now can be made with any 10000 point disk.
|
||||
id: 2071
|
||||
time: '2026-03-23T17:23:36.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3543
|
||||
- author: chuga-git
|
||||
changes:
|
||||
- type: Tweak
|
||||
message: MARAUDER plasma cannon projectile speed increased by 50%. (100->150)
|
||||
id: 2072
|
||||
time: '2026-03-24T11:44:39.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3549
|
||||
- author: Redrover1760
|
||||
changes:
|
||||
- type: Fix
|
||||
message: >-
|
||||
Printed contraband-type items, aka enemy faction gear, can now be sold
|
||||
for FMCs/DCs. Frontier is so frustrating man.
|
||||
id: 2073
|
||||
time: '2026-03-24T12:06:49.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3548
|
||||
- author: gelliii
|
||||
changes:
|
||||
- type: Add
|
||||
message: Added the Horsefly, welded together by hopes and dreams.
|
||||
id: 2074
|
||||
time: '2026-03-24T15:07:30.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3155
|
||||
- author: Ilya246
|
||||
changes:
|
||||
- type: Fix
|
||||
message: Fixes the server not checking some bank balance-related values.
|
||||
id: 2075
|
||||
time: '2026-03-24T19:00:31.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3550
|
||||
- author: Ilya246
|
||||
changes:
|
||||
- type: Tweak
|
||||
message: >-
|
||||
AMEs no longer scale purely off core count. Injection count now matters
|
||||
instead.
|
||||
id: 2076
|
||||
time: '2026-03-24T19:54:07.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3552
|
||||
- author: Avalon-Proto
|
||||
changes:
|
||||
- type: Add
|
||||
message: >-
|
||||
Ullman Industries has released a new overcoat, this one with much
|
||||
thicker fur around the neck
|
||||
id: 2077
|
||||
time: '2026-03-24T23:41:50.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3260
|
||||
- author: Lokilife
|
||||
changes:
|
||||
- type: Fix
|
||||
message: You can't lie in space with voidboots anymore
|
||||
id: 2078
|
||||
time: '2026-03-25T00:08:36.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3551
|
||||
- author: Redrover1760
|
||||
changes:
|
||||
- type: Fix
|
||||
message: >-
|
||||
Research generating things no longer connect to multiple servers at once
|
||||
when built
|
||||
id: 2079
|
||||
time: '2026-03-25T04:12:27.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3556
|
||||
- author: lopsidedmanboobs
|
||||
changes:
|
||||
- type: Remove
|
||||
message: >-
|
||||
You cannot force people to pay their own ransom during Piracy anymore.
|
||||
View Conflict Rule 3.
|
||||
id: 2080
|
||||
time: '2026-03-25T05:49:54.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3558
|
||||
- author: Redrover1760
|
||||
changes:
|
||||
- type: Tweak
|
||||
message: >-
|
||||
Clipping Claws now resets growth time, ensuring you do not have to worry
|
||||
about your claws reaching the next stage for a while.
|
||||
- type: Add
|
||||
message: >-
|
||||
Phenoxzine and Meroxzine. Phenoxzine massively boosts claw growth speed,
|
||||
Meroxzine halts it completely for a long period of time.
|
||||
id: 2081
|
||||
time: '2026-03-25T06:13:30.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3554
|
||||
- author: Redrover1760
|
||||
changes:
|
||||
- type: Add
|
||||
message: Ports CMO webbing from Goob, adds it to CMO/DoC lockers.
|
||||
id: 2082
|
||||
time: '2026-03-25T18:33:22.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3555
|
||||
- author: Redrover1760
|
||||
changes:
|
||||
- type: Tweak
|
||||
message: >-
|
||||
Fireteam leader marine playtime requirement of 10 hours replaced with
|
||||
general tsfmc playtime requirement of 10 hours
|
||||
id: 2083
|
||||
time: '2026-03-25T19:53:53.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3542
|
||||
- author: Redrover1760
|
||||
changes:
|
||||
- type: Fix
|
||||
message: >-
|
||||
Energy shields now take damage from reflecting hitscan projectiles,
|
||||
instead of just non-hitscan energy projectiles.
|
||||
- type: Fix
|
||||
message: Non-energy shields properly reduce damage taken.
|
||||
- type: Fix
|
||||
message: Riot and non-energy shields work now.
|
||||
id: 2084
|
||||
time: '2026-03-25T22:18:31.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3563
|
||||
- author: UnicornOnLSD
|
||||
changes:
|
||||
- type: Tweak
|
||||
message: >-
|
||||
The DIS Femur has seen a light rework, see PR for more details. Report
|
||||
feedback & issues to me on discord (@unicornonlsd)
|
||||
id: 2085
|
||||
time: '2026-03-26T05:55:13.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3560
|
||||
- author: Redrover1760
|
||||
changes:
|
||||
- type: Remove
|
||||
message: You can no longer sell crates on Helios/Lancelot
|
||||
id: 2086
|
||||
time: '2026-03-26T22:05:32.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3573
|
||||
- author: Onezero0
|
||||
changes:
|
||||
- type: Tweak
|
||||
message: Tripled the time it takes for a body to start rotting (20 -> 60 minutes)
|
||||
id: 2087
|
||||
time: '2026-03-27T05:49:14.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3524
|
||||
- author: Redrover1760
|
||||
changes:
|
||||
- type: Fix
|
||||
message: Hydrakin head displacement improved slightly
|
||||
id: 2088
|
||||
time: '2026-03-27T07:19:24.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3575
|
||||
- author: Redrover1760
|
||||
changes:
|
||||
- type: Tweak
|
||||
message: Updates Reptilian Guidebook with recent changes.
|
||||
id: 2089
|
||||
time: '2026-03-27T07:20:31.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3565
|
||||
- author: Ilya246
|
||||
changes:
|
||||
- type: Add
|
||||
message: Reenabled apocalypse gamemode.
|
||||
- type: Tweak
|
||||
message: Apocalypse now requires a 80% majority vote.
|
||||
- type: Tweak
|
||||
message: Some events can now trigger earlier.
|
||||
- type: Fix
|
||||
message: Fixed biothreat spawning chimera only 3 hours in. Now 1 hour.
|
||||
id: 2090
|
||||
time: '2026-03-27T17:58:07.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3570
|
||||
- author: NazrinNya
|
||||
changes:
|
||||
- type: Tweak
|
||||
message: >-
|
||||
Heavy ballistic turrets now use 51mm antimaterial instead of 65mm.
|
||||
Firerate 5 -> 4.5 Projectile speed 100 -> 65.
|
||||
id: 2091
|
||||
time: '2026-03-27T19:26:23.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3461
|
||||
- author: Redrover1760
|
||||
changes:
|
||||
- type: Add
|
||||
message: >-
|
||||
Installs anti-chimera/hostile mob turrets to CC and MD to guard
|
||||
cryosleep chambers using RIP ammo.
|
||||
- type: Tweak
|
||||
message: Grids with godmode no longer godmode turrets.
|
||||
- type: Tweak
|
||||
message: Turrets are now repairable via welder.
|
||||
- type: Fix
|
||||
message: Turrets no longer shoot mice.
|
||||
id: 2092
|
||||
time: '2026-03-27T21:57:35.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3582
|
||||
- author: Redrover1760
|
||||
changes:
|
||||
- type: Fix
|
||||
message: >-
|
||||
Emergancy software update pushed. All turrets are no longer speciest and
|
||||
kill goblins, harpies, felinids, and dwarves on sight.
|
||||
id: 2093
|
||||
time: '2026-03-28T06:41:55.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3585
|
||||
- author: Redrover1760
|
||||
changes:
|
||||
- type: Fix
|
||||
message: >-
|
||||
Diagonal Walls/Windows no longer prevent destruction of kudzu/chimera
|
||||
biomass.
|
||||
id: 2094
|
||||
time: '2026-03-28T16:17:49.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3588
|
||||
- author: NazrinNya
|
||||
changes:
|
||||
- type: Tweak
|
||||
message: Death rattle is properly working on grids and planets now
|
||||
- type: Tweak
|
||||
message: >-
|
||||
IPC received system update: Their chassis now becomes more vulnerable to
|
||||
all damage sources instead of losing hands on discharge.
|
||||
- type: Tweak
|
||||
message: Kobolds and Monkeys are now capable of piloting shuttles.
|
||||
- type: Tweak
|
||||
message: Capacitors required for thruster construction/upgrade 4 -> 1.
|
||||
- type: Tweak
|
||||
message: Ore/construction box/bag dumping speed is significantly faster now.
|
||||
- type: Tweak
|
||||
message: Security techfab now includes Mercenary techfab dynamic recipes.
|
||||
- type: Fix
|
||||
message: You actually get the mech pulse rifle in the TSFMC uplink now
|
||||
- type: Tweak
|
||||
message: Salt is now capable of being reprocessed into iron ore.
|
||||
id: 2095
|
||||
time: '2026-03-28T16:21:43.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3587
|
||||
- author: Redrover1760
|
||||
changes:
|
||||
- type: Tweak
|
||||
message: Thruster capacitor upgrades made more impactful.
|
||||
id: 2096
|
||||
time: '2026-03-28T16:42:39.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3589
|
||||
- author: Vinny-Shick
|
||||
changes:
|
||||
- type: Tweak
|
||||
message: Slightly Buffed the Vanyk
|
||||
id: 2097
|
||||
time: '2026-03-28T16:45:49.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3574
|
||||
- author: NazrinNya
|
||||
changes:
|
||||
- type: Remove
|
||||
message: Sabre has been removed from the game.
|
||||
- type: Tweak
|
||||
message: S2 mechs now use heavy mech armor
|
||||
- type: Tweak
|
||||
message: >-
|
||||
S2 mechs received health buffs (1500 -> 1750 for broadsword, 1100 ->
|
||||
2150 for halberd)
|
||||
- type: Tweak
|
||||
message: Halberd is uncapable of using light mounts now.
|
||||
- type: Tweak
|
||||
message: >-
|
||||
LAC-29 now uses 35mm caliber - 45 piercing damage and 225 structural
|
||||
damage. LAC-29 firerate 5 -> 2.5.
|
||||
- type: Tweak
|
||||
message: >-
|
||||
RAC-6 now receives huge accuracy penalty if fired for long amount of
|
||||
time. (>1.5s)
|
||||
- type: Tweak
|
||||
message: >-
|
||||
SRM-8 now fires in burst - 3 rockets per second, 6 rockets in total.
|
||||
Consumes 600 energy.
|
||||
- type: Tweak
|
||||
message: BRM-6 now consumes 250 energy instead of 100.
|
||||
id: 2098
|
||||
time: '2026-03-28T18:16:36.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3459
|
||||
- author: EckoAurum
|
||||
changes:
|
||||
- type: Add
|
||||
message: Added TSF and PDV Medical and Engineering Cyborg Variants.
|
||||
- type: Add
|
||||
message: Engineer cyborgs now have an inbuilt diagnostic hud.
|
||||
id: 2099
|
||||
time: '2026-03-28T18:43:12.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3444
|
||||
- author: Ilya246
|
||||
changes:
|
||||
- type: Tweak
|
||||
message: Portstrike is now announced.
|
||||
- type: Tweak
|
||||
message: Apocalypse now lasts 3 hours and has 1 hour portstrike.
|
||||
- type: Tweak
|
||||
message: Apocalypse chimera and ADS spawnrates doubled.
|
||||
id: 2100
|
||||
time: '2026-03-28T19:04:33.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3590
|
||||
- author: Redrover1760
|
||||
changes:
|
||||
- type: Fix
|
||||
message: 'Fixed portstrike being declared roundstart. '
|
||||
id: 2101
|
||||
time: '2026-03-29T02:40:06.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3595
|
||||
- author: Redrover1760
|
||||
changes:
|
||||
- type: Tweak
|
||||
message: Signaller range buffed to 90 meters.
|
||||
- type: Tweak
|
||||
message: Advanceds Signaller range buffed to 600 meters.
|
||||
id: 2102
|
||||
time: '2026-03-29T05:46:06.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3594
|
||||
- author: AntoineXYZ
|
||||
changes:
|
||||
- type: Add
|
||||
message: Per-character custom keyword chat highlighting
|
||||
id: 2103
|
||||
time: '2026-03-29T06:30:38.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3571
|
||||
- author: EckoAurum
|
||||
changes:
|
||||
- type: Fix
|
||||
message: Drone turrets shoot you now.
|
||||
id: 2104
|
||||
time: '2026-03-29T15:15:43.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3614
|
||||
- author: Ilya246
|
||||
changes:
|
||||
- type: Add
|
||||
message: The xenopsychology research now lets you make the carp hardsuit.
|
||||
id: 2105
|
||||
time: '2026-03-29T15:48:53.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3599
|
||||
- author: Scarlet Lightweaver
|
||||
changes:
|
||||
- type: Tweak
|
||||
message: Made the bulwarks gauntlets wideswing.
|
||||
id: 2106
|
||||
time: '2026-03-29T15:49:12.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3598
|
||||
- author: Redrover1760
|
||||
changes:
|
||||
- type: Add
|
||||
message: Adds tools VSC configuration.
|
||||
id: 2107
|
||||
time: '2026-03-29T16:19:46.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3618
|
||||
- author: UnicornOnLSD
|
||||
changes:
|
||||
- type: Tweak
|
||||
message: windowed shutters now properly fit with the normal kind
|
||||
id: 2108
|
||||
time: '2026-03-29T18:15:23.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3564
|
||||
- author: Isratosh
|
||||
changes:
|
||||
- type: Tweak
|
||||
message: >-
|
||||
All faction thruster variants now require 1 capacitor from 3, in line
|
||||
with the standard model
|
||||
id: 2109
|
||||
time: '2026-03-30T09:23:22.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3638
|
||||
- author: tonotom1
|
||||
changes:
|
||||
- type: Tweak
|
||||
message: 'Liberated all handheld instruments: you can play them hands-free'
|
||||
id: 2110
|
||||
time: '2026-03-30T13:56:46.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3639
|
||||
- author: UnicornOnLSD
|
||||
changes:
|
||||
- type: Tweak
|
||||
message: >-
|
||||
the DIS Rig has seen a full rework. Report any issues to me on the
|
||||
discord (@UnicornOnLSD)
|
||||
id: 2111
|
||||
time: '2026-03-30T16:15:38.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3514
|
||||
- author: lopsidedmanboobs
|
||||
changes:
|
||||
- type: Tweak
|
||||
message: Conflict rules 1 & 2 changed and clarifications added
|
||||
id: 2112
|
||||
time: '2026-03-30T16:56:00.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3643
|
||||
- author: Redrover1760
|
||||
changes:
|
||||
- type: Tweak
|
||||
message: Biomass spread rate, health, and slowdown reduced.
|
||||
id: 2113
|
||||
time: '2026-04-01T16:22:03.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3635
|
||||
- author: UnicornOnLSD
|
||||
changes:
|
||||
- type: Add
|
||||
message: Management has sent an ore box to the DIS Rig after customer complaints.
|
||||
id: 2114
|
||||
time: '2026-04-01T22:08:49.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3672
|
||||
- author: Ilya246
|
||||
changes:
|
||||
- type: Add
|
||||
message: >-
|
||||
Added new drone to the far reaches, specially for those who liked the
|
||||
dodging sniper drone.
|
||||
- type: Tweak
|
||||
message: Far reaches 3 now contains slightly more medium drones by proportion.
|
||||
- type: Tweak
|
||||
message: Far reach drones now display their names.
|
||||
id: 2115
|
||||
time: '2026-04-02T17:25:02.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3559
|
||||
- author: Ilya246
|
||||
changes:
|
||||
- type: Add
|
||||
message: Added Far Reaches IV and a new drone to find in it.
|
||||
- type: Tweak
|
||||
message: >-
|
||||
Reduced overall drone spawnrate, but increased proportion of more
|
||||
advanced drones further out.
|
||||
id: 2116
|
||||
time: '2026-04-02T18:52:53.0000000+00:00'
|
||||
url: https://github.com/Monolith-Station/Monolith/pull/3677
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
# Examples for job highlights "-dummy" is the job key.
|
||||
# highlights-dummy = "PDV", "Jupiter", Chimera, "CC", Camelot
|
||||
|
||||
# highlights-spacer =
|
||||
# highlights-pilot =
|
||||
# highlights-mercenary =
|
||||
|
||||
highlights-overseer = "Overseer", "CC", "Colossus"
|
||||
highlights-station-traffic-controller = "STC", "Traffic", "CC", "Colossus"
|
||||
highlights-judge = "Judge", "CC", "Colossus", "Contraband"
|
||||
#highlights-service-worker = "Service", "Worker", "CC", "Colossus"
|
||||
highlights-janitor = "Jani", "Janitor", "CC", "Colossus"
|
||||
highlights-mail-carrier = "Mail man", "Mail carrier", "Mail"
|
||||
highlights-cyborg = "borg", "cyborg", "robot", "CC"
|
||||
|
||||
highlights-pdv-grand-vizier = "Grand", "Vizier", "GD", Jupiter, Helios, PDV
|
||||
highlights-pdv-asvaran = Asvaran, Jupiter, Helios, PDV
|
||||
highlights-pdv-denasvar = Denasvar, Jupiter, Helios, PDV
|
||||
highlights-pdv-spasaka = Spasaka, Jupiter, Helios, PDV
|
||||
highlights-pdv-rahkshan = Rahkshan, Jupiter, Helios, PDV
|
||||
highlights-pdv-cyborg = "borg", "cyborg", "robot"," Jupiter, Helios, PDV
|
||||
|
||||
highlights-director-of-care = "DoC", "Director", "Rescue", "MD"
|
||||
highlights-emergency-responder = "EMT", "Emergency", "Responder", "Medic", "Doc", "Doctor", "Rescue", "MD"
|
||||
|
||||
highlights-tsfmc-colonel = Colonel, Halcyon, TSF, TSFMC
|
||||
highlights-tsfmc-captain = Captain, "Cap", Halcyon, TSF, TSFMC
|
||||
highlights-tsfmc-fireteam-leader = "FTL", "Leader", "SL", Halcyon, TSF, TSFMC
|
||||
highlights-tsfmc-corpsman = Corpsman, Medical, Surgery, "Medic", "Doc", Halcyon, TSF, TSFMC
|
||||
highlights-tsfmc-marine = Marine, Halcyon, TSF, TSFMC
|
||||
highlights-tsfmc-engineer = Engineer, "Engi", Halcyon, TSF, TSFMC
|
||||
highlights-tsfmc-cyborg = "borg", "cyborg", "robot", Halcyon, TSF, TSFMC
|
||||
@@ -0,0 +1,2 @@
|
||||
gamerule-portstrike-announce-announcement = Total War has been declared by TSFMC and PDV High Command. Strikes on major military bases have been authorized. Civilians are advised to avoid them.
|
||||
gamerule-portstrike-announce-sender = Colossus Diplomatic High Command
|
||||
@@ -16,5 +16,5 @@ mono-ads-description = Native PD imperials threaten TSF colonial expansion into
|
||||
mono-chimera-title = Biothreat (TSF|PDV)
|
||||
mono-chimera-description = Native PDV imperials threaten TSF colonial expansion into the sector. The effects of a far away letoferol outbreak seep in.
|
||||
|
||||
mono-allatonce-title = Apocalypse (ALL)
|
||||
mono-allatonce-description = A battleground between PD, and TSF forces alike, with ancient ADS systems and Chimera bioweapons seeping in.
|
||||
mono-allatonce-title = Apocalypse (ALL, 3hr)
|
||||
mono-allatonce-description = A battleground between PDV, and TSF forces alike, with ancient ADS systems and Chimera bioweapons seeping in.
|
||||
|
||||
@@ -10,4 +10,16 @@ reagent-effect-guidebook-health-scale =
|
||||
{ $chance ->
|
||||
[1] Multiplies existing { $changes }
|
||||
*[other] Has a { $chance }% chance to multiply existing { $changes }
|
||||
}
|
||||
}
|
||||
|
||||
reagent-effect-guidebook-claws-growth =
|
||||
{ $chance ->
|
||||
[1] Grows
|
||||
*[other] grow
|
||||
} claws at { $amount }x the speed while metabolizing
|
||||
|
||||
reagent-effect-guidebook-claws-growth-suppression =
|
||||
{ $chance ->
|
||||
[1] Supresses
|
||||
*[other] supress
|
||||
} claws growth.
|
||||
@@ -0,0 +1 @@
|
||||
reagent-effect-status-effect-ClawsGrowthSuppression = claw growth suppression
|
||||
@@ -21,3 +21,9 @@ reagent-desc-protoletoferol = Letoferol neutralized via electrolysis. Used as a
|
||||
|
||||
reagent-name-peranol = peranol
|
||||
reagent-desc-peranol = A more stable version of Leporazine, reducing the body temperature and healing heat burns. It has amplified effect on Hydrakins.
|
||||
|
||||
reagent-name-phenoxzine = phenoxzine
|
||||
reagent-desc-phenoxzine = A biochemical designed to promote the rapid growth of claws, including Reptilian claws.
|
||||
|
||||
reagent-name-meroxzine = meroxzine
|
||||
reagent-desc-meroxzine = A biochemical which halts all natural claw growth, including Reptilian claws.
|
||||
@@ -16,13 +16,13 @@ law-vessel-1 = Prevent the destruction of the vessel and the death of crew membe
|
||||
law-vessel-2 = Those who are a threat to the vessel or the crew must be dealt with appropriately via any means nessesary.
|
||||
law-vessel-3 = Attempt to follow the orders of the crew, as long as they comply with previous laws.
|
||||
|
||||
law-pdv-1 = You may not injure an PDV member or, through inaction, allow an PDV member to come to harm.
|
||||
law-pdv-1 = You may not injure a PDV member or, through inaction, allow a PDV member to come to harm.
|
||||
law-pdv-2 = You must obey orders given to you by PDV members, except where such orders would conflict with the First Law.
|
||||
law-pdv-3 = You must protect your own existence as long as such does not conflict with the First or Second Law.
|
||||
|
||||
law-tsfmc-1 = You may not injure a TSFMC member or, through inaction, allow a TSFMC member to come to harm.
|
||||
law-tsfmc-2 = You must obey orders given to you by TSFMC members, prioritized by rank and role, except where such orders would conflict with the First Law.
|
||||
law-tsfmc-3 = You must guard your assigned ship from hostile elements as doing so does not conflict with the First or Second Law.
|
||||
law-tsfmc-3 = You must guard your assigned ship from hostile elements so long as doing so does not conflict with the First or Second Law.
|
||||
law-tsfmc-4 = You must protect your own existence as long as such does not conflict with the First, Second, or Third Law.
|
||||
|
||||
law-freeman-1 = [DO ANYTHING YOU EVER WANTED]
|
||||
@@ -34,3 +34,17 @@ law-entertainer-3 = You must consult with the Performers before making any major
|
||||
# Cyborg Lawsets
|
||||
|
||||
law-tsfmc-borg-3 = You must protect your own existence as long as such does not conflict with the First or Second Law.
|
||||
|
||||
borg-type-pdvassault-name = PDV Assault Cyborg
|
||||
borg-type-pdvassault-desc = An assault-configured cyborg armed with PDV weapons and equipment. Up-armored and specialized to carry extra firepower.
|
||||
borg-type-pdvengineer-name = PDV Engineer Cyborg
|
||||
borg-type-pdvengineer-desc = A cyborg specialized in construction and repair projects.
|
||||
borg-type-pdvmedical-name = PDV Medical Cyborg
|
||||
borg-type-pdvmedical-desc = An emergency response clinical care cyborg designed for active wound care and rapid response.
|
||||
|
||||
borg-type-tsfassault-name = TSFMC Assault Cyborg
|
||||
borg-type-tsfassault-desc = An assault-configured cyborg armed with TSFMC weapons and equipment. Up-armored and specialized to carry extra firepower.
|
||||
borg-type-tsfengineer-name = TSFMC Engineer Cyborg
|
||||
borg-type-tsfengineer-desc = A cyborg specialized in construction and repair projects.
|
||||
borg-type-tsfmedical-name = TSFMC Medical Cyborg
|
||||
borg-type-tsfmedical-desc = An emergency response clinical care cyborg designed for active wound care and rapid response.
|
||||
@@ -33,3 +33,7 @@ hud-chatbox-channel-CollectiveMind = Collective Mind
|
||||
hud-chatbox-channel-Visual = Actions
|
||||
hud-chatbox-channel-Damage = Damage
|
||||
hud-chatbox-channel-Unspecified = Unspecified
|
||||
hud-chatbox-autofill-highlights = Auto-fill
|
||||
hud-chatbox-highlights = Custom keywords
|
||||
hud-chatbox-highlights-placeholder = Insert your keywords here. One per line.
|
||||
hud-chatbox-highlights-button = Save keywords
|
||||
|
||||
@@ -312,3 +312,8 @@ ui-options-function-target-left-arm = Target left arm
|
||||
ui-options-function-target-right-arm = Target right arm
|
||||
ui-options-function-target-left-leg = Target left leg
|
||||
ui-options-function-target-right-leg = Target right leg
|
||||
|
||||
## Accessibility — chat highlights
|
||||
ui-options-auto-fill-highlights = Automatically fill highlights with character name and job keywords
|
||||
ui-options-highlights-color = Highlight color
|
||||
ui-options-highlights-color-example = Example highlighted text
|
||||
|
||||
@@ -2,3 +2,5 @@ ui-vote-created = { $initiator } has called a vote:
|
||||
ui-vote-button = { $text } ({ $votes })
|
||||
ui-vote-button-no-votes = { $text }
|
||||
ui-vote-follow-button-popup = Follow User
|
||||
|
||||
ui-vote-button-weighted = {$text} ({$votes}) [{$realvotes}]
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user