├── .gitignore ├── .vscode └── tasks.json ├── Art ├── Nutcracker.png ├── StungByBees.png ├── icon.png └── manifest.json ├── CHANGELOG.md ├── Coroner.sln ├── Coroner ├── API.cs ├── AdvancedCauseOfDeath.cs ├── Coroner.csproj ├── Directory.Build.props ├── LanguageHandler.cs ├── NetworkRPC.cs ├── Patch │ ├── CauseOfDeathPatch.cs │ └── HUDManagerPatch.cs ├── Plugin.cs └── PluginConfig.cs ├── LanguageData ├── Strings_de.xml ├── Strings_en-us.xml ├── Strings_es.xml ├── Strings_fr.xml ├── Strings_hu.xml ├── Strings_it.xml ├── Strings_ko.xml ├── Strings_nl.xml ├── Strings_pt-br.xml ├── Strings_ru.xml ├── Strings_test.xml └── Strings_zh-cn.xml ├── MODDING.md ├── NuGet.Config ├── README.md ├── Releases └── build.bat └── TRANSLATING.md /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Ll]og/ 33 | [Ll]ogs/ 34 | 35 | # Visual Studio 2015/2017 cache/options directory 36 | .vs/ 37 | # Uncomment if you have tasks that create the project's static files in wwwroot 38 | #wwwroot/ 39 | 40 | # Visual Studio 2017 auto generated files 41 | Generated\ Files/ 42 | 43 | # MSTest test Results 44 | [Tt]est[Rr]esult*/ 45 | [Bb]uild[Ll]og.* 46 | 47 | # NUnit 48 | *.VisualState.xml 49 | TestResult.xml 50 | nunit-*.xml 51 | 52 | # Build Results of an ATL Project 53 | [Dd]ebugPS/ 54 | [Rr]eleasePS/ 55 | dlldata.c 56 | 57 | # Benchmark Results 58 | BenchmarkDotNet.Artifacts/ 59 | 60 | # .NET Core 61 | project.lock.json 62 | project.fragment.lock.json 63 | artifacts/ 64 | 65 | # ASP.NET Scaffolding 66 | ScaffoldingReadMe.txt 67 | 68 | # StyleCop 69 | StyleCopReport.xml 70 | 71 | # Files built by Visual Studio 72 | *_i.c 73 | *_p.c 74 | *_h.h 75 | *.ilk 76 | *.meta 77 | *.obj 78 | *.iobj 79 | *.pch 80 | *.pdb 81 | *.ipdb 82 | *.pgc 83 | *.pgd 84 | *.rsp 85 | *.sbr 86 | *.tlb 87 | *.tli 88 | *.tlh 89 | *.tmp 90 | *.tmp_proj 91 | *_wpftmp.csproj 92 | *.log 93 | *.tlog 94 | *.vspscc 95 | *.vssscc 96 | .builds 97 | *.pidb 98 | *.svclog 99 | *.scc 100 | 101 | # Chutzpah Test files 102 | _Chutzpah* 103 | 104 | # Visual C++ cache files 105 | ipch/ 106 | *.aps 107 | *.ncb 108 | *.opendb 109 | *.opensdf 110 | *.sdf 111 | *.cachefile 112 | *.VC.db 113 | *.VC.VC.opendb 114 | 115 | # Visual Studio profiler 116 | *.psess 117 | *.vsp 118 | *.vspx 119 | *.sap 120 | 121 | # Visual Studio Trace Files 122 | *.e2e 123 | 124 | # TFS 2012 Local Workspace 125 | $tf/ 126 | 127 | # Guidance Automation Toolkit 128 | *.gpState 129 | 130 | # ReSharper is a .NET coding add-in 131 | _ReSharper*/ 132 | *.[Rr]e[Ss]harper 133 | *.DotSettings.user 134 | 135 | # TeamCity is a build add-in 136 | _TeamCity* 137 | 138 | # DotCover is a Code Coverage Tool 139 | *.dotCover 140 | 141 | # AxoCover is a Code Coverage Tool 142 | .axoCover/* 143 | !.axoCover/settings.json 144 | 145 | # Coverlet is a free, cross platform Code Coverage Tool 146 | coverage*.json 147 | coverage*.xml 148 | coverage*.info 149 | 150 | # Visual Studio code coverage results 151 | *.coverage 152 | *.coveragexml 153 | 154 | # NCrunch 155 | _NCrunch_* 156 | .*crunch*.local.xml 157 | nCrunchTemp_* 158 | 159 | # MightyMoose 160 | *.mm.* 161 | AutoTest.Net/ 162 | 163 | # Web workbench (sass) 164 | .sass-cache/ 165 | 166 | # Installshield output folder 167 | [Ee]xpress/ 168 | 169 | # DocProject is a documentation generator add-in 170 | DocProject/buildhelp/ 171 | DocProject/Help/*.HxT 172 | DocProject/Help/*.HxC 173 | DocProject/Help/*.hhc 174 | DocProject/Help/*.hhk 175 | DocProject/Help/*.hhp 176 | DocProject/Help/Html2 177 | DocProject/Help/html 178 | 179 | # Click-Once directory 180 | publish/ 181 | 182 | # Publish Web Output 183 | *.[Pp]ublish.xml 184 | *.azurePubxml 185 | # Note: Comment the next line if you want to checkin your web deploy settings, 186 | # but database connection strings (with potential passwords) will be unencrypted 187 | *.pubxml 188 | *.publishproj 189 | 190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 191 | # checkin your Azure Web App publish settings, but sensitive information contained 192 | # in these scripts will be unencrypted 193 | PublishScripts/ 194 | 195 | # NuGet Packages 196 | *.nupkg 197 | # NuGet Symbol Packages 198 | *.snupkg 199 | # The packages folder can be ignored because of Package Restore 200 | **/[Pp]ackages/* 201 | # except build/, which is used as an MSBuild target. 202 | !**/[Pp]ackages/build/ 203 | # Uncomment if necessary however generally it will be regenerated when needed 204 | #!**/[Pp]ackages/repositories.config 205 | # NuGet v3's project.json files produces more ignorable files 206 | *.nuget.props 207 | *.nuget.targets 208 | 209 | # Microsoft Azure Build Output 210 | csx/ 211 | *.build.csdef 212 | 213 | # Microsoft Azure Emulator 214 | ecf/ 215 | rcf/ 216 | 217 | # Windows Store app package directories and files 218 | AppPackages/ 219 | BundleArtifacts/ 220 | Package.StoreAssociation.xml 221 | _pkginfo.txt 222 | *.appx 223 | *.appxbundle 224 | *.appxupload 225 | 226 | # Visual Studio cache files 227 | # files ending in .cache can be ignored 228 | *.[Cc]ache 229 | # but keep track of directories ending in .cache 230 | !?*.[Cc]ache/ 231 | 232 | # Others 233 | ClientBin/ 234 | ~$* 235 | *~ 236 | *.dbmdl 237 | *.dbproj.schemaview 238 | *.jfm 239 | *.pfx 240 | *.publishsettings 241 | orleans.codegen.cs 242 | 243 | # Including strong name files can present a security risk 244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 245 | #*.snk 246 | 247 | # Since there are multiple workflows, uncomment next line to ignore bower_components 248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 249 | #bower_components/ 250 | 251 | # RIA/Silverlight projects 252 | Generated_Code/ 253 | 254 | # Backup & report files from converting an old project file 255 | # to a newer Visual Studio version. Backup files are not needed, 256 | # because we have git ;-) 257 | _UpgradeReport_Files/ 258 | Backup*/ 259 | UpgradeLog*.XML 260 | UpgradeLog*.htm 261 | ServiceFabricBackup/ 262 | *.rptproj.bak 263 | 264 | # SQL Server files 265 | *.mdf 266 | *.ldf 267 | *.ndf 268 | 269 | # Business Intelligence projects 270 | *.rdl.data 271 | *.bim.layout 272 | *.bim_*.settings 273 | *.rptproj.rsuser 274 | *- [Bb]ackup.rdl 275 | *- [Bb]ackup ([0-9]).rdl 276 | *- [Bb]ackup ([0-9][0-9]).rdl 277 | 278 | # Microsoft Fakes 279 | FakesAssemblies/ 280 | 281 | # GhostDoc plugin setting file 282 | *.GhostDoc.xml 283 | 284 | # Node.js Tools for Visual Studio 285 | .ntvs_analysis.dat 286 | node_modules/ 287 | 288 | # Visual Studio 6 build log 289 | *.plg 290 | 291 | # Visual Studio 6 workspace options file 292 | *.opt 293 | 294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 295 | *.vbw 296 | 297 | # Visual Studio 6 auto-generated project file (contains which files were open etc.) 298 | *.vbp 299 | 300 | # Visual Studio 6 workspace and project file (working project files containing files to include in project) 301 | *.dsw 302 | *.dsp 303 | 304 | # Visual Studio 6 technical files 305 | *.ncb 306 | *.aps 307 | 308 | # Visual Studio LightSwitch build output 309 | **/*.HTMLClient/GeneratedArtifacts 310 | **/*.DesktopClient/GeneratedArtifacts 311 | **/*.DesktopClient/ModelManifest.xml 312 | **/*.Server/GeneratedArtifacts 313 | **/*.Server/ModelManifest.xml 314 | _Pvt_Extensions 315 | 316 | # Paket dependency manager 317 | .paket/paket.exe 318 | paket-files/ 319 | 320 | # FAKE - F# Make 321 | .fake/ 322 | 323 | # CodeRush personal settings 324 | .cr/personal 325 | 326 | # Python Tools for Visual Studio (PTVS) 327 | __pycache__/ 328 | *.pyc 329 | 330 | # Cake - Uncomment if you are using it 331 | # tools/** 332 | # !tools/packages.config 333 | 334 | # Tabs Studio 335 | *.tss 336 | 337 | # Telerik's JustMock configuration file 338 | *.jmconfig 339 | 340 | # BizTalk build output 341 | *.btp.cs 342 | *.btm.cs 343 | *.odx.cs 344 | *.xsd.cs 345 | 346 | # OpenCover UI analysis results 347 | OpenCover/ 348 | 349 | # Azure Stream Analytics local run output 350 | ASALocalRun/ 351 | 352 | # MSBuild Binary and Structured Log 353 | *.binlog 354 | 355 | # NVidia Nsight GPU debugger configuration file 356 | *.nvuser 357 | 358 | # MFractors (Xamarin productivity tool) working folder 359 | .mfractor/ 360 | 361 | # Local History for Visual Studio 362 | .localhistory/ 363 | 364 | # Visual Studio History (VSHistory) files 365 | .vshistory/ 366 | 367 | # BeatPulse healthcheck temp database 368 | healthchecksdb 369 | 370 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 371 | MigrationBackup/ 372 | 373 | # Ionide (cross platform F# VS Code tools) working folder 374 | .ionide/ 375 | 376 | # Fody - auto-generated XML schema 377 | FodyWeavers.xsd 378 | 379 | # VS Code files for those working on multiple tools 380 | .vscode/* 381 | !.vscode/settings.json 382 | !.vscode/tasks.json 383 | !.vscode/launch.json 384 | !.vscode/extensions.json 385 | *.code-workspace 386 | 387 | # Local History for Visual Studio Code 388 | .history/ 389 | 390 | # Windows Installer files from build outputs 391 | *.cab 392 | *.msi 393 | *.msix 394 | *.msm 395 | *.msp 396 | 397 | # JetBrains Rider 398 | *.sln.iml 399 | 400 | ## CUSTOM 401 | 402 | # Exclude build DLLs. 403 | Coroner/include/*.dll -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "dotnet: debug build", 6 | "type": "process", 7 | "command": "dotnet", 8 | "args": [ 9 | "build", 10 | "${workspaceFolder}/Coroner.sln", 11 | "-c Release", 12 | "/property:GenerateFullPaths=true", 13 | "/consoleloggerparameters:NoSummary", 14 | "--no-dependencies" 15 | ], 16 | "problemMatcher": [ 17 | "$msCompile" 18 | ] 19 | } 20 | ] 21 | } -------------------------------------------------------------------------------- /Art/Nutcracker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EliteMasterEric/Coroner/e8e07e1de455e3b876c0c27ad3713f97d01a3d33/Art/Nutcracker.png -------------------------------------------------------------------------------- /Art/StungByBees.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EliteMasterEric/Coroner/e8e07e1de455e3b876c0c27ad3713f97d01a3d33/Art/StungByBees.png -------------------------------------------------------------------------------- /Art/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EliteMasterEric/Coroner/e8e07e1de455e3b876c0c27ad3713f97d01a3d33/Art/icon.png -------------------------------------------------------------------------------- /Art/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Coroner", 3 | "version_number": "2.3.0", 4 | "website_url": "https://github.com/EliteMasterEric/Coroner", 5 | "description": "Add Cause of Death to the performance report, now with a Mod API!", 6 | "dependencies": [ 7 | "BepInEx-BepInExPack-5.4.2100", 8 | "xilophor-StaticNetcodeLib-1.1.1" 9 | ] 10 | } -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # [Coroner](https://github.com/EliteMasterEric/Coroner) Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). Dates are based on UTC. 7 | 8 | ## Known Issues 9 | - Reinstalling the mod may sometimes cause modded language data to be deleted. 10 | 11 | # 2.3.0 (2025-07-07) 12 | This update updates the game for provides some updated language strings as well as a bugfix. 13 | 14 | ## Added 15 | - Added cause of death for the new enemy from v70 16 | - Added cause of death for a potentially deadly furniture piece from v70 17 | - Added additional death messages for English (via Lynn Koya). 18 | - Added additional death messages for English (via Thundermaker300). 19 | # Changed 20 | - Updated Italian translations (via MakinDay) 21 | - Updated Russian translations (via D4N9-Twitch) 22 | ## Fixed 23 | - Fixed an issue when getting captured by the Masked and then getting saved. 24 | 25 | # 2.2.0 (2024-09-06) 26 | This update improves the documentation as well as adds support for v64. 27 | 28 | ### Added 29 | - Added cause of death for the new event in v64. 30 | ### Changed 31 | - Improved documentation for the modding API and translations (major thanks to Jatc251!). 32 | ### Fixed 33 | - Fixed a crash found when dying to the Eyeless Dogs. 34 | 35 | # 2.1.0 (2024-08-28) 36 | This update finalizes the modding API! 37 | 38 | ### Added 39 | - Added cause of death for the new enemy in v60/61. 40 | - Finished up the Modding API! 41 | - See the [modding docs](https://github.com/EliteMasterEric/Coroner/blob/master/MODDING.md) for more info. 42 | - Check out the [Coroner Mimic plugin](https://github.com/EliteMasterEric/Coroner-Mimics) for an example of how to implement this 43 | - Split up cause of death for pits to differentiate between different tiles. 44 | - Added specific cause of death for that one pit in the Facility. You know the one. 45 | 46 | ### Fixed 47 | - Fixed an issue with fallback behavior (for when a language is missing translations). 48 | 49 | # 2.0.0 (2024-07-14) 50 | This update represents a major refactor of Coroner's codebase. 51 | 52 | ### Added 53 | - Added new causes of death for version 50. 54 | - Added new causes of death for version 55/56. 55 | - Added a cause of death specifically for dying of falling in pits in the facility. 56 | - Split up causes of death for coworkers murdering with different weapons into different types (for example, Stop Signs vs Knives). 57 | - Added a documented `Coroner.API` class to make it easy for mods to add their own integrations. 58 | - NOTE: This feature is not currently 100% complete as mods cannot display their own custom causes of death right now. 59 | - Added a `test` language which displays generic death messages for debugging purposes. 60 | 61 | ### Changed 62 | - Replaced `LC_API` with `StaticNetcodeLib` for more reliable, less bloated networking that doesn't depend on an outdated library. 63 | 64 | ### Removed 65 | - Removed all languages except for English, due to the other languages now having missing causes of death. A long-term solution for this problem will come later. 66 | 67 | ### Fixed 68 | - Fixed a bug where leaving the game before the Performance Report and then joining a new lobby would not clear causes of death, resulting in incorrect causes of death being displayed later. 69 | 70 | ### Known Issues 71 | - Coroner may sometimes fail to distinguish between the driver and passenger of the Company Cruiser. 72 | - Languages other than English may be missing causes of death, they should fall back to English if one is missing. 73 | 74 | # 1.6.2 (2024-03-05) 75 | ### Fixed 76 | - Fixed an issue where Coroner fails to detect the config folder (even when it is in the proper location). 77 | 78 | # 1.6.1 (2024-03-04) 79 | ### Fixed 80 | - Improved the clarity of the error messages for when people install the mod incorrectly (you won't get this error if you use R2Modman!). 81 | 82 | # 1.6.0 (2024-02-03) 83 | ### Added 84 | - Added new custom messages for specific causes of death: 85 | - Holding a Stun Grenade 86 | - Extension Ladder 87 | - Added support for the expanded Unicode character set while [FontFixer](https://thunderstore.io/c/lethal-company/p/EliteMasterEric/FontFixer/) is installed. 88 | - Added a new Spanish localization. 89 | - Added a new German localization. 90 | - Added a new Italian localization. 91 | - Added a new Korean localization. 92 | - Added a new Hungarian localization. 93 | - Added a new Chinese (Simplified) localization. 94 | - Added a new Portuguese (Brazilian) localization. 95 | 96 | ### Changed 97 | - Numerous translation changes. 98 | - The English Translation now has additional notes to assist other translators. 99 | - Moved the localization files into the config folder. 100 | - This should allow modpacks to properly override them. 101 | - Changed translation handling to fallback to English if specific lines are missing. 102 | - This applies when some lines are present and some aren't. 103 | 104 | ### Fixed 105 | - Fixes for Lethal Company v49. 106 | 107 | # 1.5.3 108 | ### Fixed 109 | - Fixed a build issue with 1.5.2. 110 | 111 | # 1.5.2 112 | ### Fixed 113 | - Attempting to fix an issue caused when installing Coroner without R2Modman. 114 | 115 | # 1.5.1 116 | ### Added 117 | - Added a new French localization. 118 | 119 | ### Changed 120 | - I have removed LC_API as a dependency from the manifest. Coroner on its own does a reasonable job of synchronizing cause of death messages across clients without it, in my experience, to a greater extent than I originally thought. I do not anticipate making it a dependency again in the future. Apologies for the inconvenience. 121 | - Improved the Dutch localization. 122 | 123 | # 1.5.0 124 | ### Added 125 | - Added a new localization feature! Coroner now has official support for English, Dutch, and Russian. 126 | - If you want to help localize Coroner for other languages, please visit the Lethal Company Modding Discord or submit a pull request on GitHub, I would GREATLY appreciate your contributions. 127 | 128 | ### Changed 129 | - LC_API has been readded as a dependency after the 3.0.0 update fixed all the weird bugs. 130 | 131 | ### Fixed 132 | - Fixed an issue where vanilla notes would be replaced with funny notes (funny notes should only display if no vanilla ones were given) 133 | - Fixed an issue where "Funny Notes" were not randomized when serious death messages were turned on. 134 | 135 | # 1.4.2 136 | ### Added 137 | - Now includes the mod lel 138 | 139 | # 1.4.1 140 | ### Removed 141 | - I decided you folks had it too good *yoinks mod away* 142 | 143 | # 1.4.0 144 | ### Added 145 | - Added custom death messages for specific types of explosions: 146 | - Landmines 147 | - Jetpack 148 | - Lightning 149 | - Added custom death message for Turrets. 150 | - Added a `SeriousDeathMessages` config option to display only more to-the-point death messages. Defaults to `false`. 151 | 152 | ### Changed 153 | - The death report now says "Cause of Death" instead of "Notes" when a player dies. 154 | - Decreased log verbosity to improve performance. 155 | 156 | # 1.3.1 157 | ### Fixed 158 | - Fixed an issue where an exception in one of the cause-of-death patches would cause the player to not die. 159 | - Fixed an issue where not having LC_API installed would cause an exception to occur. 160 | 161 | # 1.3.0 162 | ### Added 163 | - Additional death messages for other death types. 164 | - Added new death messages for the enemies from v45. 165 | 166 | ### Fixed 167 | - Fixed some bugs related to v45. 168 | 169 | # 1.2.0 170 | ### Added 171 | - Each death type can now randomly display one of several messages. 172 | - Messages should now match across clients, even when randomized. 173 | - Added new death messages for the enemies that didn't have them. 174 | - Bunker Spider 175 | - Coil Head 176 | - Hoarder Bug 177 | - Hygrodere 178 | - Spore Lizard 179 | - Thumper 180 | 181 | ### Removed 182 | - Removed LC_API as a dependency from the manifest (Thunderstore was enforcing it as mandatory rather than optional). It is still recommended that players install LC_API alongside this if possible. 183 | 184 | ### Fixed 185 | - Fixed an issue where Bunkers Spiders were called Sand Spiders. 186 | - Fixed an issue where the mod ZIP was included inside the mod ZIP, causing a console error. 187 | 188 | # 1.1.0 189 | ### Added 190 | - Added a custom cause of death for the dropship. 191 | - Added an optional dependency on LC_API and used it to improve accuracy of cause of death reports over multiplayer. 192 | 193 | ### Fixed 194 | - Fixed a softlock/crash related to checking if the player has a Jetpack. 195 | - Fixed the cause of death not being evaluated properly when being crushed by a ladder. 196 | - Fixed the cause of death not being evaluated properly when drowning in Quicksand. 197 | - Fixed a bug where notes would not start with "Notes:". 198 | - Fixed an issue where BepInEx was not listed as a mandatory dependency. 199 | - Fixed an issue with enemy-related custom deaths not working 200 | 201 | # 1.0.0 202 | Initial release 203 | 204 | ### Added 205 | - Added cause of death to the results screen. 206 | - Added advanced cause-of-death tracking for specific enemies, falling back to built-in tracking on failure. 207 | -------------------------------------------------------------------------------- /Coroner.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.5.002.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Coroner", "Coroner\Coroner.csproj", "{04FD6926-5D80-4206-8FDF-1ACC140E9DD7}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {04FD6926-5D80-4206-8FDF-1ACC140E9DD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {04FD6926-5D80-4206-8FDF-1ACC140E9DD7}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {04FD6926-5D80-4206-8FDF-1ACC140E9DD7}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {04FD6926-5D80-4206-8FDF-1ACC140E9DD7}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {9973961F-F45A-4406-8788-DFF58FC1CA65} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /Coroner/API.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using GameNetcodeStuff; 3 | 4 | #nullable enable 5 | 6 | namespace Coroner 7 | { 8 | public class API 9 | { 10 | /// 11 | /// Sets the cause of death for a player object. 12 | /// You can set this to a default one (see `Coroner.AdvancedCauseOfDeath`) or a custom one (see `Register()`). 13 | /// 14 | /// The player to set the cause of death for. 15 | /// The cause of death to use. Set to `null` to clear. 16 | /// SetCauseOfDeath(player, AdvancedCauseOfDeath.Enemy_ForestGiant); 17 | public static void SetCauseOfDeath(PlayerControllerB player, AdvancedCauseOfDeath? causeOfDeath) 18 | { 19 | // Call the proper internal method. 20 | AdvancedDeathTracker.SetCauseOfDeath(player, causeOfDeath); 21 | } 22 | 23 | /// 24 | /// Sets the cause of death for a player with the given ID. 25 | /// You can set this to a default one (see `Coroner.AdvancedCauseOfDeath`) or a custom one (see `Register()`). 26 | /// 27 | /// The ID of the player. 28 | /// The cause of death to use. Set to `null` to clear. 29 | /// SetCauseOfDeath(0, AdvancedCauseOfDeath.Enemy_ForestGiant); 30 | public static void SetCauseOfDeath(int playerId, AdvancedCauseOfDeath? causeOfDeath) 31 | { 32 | // Call the proper internal method. 33 | AdvancedDeathTracker.SetCauseOfDeath(playerId, causeOfDeath); 34 | } 35 | 36 | /// 37 | /// Gets the cause of death for a player object. 38 | /// 39 | /// The player to get the cause of death for. 40 | /// The cause of death for the player. May be null if none is set, or a custom value provided by a mod. 41 | /// GetCauseOfDeath(player); 42 | public static AdvancedCauseOfDeath? GetCauseOfDeath(PlayerControllerB player) 43 | { 44 | // Call the proper internal method. 45 | return AdvancedDeathTracker.GetCauseOfDeath(player); 46 | } 47 | 48 | /// 49 | /// Gets the cause of death for a player with the given ID. 50 | /// 51 | /// The ID of the player. 52 | /// The cause of death for the player. 53 | /// GetCauseOfDeath(0); 54 | public static AdvancedCauseOfDeath? GetCauseOfDeath(int playerId) 55 | { 56 | // Call the proper internal method. 57 | return AdvancedDeathTracker.GetCauseOfDeath(playerId); 58 | } 59 | 60 | /// 61 | /// Register a new cause of death. Useful for mods. 62 | /// Choose one that is unique to your mod, and store the value statically for reuse. 63 | /// Then, call SetCauseOfDeath(player, customCauseOfDeath) to use it. 64 | /// 65 | /// The language key to use for the cause of death. 66 | /// The newly registered cause of death. 67 | public static AdvancedCauseOfDeath Register(string key) 68 | { 69 | // Call the proper internal method. 70 | return AdvancedCauseOfDeath.Build(key); 71 | } 72 | 73 | // 74 | // Determine whether a cause of death is registered. 75 | // 76 | // The language key to use for the cause of death. 77 | // Whether that cause of death is already registered. 78 | public static bool IsRegistered(string key) 79 | { 80 | return AdvancedCauseOfDeath.IsTagRegistered(key); 81 | } 82 | 83 | /// 84 | /// Convert a cause of death to a language string as used in-game. 85 | /// 86 | /// The cause of death to convert. 87 | /// Optionally specify a random number generator to use. If you seed this the same between clients, they'll produce the same value. 88 | /// One of the available language strings for that cause of death. 89 | public static string StringifyCauseOfDeath(AdvancedCauseOfDeath causeOfDeath, Random? random) 90 | { 91 | // Call the proper internal method. 92 | return AdvancedDeathTracker.StringifyCauseOfDeath(causeOfDeath, random != null ? random : Plugin.RANDOM); 93 | } 94 | } 95 | } -------------------------------------------------------------------------------- /Coroner/Coroner.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.1 5 | 6 | EliteMasterEric 7 | Coroner 8 | com.elitemastereric.coroner 9 | 2.3.0 10 | 11 | Coroner 12 | A Lethal Company plugin which overhauls the end-of-mission performance report with new information, including cause of death for any deceased players with some fun easter eggs thrown in too. 13 | 14 | true 15 | 16 | preview 17 | false 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | false 35 | ..\include\Assembly-CSharp.dll 36 | 37 | 38 | false 39 | ..\include\DissonanceVoip.dll 40 | 41 | 42 | false 43 | ..\include\Facepunch Transport for Netcode for GameObjects.dll 44 | 45 | 46 | false 47 | ..\include\Facepunch.Steamworks.Win64.dll 48 | 49 | 50 | false 51 | ..\include\Unity.Collections.dll 52 | 53 | 54 | false 55 | ..\include\Unity.RenderPipelines.HighDefinition.Config.Runtime.dll 56 | 57 | 58 | false 59 | ..\include\Unity.RenderPipelines.HighDefinition.Runtime.dll 60 | 61 | 62 | false 63 | ..\include\Unity.Netcode.Components.dll 64 | 65 | 66 | false 67 | ..\include\Unity.Netcode.Runtime.dll 68 | 69 | 70 | false 71 | ..\include\Unity.TextMeshPro.dll 72 | 73 | 74 | false 75 | ..\include\UnityEngine.UI.dll 76 | 77 | 78 | 84 | 85 | 86 | false 87 | ..\include\Xilophor.StaticNetcodeLib.dll 88 | 89 | 90 | 91 | 92 | 97 | 98 | %(RecursiveDir)%(Filename)%(Extension) 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /Coroner/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | ./build/bin 4 | ./build/obj 5 | 6 | 7 | -------------------------------------------------------------------------------- /Coroner/LanguageHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Net.WebSockets; 6 | using System.Xml.Linq; 7 | 8 | #nullable enable 9 | 10 | namespace Coroner 11 | { 12 | class LanguageHandler 13 | { 14 | public const string DEFAULT_LANGUAGE = "en-us"; 15 | 16 | public const string TAG_FUNNY_NOTES = "FunnyNote"; 17 | 18 | public const string TAG_UI_NOTES = "UINotes"; 19 | public const string TAG_UI_DEATH = "UICauseOfDeath"; 20 | 21 | // Basic causes of death 22 | public const string TAG_DEATH_GENERIC_BLUDGEONING = "DeathBludgeoning"; 23 | public const string TAG_DEATH_GENERIC_GRAVITY = "DeathGravity"; 24 | public const string TAG_DEATH_GENERIC_BLAST = "DeathBlast"; 25 | public const string TAG_DEATH_GENERIC_STRANGULATION = "DeathStrangulation"; 26 | public const string TAG_DEATH_GENERIC_SUFFOCATION = "DeathSuffocation"; 27 | public const string TAG_DEATH_GENERIC_MAULING = "DeathMauling"; 28 | public const string TAG_DEATH_GENERIC_GUNSHOTS = "DeathGunshots"; 29 | public const string TAG_DEATH_GENERIC_CRUSHING = "DeathCrushing"; 30 | public const string TAG_DEATH_GENERIC_DROWNING = "DeathDrowning"; 31 | public const string TAG_DEATH_GENERIC_ABANDONED = "DeathAbandoned"; 32 | public const string TAG_DEATH_GENERIC_ELECTROCUTION = "DeathElectrocution"; 33 | public const string TAG_DEATH_GENERIC_KICKING = "DeathKicking"; // New in v45 34 | public const string TAG_DEATH_GENERIC_BURNING = "DeathBurning"; // New in v50 35 | public const string TAG_DEATH_GENERIC_STABBING = "DeathStabbing"; // New in v50 36 | public const string TAG_DEATH_GENERIC_FAN = "DeathFan"; // New in v50 37 | public const string TAG_DEATH_GENERIC_INERTIA = "DeathInertia"; // New in v55 38 | public const string TAG_DEATH_GENERIC_SNIPPED = "DeathSnipped"; // New in v55 39 | 40 | 41 | // Custom causes (enemies) 42 | public const string TAG_DEATH_ENEMY_BABOON_HAWK = "DeathEnemyBaboonHawk"; 43 | public const string TAG_DEATH_ENEMY_BRACKEN = "DeathEnemyBracken"; 44 | public const string TAG_DEATH_ENEMY_BUNKER_SPIDER = "DeathEnemyBunkerSpider"; 45 | public const string TAG_DEATH_ENEMY_CIRCUIT_BEES = "DeathEnemyCircuitBees"; 46 | public const string TAG_DEATH_ENEMY_COILHEAD = "DeathEnemyCoilHead"; 47 | public const string TAG_DEATH_ENEMY_EARTH_LEVIATHAN = "DeathEnemyEarthLeviathan"; 48 | public const string TAG_DEATH_ENEMY_EYELESS_DOG = "DeathEnemyEyelessDog"; 49 | public const string TAG_DEATH_ENEMY_GHOST_GIRL = "DeathEnemyGhostGirl"; 50 | public const string TAG_DEATH_ENEMY_HOARDER_BUG = "DeathEnemyHoarderBug"; 51 | public const string TAG_DEATH_ENEMY_HYGRODERE = "DeathEnemyHygrodere"; 52 | public const string TAG_DEATH_ENEMY_JESTER = "DeathEnemyJester"; 53 | public const string TAG_DEATH_ENEMY_LASSO_MAN = "DeathEnemyLassoMan"; 54 | public const string TAG_DEATH_ENEMY_SNARE_FLEA = "DeathEnemySnareFlea"; 55 | public const string TAG_DEATH_ENEMY_SPORE_LIZARD = "DeathEnemySporeLizard"; 56 | public const string TAG_DEATH_ENEMY_THUMPER = "DeathEnemyThumper"; 57 | 58 | public const string TAG_DEATH_ENEMY_FOREST_GIANT_EATEN = "DeathEnemyForestGiantEaten"; 59 | public const string TAG_DEATH_ENEMY_FOREST_GIANT_DEATH = "DeathEnemyForestGiantDeath"; 60 | 61 | // Enemies from v45 62 | public const string TAG_DEATH_ENEMY_MASKED_PLAYER_WEAR = "DeathEnemyMaskedPlayerWear"; 63 | public const string TAG_DEATH_ENEMY_MASKED_PLAYER_VICTIM = "DeathEnemyMaskedPlayerVictim"; 64 | public const string TAG_DEATH_ENEMY_NUTCRACKER_KICKED = "DeathEnemyNutcrackerKicked"; 65 | public const string TAG_DEATH_ENEMY_NUTCRACKER_SHOT = "DeathEnemyNutcrackerShot"; 66 | 67 | // Enemies from v50 68 | public const string TAG_DEATH_ENEMY_BUTLER_STAB = "DeathEnemyButlerStab"; 69 | public const string TAG_DEATH_ENEMY_BUTLER_EXPLODE = "DeathEnemyButlerExplode"; 70 | public const string TAG_DEATH_ENEMY_MASK_HORNETS = "DeathEnemyMaskHornets"; 71 | public const string TAG_DEATH_ENEMY_TULIP_SNAKE_DROP = "DeathEnemyTulipSnakeDrop"; 72 | public const string TAG_DEATH_ENEMY_OLD_BIRD_ROCKET = "DeathEnemyOldBirdRocket"; 73 | public const string TAG_DEATH_ENEMY_OLD_BIRD_STOMP = "DeathEnemyOldBirdStomp"; 74 | public const string TAG_DEATH_ENEMY_OLD_BIRD_CHARGE = "DeathEnemyOldBirdCharge"; 75 | public const string TAG_DEATH_ENEMY_OLD_BIRD_TORCH = "DeathEnemyOldBirdTorch"; 76 | 77 | // Enemies from v55 78 | public const string TAG_DEATH_ENEMY_KIDNAPPER_FOX = "DeathEnemyKidnapperFox"; 79 | public const string TAG_DEATH_ENEMY_BARBER = "DeathEnemyBarber"; 80 | 81 | // Enemies from v60 82 | public const string TAG_DEATH_ENEMY_MANEATER = "DeathEnemyManeater"; 83 | 84 | // Enemies from v70 85 | public const string TAG_DEATH_ENEMY_GIANT_SAPSUCKER = "DeathEnemyGiantSapsucker"; 86 | 87 | // Custom causes (player) 88 | public const string TAG_DEATH_PLAYER_JETPACK_GRAVITY = "DeathPlayerJetpackGravity"; 89 | public const string TAG_DEATH_PLAYER_JETPACK_BLAST = "DeathPlayerJetpackBlast"; 90 | public const string TAG_DEATH_PLAYER_LADDER = "DeathPlayerLadder"; 91 | public const string TAG_DEATH_PLAYER_MURDER_SHOVEL = "DeathPlayerMurderShovel"; 92 | public const string TAG_DEATH_PLAYER_MURDER_STOP_SIGN = "DeathPlayerMurderStopSign"; 93 | public const string TAG_DEATH_PLAYER_MURDER_YIELD_SIGN = "DeathPlayerMurderYieldSign"; 94 | public const string TAG_DEATH_PLAYER_MURDER_KNIFE = "DeathPlayerMurderKnife"; 95 | public const string TAG_DEATH_PLAYER_EASTER_EGG = "DeathPlayerEasterEgg"; 96 | public const string TAG_DEATH_PLAYER_MURDER_SHOTGUN = "DeathPlayerMurderShotgun"; 97 | public const string TAG_DEATH_PLAYER_QUICKSAND = "DeathPlayerQuicksand"; 98 | public const string TAG_DEATH_PLAYER_STUN_GRENADE = "DeathPlayerStunGrenade"; 99 | public const string TAG_DEATH_PLAYER_ELECTRIC_CHAIR = "DeathPlayerElectricChair"; 100 | 101 | // Custom causes (player vehicles) 102 | public const string TAG_DEATH_PLAYER_CRUISER_DRIVER = "DeathPlayerCruiserDriver"; 103 | public const string TAG_DEATH_PLAYER_CRUISER_PASSENGER = "DeathPlayerCruiserPassenger"; 104 | public const string TAG_DEATH_PLAYER_CRUISER_EXPLODE_BYSTANDER = "DeathPlayerCruiserExplodeBystander"; 105 | public const string TAG_DEATH_PLAYER_CRUISER_RAN_OVER = "DeathPlayerCruiserRanOver"; 106 | 107 | // Custom causes (pits) 108 | public const string TAG_DEATH_PIT_GENERIC = "DeathPitGeneric"; 109 | public const string TAG_DEATH_PIT_FACILITY_PIT = "DeathPitFacilityPit"; 110 | public const string TAG_DEATH_PIT_FACILITY_CATWALK_JUMP = "DeathPitFacilityCatwalkJump"; 111 | public const string TAG_DEATH_PIT_MINE_PIT = "DeathPitMinePit"; 112 | public const string TAG_DEATH_PIT_MINE_CAVE = "DeathPitMineCave"; 113 | public const string TAG_DEATH_PIT_MINE_ELEVATOR = "DeathPitMineElevator"; 114 | 115 | // Custom causes (other) 116 | public const string TAG_DEATH_OTHER_DEPOSIT_ITEMS_DESK = "DeathOtherDepositItemsDesk"; 117 | public const string TAG_DEATH_OTHER_ITEM_DROPSHIP = "DeathOtherItemDropship"; 118 | public const string TAG_DEATH_OTHER_LANDMINE = "DeathOtherLandmine"; 119 | public const string TAG_DEATH_OTHER_TURRET = "DeathOtherTurret"; 120 | public const string TAG_DEATH_OTHER_LIGHTNING = "DeathOtherLightning"; 121 | public const string TAG_DEATH_OTHER_METEOR = "DeathOtherMeteor"; 122 | public const string TAG_DEATH_OTHER_SPIKE_TRAP = "DeathOtherSpikeTrap"; 123 | public const string TAG_DEATH_OTHER_OUT_OF_BOUNDS = "DeathOtherOutOfBounds"; 124 | 125 | public const string TAG_DEATH_UNKNOWN = "DeathUnknown"; 126 | 127 | public string languageCode; 128 | Dictionary> languageData; 129 | bool fallback; 130 | 131 | public LanguageHandler(string languageCode, bool fallback = false) 132 | { 133 | Plugin.Instance.PluginLogger.LogInfo($"{PluginInfo.PLUGIN_NAME} loading {(fallback ? "fallback " : "")}language support: {languageCode}"); 134 | this.languageCode = languageCode; 135 | this.fallback = fallback; 136 | this.languageData = new Dictionary>(); 137 | 138 | LoadLanguageData(languageCode); 139 | } 140 | 141 | void LoadLanguageData(string languageCode) 142 | { 143 | if (!Directory.Exists(Plugin.Instance.GetConfigPath())) 144 | { 145 | Plugin.Instance.PluginLogger.LogError($"Config folder not found at: {Plugin.Instance.GetConfigPath()}"); 146 | var wrongConfigPath = $"{Plugin.AssemblyDirectory}/BepInEx/config/{PluginInfo.PLUGIN_AUTHOR}-{PluginInfo.PLUGIN_NAME}/Strings_{languageCode}.xml"; 147 | if (File.Exists(wrongConfigPath)) 148 | { 149 | Plugin.Instance.PluginLogger.LogError($"IMPORTANT: You didn't install the mod correctly! Move the BepInEx/config folder to the right spot!"); 150 | } 151 | else 152 | { 153 | Plugin.Instance.PluginLogger.LogError($"Try reinstalling the mod from scratch."); 154 | } 155 | } 156 | else if (!File.Exists($"{Plugin.Instance.GetConfigPath()}/Strings_{languageCode}.xml")) 157 | { 158 | Plugin.Instance.PluginLogger.LogError($"Localization File not found at: {Plugin.Instance.GetConfigPath()}"); 159 | } 160 | else 161 | { 162 | Plugin.Instance.PluginLogger.LogInfo($"Loading language data from config folder: {Plugin.Instance.GetConfigPath()}"); 163 | // Load the main language document. 164 | var languageDoc = XDocument.Load($"{Plugin.Instance.GetConfigPath()}/Strings_{languageCode}.xml"); 165 | 166 | if (languageDoc == null) 167 | { 168 | Plugin.Instance.PluginLogger.LogError($"Localization could not be parsed at: {Plugin.Instance.GetConfigPath()}/Strings_{languageCode}.xml"); 169 | return; 170 | } 171 | 172 | PopulateLanguageData(languageDoc); 173 | 174 | // Look for additional language documents. 175 | var additionalLanguageFiles = Directory.GetFiles(Plugin.Instance.GetConfigPath(), $"Strings_{languageCode}_*.xml").ToArray(); 176 | Plugin.Instance.PluginLogger.LogInfo($"Loading {additionalLanguageFiles.Length} additional language data files from config folder"); 177 | for (int index = 0; index < additionalLanguageFiles.Length; index++) 178 | { 179 | Plugin.Instance.PluginLogger.LogInfo($"Loading additional language data file: {additionalLanguageFiles[index]}"); 180 | var additionalLanguageDoc = XDocument.Load(additionalLanguageFiles[index]); 181 | PopulateLanguageData(additionalLanguageDoc, true); 182 | } 183 | 184 | Plugin.Instance.PluginLogger.LogInfo($"Success, loaded {languageData.Count()} types of language tags with {CountLanguageEntries()} total entries."); 185 | } 186 | } 187 | 188 | /** 189 | * Populate the Language Data dictionary with keys from the XML data. 190 | * If `append` is false, the tag will be cleared before populating. 191 | */ 192 | public void PopulateLanguageData(XDocument languageDoc, bool append = false) 193 | { 194 | if (!append) 195 | { 196 | languageData.Clear(); 197 | } 198 | 199 | var stringsTag = languageDoc.Descendants("strings").First(); 200 | foreach (var tag in stringsTag.Descendants()) 201 | { 202 | var key = tag.Name.ToString(); 203 | var value = tag.Attribute("text").Value; 204 | 205 | // Create a new array if the key doesn't exist 206 | if (!languageData.ContainsKey(key)) 207 | { 208 | languageData[key] = []; 209 | } 210 | 211 | // Add the value to the array 212 | var currentValues = languageData[key]; 213 | if (currentValues != null) 214 | { 215 | currentValues.Add(value); 216 | // Plugin.Instance.PluginLogger.LogDebug($"Current values for key '{key}': [{string.Join(", ", currentValues)}] + {value}"); 217 | languageData[key] = currentValues; 218 | } 219 | else 220 | { 221 | Plugin.Instance.PluginLogger.LogError($"Current values for key '{key}' is null!"); 222 | } 223 | } 224 | } 225 | 226 | public int CountLanguageEntries() 227 | { 228 | return languageData.Sum(x => x.Value.Count); 229 | } 230 | 231 | public string GetFirstValueByTag(string tag) 232 | { 233 | return GetValuesByTag(tag)[0]; 234 | } 235 | 236 | public string[] GetValuesByTag(string tag) 237 | { 238 | if (languageData.Count == 0 && languageCode != DEFAULT_LANGUAGE) 239 | { 240 | Plugin.Instance.PluginLogger.LogWarning($"No language data loaded for '{languageCode}', displaying fallback language {DEFAULT_LANGUAGE}..."); 241 | return Plugin.Instance.FallbackLanguageHandler.GetValuesByTag(tag); 242 | } 243 | else if (languageData.Count == 0) 244 | { 245 | Plugin.Instance.PluginLogger.LogWarning("No language data loaded for default language, displaying error text..."); 246 | return [$"{{'{tag}'}}"]; 247 | } 248 | 249 | if (!languageData.ContainsKey(tag) && languageCode != DEFAULT_LANGUAGE) 250 | { 251 | Plugin.Instance.PluginLogger.LogWarning($"No values found for tag '{tag}' in language '{languageCode}', displaying fallback language {DEFAULT_LANGUAGE}..."); 252 | return Plugin.Instance.FallbackLanguageHandler.GetValuesByTag(tag); 253 | } 254 | else if (!languageData.ContainsKey(tag)) 255 | { 256 | Plugin.Instance.PluginLogger.LogWarning($"No values found for tag '{tag}' in language '{languageCode}', displaying error text..."); 257 | return [$"{{'{tag}'}}"]; 258 | } 259 | 260 | var values = languageData[tag]; 261 | 262 | if ((values == null || values.Count == 0) && languageCode != DEFAULT_LANGUAGE) 263 | { 264 | Plugin.Instance.PluginLogger.LogWarning($"No values found for tag '{tag}' in language '{languageCode}', displaying fallback language {DEFAULT_LANGUAGE}..."); 265 | return Plugin.Instance.FallbackLanguageHandler.GetValuesByTag(tag); 266 | } 267 | else if (values == null || values.Count == 0) 268 | { 269 | Plugin.Instance.PluginLogger.LogWarning($"No values found for tag '{tag}' in language '{languageCode}', displaying error text..."); 270 | return [$"{{'{tag}'}}"]; 271 | } 272 | 273 | return values.ToArray(); 274 | } 275 | } 276 | } -------------------------------------------------------------------------------- /Coroner/NetworkRPC.cs: -------------------------------------------------------------------------------- 1 | using StaticNetcodeLib; 2 | using Unity.Netcode; 3 | 4 | #nullable enable 5 | 6 | namespace Coroner 7 | { 8 | /** 9 | * Uses StaticNetcodeLib to perform RPCs 10 | */ 11 | [StaticNetcode] 12 | class NetworkRPC 13 | { 14 | /** 15 | * The client died, and wishes to report the cause to the server. 16 | * Call this function on any client, and it will be invoked on the server. 17 | */ 18 | [ServerRpc(RequireOwnership = false)] 19 | public static void ReportCauseOfDeathServerRpc(int playerClientId, string? codLanguageTag, bool forceOverride) { 20 | // Send the new cause of death to all clients. 21 | Plugin.Instance.PluginLogger.LogDebug($"Server received cause of death via RPC: ({playerClientId}, {(codLanguageTag == null ? "null" : codLanguageTag)})"); 22 | BroadcastCauseOfDeathClientRpc(playerClientId, codLanguageTag, forceOverride); 23 | } 24 | 25 | /** 26 | * The server has received a cause of death from a client (possibly itself), 27 | * and wishes to report it back to all clients. 28 | * Call this function on the server, and it will be invoked on all clients. 29 | */ 30 | [ClientRpc] 31 | public static void BroadcastCauseOfDeathClientRpc(int playerClientId, string? codLanguageTag, bool forceOverride) { 32 | Plugin.Instance.PluginLogger.LogDebug($"Client received cause of death via RPC: ({playerClientId}, {(codLanguageTag == null ? "null" : codLanguageTag)})"); 33 | 34 | if (codLanguageTag == null || !AdvancedCauseOfDeath.IsTagRegistered(codLanguageTag)) { 35 | Plugin.Instance.PluginLogger.LogError($"Could not deserialize cause of death ({codLanguageTag})"); 36 | return; 37 | } 38 | 39 | AdvancedCauseOfDeath? causeOfDeath = AdvancedCauseOfDeath.Fetch(codLanguageTag); 40 | 41 | Plugin.Instance.PluginLogger.LogDebug($"Deserialized cause of death to {causeOfDeath}"); 42 | AdvancedDeathTracker.StoreLocalCauseOfDeath(playerClientId, causeOfDeath, forceOverride); 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /Coroner/Patch/HUDManagerPatch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using GameNetcodeStuff; 3 | using TMPro; 4 | 5 | #nullable enable 6 | 7 | namespace Coroner.Patch 8 | { 9 | [HarmonyLib.HarmonyPatch(typeof(HUDManager))] 10 | [HarmonyLib.HarmonyPatch("FillEndGameStats")] 11 | class HUDManagerFillEndGameStatsPatch 12 | { 13 | const string EMPTY_NOTES = "Notes: \n"; 14 | 15 | public static void Postfix(HUDManager __instance) 16 | { 17 | try 18 | { 19 | OverridePerformanceReport(__instance); 20 | } 21 | catch (Exception e) 22 | { 23 | Plugin.Instance.PluginLogger.LogError("Error in HUDManagerFillEndGameStatsPatch.Postfix: " + e); 24 | Plugin.Instance.PluginLogger.LogError(e.StackTrace); 25 | } 26 | } 27 | 28 | static Random BuildSyncedRandom() 29 | { 30 | var seed = StartOfRound.Instance.randomMapSeed; 31 | Plugin.Instance.PluginLogger.LogDebug("Syncing randomization to map seed: '" + seed + "'"); 32 | return new Random(seed); 33 | } 34 | 35 | /* 36 | * Override the performance report to display our notes. 37 | */ 38 | static void OverridePerformanceReport(HUDManager __instance) 39 | { 40 | Plugin.Instance.PluginLogger.LogDebug("Applying Coroner patches to player notes..."); 41 | 42 | var syncedRandom = BuildSyncedRandom(); 43 | 44 | for (int playerIndex = 0; playerIndex < __instance.statsUIElements.playerNotesText.Length; playerIndex++) 45 | { 46 | PlayerControllerB playerController = __instance.playersManager.allPlayerScripts[playerIndex]; 47 | if (!playerController.disconnectedMidGame && !playerController.isPlayerDead && !playerController.isPlayerControlled) 48 | { 49 | Plugin.Instance.PluginLogger.LogInfo("Player " + playerIndex + " is not controlled by a player. Skipping..."); 50 | continue; 51 | } 52 | 53 | TextMeshProUGUI textMesh = __instance.statsUIElements.playerNotesText[playerIndex]; 54 | if (playerController.isPlayerDead) 55 | { 56 | if (Plugin.Instance.PluginConfig.ShouldDisplayCauseOfDeath()) 57 | { 58 | if (Plugin.Instance.PluginConfig.ShouldDeathReplaceNotes()) 59 | { 60 | Plugin.Instance.PluginLogger.LogInfo("[REPORT] Player " + playerIndex + " is dead! Replacing notes with Cause of Death..."); 61 | // Reset the notes. 62 | textMesh.text = Plugin.Instance.LanguageHandler.GetFirstValueByTag(LanguageHandler.TAG_UI_DEATH) + "\n"; 63 | } 64 | else 65 | { 66 | Plugin.Instance.PluginLogger.LogInfo("[REPORT] Player " + playerIndex + " is dead! Appending notes with Cause of Death..."); 67 | } 68 | 69 | var causeOfDeath = AdvancedDeathTracker.GetCauseOfDeath(playerController); 70 | textMesh.text += "* " + AdvancedDeathTracker.StringifyCauseOfDeath(causeOfDeath, syncedRandom) + "\n"; 71 | } 72 | else 73 | { 74 | Plugin.Instance.PluginLogger.LogInfo("[REPORT] Player " + playerIndex + " is dead, but Config says leave it be..."); 75 | } 76 | } 77 | else 78 | { 79 | if (textMesh.text == EMPTY_NOTES) 80 | { 81 | if (Plugin.Instance.PluginConfig.ShouldDisplayFunnyNotes()) 82 | { 83 | Plugin.Instance.PluginLogger.LogInfo("[REPORT] Player " + playerIndex + " has no notes! Injecting something funny..."); 84 | 85 | textMesh.text = Plugin.Instance.LanguageHandler.GetFirstValueByTag(LanguageHandler.TAG_UI_NOTES) + "\n"; 86 | textMesh.text += "* " + AdvancedDeathTracker.StringifyCauseOfDeath(null, syncedRandom) + "\n"; 87 | } 88 | else 89 | { 90 | Plugin.Instance.PluginLogger.LogInfo("[REPORT] Player " + playerIndex + " has no notes, but Config says leave it be..."); 91 | } 92 | } 93 | else 94 | { 95 | Plugin.Instance.PluginLogger.LogInfo("[REPORT] Player " + playerIndex + " has notes, don't override them..."); 96 | } 97 | } 98 | } 99 | 100 | // We are done with the death tracker, so clear it. 101 | AdvancedDeathTracker.ClearDeathTracker(); 102 | } 103 | } 104 | } -------------------------------------------------------------------------------- /Coroner/Plugin.cs: -------------------------------------------------------------------------------- 1 | using BepInEx; 2 | 3 | using HarmonyLib; 4 | using BepInEx.Logging; 5 | using System; 6 | using System.Reflection; 7 | using System.IO; 8 | using static BepInEx.BepInDependency; 9 | 10 | #nullable enable 11 | 12 | namespace Coroner 13 | { 14 | public static class PluginInfo 15 | { 16 | public const string PLUGIN_ID = "Coroner"; 17 | public const string PLUGIN_NAME = "Coroner"; 18 | public const string PLUGIN_AUTHOR = "EliteMasterEric"; 19 | public const string PLUGIN_VERSION = "2.3.0"; 20 | public const string PLUGIN_GUID = "com.elitemastereric.coroner"; 21 | } 22 | 23 | [BepInPlugin(PluginInfo.PLUGIN_GUID, PluginInfo.PLUGIN_NAME, PluginInfo.PLUGIN_VERSION)] 24 | // [BepInDependency("LethalNetworkAPI")] 25 | [BepInDependency(StaticNetcodeLib.MyPluginInfo.PLUGIN_GUID, DependencyFlags.HardDependency)] 26 | public class Plugin : BaseUnityPlugin 27 | { 28 | // Variables instantiated in Awake() should never be null. 29 | #nullable disable 30 | public static Plugin Instance { get; private set; } 31 | 32 | public static readonly Random RANDOM = new Random(); 33 | 34 | public PluginLogger PluginLogger; 35 | 36 | internal PluginConfig PluginConfig; 37 | 38 | internal LanguageHandler LanguageHandler; // Uses player selected language, default to English (American) 39 | internal LanguageHandler FallbackLanguageHandler; // Always uses English (American) 40 | #nullable enable 41 | 42 | public static string AssemblyDirectory 43 | { 44 | get 45 | { 46 | // TODO: Replace with Plugin.Info.Location 47 | string codeBase = Assembly.GetExecutingAssembly().CodeBase; 48 | UriBuilder uri = new UriBuilder(codeBase); 49 | string path = Uri.UnescapeDataString(uri.Path); 50 | return Path.GetDirectoryName(path); 51 | } 52 | } 53 | 54 | private void Awake() 55 | { 56 | Instance = this; 57 | 58 | PluginLogger = new PluginLogger(Logger); 59 | 60 | // Apply Harmony patches (if any exist) 61 | Harmony harmony = new Harmony(PluginInfo.PLUGIN_GUID); 62 | harmony.PatchAll(); 63 | 64 | // Plugin startup logic 65 | PluginLogger.LogInfo($"Plugin {PluginInfo.PLUGIN_NAME} ({PluginInfo.PLUGIN_GUID}) is loaded!"); 66 | 67 | LoadConfig(); 68 | LoadLanguageHandlers(); 69 | } 70 | 71 | public string GetConfigPath() 72 | { 73 | return $"{Paths.ConfigPath}/{PluginInfo.PLUGIN_AUTHOR}-{PluginInfo.PLUGIN_NAME}"; 74 | } 75 | 76 | public void LoadLanguageHandlers() 77 | { 78 | LanguageHandler = new LanguageHandler(PluginConfig.GetSelectedLanguage()); 79 | FallbackLanguageHandler = new LanguageHandler(LanguageHandler.DEFAULT_LANGUAGE, true); 80 | } 81 | 82 | private void LoadConfig() 83 | { 84 | PluginConfig = new PluginConfig(); 85 | PluginConfig.BindConfig(Config); 86 | } 87 | } 88 | 89 | public class PluginLogger 90 | { 91 | ManualLogSource manualLogSource; 92 | 93 | public PluginLogger(ManualLogSource manualLogSource) 94 | { 95 | this.manualLogSource = manualLogSource; 96 | } 97 | 98 | public void LogFatal(object data) 99 | { 100 | manualLogSource.LogFatal(data); 101 | } 102 | 103 | public void LogError(object data) 104 | { 105 | manualLogSource.LogError(data); 106 | } 107 | 108 | public void LogWarning(object data) 109 | { 110 | manualLogSource.LogWarning(data); 111 | } 112 | 113 | public void LogMessage(object data) 114 | { 115 | manualLogSource.LogMessage(data); 116 | } 117 | 118 | public void LogInfo(object data) 119 | { 120 | manualLogSource.LogInfo(data); 121 | } 122 | 123 | public void LogDebug(object data) 124 | { 125 | manualLogSource.LogDebug(data); 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /Coroner/PluginConfig.cs: -------------------------------------------------------------------------------- 1 | using BepInEx.Configuration; 2 | 3 | #nullable enable 4 | 5 | namespace Coroner 6 | { 7 | class PluginConfig 8 | { 9 | // Config entries are null until bound. 10 | ConfigEntry? DisplayCauseOfDeath = null; 11 | ConfigEntry? SeriousDeathMessages = null; 12 | ConfigEntry? DisplayFunnyNotes = null; 13 | ConfigEntry? DeathReplacesNotes = null; 14 | ConfigEntry? LanguagePicker = null; 15 | 16 | // Constructor 17 | public PluginConfig() 18 | { 19 | } 20 | 21 | // Bind config values to fields 22 | public void BindConfig(ConfigFile _config) 23 | { 24 | DisplayCauseOfDeath = _config.Bind("General", "DisplayCauseOfDeath", true, "Display the cause of death in the player notes."); 25 | SeriousDeathMessages = _config.Bind("General", "SeriousDeathMessages", false, "Cause of death messages are more to-the-point."); 26 | DisplayFunnyNotes = _config.Bind("General", "DisplayFunnyNotes", true, "Display a random note when the player has no notes."); 27 | DeathReplacesNotes = _config.Bind("General", "DeathReplacesNotes", true, "True to replace notes when the player dies, false to append."); 28 | 29 | LanguagePicker = _config.Bind("Language", "LanguagePicker", "en-us", "Select a language to use.");// + LanguageHandler.GetLanguageList()); 30 | } 31 | 32 | public bool ShouldDisplayCauseOfDeath() 33 | { 34 | if (DisplayCauseOfDeath == null) { 35 | Plugin.Instance.PluginLogger.LogWarning("Invalid access to uninstantiated config value DisplayCauseOfDeath"); 36 | return true; // default value 37 | } 38 | return DisplayCauseOfDeath.Value; 39 | } 40 | 41 | public bool ShouldUseSeriousDeathMessages() 42 | { 43 | if (SeriousDeathMessages == null) { 44 | Plugin.Instance.PluginLogger.LogWarning("Invalid access to uninstantiated config value SeriousDeathMessages"); 45 | return false; // default value 46 | } 47 | return SeriousDeathMessages.Value; 48 | } 49 | 50 | public bool ShouldDisplayFunnyNotes() 51 | { 52 | if (DisplayFunnyNotes == null) { 53 | Plugin.Instance.PluginLogger.LogWarning("Invalid access to uninstantiated config value DisplayFunnyNotes"); 54 | return true; // default value 55 | } 56 | return DisplayFunnyNotes.Value; 57 | } 58 | 59 | public bool ShouldDeathReplaceNotes() 60 | { 61 | if (DeathReplacesNotes == null) { 62 | Plugin.Instance.PluginLogger.LogWarning("Invalid access to uninstantiated config value DeathReplacesNotes"); 63 | return true; // default value 64 | } 65 | return DeathReplacesNotes.Value; 66 | } 67 | 68 | public string GetSelectedLanguage() 69 | { 70 | if (LanguagePicker == null) { 71 | Plugin.Instance.PluginLogger.LogWarning("Invalid access to uninstantiated config value LanguagePicker"); 72 | return "en-us"; // default value 73 | } 74 | return LanguagePicker.Value.Replace('_', '-'); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /LanguageData/Strings_de.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | -------------------------------------------------------------------------------- /LanguageData/Strings_es.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 101 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 126 | 127 | 128 | 129 | 130 | 131 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | -------------------------------------------------------------------------------- /LanguageData/Strings_fr.xml: -------------------------------------------------------------------------------- 1 |  2 | 4 | 5 | 6 | 7 | 8 | 19 | 20 | 21 | 22 | 23 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 223 | 224 | 225 | 226 | 227 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | -------------------------------------------------------------------------------- /LanguageData/Strings_hu.xml: -------------------------------------------------------------------------------- 1 |  2 | 4 | 5 | 6 | 7 | 8 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | -------------------------------------------------------------------------------- /LanguageData/Strings_it.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 18 | 19 | 20 | 21 | 22 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 162 | 163 | 164 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | -------------------------------------------------------------------------------- /LanguageData/Strings_ko.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | -------------------------------------------------------------------------------- /LanguageData/Strings_nl.xml: -------------------------------------------------------------------------------- 1 |  2 | 4 | 5 | 6 | 7 | 8 | 9 | 19 | 20 | 21 | 22 | 23 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 202 | 203 | 204 | 205 | 206 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | -------------------------------------------------------------------------------- /LanguageData/Strings_pt-br.xml: -------------------------------------------------------------------------------- 1 |  2 | 4 | 5 | 6 | 7 | 8 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | -------------------------------------------------------------------------------- /LanguageData/Strings_ru.xml: -------------------------------------------------------------------------------- 1 |  2 | 4 | 5 | 6 | 7 | 8 | 18 | 19 | 20 | 21 | 22 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 226 | 227 | 228 | 229 | 230 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | -------------------------------------------------------------------------------- /LanguageData/Strings_zh-cn.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 18 | 19 | 20 | 21 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | -------------------------------------------------------------------------------- /MODDING.md: -------------------------------------------------------------------------------- 1 | # Modding Support 2 | 3 | As of v2.1.0, Coroner provides an API which allows other mods and their developers (such as [CoronerMimics](https://thunderstore.io/c/lethal-company/p/EliteMasterEric/CoronerMimics/)) to access, create, and assign a player's cause of death. Players are also able to create or edit their own custom death messages via a mod, which can be shared to others by including it in a modpack (such as on [Thunderstore](https://thunderstore.io/c/lethal-company/?section=modpacks)), or by distributing the mod directly. 4 | 5 | ## Adding or Replacing Language Strings 6 | To begin, follow these instructions for both adding and replacing: 7 | 1. Create a new Thunderstore mod. For more information, check H3VR Modding Wiki's [guide to creating a Thunderstore mod/package](https://h3vr-modding.github.io/wiki/creating/thunderstore/uploading.html#manual-creation) from the **Manual Creation** section. 8 | 2. Create a folder `yourmod/BepInEx/config/EliteMasterEric-Coroner` in your mod's folder (where the `yourmod` folder has `manifest.json`). 9 | 10 | > **NOTE:** It is important to update your mod whenever there is an update to Lethal Company which adds a new way of dying, otherwise the mod will use its default values for death messages. 11 | 12 | ### Adding New Language Strings 13 | 14 | 1. Create the file `Strings__.xml` in the folder `EliteMasterEric-Coroner`. Replace `` with the language you want to target (most commonly `en-us`) and `` with something unique. You should end up with a folder structure like this: 15 | 16 | ``` 17 | yourmod/ 18 | BepInEx/config/EliteMasterEric-Coroner/Strings__.xml 19 | icon.png 20 | manifest.json 21 | README.md 22 | ``` 23 | 2. Add the following code to the file `Strings__.xml`: 24 | 25 | ```xml 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | ``` 39 | 40 | 3. Add tags in the `` section with the values you want to replace. For all available tags, see [`Strings_en-us.xml`](https://github.com/EliteMasterEric/Coroner/blob/master/LanguageData/Strings_en-us.xml). 41 | 4. You're done! Whenever your mod is installed alongside Coroner, all `Strings_.xml` and `Strings__.xml` files will be added together into one xml file in memory and Coroner will pick a death message from the combined file. 42 | 43 | ### Replacing Existing Language Strings 44 | 45 | 1. Create the file `Strings_.xml` in the folder `EliteMasterEric-Coroner`. Replace `` with the language you want to target (most commonly `en-us`). You should end up with a folder structure like this: 46 | 47 | ``` 48 | yourmod/ 49 | BepInEx/config/EliteMasterEric-Coroner/Strings_.xml 50 | icon.png 51 | manifest.json 52 | README.md 53 | ``` 54 | 2. Copy the contents of the language you want to target (most commonly [`Strings_en-us.xml`](https://github.com/EliteMasterEric/Coroner/blob/master/LanguageData/Strings_en-us.xml)) into `Strings_.xml`. 55 | 3. Modify the language file as desired. 56 | 4. You're done! Whenever your mod is installed alongside Coroner, all death messages from your mod will replace the death messages that were included with the mod's default language file for your targeted language. 57 | 58 | ## Creating Custom Causes of Death 59 | 60 | This is the most common operation to perform with Coroner's API. 61 | 62 | First, build a new AdvancedCauseOfDeath, and store it statically so it can be used later. 63 | 64 | ```cs 65 | static const MIMIC_LANGUAGE_KEY = "Enemy_Mimic"; 66 | static AdvancedCauseOfDeath MIMIC = Coroner.API.Register(MIMIC_LANGUAGE_KEY); 67 | ``` 68 | 69 | Then, when the player dies, apply this cause of death for the player: 70 | 71 | ```cs 72 | Coroner.API.SetCauseOfDeath(player, MIMIC); 73 | ``` 74 | 75 | ### Adding Language Strings 76 | 77 | The above will currently display `{Enemy_Mimic}` as the cause of death rather than your desired string. You need to provide an XML config which includes your language strings: 78 | 79 | In `BepInEx/config/EliteMasterEric-Coroner/` in your mod upload, create a file named `Strings__.xml`, where `` should be the language code you want (`en-us` is the English (American) language and the default for most players) and `suffix` is a value of your choice (try to choose something that another mod won't use on accident). Add tags to `` for each cause of death you want to add. You can include multiple tags for each cause of death and the game will randomize between them. 80 | 81 | ```xml 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | ``` 94 | 95 | ## List of Methods 96 | 97 | - `Coroner.API.Register(string key)` 98 | - Registers a new cause of death that uses a given language key. 99 | - Returns: An `AdvancedCauseOfDeath` corresponding to the new cause of death. Store this statically and reuse it. 100 | - `Coroner.API.IsRegistered(string key)` 101 | - Check whether a given language key is already registered. 102 | - Returns: A boolean value. 103 | - `Coroner.API.GetCauseOfDeath(int playerId)` 104 | - Retrieves the currently known cause of death for the player by their client ID, if any. 105 | - Returns: An `AdvancedCauseOfDeath`, or `null` if no cause of death is known. 106 | - `Coroner.API.GetCauseOfDeath(PlayerControllerB player)` 107 | - Retrieves the currently known cause of death for the player by reference, if any. 108 | - Returns: An `AdvancedCauseOfDeath`, or `null` if no cause of death is known. 109 | - `Coroner.API.SetCauseOfDeath(PlayerControllerB player, AdvancedCauseOfDeath? causeOfDeath)` 110 | - Applies a given cause of death to the player by their client ID. 111 | - Provide the `AdvancedCauseOfDeath` via argument. `AdvancedCauseOfDeath` has static constants for all the vanilla causes of death, or you can use one created by `Coroner.API.Register()`. 112 | - `Coroner.API.SetCauseOfDeath(int playerId, AdvancedCauseOfDeath? causeOfDeath)` 113 | - Applies a given cause of death to the player by reference. 114 | - Provide the `AdvancedCauseOfDeath` via argument. `AdvancedCauseOfDeath` has static constants for all the vanilla causes of death, or you can use one created by `Coroner.API.Register()`. 115 | - `Coroner.API.StringifyCauseOfDeath(AdvancedCauseOfDeath causeOfDeath, Random? random)` 116 | - Translate a cause of death to the user's current language. 117 | - Pass this the result of `Coroner.API.GetCauseOfDeath()` for best results. 118 | - The `Random` argument is optional, only pass it in if you need to modify how language strings are chosen. The default works well and syncs properly across clients. 119 | 120 | ## Issues 121 | Report any issues on the [Lethal Company Modding Discord](https://discord.gg/lcmod) or via the [GitHub Issue Tracker](https://github.com/EliteMasterEric/Coroner/issues). -------------------------------------------------------------------------------- /NuGet.Config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Coroner 2 | A Lethal Company plugin which overhauls the end-of-mission performance report with new information, including cause of death for any deceased players with some fun easter eggs thrown in too. Available to download from [Thunderstore](https://thunderstore.io/c/lethal-company/p/EliteMasterEric/Coroner/) or view the source code on [GitHub](https://github.com/EliteMasterEric/Coroner). 3 | 4 | > **NOTE:** If you have issues when using foreign language fonts, install FontFixer via [Thunderstore](https://thunderstore.io/c/lethal-company/p/EliteMasterEric/FontFixer/) or [GitHub](https://github.com/EliteMasterEric/FontFixer) BEFORE reporting. 5 | 6 | ![](https://raw.githubusercontent.com/EliteMasterEric/Coroner/master/Art/README_nutcracker.png) 7 | 8 | ### Issues 9 | If you encounter any issues with the mod, please report them on the [Lethal Company Modding Discord](https://discord.gg/lcmod) or via the [GitHub Issue Tracker](https://github.com/EliteMasterEric/Coroner/issues). Please ensure you check for known issues on the [GitHub Issue Tracker](https://github.com/EliteMasterEric/Coroner/issues) or [`CHANGELOG.md`](https://github.com/EliteMasterEric/Coroner/blob/master/CHANGELOG.md) BEFORE reporting. 10 | 11 | # Translations and Customization 12 | ## Translations 13 | Coroner has support for multiple languages, and you're able to create your own translations if they're inaccurate or your language isn't available! Choose your language's code from the [List of Available Translations](https://github.com/EliteMasterEric/Coroner/blob/master/TRANSLATING.md#list-of-available-translations), and edit the `LanguagePicker` option in the config file for the mod (or use the [Thunderstore app](https://www.overwolf.com/app/Thunderstore-Thunderstore_Mod_Manager)/[R2modman](https://r2modman.net/) config editor). 14 | 15 | For more information on translations, or how to add/edit your language, please check [`TRANSLATING.md`](https://github.com/EliteMasterEric/Coroner/blob/master/TRANSLATING.md). 16 | 17 | ## Create or Edit Custom Death Messages 18 | 19 | Coroner provides the ability to add or replace the death messages provided in the default languages, and these edits can be shared with your friends via a user created mod. Check out [this guide](https://github.com/EliteMasterEric/Coroner/blob/master/MODDING.md#replacing-language-strings) for more information. 20 | 21 | It is urged that you follow this guide and **do not** reupload Coroner to Thunderstore in order to make changes to the language files. It will cause you, your friends, and others to use an outdated version of the mod, which harms development and may have severe impacts on gameplay, performance, and security. 22 | 23 | # Mod Dependencies and Compatibility 24 | ## Dependencies 25 | - [BepInExPack](https://thunderstore.io/c/lethal-company/p/BepInEx/BepInExPack/) (5.4.2100) by [BepInEx](https://thunderstore.io/c/lethal-company/p/BepInEx/) 26 | - [StaticNetcodeLib](https://thunderstore.io/c/lethal-company/p/xilophor/StaticNetcodeLib/) (1.1.1) by [Xilophor](https://github.com/Xilophor/) 27 | ## Compatibility 28 | - Compatible with [More Company](https://thunderstore.io/c/lethal-company/p/notnotnotswipez/MoreCompany), and its changes to the performance report 29 | - Incompatible with Bigger Company, as it disables performance reports 30 | 31 | # Credits 32 | - [EliteMasterEric](https://github.com/EliteMasterEric): Programming 33 | - [Ceva](https://twitter.com/cevaskullderg): Playtesting 34 | - [Lynn Koya](https://gaywhiteboy.newgrounds.com/): Additional death message 35 | - [NickolasFleim](https://github.com/NickolasFleim): Programming (custom language support) 36 | - [Jatc251](https://jatc251.com): Miscellaneous cleanup of README.md, TRANSLATING.md, MODDING.md, and repository 37 | - All [contributors](https://github.com/EliteMasterEric/Coroner/blob/master/TRANSLATING.md) who added or helped improve their language's translations 38 | - [Xilophor](https://github.com/Xilophor/): Creating [StaticNetcodeLib](https://thunderstore.io/c/lethal-company/p/xilophor/StaticNetcodeLib/) 39 | - [giosuel](https://github.com/giosuel): Creating [Imperium](https://thunderstore.io/c/lethal-company/p/giosuel/Imperium/) which kept us sane during playtesting 40 | -------------------------------------------------------------------------------- /Releases/build.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | REM Copy ../Art/icon.png to the current directory 4 | copy /y ..\Art\icon.png . 5 | REM Copy ../Art/manifest.json to the current directory 6 | copy /y ..\Art\manifest.json . 7 | REM Copy ../README.md to the current directory 8 | copy /y ..\README.md . 9 | REM Copy ../CHANGELOG.md to the current directory 10 | copy /y ..\CHANGELOG.md . 11 | REM Copy all files from ../Coroner/build/bin/Debug to the current directory 12 | xcopy /s /y /q ..\Coroner\build\bin\Debug\* .\ 13 | REM Copy Strings_* files from ../Coroner to the current directory, excluding Strings_test.xml 14 | xcopy /s /y /q ..\LanguageData\* .\BepInEx\config\EliteMasterEric-Coroner\ 15 | 16 | REM Create a zip file named Coroner.zip containing all files (except build.bat and Strings_test.xml) in the current directory 17 | "C:\Program Files\7-Zip\7z.exe" a -r Coroner.zip * -x!build.bat -x!Coroner.zip 18 | 19 | for %%I in (*) do if not "%%I"=="Coroner.zip" if not "%%I"=="build.bat" del /q "%%I" 20 | for /d %%D in (*) do if not "%%D"=="Coroner.zip" if not "%%D"=="build.bat" rd /s /q "%%D" -------------------------------------------------------------------------------- /TRANSLATING.md: -------------------------------------------------------------------------------- 1 | # Translating 2 | In order to create a translation, create a copy of the [`Strings_en.xml`](https://github.com/EliteMasterEric/Coroner/blob/master/LanguageData/Strings_en.xml) file and change the file name to replace the `en` with your language's code from [ISO 639-1](https://www.iso.org/iso-639-language-code). A list of these codes can be easily found and searched via [this list on Wikipedia](https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes). It's best to copy from the English translation as it will always be the most up to date version of the translation values. If your language isn't apart of ISO 639-1, choose a two-character code (or append a two-character code if you're creating a translation for a locale, such as Simplified (`zh-cn`) or Traditional (`zh-tw`) Chinese, or American (`en-us`) or British (`en-uk`) English) which most accurately represents your language, provided it isn't already used in ISO 639-1. 3 | 4 | When you've finalized your translation, ensure that you add or edit your translation's information (such as version) below under the [List of Available Translations](https://github.com/EliteMasterEric/Coroner/blob/master/TRANSLATING.md#list-of-available-translations), as well as adding yourself to the contributors with a link to your GitHub profile. 5 | 6 | # Create or Edit Custom Death Messages 7 | If you're trying to create your own variation of an already added language, please check [`MODDING.md`]("https://github.com/EliteMasterEric/Coroner/blob/master/MODDING.md#adding-or-replacing-language-strings") for more information on how to add or replace text in an already created translation. 8 | 9 | # List of Available Translations 10 | Below is a list of currently included languages, the version of the translation, and their contributor(s). Any language which isn't on the latest version is in need of translation. To join the list, create or edit a translation and submit a [pull request](https://github.com/EliteMasterEric/Coroner/pulls)! 11 | 12 | - English (American) (`en-us`) [v4] | [EliteMasterEric](https://github.com/EliteMasterEric), [Thundermaker300](https://github.com/Thundermaker300/Coroner) 13 | - Chinese (Simplified) (`zh-cn`) [v2] | [RAINighty (颜绎)](https://github.com/RAINighty) 14 | - Dutch (`nl`) [v4] | [Ceva](https://twitter.com/cevaskullderg) 15 | - French (`fr`) [v4] | Fleetway, [AlexandrinFR (Alexandrin)](https://github.com/AlexandrinFR) 16 | - German (`de`) [v0] | [YoBii](https://github.com/YoBii) 17 | - Hungarian (`hu`) [v0] | [Kultercode (Kristóf Juhász)](https://github.com/Kultercode) 18 | - Italian (`it`) [v1] | [MakinDay (Federico G.)](https://github.com/MakinDay) 19 | - Korean (`ko`) [v0] | [sgkill8 (킬육)](https://github.com/sgkill6) 20 | - Portuguese (Brazil) (`pt-br`) [v0] | Foxeru 21 | - Russian (`ru`) [v4] | [NickolasFleim](https://github.com/NickolasFleim), [D4N9 (D4N9-Twitch)](https://github.com/D4N9-Twitch) 22 | - Spanish (`es`) [v0] | Helado de Pato 23 | - Debug (`test`) [v3] 24 | 25 | # Versions of Translations 26 | Please ensure when creating or amending a translation that the correct version number is noted at the top of the translation's file. 27 | ### v4 28 | - Added v64 death messages 29 | ### v3 30 | - Added v60 death messages 31 | - Added specific pit death messages 32 | ### v2 33 | - Added v50/55 death messages 34 | ### v1 35 | - Added translation notes to assist translators 36 | ### v0 37 | --------------------------------------------------------------------------------