├── .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 | 
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 |
--------------------------------------------------------------------------------