A MelonLoader mod that adds a manager-only intercom to Dale & Dawson Stationery Supplies. Whoever holds the Manager role can broadcast their voice to the whole office from their desk, bypassing the game's normal proximity voice chat, with a cooldown so it can't be spammed.
- Manager-only. The intercom option only appears for whoever currently holds the Manager role, and only at the Manager's own desk.
- Radial menu integration. Used the same way as the desk's computer/phone: sit down, hold the interact key, pick "Use the Intercom". Standing up turns it off automatically.
- Distance bypass. While broadcasting, the Manager's voice is audible everywhere in the office instead of fading out with distance like normal proximity chat.
- PA speaker effect. The broadcast voice is band-limited and lightly distorted so it sounds like it's coming out of an intercom speaker, not a normal conversation.
- Cooldown. Configurable (see below), enforced by the host so it can't be bypassed by a modified client.
- Localized. UI text follows whichever of the game's 23 languages is currently selected.
- Dale & Dawson Stationery Supplies.
- MelonLoader installed in the game folder.
- Install MelonLoader in the game's install folder if you haven't already.
- Download
PaMod.dllfrom the Releases page. - Drop it into the game's
Modsfolder (create it if it doesn't exist next to the game's.exe). - Launch the game once - a settings section will be added automatically (see Configuration).
Every player who wants to hear the intercom broadcast needs the mod installed, not just the Manager or the host - the voice/distance-bypass logic runs on whoever is listening, not on whoever is speaking.
- Whoever is the current Manager sits down at their desk.
- Hold the interact key to open the radial menu, same as for the computer or phone.
- Pick Use the Intercom to start broadcasting, Turn Off the Intercom to stop (or just stand up).
Settings are stored in the game's shared MelonLoader config file:
<game folder>/UserData/MelonPreferences.cfg
under a [PaMod] section:
[PaMod]Cooldown = 60.0
Enabled = true| Setting | Range | Description |
|---|---|---|
Cooldown | 0 - 180 | Seconds before the intercom can be used again after being turned off. |
Enabled | true/false | Whether the intercom feature is available at all. |
Only the host's value matters. The host's settings are read once at the start of each round and broadcast to every connected client, so everyone plays with the same rules for that round. Edit the file before starting a game - changes made mid-round won't apply until the next one.
Open PaMod.csproj and set GameDir to your own game install path, then build with the
.NET SDK (dotnet build -c Release). The compiled PaMod.dll ends up in
bin/Release/net6.0/.
| File | Responsibility |
|---|---|
Source/PaModMain.cs | Mod entry point; the toggle/cooldown/broadcast state machine. |
Source/MicInteraction.cs | Adds the radial-menu option to the Manager's desk; finds the manager's and the dedicated signal desk. |
Source/PaConfig.cs | Host-configurable settings (MelonPreferences) and their round-start sync. |
Source/VoiceEffect.cs | The PA speaker audio filter applied to the broadcast voice. |
Source/RoomEffectBypass.cs | Bypasses the game's own wall-muffling volume/filter for the boosted voice. |
Source/Jingle.cs | Procedurally generated open/close chime. |
Source/MessageDisplay.cs | The on-screen warning text (cooldown, wrong role, etc). |
Source/Localization.cs | UI text in all 23 of the game's languages. |
The game is an IL2CPP build, which rules out a few approaches that would otherwise be the obvious way to do this:
- No new Mirror network message types. Mirror's
NetworkMessageis an interface that astructmust implement; IL2CPP can neither inject new value types at runtime nor have an injected class implement an existing IL2CPP interface. Don't try to add a customNetworkMessage- it throws at registration time. [ClientRpc]methods never reach non-host clients in this build. Confirmed twice, on two unrelated Rpcs: this mod's ownRpcSetInteractionTimeCounterattempt, and (still compiled into the Dissonance package itself, not our code)PositionTracker.RpcSetPlayerID. Both reach the server/host and stop there. Treat any[ClientRpc]as unreliable for anything a non-host client needs to see, and prefer a polled SyncVar instead (see below).[Command](client -> server) has been reliable throughout testing and is unaffected.- The PA toggle and the settings sync both ride on
Interactable's existingCmdSetInteractionTimeCounter(client -> server, a[Command]) plus a plain SyncVar,interactionCoolDown, polled by every client every 0.5s - not the matchingRpcSetInteractionTimeCounter, which was dropped for the reason above. Both features write their value onto a dedicated signal desk (MicInteraction.FindSignalDesk, chosen deterministically by lowestnetId, always excluding the Manager's own desk) rather than the Manager's own desk, since hijacking a desk's own cooldown also blocks its radial menu. Real usage ofinteractionCoolDownis always a non-negative value below the PA toggle's own range, so two disjoint value ranges smuggle both kinds of messages through it without a new network message type - see the sentinel/range constants inPaModMain.cs/PaConfig.cs. If you add a third kind of message, give it its own non-overlapping range. - The Manager's Dissonance voice is matched by position, not by Dissonance's own player id.
PositionTracker.PlayerIdis only ever set through the broken Rpc mentioned above, soStartVoiceBoost(PaModMain.cs) instead finds the closestBaseVoicePlaybackto the Manager's character transform (seeVoiceMatchMaxDistance). This works because normal proximity voice chat already depends on the same position data reaching every client correctly. - Wall-muffling is a separate system from Dissonance's own distance attenuation. The
game's
RoomEffectController(not part of Dissonance) independently lowers volume and applies its ownAudioLowPassFilterbased on wall thickness between rooms, regardless of Dissonance'sAllowPositionalPlaybackflag.RoomEffectBypasspatches itsUpdate()with a postfix that forces full volume and our own desired cutoff back onto the boosted voice's entry every frame, the same "re-assert every frame" approachBroadcastHeartbeatuses for the cooldown SyncVar. AudioClip.SetDatathrowsMissingMethodExceptionin this MelonLoader/Il2CppInterop build (a broken interop binding forReadOnlySpan<T>.GetPinnableReference(), not something fixable by changing the array type). UseAudioClip.Create's streamingPCMReaderCallbackinstead - seeJingle.cs.
This mod was developed with assistance from an AI coding assistant - reverse-engineering the game's decompiled IL2CPP code and helping on the implementation.
MIT - do whatever you want with it, just keep the copyright notice.