Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 0 additions & 10 deletions .github/FOR MOD DEVELOPERS.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,16 +63,6 @@ Location: `Submerged.Map.Patches.ShipStatus_CalculateLightRadius_Patch`

<br>

## `void ArrowBehaviour.UpdatePosition()`

<u>When playing on Submerged</u>, this method is completely overwritten by the mod to make arrows point to the nearest elevator if their target is on the other floor.

This patch may work incorrectly with mods that make use of custom arrow behaviours, since those might not be affected by this.

Location: `Submerged.Minigames.Patches.ArrowBehaviour_Update_Patch`

<br>

## `void Console.Use()`

<u>When playing on Submerged</u>, this method is completely overwritten by the mod to check if the player is trying to open the Fix Wiring task in Electrical, and provide the 8-wires minigame instead of the 4-wires one.
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ The table below lists the most recent Submerged release for each Among Us versio

| Among Us Version | Submerged Version | Links |
|:---------------------------------------------------------------------------------------------:|:-----------------:|:-----------------------------------------------------------------------------------:|
| `v17.1.0` | `v2025.11.20` | [Download](https://github.com/SubmergedAmongUs/Submerged/releases/tag/v2025.11.20/) |
| `v17.0.1`<br>`v17.0.0` | `v2025.10.22` | [Download](https://github.com/SubmergedAmongUs/Submerged/releases/tag/v2025.10.22/) |
| `v16.1.0`<br>`v16.0.5`<br>`v16.0.3`<br>`v16.0.2`<br>`v16.0.0` | Unavailable | - |
| `v2024.11.26`<br>`v2024.10.29`<br>`v2024.9.4`<br>`v2024.8.13` | `v2025.1.30` | [Download](https://github.com/SubmergedAmongUs/Submerged/releases/tag/v2025.1.30/) |
Expand Down
3 changes: 2 additions & 1 deletion Submerged/BaseGame/BaseGameCodeAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ public enum LastChecked
{
// ReSharper disable InconsistentNaming
v17_0_0,
v17_0_1
v17_0_1,
v17_1_0,
// ReSharper restore InconsistentNaming
}

Expand Down
39 changes: 39 additions & 0 deletions Submerged/Elevators/Objects/ElevatorRoomTrackerCollider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using Il2CppInterop.Runtime.Attributes;
using Il2CppInterop.Runtime.InteropTypes.Fields;
using Reactor.Utilities.Attributes;
using UnityEngine;

namespace Submerged.Elevators.Objects;

[RegisterInIl2Cpp]
public sealed class ElevatorRoomTrackerCollider(nint ptr) : MonoBehaviour(ptr)
{
public Il2CppReferenceField<PolygonCollider2D> targetCollider;
public Il2CppReferenceField<BoxCollider2D> collider1;
public Il2CppReferenceField<BoxCollider2D> collider2;

private void Awake()
{
PolygonCollider2D col = targetCollider.Value;
col.pathCount = 2;
col.SetPath(0, GetPath(collider1.Value));
col.SetPath(1, GetPath(collider2.Value));
}

[HideFromIl2Cpp]
private Vector2[] GetPath(BoxCollider2D col)
{
Vector2 ext = col.size * 0.5f;
Vector2 off = col.offset;
Transform t = col.transform;
Transform myT = transform;

return
[
myT.InverseTransformPoint(t.TransformPoint(off + new Vector2(-ext.x, -ext.y))),
myT.InverseTransformPoint(t.TransformPoint(off + new Vector2(-ext.x, ext.y))),
myT.InverseTransformPoint(t.TransformPoint(off + new Vector2( ext.x, ext.y))),
myT.InverseTransformPoint(t.TransformPoint(off + new Vector2( ext.x, -ext.y)))
];
}
}
82 changes: 82 additions & 0 deletions Submerged/Elevators/Objects/MultifloorArrowBehaviour.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
using System.Linq;
using Reactor.Utilities.Attributes;
using Submerged.Enums;
using Submerged.Floors;
using Submerged.Map;
using Submerged.Systems.Elevator;
using UnityEngine;

namespace Submerged.Elevators.Objects;

[RegisterInIl2Cpp]
public sealed class MultifloorArrowBehaviour(nint ptr) : MonoBehaviour(ptr)
{
private static SCG.List<(SubmarineElevator elevator, Vector3 position)> _lowerElevatorPositions;
private static SCG.List<(SubmarineElevator elevator, Vector3 position)> _upperElevatorPositions;

public ArrowBehaviour arrowBehaviour;

public Vector3 lastSetTarget;
public Vector3 originalTarget;

private void Awake()
{
arrowBehaviour = GetComponent<ArrowBehaviour>();
}

public void Update()
{
if (lastSetTarget != arrowBehaviour.target)
{
originalTarget = arrowBehaviour.target;
}

lastSetTarget = arrowBehaviour.target = GetElevatorPosition(originalTarget);
}

public static Vector3 GetElevatorPosition(Vector3 target)
{
if (_lowerElevatorPositions == null || _upperElevatorPositions == null || !_lowerElevatorPositions[0].elevator)
{
_lowerElevatorPositions = SubmarineStatus.instance.elevators.Select(e => (e, e.lowerOuterDoor.Value.transform.position)).ToList();
_upperElevatorPositions = SubmarineStatus.instance.elevators.Select(e => (e, e.upperOuterDoor.Value.transform.position)).ToList();
}

FloorHandler floorHandler = FloorHandler.LocalPlayer;

Vector3 localPlayerPos = PlayerControl.LocalPlayer.transform.position;

if (target.y < FloorHandler.FLOOR_CUTOFF) // If target is on lower deck
{
if (!floorHandler.onUpper) return target;
}
else
{
if (floorHandler.onUpper) return target;
}

float maxDist = float.MaxValue;
Vector2 current = Vector2.zero;
int elevatorIndex = 0;

for (int index = 0; index < (floorHandler.onUpper ? _upperElevatorPositions : _lowerElevatorPositions).Count; index++)
{
(SubmarineElevator elevator, Vector3 pos) = (floorHandler.onUpper ? _upperElevatorPositions : _lowerElevatorPositions)[index];
if (elevator.system.systemTypes != CustomSystemTypes.ElevatorService &&
elevator.system.upperDeckIsTargetFloor != floorHandler.onUpper) continue;

float distance = Vector2.Distance(pos, localPlayerPos);

if (distance < maxDist)
{
maxDist = distance;
current = pos;
elevatorIndex = index;
}
}

if (SubmarineStatus.instance.elevators[elevatorIndex].CheckInElevator(localPlayerPos)) current = localPlayerPos;

return current;
}
}
3 changes: 1 addition & 2 deletions Submerged/Elevators/SubmarineElevatorSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ public sealed class SubmarineElevatorSystem(nint ptr) : CppObject(ptr), AU.ISyst

public readonly SystemTypes systemTypes;

private SubmarineElevatorSystem _tandem;
public ElevatorMovementStage lastStage = ElevatorMovementStage.Complete;
public float lerpTimer;
public bool moving;
Expand All @@ -41,7 +40,7 @@ public SubmarineElevatorSystem(SystemTypes systemType, bool startsOnUpper, Syste
tandemSystemType = tandemElevator;
}

private SubmarineElevatorSystem Tandem => _tandem ??= ShipStatus.Instance.Systems[tandemSystemType].Cast<SubmarineElevatorSystem>();
private SubmarineElevatorSystem Tandem => field ??= ShipStatus.Instance.Systems[tandemSystemType].Cast<SubmarineElevatorSystem>();

public bool IsDirty { get; private set; }

Expand Down
19 changes: 17 additions & 2 deletions Submerged/Enums/CustomStringNames.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,19 @@ private CustomStringNames(int stringName, string constantValue) : this(stringNam
public static readonly CustomStringNames Ballast = new(555_1_005, () => Locations.Ballast);
public static readonly CustomStringNames LowerCentral = new(555_1_006, () => Locations.Central_Lower);
public static readonly CustomStringNames LowerLobby = new(555_1_007, () => Locations.Lobby_Lower);
public static readonly CustomStringNames Elevator = new(555_1_008, () => Locations.Elevator);
public static readonly CustomStringNames ElevatorService = new(555_1_009, () => Locations.Elevator_Service);
public static readonly CustomStringNames ElevatorService = new(555_1_009, () => Locations.Elevators_Service);
public static readonly CustomStringNames ElevatorsWest = new(555_1_010, () =>
{
return Locations.Elevators_West == "West Elevators" && !string.IsNullOrEmpty(Deprecated.Elevator)
? Deprecated.Elevator + Deprecated.ElevatorSuffix_West
: Locations.Elevators_West;
});
public static readonly CustomStringNames ElevatorsEast = new(555_1_011, () =>
{
return Locations.Elevators_East == "East Elevators" && !string.IsNullOrEmpty(Deprecated.Elevator)
? Deprecated.Elevator + Deprecated.ElevatorSuffix_East
: Locations.Elevators_East;
});

// Tasks
public static readonly CustomStringNames PlugLeaks = new(555_2_000, () => Tasks.PlugLeaks);
Expand Down Expand Up @@ -81,6 +92,10 @@ private CustomStringNames(int stringName, string constantValue) : this(stringNam
public static readonly CustomStringNames RetrieveOxygenMask = new(555_2_023, () => Tasks.RetrieveOxygenMask);
public static readonly CustomStringNames StabilizeWaterLevels = new(555_2_024, () => Tasks.StabilizeWaterLevels);

// Deprecated
[Obsolete("Elevators are now split into East and West, this StringName will be removed in a future update.")]
public static readonly CustomStringNames Elevator = new(555_1_008, () => !string.IsNullOrEmpty(Deprecated.Elevator) ? Deprecated.Elevator : "Elevator");

// ReSharper restore InconsistentNaming

#endregion
Expand Down
23 changes: 17 additions & 6 deletions Submerged/Enums/CustomSystemTypes.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Submerged.Enums;

public readonly struct CustomSystemTypes
public readonly struct CustomSystemTypes : IEquatable<CustomSystemTypes>
{
internal static void Initialize()
{
Expand Down Expand Up @@ -33,6 +34,16 @@ private CustomSystemTypes(int systemType, StringNames stringName = StringNames.N

public static explicit operator byte(CustomSystemTypes self) => (byte) self.systemType;

public bool Equals(CustomSystemTypes other) => systemType == other.systemType;

public override bool Equals(object obj) => obj is CustomSystemTypes other && Equals(other);

public override int GetHashCode() => (int) systemType;

public static bool operator ==(CustomSystemTypes left, CustomSystemTypes right) => left.Equals(right);

public static bool operator !=(CustomSystemTypes left, CustomSystemTypes right) => !left.Equals(right);

#endregion

#region Enum members
Expand Down Expand Up @@ -67,16 +78,16 @@ private CustomSystemTypes(int systemType, StringNames stringName = StringNames.N
public static readonly CustomSystemTypes LowerLobby = new(0x87, CustomStringNames.LowerLobby);

[UsedImplicitly]
public static readonly CustomSystemTypes ElevatorHallwayLeft = new(0x88, CustomStringNames.Elevator);
public static readonly CustomSystemTypes ElevatorHallwayLeft = new(0x88, CustomStringNames.ElevatorsWest);

[UsedImplicitly]
public static readonly CustomSystemTypes ElevatorHallwayRight = new(0x89, CustomStringNames.Elevator);
public static readonly CustomSystemTypes ElevatorHallwayRight = new(0x89, CustomStringNames.ElevatorsWest);

[UsedImplicitly]
public static readonly CustomSystemTypes ElevatorLobbyLeft = new(0x8a, CustomStringNames.Elevator);
public static readonly CustomSystemTypes ElevatorLobbyLeft = new(0x8a, CustomStringNames.ElevatorsEast);

[UsedImplicitly]
public static readonly CustomSystemTypes ElevatorLobbyRight = new(0x8b, CustomStringNames.Elevator);
public static readonly CustomSystemTypes ElevatorLobbyRight = new(0x8b, CustomStringNames.ElevatorsEast);

[UsedImplicitly]
public static readonly CustomSystemTypes ElevatorService = new(0x8c, CustomStringNames.ElevatorService);
Expand Down
7 changes: 0 additions & 7 deletions Submerged/HudMap/Patches/AdminPatches.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,6 @@ namespace Submerged.HudMap.Patches;
[HarmonyPatch]
public static class AdminPatches
{
[HarmonyPatch(typeof(MapBehaviour), nameof(MapBehaviour.Awake))]
[HarmonyPrefix]
public static void ReplacePlayerIconPatch(MapBehaviour __instance)
{
__instance.countOverlay.GetComponent<ObjectPoolBehavior>().Prefab = MapLoader.Skeld.MapPrefab.countOverlay.GetComponent<ObjectPoolBehavior>().Prefab;
}

[HarmonyPatch(typeof(UseButton), nameof(UseButton.Awake))]
[HarmonyPrefix]
public static void AddAdminUseButtonPatch(UseButton __instance)
Expand Down
24 changes: 24 additions & 0 deletions Submerged/HudMap/SubmergedHudMap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public sealed class SubmergedHudMap(nint ptr) : MonoBehaviour(ptr)
public Il2CppReferenceField<GameObject> downArrow;

private bool _disableChangeFloor;
private bool _startedOnTop;

private void Start()
{
Expand Down Expand Up @@ -63,22 +64,45 @@ private void Update()
private void OnEnable()
{
if (PlayerControl.LocalPlayer.transform.position.y < -10f)
{
MoveMapDown();
}
else
{
MoveMapUp();
_startedOnTop = true;
}
}

public void MoveMapUp()
{
upArrow.Value.SetActive(false);
downArrow.Value.SetActive(!_disableChangeFloor);
hudTransform.Value.localPosition = Vector3.zero;

foreach (UiElement button in map.Value.detectiveLocationControllerButtons)
{
if (button.name.EndsWith("_Scrolled") == _startedOnTop)
{
button.transform.localPosition -= new Vector3(0, LOWER_Y, 0);
button.name = !_startedOnTop ? button.name + "_Scrolled" : button.name[..^"_Scrolled".Length];
}
}
}

public void MoveMapDown()
{
upArrow.Value.SetActive(!_disableChangeFloor);
downArrow.Value.SetActive(false);
hudTransform.Value.localPosition = new Vector3(0, LOWER_Y, 0);

foreach (UiElement button in map.Value.detectiveLocationControllerButtons)
{
if (button.name.EndsWith("_Scrolled") != _startedOnTop)
{
button.transform.localPosition += new Vector3(0, LOWER_Y, 0);
button.name = _startedOnTop ? button.name + "_Scrolled" : button.name[..^"_Scrolled".Length];
}
}
}
}
Loading